Add Order repositories, prepping Stripe integration

This commit is contained in:
lumijiez
2025-06-17 15:22:55 +03:00
parent 40906bea78
commit 64a50a61a4
9 changed files with 638 additions and 6 deletions

View File

@@ -0,0 +1,69 @@
using FluentValidation;
using Imprink.Domain.Models;
namespace Imprink.Application.Validation.Models;
public class OrderFilterParametersValidator : AbstractValidator<OrderFilterParameters>
{
public OrderFilterParametersValidator()
{
RuleFor(x => x.PageNumber)
.GreaterThan(0).WithMessage("PageNumber must be greater than 0.");
RuleFor(x => x.PageSize)
.InclusiveBetween(1, 100).WithMessage("PageSize must be between 1 and 100.");
RuleFor(x => x.UserId)
.Length(1, 450).WithMessage("UserId length must be between 1 and 450 characters.")
.When(x => !string.IsNullOrWhiteSpace(x.UserId));
RuleFor(x => x.OrderNumber)
.Length(1, 50).WithMessage("OrderNumber length must be between 1 and 50 characters.")
.When(x => !string.IsNullOrWhiteSpace(x.OrderNumber));
RuleFor(x => x.OrderStatusId)
.GreaterThan(0).When(x => x.OrderStatusId.HasValue)
.WithMessage("OrderStatusId must be greater than 0.");
RuleFor(x => x.ShippingStatusId)
.GreaterThan(0).When(x => x.ShippingStatusId.HasValue)
.WithMessage("ShippingStatusId must be greater than 0.");
RuleFor(x => x.StartDate)
.LessThanOrEqualTo(DateTime.UtcNow.AddDays(1)).When(x => x.StartDate.HasValue)
.WithMessage("StartDate cannot be in the future.");
RuleFor(x => x.EndDate)
.LessThanOrEqualTo(DateTime.UtcNow.AddDays(1)).When(x => x.EndDate.HasValue)
.WithMessage("EndDate cannot be in the future.");
RuleFor(x => x)
.Must(x => !x.StartDate.HasValue || !x.EndDate.HasValue || x.StartDate <= x.EndDate)
.WithMessage("StartDate cannot be greater than EndDate.");
RuleFor(x => x.MinTotalPrice)
.GreaterThanOrEqualTo(0).When(x => x.MinTotalPrice.HasValue)
.WithMessage("MinTotalPrice cannot be negative.");
RuleFor(x => x.MaxTotalPrice)
.GreaterThanOrEqualTo(0).When(x => x.MaxTotalPrice.HasValue)
.WithMessage("MaxTotalPrice cannot be negative.");
RuleFor(x => x)
.Must(x => !x.MinTotalPrice.HasValue || !x.MaxTotalPrice.HasValue || x.MinTotalPrice <= x.MaxTotalPrice)
.WithMessage("MinTotalPrice cannot be greater than MaxTotalPrice.");
RuleFor(x => x.SortBy)
.NotEmpty().WithMessage("SortBy is required.")
.Must(value => AllowedSortColumns.Contains(value, StringComparer.OrdinalIgnoreCase))
.WithMessage("SortBy must be one of: OrderDate, TotalPrice, OrderNumber.");
RuleFor(x => x.SortDirection)
.NotEmpty().WithMessage("SortDirection is required.")
.Must(value => value.Equals("ASC", StringComparison.OrdinalIgnoreCase)
|| value.Equals("DESC", StringComparison.OrdinalIgnoreCase))
.WithMessage("SortDirection must be 'ASC' or 'DESC'.");
}
private static readonly string[] AllowedSortColumns = ["OrderDate", "TotalPrice", "OrderNumber"];
}

View File

@@ -1,6 +1,5 @@
using FluentValidation;
using Imprink.Application.Domains.Products;
using Imprink.Application.Products;
using Imprink.Application.Validation.Models;
namespace Imprink.Application.Validation.Products;

View File

