Add address/order handling
This commit is contained in:
@@ -11,7 +11,7 @@ public interface IUnitOfWork
|
|||||||
public IUserRoleRepository UserRoleRepository { get; }
|
public IUserRoleRepository UserRoleRepository { get; }
|
||||||
public IRoleRepository RoleRepository { get; }
|
public IRoleRepository RoleRepository { get; }
|
||||||
public IOrderRepository OrderRepository { get; }
|
public IOrderRepository OrderRepository { get; }
|
||||||
public IOrderItemRepository OrderItemRepository { get; }
|
public IAddressRepository AddressRepository { get; }
|
||||||
|
|
||||||
Task SaveAsync(CancellationToken cancellationToken = default);
|
Task SaveAsync(CancellationToken cancellationToken = default);
|
||||||
Task BeginTransactionAsync(CancellationToken cancellationToken = default);
|
Task BeginTransactionAsync(CancellationToken cancellationToken = default);
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ public class ProductMappingProfile: Profile
|
|||||||
.ForMember(dest => dest.ModifiedAt, opt => opt.Ignore())
|
.ForMember(dest => dest.ModifiedAt, opt => opt.Ignore())
|
||||||
.ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
|
.ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
|
||||||
.ForMember(dest => dest.ModifiedBy, opt => opt.Ignore())
|
.ForMember(dest => dest.ModifiedBy, opt => opt.Ignore())
|
||||||
.ForMember(dest => dest.Product, opt => opt.Ignore())
|
.ForMember(dest => dest.Product, opt => opt.Ignore());
|
||||||
.ForMember(dest => dest.OrderItems, opt => opt.Ignore());
|
|
||||||
|
|
||||||
CreateMap<ProductVariant, ProductVariantDto>();
|
CreateMap<ProductVariant, ProductVariantDto>();
|
||||||
CreateMap<ProductVariantDto, ProductVariant>()
|
CreateMap<ProductVariantDto, ProductVariant>()
|
||||||
.ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
|
.ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
|
||||||
.ForMember(dest => dest.ModifiedBy, opt => opt.Ignore())
|
.ForMember(dest => dest.ModifiedBy, opt => opt.Ignore());
|
||||||
.ForMember(dest => dest.OrderItems, opt => opt.Ignore());
|
|
||||||
|
|
||||||
CreateMap<Product, ProductDto>();
|
CreateMap<Product, ProductDto>();
|
||||||
|
|
||||||
@@ -34,8 +32,7 @@ public class ProductMappingProfile: Profile
|
|||||||
.ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
|
.ForMember(dest => dest.CreatedBy, opt => opt.Ignore())
|
||||||
.ForMember(dest => dest.ModifiedBy, opt => opt.Ignore())
|
.ForMember(dest => dest.ModifiedBy, opt => opt.Ignore())
|
||||||
.ForMember(dest => dest.Category, opt => opt.Ignore())
|
.ForMember(dest => dest.Category, opt => opt.Ignore())
|
||||||
.ForMember(dest => dest.ProductVariants, opt => opt.Ignore())
|
.ForMember(dest => dest.ProductVariants, opt => opt.Ignore());
|
||||||
.ForMember(dest => dest.OrderItems, opt => opt.Ignore());
|
|
||||||
|
|
||||||
CreateMap<Category, CategoryDto>();
|
CreateMap<Category, CategoryDto>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,22 @@ public class Address : EntityBase
|
|||||||
{
|
{
|
||||||
public required string UserId { get; set; }
|
public required string UserId { get; set; }
|
||||||
public required string AddressType { get; set; }
|
public required string AddressType { get; set; }
|
||||||
public required string Street { get; set; }
|
public string? FirstName { get; set; }
|
||||||
|
public string? LastName { get; set; }
|
||||||
|
public string? Company { get; set; }
|
||||||
|
public required string AddressLine1 { get; set; }
|
||||||
|
public string? AddressLine2 { get; set; }
|
||||||
|
public string? ApartmentNumber { get; set; }
|
||||||
|
public string? BuildingNumber { get; set; }
|
||||||
|
public string? Floor { get; set; }
|
||||||
public required string City { get; set; }
|
public required string City { get; set; }
|
||||||
public required string State { get; set; }
|
public required string State { get; set; }
|
||||||
public required string PostalCode { get; set; }
|
public required string PostalCode { get; set; }
|
||||||
public required string Country { get; set; }
|
public required string Country { get; set; }
|
||||||
|
public string? PhoneNumber { get; set; }
|
||||||
|
public string? Instructions { get; set; }
|
||||||
public required bool IsDefault { get; set; }
|
public required bool IsDefault { get; set; }
|
||||||
public required bool IsActive { get; set; }
|
public required bool IsActive { get; set; }
|
||||||
|
|
||||||
|
public virtual User User { get; set; } = null!;
|
||||||
}
|
}
|
||||||
@@ -4,15 +4,24 @@ public class Order : EntityBase
|
|||||||
{
|
{
|
||||||
public string UserId { get; set; } = null!;
|
public string UserId { get; set; } = null!;
|
||||||
public DateTime OrderDate { get; set; }
|
public DateTime OrderDate { get; set; }
|
||||||
public decimal TotalPrice { get; set; }
|
public decimal Amount { get; set; }
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
public Guid ProductId { get; set; }
|
||||||
|
public Guid? ProductVariantId { get; set; }
|
||||||
public int OrderStatusId { get; set; }
|
public int OrderStatusId { get; set; }
|
||||||
public int ShippingStatusId { get; set; }
|
public int ShippingStatusId { get; set; }
|
||||||
public string OrderNumber { get; set; } = null!;
|
public string OrderNumber { get; set; } = null!;
|
||||||
public string Notes { get; set; } = null!;
|
public string? Notes { get; set; }
|
||||||
|
public string? MerchantId { get; set; }
|
||||||
|
public string? ComposingImageUrl { get; set; }
|
||||||
|
public string[] OriginalImageUrls { get; set; } = [];
|
||||||
|
public string CustomizationImageUrl { get; set; } = null!;
|
||||||
|
public string CustomizationDescription { get; set; } = null!;
|
||||||
|
|
||||||
public OrderStatus OrderStatus { get; set; } = null!;
|
public OrderStatus OrderStatus { get; set; } = null!;
|
||||||
public User User { get; set; } = null!;
|
public User User { get; set; } = null!;
|
||||||
public ShippingStatus ShippingStatus { get; set; } = null!;
|
public ShippingStatus ShippingStatus { get; set; } = null!;
|
||||||
public OrderAddress OrderAddress { get; set; } = null!;
|
public OrderAddress OrderAddress { get; set; } = null!;
|
||||||
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
public Product Product { get; set; } = null!;
|
||||||
|
public ProductVariant? ProductVariant { get; set; }
|
||||||
}
|
}
|
||||||
@@ -3,11 +3,21 @@ namespace Imprink.Domain.Entities;
|
|||||||
public class OrderAddress : EntityBase
|
public class OrderAddress : EntityBase
|
||||||
{
|
{
|
||||||
public Guid OrderId { get; set; }
|
public Guid OrderId { get; set; }
|
||||||
public required string Street { get; set; }
|
public required string AddressType { get; set; }
|
||||||
|
public string? FirstName { get; set; }
|
||||||
|
public string? LastName { get; set; }
|
||||||
|
public string? Company { get; set; }
|
||||||
|
public required string AddressLine1 { get; set; }
|
||||||
|
public string? AddressLine2 { get; set; }
|
||||||
|
public string? ApartmentNumber { get; set; }
|
||||||
|
public string? BuildingNumber { get; set; }
|
||||||
|
public string? Floor { get; set; }
|
||||||
public required string City { get; set; }
|
public required string City { get; set; }
|
||||||
public required string State { get; set; }
|
public required string State { get; set; }
|
||||||
public required string PostalCode { get; set; }
|
public required string PostalCode { get; set; }
|
||||||
public required string Country { get; set; }
|
public required string Country { get; set; }
|
||||||
|
public string? PhoneNumber { get; set; }
|
||||||
|
public string? Instructions { get; set; }
|
||||||
|
|
||||||
public virtual required Order Order { get; set; }
|
public virtual required Order Order { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace Imprink.Domain.Entities;
|
|
||||||
|
|
||||||
public class OrderItem : EntityBase
|
|
||||||
{
|
|
||||||
public Guid OrderId { get; set; }
|
|
||||||
public Guid ProductId { get; set; }
|
|
||||||
public Guid? ProductVariantId { get; set; }
|
|
||||||
public int Quantity { get; set; }
|
|
||||||
public decimal UnitPrice { get; set; }
|
|
||||||
public decimal TotalPrice { get; set; }
|
|
||||||
public string CustomizationImageUrl { get; set; } = null!;
|
|
||||||
public string CustomizationDescription { get; set; } = null!;
|
|
||||||
|
|
||||||
public Order Order { get; set; } = null!;
|
|
||||||
public Product Product { get; set; } = null!;
|
|
||||||
public ProductVariant ProductVariant { get; set; } = null!;
|
|
||||||
}
|
|
||||||
@@ -12,5 +12,5 @@ public class Product : EntityBase
|
|||||||
|
|
||||||
public virtual required Category Category { get; set; }
|
public virtual required Category Category { get; set; }
|
||||||
public virtual ICollection<ProductVariant> ProductVariants { get; set; } = new List<ProductVariant>();
|
public virtual ICollection<ProductVariant> ProductVariants { get; set; } = new List<ProductVariant>();
|
||||||
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||||
}
|
}
|
||||||
@@ -12,5 +12,5 @@ public class ProductVariant : EntityBase
|
|||||||
public bool IsActive { get; set; }
|
public bool IsActive { get; set; }
|
||||||
|
|
||||||
public virtual required Product Product { get; set; }
|
public virtual required Product Product { get; set; }
|
||||||
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
|
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,15 @@ public class User
|
|||||||
public required string Email { get; set; }
|
public required string Email { get; set; }
|
||||||
public bool EmailVerified { get; set; }
|
public bool EmailVerified { get; set; }
|
||||||
|
|
||||||
public string? FirstName { get; set; } = null!;
|
public string? FirstName { get; set; }
|
||||||
public string? LastName { get; set; } = null!;
|
public string? LastName { get; set; }
|
||||||
public string? PhoneNumber { get; set; }
|
public string? PhoneNumber { get; set; }
|
||||||
public required bool IsActive { get; set; }
|
public required bool IsActive { get; set; }
|
||||||
|
|
||||||
public virtual ICollection<Address> Addresses { get; set; } = new List<Address>();
|
public virtual ICollection<Address> Addresses { get; set; } = new List<Address>();
|
||||||
public virtual ICollection<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
public virtual ICollection<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
||||||
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
|
||||||
|
public virtual ICollection<Order> MerchantOrders { get; set; } = new List<Order>();
|
||||||
|
|
||||||
public Address? DefaultAddress => Addresses.FirstOrDefault(a => a is { IsDefault: true, IsActive: true });
|
public Address? DefaultAddress => Addresses.FirstOrDefault(a => a is { IsDefault: true, IsActive: true });
|
||||||
public IEnumerable<Role> Roles => UserRoles.Select(ur => ur.Role);
|
public IEnumerable<Role> Roles => UserRoles.Select(ur => ur.Role);
|
||||||
|
|||||||
22
src/Imprink.Domain/Repositories/IAddressRepository.cs
Normal file
22
src/Imprink.Domain/Repositories/IAddressRepository.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using Imprink.Domain.Entities;
|
||||||
|
|
||||||
|
namespace Imprink.Domain.Repositories;
|
||||||
|
|
||||||
|
public interface IAddressRepository
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Address>> GetByUserIdAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
|
Task<IEnumerable<Address>> GetActiveByUserIdAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
|
Task<Address?> GetDefaultByUserIdAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
|
Task<IEnumerable<Address>> GetByUserIdAndTypeAsync(string userId, string addressType, CancellationToken cancellationToken = default);
|
||||||
|
Task<Address?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
||||||
|
Task<Address?> GetByIdAndUserIdAsync(Guid id, string userId, CancellationToken cancellationToken = default);
|
||||||
|
Task<Address> AddAsync(Address address, CancellationToken cancellationToken = default);
|
||||||
|
Task<Address> UpdateAsync(Address address, CancellationToken cancellationToken = default);
|
||||||
|
Task<bool> DeleteAsync(Guid id, CancellationToken cancellationToken = default);
|
||||||
|
Task<bool> DeleteByUserIdAsync(Guid id, string userId, CancellationToken cancellationToken = default);
|
||||||
|
Task SetDefaultAddressAsync(string userId, Guid addressId, CancellationToken cancellationToken = default);
|
||||||
|
Task DeactivateAddressAsync(Guid addressId, CancellationToken cancellationToken = default);
|
||||||
|
Task ActivateAddressAsync(Guid addressId, CancellationToken cancellationToken = default);
|
||||||
|
Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default);
|
||||||
|
Task<bool> IsUserAddressAsync(Guid id, string userId, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
using Imprink.Domain.Entities;
|
|
||||||
|
|
||||||
namespace Imprink.Domain.Repositories;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@@ -6,22 +6,24 @@ namespace Imprink.Domain.Repositories;
|
|||||||
public interface IOrderRepository
|
public interface IOrderRepository
|
||||||
{
|
{
|
||||||
Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
Task<Order?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
||||||
Task<Order?> GetByIdWithItemsAsync(Guid id, CancellationToken cancellationToken = default);
|
Task<Order?> GetByIdWithDetailsAsync(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<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>> GetByUserIdAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<Order>> GetByUserIdPagedAsync(string userId, int pageNumber, int pageSize, CancellationToken cancellationToken = default);
|
Task<IEnumerable<Order>> GetByUserIdWithDetailsAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<Order>> GetByOrderStatusAsync(int orderStatusId, CancellationToken cancellationToken = default);
|
Task<IEnumerable<Order>> GetByMerchantIdAsync(string merchantId, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<Order>> GetByShippingStatusAsync(int shippingStatusId, CancellationToken cancellationToken = default);
|
Task<IEnumerable<Order>> GetByMerchantIdWithDetailsAsync(string merchantId, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<Order>> GetByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default);
|
Task<IEnumerable<Order>> GetByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default);
|
||||||
|
Task<IEnumerable<Order>> GetByStatusAsync(int statusId, CancellationToken cancellationToken = default);
|
||||||
|
Task<IEnumerable<Order>> GetByShippingStatusAsync(int shippingStatusId, CancellationToken cancellationToken = default);
|
||||||
Task<Order> AddAsync(Order order, CancellationToken cancellationToken = default);
|
Task<Order> AddAsync(Order order, CancellationToken cancellationToken = default);
|
||||||
Task<Order> UpdateAsync(Order order, CancellationToken cancellationToken = default);
|
Task<Order> UpdateAsync(Order order, CancellationToken cancellationToken = default);
|
||||||
Task DeleteAsync(Guid id, CancellationToken cancellationToken = default);
|
Task<bool> DeleteAsync(Guid id, CancellationToken cancellationToken = default);
|
||||||
Task<bool> ExistsAsync(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<bool> IsOrderNumberUniqueAsync(string orderNumber, CancellationToken cancellationToken = default);
|
||||||
Task<decimal> GetTotalRevenueAsync(CancellationToken cancellationToken = default);
|
Task<bool> IsOrderNumberUniqueAsync(string orderNumber, Guid excludeOrderId, CancellationToken cancellationToken = default);
|
||||||
Task<decimal> GetTotalRevenueByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default);
|
Task<string> GenerateOrderNumberAsync(CancellationToken cancellationToken = default);
|
||||||
Task<int> GetOrderCountByStatusAsync(int orderStatusId, CancellationToken cancellationToken = default);
|
Task UpdateStatusAsync(Guid orderId, int statusId, CancellationToken cancellationToken = default);
|
||||||
|
Task UpdateShippingStatusAsync(Guid orderId, int shippingStatusId, CancellationToken cancellationToken = default);
|
||||||
|
Task AssignMerchantAsync(Guid orderId, string merchantId, CancellationToken cancellationToken = default);
|
||||||
|
Task UnassignMerchantAsync(Guid orderId, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
@@ -18,10 +18,31 @@ public class AddressConfiguration : EntityBaseConfiguration<Address>
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(50);
|
.HasMaxLength(50);
|
||||||
|
|
||||||
builder.Property(a => a.Street)
|
builder.Property(a => a.FirstName)
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(a => a.LastName)
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(a => a.Company)
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
builder.Property(a => a.AddressLine1)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(200);
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
builder.Property(a => a.AddressLine2)
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
builder.Property(a => a.ApartmentNumber)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
|
builder.Property(a => a.BuildingNumber)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
|
builder.Property(a => a.Floor)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
builder.Property(a => a.City)
|
builder.Property(a => a.City)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
@@ -37,6 +58,12 @@ public class AddressConfiguration : EntityBaseConfiguration<Address>
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(a => a.PhoneNumber)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
|
builder.Property(a => a.Instructions)
|
||||||
|
.HasMaxLength(500);
|
||||||
|
|
||||||
builder.Property(a => a.IsDefault)
|
builder.Property(a => a.IsDefault)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasDefaultValue(false);
|
.HasDefaultValue(false);
|
||||||
@@ -45,6 +72,12 @@ public class AddressConfiguration : EntityBaseConfiguration<Address>
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasDefaultValue(true);
|
.HasDefaultValue(true);
|
||||||
|
|
||||||
|
builder.HasOne(a => a.User)
|
||||||
|
.WithMany(u => u.Addresses)
|
||||||
|
.HasForeignKey(a => a.UserId)
|
||||||
|
.HasPrincipalKey(u => u.Id)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
builder.HasIndex(a => a.UserId)
|
builder.HasIndex(a => a.UserId)
|
||||||
.HasDatabaseName("IX_Address_UserId");
|
.HasDatabaseName("IX_Address_UserId");
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,35 @@ public class OrderAddressConfiguration : EntityBaseConfiguration<OrderAddress>
|
|||||||
builder.Property(oa => oa.OrderId)
|
builder.Property(oa => oa.OrderId)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
builder.Property(oa => oa.Street)
|
builder.Property(oa => oa.AddressType)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.FirstName)
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.LastName)
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.Company)
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.AddressLine1)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(200);
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.AddressLine2)
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.ApartmentNumber)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.BuildingNumber)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.Floor)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
builder.Property(oa => oa.City)
|
builder.Property(oa => oa.City)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
@@ -32,6 +57,12 @@ public class OrderAddressConfiguration : EntityBaseConfiguration<OrderAddress>
|
|||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.PhoneNumber)
|
||||||
|
.HasMaxLength(20);
|
||||||
|
|
||||||
|
builder.Property(oa => oa.Instructions)
|
||||||
|
.HasMaxLength(500);
|
||||||
|
|
||||||
builder.HasIndex(oa => oa.OrderId)
|
builder.HasIndex(oa => oa.OrderId)
|
||||||
.IsUnique()
|
.IsUnique()
|
||||||
.HasDatabaseName("IX_OrderAddress_OrderId");
|
.HasDatabaseName("IX_OrderAddress_OrderId");
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Text.Json;
|
||||||
using Imprink.Domain.Entities;
|
using Imprink.Domain.Entities;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
@@ -5,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|||||||
namespace Imprink.Infrastructure.Configuration;
|
namespace Imprink.Infrastructure.Configuration;
|
||||||
|
|
||||||
public class OrderConfiguration : EntityBaseConfiguration<Order>
|
public class OrderConfiguration : EntityBaseConfiguration<Order>
|
||||||
{
|
{
|
||||||
public override void Configure(EntityTypeBuilder<Order> builder)
|
public override void Configure(EntityTypeBuilder<Order> builder)
|
||||||
{
|
{
|
||||||
base.Configure(builder);
|
base.Configure(builder);
|
||||||
@@ -17,10 +18,17 @@ public class OrderConfiguration : EntityBaseConfiguration<Order>
|
|||||||
builder.Property(o => o.OrderDate)
|
builder.Property(o => o.OrderDate)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
builder.Property(o => o.TotalPrice)
|
builder.Property(o => o.Amount)
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("decimal(18,2)");
|
.HasColumnType("decimal(18,2)");
|
||||||
|
|
||||||
|
builder.Property(o => o.Quantity)
|
||||||
|
.IsRequired()
|
||||||
|
.HasDefaultValue(1);
|
||||||
|
|
||||||
|
builder.Property(o => o.ProductId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
builder.Property(o => o.OrderStatusId)
|
builder.Property(o => o.OrderStatusId)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
@@ -34,6 +42,26 @@ public class OrderConfiguration : EntityBaseConfiguration<Order>
|
|||||||
builder.Property(o => o.Notes)
|
builder.Property(o => o.Notes)
|
||||||
.HasMaxLength(1000);
|
.HasMaxLength(1000);
|
||||||
|
|
||||||
|
builder.Property(o => o.MerchantId)
|
||||||
|
.HasMaxLength(450);
|
||||||
|
|
||||||
|
builder.Property(o => o.ComposingImageUrl)
|
||||||
|
.HasMaxLength(1000);
|
||||||
|
|
||||||
|
builder.Property(o => o.OriginalImageUrls)
|
||||||
|
.HasConversion(
|
||||||
|
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
|
||||||
|
v => JsonSerializer.Deserialize<string[]>(v, (JsonSerializerOptions?)null) ?? Array.Empty<string>())
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
builder.Property(o => o.CustomizationImageUrl)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1000);
|
||||||
|
|
||||||
|
builder.Property(o => o.CustomizationDescription)
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2000);
|
||||||
|
|
||||||
builder.HasOne(o => o.OrderStatus)
|
builder.HasOne(o => o.OrderStatus)
|
||||||
.WithMany(os => os.Orders)
|
.WithMany(os => os.Orders)
|
||||||
.HasForeignKey(o => o.OrderStatusId)
|
.HasForeignKey(o => o.OrderStatusId)
|
||||||
@@ -55,6 +83,22 @@ public class OrderConfiguration : EntityBaseConfiguration<Order>
|
|||||||
.HasPrincipalKey(u => u.Id)
|
.HasPrincipalKey(u => u.Id)
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
builder.HasOne<User>()
|
||||||
|
.WithMany(u => u.MerchantOrders)
|
||||||
|
.HasForeignKey(o => o.MerchantId)
|
||||||
|
.HasPrincipalKey(u => u.Id)
|
||||||
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
|
builder.HasOne(o => o.Product)
|
||||||
|
.WithMany(p => p.Orders)
|
||||||
|
.HasForeignKey(o => o.ProductId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
builder.HasOne(o => o.ProductVariant)
|
||||||
|
.WithMany(pv => pv.Orders)
|
||||||
|
.HasForeignKey(o => o.ProductVariantId)
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
builder.HasIndex(o => o.UserId)
|
builder.HasIndex(o => o.UserId)
|
||||||
.HasDatabaseName("IX_Order_UserId");
|
.HasDatabaseName("IX_Order_UserId");
|
||||||
|
|
||||||
@@ -71,7 +115,22 @@ public class OrderConfiguration : EntityBaseConfiguration<Order>
|
|||||||
builder.HasIndex(o => o.ShippingStatusId)
|
builder.HasIndex(o => o.ShippingStatusId)
|
||||||
.HasDatabaseName("IX_Order_ShippingStatusId");
|
.HasDatabaseName("IX_Order_ShippingStatusId");
|
||||||
|
|
||||||
|
builder.HasIndex(o => o.MerchantId)
|
||||||
|
.HasDatabaseName("IX_Order_MerchantId");
|
||||||
|
|
||||||
|
builder.HasIndex(o => o.ProductId)
|
||||||
|
.HasDatabaseName("IX_Order_ProductId");
|
||||||
|
|
||||||
|
builder.HasIndex(o => o.ProductVariantId)
|
||||||
|
.HasDatabaseName("IX_Order_ProductVariantId");
|
||||||
|
|
||||||
builder.HasIndex(o => new { o.UserId, o.OrderDate })
|
builder.HasIndex(o => new { o.UserId, o.OrderDate })
|
||||||
.HasDatabaseName("IX_Order_User_Date");
|
.HasDatabaseName("IX_Order_User_Date");
|
||||||
|
|
||||||
|
builder.HasIndex(o => new { o.MerchantId, o.OrderDate })
|
||||||
|
.HasDatabaseName("IX_Order_Merchant_Date");
|
||||||
|
|
||||||
|
builder.HasIndex(o => new { o.ProductId, o.OrderDate })
|
||||||
|
.HasDatabaseName("IX_Order_Product_Date");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
using Imprink.Domain.Entities;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
||||||
|
|
||||||
namespace Imprink.Infrastructure.Configuration;
|
|
||||||
|
|
||||||
public class OrderItemConfiguration : EntityBaseConfiguration<OrderItem>
|
|
||||||
{
|
|
||||||
public override void Configure(EntityTypeBuilder<OrderItem> builder)
|
|
||||||
{
|
|
||||||
base.Configure(builder);
|
|
||||||
|
|
||||||
builder.Property(oi => oi.OrderId)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
builder.Property(oi => oi.ProductId)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
builder.Property(oi => oi.Quantity)
|
|
||||||
.IsRequired()
|
|
||||||
.HasDefaultValue(1);
|
|
||||||
|
|
||||||
builder.Property(oi => oi.UnitPrice)
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("decimal(18,2)");
|
|
||||||
|
|
||||||
builder.Property(oi => oi.TotalPrice)
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("decimal(18,2)");
|
|
||||||
|
|
||||||
builder.Property(oi => oi.CustomizationImageUrl)
|
|
||||||
.HasMaxLength(500);
|
|
||||||
|
|
||||||
builder.Property(oi => oi.CustomizationDescription)
|
|
||||||
.HasMaxLength(2000);
|
|
||||||
|
|
||||||
builder.HasOne(oi => oi.Order)
|
|
||||||
.WithMany(o => o.OrderItems)
|
|
||||||
.HasForeignKey(oi => oi.OrderId)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
builder.HasOne(oi => oi.Product)
|
|
||||||
.WithMany(p => p.OrderItems)
|
|
||||||
.HasForeignKey(oi => oi.ProductId)
|
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
|
||||||
|
|
||||||
builder.HasOne(oi => oi.ProductVariant)
|
|
||||||
.WithMany(pv => pv.OrderItems)
|
|
||||||
.HasForeignKey(oi => oi.ProductVariantId)
|
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
|
||||||
|
|
||||||
builder.HasIndex(oi => oi.OrderId)
|
|
||||||
.HasDatabaseName("IX_OrderItem_OrderId");
|
|
||||||
|
|
||||||
builder.HasIndex(oi => oi.ProductId)
|
|
||||||
.HasDatabaseName("IX_OrderItem_ProductId");
|
|
||||||
|
|
||||||
builder.HasIndex(oi => oi.ProductVariantId)
|
|
||||||
.HasDatabaseName("IX_OrderItem_ProductVariantId");
|
|
||||||
|
|
||||||
builder.HasIndex(oi => new { oi.OrderId, oi.ProductId })
|
|
||||||
.HasDatabaseName("IX_OrderItem_Order_Product");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,8 +25,7 @@ public class UserConfiguration : IEntityTypeConfiguration<User>
|
|||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
|
|
||||||
builder.Property(u => u.EmailVerified)
|
builder.Property(u => u.EmailVerified)
|
||||||
.IsRequired()
|
.IsRequired();
|
||||||
.HasMaxLength(100);
|
|
||||||
|
|
||||||
builder.Property(u => u.FirstName)
|
builder.Property(u => u.FirstName)
|
||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options
|
|||||||
public DbSet<Product> Products { get; set; }
|
public DbSet<Product> Products { get; set; }
|
||||||
public DbSet<ProductVariant> ProductVariants { get; set; }
|
public DbSet<ProductVariant> ProductVariants { get; set; }
|
||||||
public DbSet<Order> Orders { get; set; }
|
public DbSet<Order> Orders { get; set; }
|
||||||
public DbSet<OrderItem> OrderItems { get; set; }
|
|
||||||
public DbSet<OrderAddress> OrderAddresses { get; set; }
|
public DbSet<OrderAddress> OrderAddresses { get; set; }
|
||||||
public DbSet<Address> Addresses { get; set; }
|
public DbSet<Address> Addresses { get; set; }
|
||||||
public DbSet<OrderStatus> OrderStatuses { get; set; }
|
public DbSet<OrderStatus> OrderStatuses { get; set; }
|
||||||
@@ -28,7 +27,6 @@ public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options
|
|||||||
modelBuilder.ApplyConfiguration(new ProductConfiguration());
|
modelBuilder.ApplyConfiguration(new ProductConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new ProductVariantConfiguration());
|
modelBuilder.ApplyConfiguration(new ProductVariantConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new OrderConfiguration());
|
modelBuilder.ApplyConfiguration(new OrderConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new OrderItemConfiguration());
|
|
||||||
modelBuilder.ApplyConfiguration(new OrderAddressConfiguration());
|
modelBuilder.ApplyConfiguration(new OrderAddressConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new AddressConfiguration());
|
modelBuilder.ApplyConfiguration(new AddressConfiguration());
|
||||||
modelBuilder.ApplyConfiguration(new OrderStatusConfiguration());
|
modelBuilder.ApplyConfiguration(new OrderStatusConfiguration());
|
||||||
|
|||||||
168
src/Imprink.Infrastructure/Repositories/AddressRepository.cs
Normal file
168
src/Imprink.Infrastructure/Repositories/AddressRepository.cs
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
using Imprink.Domain.Entities;
|
||||||
|
using Imprink.Domain.Repositories;
|
||||||
|
using Imprink.Infrastructure.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Imprink.Infrastructure.Repositories;
|
||||||
|
|
||||||
|
public class AddressRepository(ApplicationDbContext context) : IAddressRepository
|
||||||
|
{
|
||||||
|
public async Task<IEnumerable<Address>> GetByUserIdAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.Where(a => a.UserId == userId)
|
||||||
|
.OrderByDescending(a => a.IsDefault)
|
||||||
|
.ThenBy(a => a.AddressType)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Address>> GetActiveByUserIdAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.Where(a => a.UserId == userId && a.IsActive)
|
||||||
|
.OrderByDescending(a => a.IsDefault)
|
||||||
|
.ThenBy(a => a.AddressType)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Address?> GetDefaultByUserIdAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.UserId == userId && a.IsDefault && a.IsActive, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Address>> GetByUserIdAndTypeAsync(string userId, string addressType, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.Where(a => a.UserId == userId && a.AddressType == addressType && a.IsActive)
|
||||||
|
.OrderByDescending(a => a.IsDefault)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Address?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Address?> GetByIdAndUserIdAsync(Guid id, string userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == id && a.UserId == userId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Address> AddAsync(Address address, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (address.IsDefault)
|
||||||
|
{
|
||||||
|
await UnsetDefaultAddressesAsync(address.UserId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Addresses.Add(address);
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Address> UpdateAsync(Address address, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var existingAddress = await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == address.Id, cancellationToken);
|
||||||
|
|
||||||
|
if (existingAddress == null)
|
||||||
|
throw new InvalidOperationException($"Address with ID {address.Id} not found");
|
||||||
|
|
||||||
|
if (address.IsDefault && !existingAddress.IsDefault)
|
||||||
|
{
|
||||||
|
await UnsetDefaultAddressesAsync(address.UserId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Entry(existingAddress).CurrentValues.SetValues(address);
|
||||||
|
return existingAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DeleteAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var address = await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == id, cancellationToken);
|
||||||
|
|
||||||
|
if (address == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
context.Addresses.Remove(address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DeleteByUserIdAsync(Guid id, string userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var address = await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == id && a.UserId == userId, cancellationToken);
|
||||||
|
|
||||||
|
if (address == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
context.Addresses.Remove(address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SetDefaultAddressAsync(string userId, Guid addressId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
await UnsetDefaultAddressesAsync(userId, cancellationToken);
|
||||||
|
|
||||||
|
var address = await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == addressId && a.UserId == userId, cancellationToken);
|
||||||
|
|
||||||
|
if (address != null)
|
||||||
|
{
|
||||||
|
address.IsDefault = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeactivateAddressAsync(Guid addressId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var address = await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == addressId, cancellationToken);
|
||||||
|
|
||||||
|
if (address != null)
|
||||||
|
{
|
||||||
|
address.IsActive = false;
|
||||||
|
if (address.IsDefault)
|
||||||
|
{
|
||||||
|
address.IsDefault = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ActivateAddressAsync(Guid addressId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var address = await context.Addresses
|
||||||
|
.FirstOrDefaultAsync(a => a.Id == addressId, cancellationToken);
|
||||||
|
|
||||||
|
if (address != null)
|
||||||
|
{
|
||||||
|
address.IsActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.AnyAsync(a => a.Id == id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsUserAddressAsync(Guid id, string userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Addresses
|
||||||
|
.AnyAsync(a => a.Id == id && a.UserId == userId, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UnsetDefaultAddressesAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var defaultAddresses = await context.Addresses
|
||||||
|
.Where(a => a.UserId == userId && a.IsDefault)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
foreach (var addr in defaultAddresses)
|
||||||
|
{
|
||||||
|
addr.IsDefault = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
using Imprink.Domain.Entities;
|
|
||||||
using Imprink.Domain.Repositories;
|
|
||||||
using Imprink.Infrastructure.Database;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Imprink.Infrastructure.Repositories;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Imprink.Domain.Entities;
|
using Imprink.Domain.Entities;
|
||||||
using Imprink.Domain.Models;
|
|
||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
using Imprink.Infrastructure.Database;
|
using Imprink.Infrastructure.Database;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -14,159 +13,79 @@ public class OrderRepository(ApplicationDbContext context) : IOrderRepository
|
|||||||
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
|
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Order?> GetByIdWithItemsAsync(Guid id, CancellationToken cancellationToken = default)
|
public async Task<Order?> GetByIdWithDetailsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Orders
|
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.OrderStatus)
|
||||||
.Include(o => o.ShippingStatus)
|
.Include(o => o.ShippingStatus)
|
||||||
.Include(o => o.OrderAddress)
|
.Include(o => o.OrderAddress)
|
||||||
.Include(o => o.OrderItems)
|
.Include(o => o.Product)
|
||||||
.ThenInclude(oi => oi.Product)
|
.Include(o => o.ProductVariant)
|
||||||
.ThenInclude(p => p.Category)
|
.Include(o => o.User)
|
||||||
.Include(o => o.OrderItems)
|
|
||||||
.ThenInclude(oi => oi.ProductVariant)
|
|
||||||
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
|
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Order?> GetByOrderNumberAsync(string orderNumber, CancellationToken cancellationToken = default)
|
public async Task<Order?> GetByOrderNumberAsync(string orderNumber, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Orders
|
return await context.Orders
|
||||||
.Include(o => o.OrderStatus)
|
|
||||||
.Include(o => o.ShippingStatus)
|
|
||||||
.FirstOrDefaultAsync(o => o.OrderNumber == orderNumber, cancellationToken);
|
.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)
|
public async Task<IEnumerable<Order>> GetByUserIdAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Orders
|
return await context.Orders
|
||||||
.Include(o => o.OrderStatus)
|
|
||||||
.Include(o => o.ShippingStatus)
|
|
||||||
.Where(o => o.UserId == userId)
|
.Where(o => o.UserId == userId)
|
||||||
.OrderByDescending(o => o.OrderDate)
|
.OrderByDescending(o => o.OrderDate)
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Order>> GetByUserIdPagedAsync(
|
public async Task<IEnumerable<Order>> GetByUserIdWithDetailsAsync(string userId, CancellationToken cancellationToken = default)
|
||||||
string userId,
|
|
||||||
int pageNumber,
|
|
||||||
int pageSize,
|
|
||||||
CancellationToken cancellationToken = default)
|
|
||||||
{
|
{
|
||||||
return await context.Orders
|
return await context.Orders
|
||||||
.Include(o => o.OrderStatus)
|
.Include(o => o.OrderStatus)
|
||||||
.Include(o => o.ShippingStatus)
|
.Include(o => o.ShippingStatus)
|
||||||
|
.Include(o => o.OrderAddress)
|
||||||
|
.Include(o => o.Product)
|
||||||
|
.Include(o => o.ProductVariant)
|
||||||
.Where(o => o.UserId == userId)
|
.Where(o => o.UserId == userId)
|
||||||
.OrderByDescending(o => o.OrderDate)
|
.OrderByDescending(o => o.OrderDate)
|
||||||
.Skip((pageNumber - 1) * pageSize)
|
|
||||||
.Take(pageSize)
|
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Order>> GetByOrderStatusAsync(int orderStatusId, CancellationToken cancellationToken = default)
|
public async Task<IEnumerable<Order>> GetByMerchantIdAsync(string merchantId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Orders
|
return await context.Orders
|
||||||
|
.Where(o => o.MerchantId == merchantId)
|
||||||
|
.OrderByDescending(o => o.OrderDate)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Order>> GetByMerchantIdWithDetailsAsync(string merchantId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Orders
|
||||||
|
.Include(o => o.OrderStatus)
|
||||||
|
.Include(o => o.ShippingStatus)
|
||||||
|
.Include(o => o.OrderAddress)
|
||||||
|
.Include(o => o.Product)
|
||||||
|
.Include(o => o.ProductVariant)
|
||||||
.Include(o => o.User)
|
.Include(o => o.User)
|
||||||
.Include(o => o.OrderStatus)
|
.Where(o => o.MerchantId == merchantId)
|
||||||
.Include(o => o.ShippingStatus)
|
.OrderByDescending(o => o.OrderDate)
|
||||||
.Where(o => o.OrderStatusId == orderStatusId)
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Order>> GetByDateRangeAsync(DateTime startDate, DateTime endDate, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Orders
|
||||||
|
.Where(o => o.OrderDate >= startDate && o.OrderDate <= endDate)
|
||||||
|
.OrderByDescending(o => o.OrderDate)
|
||||||
|
.ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Order>> GetByStatusAsync(int statusId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await context.Orders
|
||||||
|
.Where(o => o.OrderStatusId == statusId)
|
||||||
.OrderByDescending(o => o.OrderDate)
|
.OrderByDescending(o => o.OrderDate)
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
@@ -174,52 +93,39 @@ public class OrderRepository(ApplicationDbContext context) : IOrderRepository
|
|||||||
public async Task<IEnumerable<Order>> GetByShippingStatusAsync(int shippingStatusId, CancellationToken cancellationToken = default)
|
public async Task<IEnumerable<Order>> GetByShippingStatusAsync(int shippingStatusId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Orders
|
return await context.Orders
|
||||||
.Include(o => o.User)
|
|
||||||
.Include(o => o.OrderStatus)
|
|
||||||
.Include(o => o.ShippingStatus)
|
|
||||||
.Where(o => o.ShippingStatusId == shippingStatusId)
|
.Where(o => o.ShippingStatusId == shippingStatusId)
|
||||||
.OrderByDescending(o => o.OrderDate)
|
.OrderByDescending(o => o.OrderDate)
|
||||||
.ToListAsync(cancellationToken);
|
.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)
|
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);
|
context.Orders.Add(order);
|
||||||
return Task.FromResult(order);
|
return Task.FromResult(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Order> UpdateAsync(Order order, CancellationToken cancellationToken = default)
|
public async Task<Order> UpdateAsync(Order order, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
order.ModifiedAt = DateTime.UtcNow;
|
var existingOrder = await context.Orders
|
||||||
context.Orders.Update(order);
|
.FirstOrDefaultAsync(o => o.Id == order.Id, cancellationToken);
|
||||||
return Task.FromResult(order);
|
|
||||||
|
if (existingOrder == null)
|
||||||
|
throw new InvalidOperationException($"Order with ID {order.Id} not found");
|
||||||
|
|
||||||
|
context.Entry(existingOrder).CurrentValues.SetValues(order);
|
||||||
|
return existingOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteAsync(Guid id, CancellationToken cancellationToken = default)
|
public async Task<bool> DeleteAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
{
|
|
||||||
var order = await GetByIdAsync(id, cancellationToken);
|
|
||||||
if (order != null)
|
|
||||||
{
|
{
|
||||||
|
var order = await context.Orders
|
||||||
|
.FirstOrDefaultAsync(o => o.Id == id, cancellationToken);
|
||||||
|
|
||||||
|
if (order == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
context.Orders.Remove(order);
|
context.Orders.Remove(order);
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
|
public async Task<bool> ExistsAsync(Guid id, CancellationToken cancellationToken = default)
|
||||||
@@ -228,38 +134,78 @@ public class OrderRepository(ApplicationDbContext context) : IOrderRepository
|
|||||||
.AnyAsync(o => o.Id == id, cancellationToken);
|
.AnyAsync(o => o.Id == id, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> OrderNumberExistsAsync(string orderNumber, Guid? excludeId = null, CancellationToken cancellationToken = default)
|
public async Task<bool> IsOrderNumberUniqueAsync(string orderNumber, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var query = context.Orders.Where(o => o.OrderNumber == orderNumber);
|
return !await context.Orders
|
||||||
|
.AnyAsync(o => o.OrderNumber == orderNumber, cancellationToken);
|
||||||
if (excludeId.HasValue)
|
|
||||||
{
|
|
||||||
query = query.Where(o => o.Id != excludeId.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return await query.AnyAsync(cancellationToken);
|
public async Task<bool> IsOrderNumberUniqueAsync(string orderNumber, Guid excludeOrderId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return !await context.Orders
|
||||||
|
.AnyAsync(o => o.OrderNumber == orderNumber && o.Id != excludeOrderId, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<decimal> GetTotalRevenueAsync(CancellationToken cancellationToken = default)
|
public async Task<string> GenerateOrderNumberAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Orders
|
string orderNumber;
|
||||||
.Where(o => o.OrderStatusId != 5) // Assuming 5 is cancelled status
|
bool isUnique;
|
||||||
.SumAsync(o => o.TotalPrice, cancellationToken);
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Generate order number format: ORD-YYYYMMDD-XXXXXX (where X is random)
|
||||||
|
var datePart = DateTime.UtcNow.ToString("yyyyMMdd");
|
||||||
|
var randomPart = Random.Shared.Next(100000, 999999).ToString();
|
||||||
|
orderNumber = $"ORD-{datePart}-{randomPart}";
|
||||||
|
|
||||||
|
isUnique = await IsOrderNumberUniqueAsync(orderNumber, cancellationToken);
|
||||||
|
}
|
||||||
|
while (!isUnique);
|
||||||
|
|
||||||
|
return orderNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<decimal> GetTotalRevenueByDateRangeAsync(
|
public async Task UpdateStatusAsync(Guid orderId, int statusId, CancellationToken cancellationToken = default)
|
||||||
DateTime startDate,
|
|
||||||
DateTime endDate,
|
|
||||||
CancellationToken cancellationToken = default)
|
|
||||||
{
|
{
|
||||||
return await context.Orders
|
var order = await context.Orders
|
||||||
.Where(o => o.OrderDate >= startDate && o.OrderDate <= endDate && o.OrderStatusId != 5)
|
.FirstOrDefaultAsync(o => o.Id == orderId, cancellationToken);
|
||||||
.SumAsync(o => o.TotalPrice, cancellationToken);
|
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
order.OrderStatusId = statusId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> GetOrderCountByStatusAsync(int orderStatusId, CancellationToken cancellationToken = default)
|
public async Task UpdateShippingStatusAsync(Guid orderId, int shippingStatusId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.Orders
|
var order = await context.Orders
|
||||||
.CountAsync(o => o.OrderStatusId == orderStatusId, cancellationToken);
|
.FirstOrDefaultAsync(o => o.Id == orderId, cancellationToken);
|
||||||
|
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
order.ShippingStatusId = shippingStatusId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AssignMerchantAsync(Guid orderId, string merchantId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var order = await context.Orders
|
||||||
|
.FirstOrDefaultAsync(o => o.Id == orderId, cancellationToken);
|
||||||
|
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
order.MerchantId = merchantId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UnassignMerchantAsync(Guid orderId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var order = await context.Orders
|
||||||
|
.FirstOrDefaultAsync(o => o.Id == orderId, cancellationToken);
|
||||||
|
|
||||||
|
if (order != null)
|
||||||
|
{
|
||||||
|
order.MerchantId = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ public class UnitOfWork(
|
|||||||
IUserRoleRepository userRoleRepository,
|
IUserRoleRepository userRoleRepository,
|
||||||
IRoleRepository roleRepository,
|
IRoleRepository roleRepository,
|
||||||
IOrderRepository orderRepository,
|
IOrderRepository orderRepository,
|
||||||
IOrderItemRepository orderItemRepository) : IUnitOfWork
|
IAddressRepository addressRepository) : IUnitOfWork
|
||||||
{
|
{
|
||||||
public IProductRepository ProductRepository => productRepository;
|
public IProductRepository ProductRepository => productRepository;
|
||||||
public IProductVariantRepository ProductVariantRepository => productVariantRepository;
|
public IProductVariantRepository ProductVariantRepository => productVariantRepository;
|
||||||
@@ -22,7 +22,7 @@ public class UnitOfWork(
|
|||||||
public IUserRoleRepository UserRoleRepository => userRoleRepository;
|
public IUserRoleRepository UserRoleRepository => userRoleRepository;
|
||||||
public IRoleRepository RoleRepository => roleRepository;
|
public IRoleRepository RoleRepository => roleRepository;
|
||||||
public IOrderRepository OrderRepository => orderRepository;
|
public IOrderRepository OrderRepository => orderRepository;
|
||||||
public IOrderItemRepository OrderItemRepository => orderItemRepository;
|
public IAddressRepository AddressRepository => addressRepository;
|
||||||
|
|
||||||
public async Task SaveAsync(CancellationToken cancellationToken = default)
|
public async Task SaveAsync(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public static class StartupApplicationExtensions
|
|||||||
services.AddScoped<IUserRepository, UserRepository>();
|
services.AddScoped<IUserRepository, UserRepository>();
|
||||||
services.AddScoped<IUserRoleRepository, UserRoleRepository>();
|
services.AddScoped<IUserRoleRepository, UserRoleRepository>();
|
||||||
services.AddScoped<IOrderRepository, OrderRepository>();
|
services.AddScoped<IOrderRepository, OrderRepository>();
|
||||||
services.AddScoped<IOrderItemRepository, OrderItemRepository>();
|
services.AddScoped<IAddressRepository, AddressRepository>();
|
||||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||||
services.AddScoped<ICurrentUserService, CurrentUserService>();
|
services.AddScoped<ICurrentUserService, CurrentUserService>();
|
||||||
services.AddScoped<Seeder>();
|
services.AddScoped<Seeder>();
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class CreateCategoryHandlerIntegrationTest : IDisposable
|
|||||||
services.AddScoped<IUserRoleRepository, UserRoleRepository>();
|
services.AddScoped<IUserRoleRepository, UserRoleRepository>();
|
||||||
services.AddScoped<IRoleRepository, RoleRepository>();
|
services.AddScoped<IRoleRepository, RoleRepository>();
|
||||||
services.AddScoped<IOrderRepository, OrderRepository>();
|
services.AddScoped<IOrderRepository, OrderRepository>();
|
||||||
services.AddScoped<IOrderItemRepository, OrderItemRepository>();
|
services.AddScoped<IAddressRepository, AddressRepository>();
|
||||||
|
|
||||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||||
services.AddScoped<CreateCategoryHandler>();
|
services.AddScoped<CreateCategoryHandler>();
|
||||||
|
|||||||
Reference in New Issue
Block a user