@@ -10,8 +10,4 @@
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="9.0.4" />
</ItemGroup>
<ItemGroup>
<Folder Include="Repositories\Orders\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,46 @@
namespace Imprink.Domain.Models;
public class OrderFilterParameters
{
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
public string? UserId { get; set; }
public string? OrderNumber { get; set; }
public int? OrderStatusId { get; set; }
public int? ShippingStatusId { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public decimal? MinTotalPrice { get; set; }
public decimal? MaxTotalPrice { get; set; }
public string SortBy { get; set; } = "OrderDate";
public string SortDirection { get; set; } = "DESC";
public bool IsValidDateRange()
{
if (StartDate.HasValue && EndDate.HasValue)
{
return StartDate.Value <= EndDate.Value;
}
return true;
}
public bool IsValidPriceRange()
{
if (MinTotalPrice.HasValue && MaxTotalPrice.HasValue)
{
return MinTotalPrice.Value <= MaxTotalPrice.Value;
}
return true;
}
}

View File

@@ -0,0 +1,27 @@
using Imprink.Domain.Entities.Orders;
namespace Imprink.Domain.Repositories.Orders;
public interface IOrderItemRepository
{
Task<OrderItem?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<OrderItem?> GetByIdWithProductAsync(Guid id, CancellationToken cancellationToken = default);
Task<OrderItem?> GetByIdWithVariantAsync(Guid id, CancellationToken cancellationToken = default);
Task<OrderItem?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default);
Task<IEnumerable<OrderItem>> GetByOrderIdAsync(Guid orderId, CancellationToken cancellationToken = default);
Task<IEnumerable<OrderItem>> GetByOrderIdWithProductsAsync(Guid orderId, CancellationToken cancellationToken = default);
Task<IEnumerable<OrderItem>> GetByProductIdAsync(Guid productId, CancellationToken cancellationToken = default);
Task<IEnumerable<OrderItem>> GetByProductVariantIdAsync(Guid productVariantId, CancellationToken cancellationToken = default);
Task<IEnumerable<OrderItem>> GetCustomizedItemsAsync(CancellationToken cancellationToken = default);
Task<IEnumerable<OrderItem>> GetByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default);
Task<OrderItem> AddAsync(OrderItem orderItem, CancellationToken cancellationToken = default);
Task<IEnumerable<OrderItem>> AddRangeAsync(IEnumerable<OrderItem> orderItems, CancellationToken cancellationToken = default);
Task<OrderItem> UpdateAsync(OrderItem orderItem, CancellationToken cancellationToken = default);
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
Task DeleteByOrderIdAsync(Guid orderId, CancellationToken cancellationToken = default);
Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default);
Task<decimal> GetTotalValueByOrderIdAsync(Guid orderId, CancellationToken cancellationToken = default);
Task<int> GetQuantityByProductIdAsync(Guid productId, CancellationToken cancellationToken = default);
Task<int> GetQuantityByVariantIdAsync(Guid productVariantId, CancellationToken cancellationToken = default);
Task<Dictionary<Guid, int>> GetProductSalesCountAsync(DateTime? startDate = null, DateTime? endDate = null, CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,27 @@
using Imprink.Domain.Entities.Orders;
using Imprink.Domain.Models;
namespace Imprink.Domain.Repositories.Orders;
public interface IOrderRepository
{
Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
Task<Order?> GetByIdWithItemsAsync(Guid id, CancellationToken cancellationToken = default);
Task<Order?> GetByIdWithAddressAsync(Guid id, CancellationToken cancellationToken = default);
Task<Order?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default);
Task<Order?> GetByOrderNumberAsync(string orderNumber, CancellationToken cancellationToken = default);
Task<PagedResult<Order>> GetPagedAsync(OrderFilterParameters filterParameters, CancellationToken cancellationToken = default);
Task<IEnumerable<Order>> GetByUserIdAsync(string userId, CancellationToken cancellationToken = default);
Task<IEnumerable<Order>> GetByUserIdPagedAsync(string userId, int pageNumber, int pageSize, CancellationToken cancellationToken = default);
Task<IEnumerable<Order>> GetByOrderStatusAsync(int orderStatusId, CancellationToken cancellationToken = default);
Task<IEnumerable<Order>> GetByShippingStatusAsync(int shippingStatusId, CancellationToken cancellationToken = default);
Task<IEnumerable<Order>> GetByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default);
Task<Order> AddAsync(Order order, CancellationToken cancellationToken = default);
Task<Order> UpdateAsync(Order order, CancellationToken cancellationToken = default);
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default);
Task<bool> OrderNumberExistsAsync(string orderNumber, Guid? excludeId = null, CancellationToken cancellationToken = default);
Task<decimal> GetTotalRevenueAsync(CancellationToken cancellationToken = default);
Task<decimal> GetTotalRevenueByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default);
Task<int> GetOrderCountByStatusAsync(int orderStatusId, CancellationToken cancellationToken = default);
}

View File

@@ -25,7 +25,6 @@
<ItemGroup>
<Folder Include="Migrations\" />
<Folder Include="Repositories\Orders\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,204 @@
using Imprink.Domain.Entities.Orders;
using Imprink.Domain.Repositories.Orders;
using Imprink.Infrastructure.Database;
using Microsoft.EntityFrameworkCore;
namespace Imprink.Infrastructure.Repositories.Orders;
public class OrderItemRepository(ApplicationDbContext context) : IOrderItemRepository
{
public async Task<OrderItem?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.FirstOrDefaultAsync(oi => oi.Id == id, cancellationToken);
}
public async Task<OrderItem?> GetByIdWithProductAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.Product)
.ThenInclude(p => p.Category)
.FirstOrDefaultAsync(oi => oi.Id == id, cancellationToken);
}
public async Task<OrderItem?> GetByIdWithVariantAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.ProductVariant)
.FirstOrDefaultAsync(oi => oi.Id == id, cancellationToken);
}
public async Task<OrderItem?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.Order)
.ThenInclude(o => o.User)
.Include(oi => oi.Product)
.ThenInclude(p => p.Category)
.Include(oi => oi.ProductVariant)
.FirstOrDefaultAsync(oi => oi.Id == id, cancellationToken);
}
public async Task<IEnumerable<OrderItem>> GetByOrderIdAsync(Guid orderId, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Where(oi => oi.OrderId == orderId)
.OrderBy(oi => oi.CreatedAt)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<OrderItem>> GetByOrderIdWithProductsAsync(Guid orderId, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.Product)
.ThenInclude(p => p.Category)
.Include(oi => oi.ProductVariant)
.Where(oi => oi.OrderId == orderId)
.OrderBy(oi => oi.CreatedAt)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<OrderItem>> GetByProductIdAsync(Guid productId, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.Order)
.Where(oi => oi.ProductId == productId)
.OrderByDescending(oi => oi.CreatedAt)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<OrderItem>> GetByProductVariantIdAsync(Guid productVariantId, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.Order)
.Where(oi => oi.ProductVariantId == productVariantId)
.OrderByDescending(oi => oi.CreatedAt)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<OrderItem>> GetCustomizedItemsAsync(CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.Product)
.Include(oi => oi.Order)
.Where(oi => !string.IsNullOrEmpty(oi.CustomizationImageUrl) || !string.IsNullOrEmpty(oi.CustomizationDescription))
.OrderByDescending(oi => oi.CreatedAt)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<OrderItem>> GetByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Include(oi => oi.Order)
.Include(oi => oi.Product)
.Where(oi => oi.Order.OrderDate >= startDate && oi.Order.OrderDate <= endDate)
.OrderByDescending(oi => oi.Order.OrderDate)
.ToListAsync(cancellationToken);
}
public Task<OrderItem> AddAsync(OrderItem orderItem, CancellationToken cancellationToken = default)
{
orderItem.Id = Guid.NewGuid();
orderItem.CreatedAt = DateTime.UtcNow;
orderItem.ModifiedAt = DateTime.UtcNow;
context.OrderItems.Add(orderItem);
return Task.FromResult(orderItem);
}
public Task<IEnumerable<OrderItem>> AddRangeAsync(IEnumerable<OrderItem> orderItems, CancellationToken cancellationToken = default)
{
var items = orderItems.ToList();
var utcNow = DateTime.UtcNow;
foreach (var item in items)
{
item.Id = Guid.NewGuid();
item.CreatedAt = utcNow;
item.ModifiedAt = utcNow;
}
context.OrderItems.AddRange(items);
return Task.FromResult<IEnumerable<OrderItem>>(items);
}
public Task<OrderItem> UpdateAsync(OrderItem orderItem, CancellationToken cancellationToken = default)
{
orderItem.ModifiedAt = DateTime.UtcNow;
context.OrderItems.Update(orderItem);
return Task.FromResult(orderItem);
}
public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
var orderItem = await GetByIdAsync(id, cancellationToken);
if (orderItem != null)
{
context.OrderItems.Remove(orderItem);
}
}
public async Task DeleteByOrderIdAsync(Guid orderId, CancellationToken cancellationToken = default)
{
var orderItems = await context.OrderItems
.Where(oi => oi.OrderId == orderId)
.ToListAsync(cancellationToken);
if (orderItems.Any())
{
context.OrderItems.RemoveRange(orderItems);
}
}
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.AnyAsync(oi => oi.Id == id, cancellationToken);
}
public async Task<decimal> GetTotalValueByOrderIdAsync(Guid orderId, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Where(oi => oi.OrderId == orderId)
.SumAsync(oi => oi.TotalPrice, cancellationToken);
}
public async Task<int> GetQuantityByProductIdAsync(Guid productId, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Where(oi => oi.ProductId == productId)
.SumAsync(oi => oi.Quantity, cancellationToken);
}
public async Task<int> GetQuantityByVariantIdAsync(Guid productVariantId, CancellationToken cancellationToken = default)
{
return await context.OrderItems
.Where(oi => oi.ProductVariantId == productVariantId)
.SumAsync(oi => oi.Quantity, cancellationToken);
}
public async Task<Dictionary<Guid, int>> GetProductSalesCountAsync(
DateTime? startDate = null,
DateTime? endDate = null,
CancellationToken cancellationToken = default)
{
var query = context.OrderItems
.Include(oi => oi.Order)
.AsQueryable();
if (startDate.HasValue)
{
query = query.Where(oi => oi.Order.OrderDate >= startDate.Value);
}
if (endDate.HasValue)
{
query = query.Where(oi => oi.Order.OrderDate <= endDate.Value);
}
return await query
.GroupBy(oi => oi.ProductId)
.Select(g => new { ProductId = g.Key, TotalQuantity = g.Sum(oi => oi.Quantity) })
.ToDictionaryAsync(x => x.ProductId, x => x.TotalQuantity, cancellationToken);
}
}

View File

@@ -0,0 +1,265 @@
using Imprink.Domain.Entities.Orders;
using Imprink.Domain.Models;
using Imprink.Domain.Repositories.Orders;
using Imprink.Infrastructure.Database;
using Microsoft.EntityFrameworkCore;
namespace Imprink.Infrastructure.Repositories.Orders;
public class OrderRepository(ApplicationDbContext context) : IOrderRepository
{
public async Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.Orders
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
}
public async Task<Order?> GetByIdWithItemsAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.Product)
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.ProductVariant)
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
}
public async Task<Order?> GetByIdWithAddressAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.OrderAddress)
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
}
public async Task<Order?> GetByIdFullAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.User)
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.Include(o => o.OrderAddress)
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.Product)
.ThenInclude(p => p.Category)
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.ProductVariant)
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
}
public async Task<Order?> GetByOrderNumberAsync(string orderNumber, CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.FirstOrDefaultAsync(o => o.OrderNumber == orderNumber, cancellationToken);
}
public async Task<PagedResult<Order>> GetPagedAsync(
OrderFilterParameters filterParameters,
CancellationToken cancellationToken = default)
{
var query = context.Orders
.Include(o => o.User)
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.AsQueryable();
if (!string.IsNullOrEmpty(filterParameters.UserId))
{
query = query.Where(o => o.UserId == filterParameters.UserId);
}
if (!string.IsNullOrEmpty(filterParameters.OrderNumber))
{
query = query.Where(o => o.OrderNumber.Contains(filterParameters.OrderNumber));
}
if (filterParameters.OrderStatusId.HasValue)
{
query = query.Where(o => o.OrderStatusId == filterParameters.OrderStatusId.Value);
}
if (filterParameters.ShippingStatusId.HasValue)
{
query = query.Where(o => o.ShippingStatusId == filterParameters.ShippingStatusId.Value);
}
if (filterParameters.StartDate.HasValue)
{
query = query.Where(o => o.OrderDate >= filterParameters.StartDate.Value);
}
if (filterParameters.EndDate.HasValue)
{
query = query.Where(o => o.OrderDate <= filterParameters.EndDate.Value);
}
if (filterParameters.MinTotalPrice.HasValue)
{
query = query.Where(o => o.TotalPrice >= filterParameters.MinTotalPrice.Value);
}
if (filterParameters.MaxTotalPrice.HasValue)
{
query = query.Where(o => o.TotalPrice <= filterParameters.MaxTotalPrice.Value);
}
query = filterParameters.SortBy.ToLower() switch
{
"orderdate" => filterParameters.SortDirection.Equals("DESC", StringComparison.CurrentCultureIgnoreCase)
? query.OrderByDescending(o => o.OrderDate)
: query.OrderBy(o => o.OrderDate),
"totalprice" => filterParameters.SortDirection.Equals("DESC", StringComparison.CurrentCultureIgnoreCase)
? query.OrderByDescending(o => o.TotalPrice)
: query.OrderBy(o => o.TotalPrice),
"ordernumber" => filterParameters.SortDirection.Equals("DESC", StringComparison.CurrentCultureIgnoreCase)
? query.OrderByDescending(o => o.OrderNumber)
: query.OrderBy(o => o.OrderNumber),
_ => query.OrderByDescending(o => o.OrderDate)
};
var totalCount = await query.CountAsync(cancellationToken);
var items = await query
.Skip((filterParameters.PageNumber - 1) * filterParameters.PageSize)
.Take(filterParameters.PageSize)
.ToListAsync(cancellationToken);
return new PagedResult<Order>
{
Items = items,
TotalCount = totalCount,
PageNumber = filterParameters.PageNumber,
PageSize = filterParameters.PageSize
};
}
public async Task<IEnumerable<Order>> GetByUserIdAsync(string userId, CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.Where(o => o.UserId == userId)
.OrderByDescending(o => o.OrderDate)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<Order>> GetByUserIdPagedAsync(
string userId,
int pageNumber,
int pageSize,
CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.Where(o => o.UserId == userId)
.OrderByDescending(o => o.OrderDate)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<Order>> GetByOrderStatusAsync(int orderStatusId, CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.User)
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.Where(o => o.OrderStatusId == orderStatusId)
.OrderByDescending(o => o.OrderDate)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<Order>> GetByShippingStatusAsync(int shippingStatusId, CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.User)
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.Where(o => o.ShippingStatusId == shippingStatusId)
.OrderByDescending(o => o.OrderDate)
.ToListAsync(cancellationToken);
}
public async Task<IEnumerable<Order>> GetByDateRangeAsync(
DateTime startDate,
DateTime endDate,
CancellationToken cancellationToken = default)
{
return await context.Orders
.Include(o => o.User)
.Include(o => o.OrderStatus)
.Include(o => o.ShippingStatus)
.Where(o => o.OrderDate >= startDate && o.OrderDate <= endDate)
.OrderByDescending(o => o.OrderDate)
.ToListAsync(cancellationToken);
}
public Task<Order> AddAsync(Order order, CancellationToken cancellationToken = default)
{
order.Id = Guid.NewGuid();
order.CreatedAt = DateTime.UtcNow;
order.ModifiedAt = DateTime.UtcNow;
context.Orders.Add(order);
return Task.FromResult(order);
}
public Task<Order> UpdateAsync(Order order, CancellationToken cancellationToken = default)
{
order.ModifiedAt = DateTime.UtcNow;
context.Orders.Update(order);
return Task.FromResult(order);
}
public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
{
var order = await GetByIdAsync(id, cancellationToken);
if (order != null)
{
context.Orders.Remove(order);
}
}
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
{
return await context.Orders
.AnyAsync(o => o.Id == id, cancellationToken);
}
public async Task<bool> OrderNumberExistsAsync(string orderNumber, Guid? excludeId = null, CancellationToken cancellationToken = default)
{
var query = context.Orders.Where(o => o.OrderNumber == orderNumber);
if (excludeId.HasValue)
{
query = query.Where(o => o.Id != excludeId.Value);
}
return await query.AnyAsync(cancellationToken);
}
public async Task<decimal> GetTotalRevenueAsync(CancellationToken cancellationToken = default)
{
return await context.Orders
.Where(o => o.OrderStatusId != 5) // Assuming 5 is cancelled status
.SumAsync(o => o.TotalPrice, cancellationToken);
}
public async Task<decimal> GetTotalRevenueByDateRangeAsync(
DateTime startDate,
DateTime endDate,
CancellationToken cancellationToken = default)
{
return await context.Orders
.Where(o => o.OrderDate >= startDate && o.OrderDate <= endDate && o.OrderStatusId != 5)
.SumAsync(o => o.TotalPrice, cancellationToken);
}
public async Task<int> GetOrderCountByStatusAsync(int orderStatusId, CancellationToken cancellationToken = default)
{
return await context.Orders
.CountAsync(o => o.OrderStatusId == orderStatusId, cancellationToken);
}
}