From 40da1bd8df95a2ab6a4047f2960f756c3f63ce38 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 7 Aug 2026 15:48:04 +0330 Subject: [PATCH 1/5] feat(order): enhance order details with user contact information and update Protobuf definitions - Added Phone property to UserAddressDto for capturing the user's mobile number. - Updated GetOrderByIdQueryHandler to include user mobile in order details. - Enhanced GetCustomerOrderQueryHandler and GetCustomerOrderResponseDto to include PostalCode and UserMobile. - Modified userorder.proto to add postal_code and user_mobile fields in GetUserOrderResponse. - Bumped Protobuf project version to reflect the addition of new features. --- .../Queries/GetOrderById/GetOrderByIdQuery.cs | 2 + .../GetOrderById/GetOrderByIdQueryHandler.cs | 4 +- .../GetCustomerOrderQueryHandler.cs | 2 + .../GetCustomerOrderResponseDto.cs | 2 + .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/userorder.proto | 3 + .../Services/DiscountOrderService.cs | 117 +++++++++++++++++- .../Services/UserOrderService.cs | 8 +- 8 files changed, 134 insertions(+), 6 deletions(-) diff --git a/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQuery.cs b/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQuery.cs index 1e4966f..98ca6a0 100644 --- a/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQuery.cs +++ b/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQuery.cs @@ -32,6 +32,8 @@ public class UserAddressDto public string Title { get; set; } public string Address { get; set; } public string PostalCode { get; set; } + /// شماره تماس سفارش‌دهنده (موبایل کاربر) برای برچسب پست + public string? Phone { get; set; } } public class OrderItemDto diff --git a/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQueryHandler.cs b/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQueryHandler.cs index 75a16da..4f00415 100644 --- a/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQueryHandler.cs +++ b/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetOrderById/GetOrderByIdQueryHandler.cs @@ -25,6 +25,7 @@ public class GetOrderByIdQueryHandler : IRequestHandler o.UserAddress) + .Include(o => o.User) .Include(o => o.OrderDetails) .ThenInclude(od => od.Product) .FirstOrDefaultAsync(cancellationToken); @@ -50,7 +51,8 @@ public class GetOrderByIdQueryHandler : IRequestHandler new OrderItemDto { diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs index 0368f24..c43e133 100644 --- a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs @@ -52,6 +52,8 @@ public class GetCustomerOrderQueryHandler : IRequestHandler new FactorDetailDto diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderResponseDto.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderResponseDto.cs index 36ba239..5ee2481 100644 --- a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderResponseDto.cs +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderResponseDto.cs @@ -20,6 +20,8 @@ public class GetCustomerOrderResponseDto public string DeliveryDescription { get; set; } public string UserFullName { get; set; } public string UserNationalCode { get; set; } + public string PostalCode { get; set; } = string.Empty; + public string UserMobile { get; set; } = string.Empty; public long VatAmount { get; set; } public double VatPercentage { get; set; } } diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index d205872..cff2532 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.205 + 0.0.206 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/userorder.proto b/src/CMSMicroservice.Protobuf/Protos/userorder.proto index 4ca6ce0..5f083bb 100644 --- a/src/CMSMicroservice.Protobuf/Protos/userorder.proto +++ b/src/CMSMicroservice.Protobuf/Protos/userorder.proto @@ -220,6 +220,9 @@ message GetUserOrderResponse google.protobuf.StringValue user_national_code = 16; // اطلاعات مالیات بر ارزش افزوده OrderVATInfo vat_info = 17; + // اطلاعات پستی برای برچسب کارتن + google.protobuf.StringValue postal_code = 18; + google.protobuf.StringValue user_mobile = 19; } // اطلاعات مالیات بر ارزش افزوده diff --git a/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs b/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs index 140660a..4249823 100644 --- a/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs +++ b/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs @@ -141,6 +141,8 @@ public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractB Address = result.Address.Address ?? "", PostalCode = result.Address.PostalCode ?? "" }; + if (!string.IsNullOrWhiteSpace(result.Address.Phone)) + response.Address.Phone = result.Address.Phone; } foreach (var item in result.Items) @@ -197,9 +199,98 @@ public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractB return response; } - public override async Task GetAllDiscountOrders(GetAllDiscountOrdersRequest request, ServerCallContext context) + public override async Task GetAllDiscountOrders( + GetAllDiscountOrdersRequest request, ServerCallContext context) { - return await _dispatchRequestToCQRS.Handle(request, context); + // Proto PaymentStatus ≠ Domain PaymentStatus (مقادیر int متفاوت) — Adapt خام باعث باگ لیست/فیلتر می‌شود + if (request.PaymentStatus is 3) // PAYMENT_REFUNDED — در دامنه وجود ندارد + { + return new GetAllDiscountOrdersResponse + { + MetaData = new CMSMicroservice.Protobuf.Protos.MetaData + { + TotalCount = 0, + PageSize = request.PageSize > 0 ? request.PageSize : 20, + CurrentPage = request.PageNumber > 0 ? request.PageNumber : 1, + TotalPage = 0 + } + }; + } + + var query = new GetAllDiscountOrdersQuery + { + PaginationQuery = new Application.Common.Models.PaginationState + { + PageNumber = request.PageNumber > 0 ? request.PageNumber : 1, + PageSize = request.PageSize > 0 ? request.PageSize : 20 + }, + UserId = request.UserId, + UserMobile = request.UserMobile, + TrackingCode = request.TrackingCode, + FromDate = request.FromDate?.ToDateTime(), + ToDate = request.ToDate?.ToDateTime(), + MinAmount = request.MinAmount, + MaxAmount = request.MaxAmount + }; + + if (request.PaymentStatus is int paymentStatus) + query.PaymentStatus = MapProtoPaymentFilterToDomain(paymentStatus); + + if (request.DeliveryStatus is int deliveryStatus) + query.DeliveryStatus = MapProtoDeliveryFilterToDomain(deliveryStatus); + + var result = await _sender.Send(query, context.CancellationToken); + + var response = new GetAllDiscountOrdersResponse + { + MetaData = new CMSMicroservice.Protobuf.Protos.MetaData + { + TotalCount = result.MetaData.TotalCount, + PageSize = result.MetaData.PageSize, + CurrentPage = result.MetaData.CurrentPage, + TotalPage = result.MetaData.TotalPage, + HasPrevious = result.MetaData.HasPrevious, + HasNext = result.MetaData.HasNext + } + }; + + foreach (var o in result.Models) + { + var model = new CMSMicroservice.Protobuf.Protos.DiscountOrder.AdminOrderDto + { + Id = o.Id, + UserId = o.UserId, + UserFullName = o.UserFullName ?? string.Empty, + UserMobile = o.UserMobile ?? string.Empty, + TotalAmount = o.TotalAmount, + DiscountBalanceUsed = o.DiscountBalanceUsed, + GatewayAmountPaid = o.GatewayAmountPaid, + VatAmount = o.VatAmount, + PaymentStatus = MapPaymentStatus(o.PaymentStatus), + DeliveryStatus = MapDeliveryStatus(o.DeliveryStatus), + ItemsCount = o.ItemsCount, + Created = Timestamp.FromDateTime(DateTime.SpecifyKind(o.Created, DateTimeKind.Utc)) + }; + + if (o.PaymentDate.HasValue) + model.PaymentDate = Timestamp.FromDateTime(DateTime.SpecifyKind(o.PaymentDate.Value, DateTimeKind.Utc)); + if (o.LastModified.HasValue) + model.LastModified = Timestamp.FromDateTime(DateTime.SpecifyKind(o.LastModified.Value, DateTimeKind.Utc)); + if (!string.IsNullOrWhiteSpace(o.ShippingAddress)) + model.ShippingAddress = o.ShippingAddress; + if (!string.IsNullOrWhiteSpace(o.ReceiverName)) + model.ReceiverName = o.ReceiverName; + if (!string.IsNullOrWhiteSpace(o.ReceiverMobile)) + model.ReceiverMobile = o.ReceiverMobile; + if (!string.IsNullOrWhiteSpace(o.TrackingCode)) + model.TrackingCode = o.TrackingCode; + if (!string.IsNullOrWhiteSpace(o.AdminNote)) + model.AdminNote = o.AdminNote; + + response.Models.Add(model); + } + + return response; } public override async Task GetDiscountSalesReport(GetDiscountSalesReportRequest request, ServerCallContext context) @@ -359,6 +450,16 @@ public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractB _ => CMSMicroservice.Protobuf.Protos.DiscountOrder.PaymentStatus.PaymentPending }; + /// + /// فیلتر UI/proto → دامنه: PENDING=0, COMPLETED=1, FAILED=2 + /// + private static DomainEnums.PaymentStatus MapProtoPaymentFilterToDomain(int protoPaymentStatus) => protoPaymentStatus switch + { + 1 => DomainEnums.PaymentStatus.Success, // PAYMENT_COMPLETED + 2 => DomainEnums.PaymentStatus.Reject, // PAYMENT_FAILED + _ => DomainEnums.PaymentStatus.Pending // PAYMENT_PENDING (0) و پیش‌فرض + }; + private static DeliveryStatus MapDeliveryStatus(DomainEnums.DeliveryStatus status) => status switch { DomainEnums.DeliveryStatus.None => DeliveryStatus.DeliveryPending, @@ -369,4 +470,16 @@ public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractB DomainEnums.DeliveryStatus.Cancelled => DeliveryStatus.DeliveryCancelled, _ => DeliveryStatus.DeliveryPending }; + + /// + /// فیلتر UI/proto → دامنه DeliveryStatus + /// + private static DomainEnums.DeliveryStatus MapProtoDeliveryFilterToDomain(int protoDeliveryStatus) => protoDeliveryStatus switch + { + 1 => DomainEnums.DeliveryStatus.Pending, // DELIVERY_PROCESSING + 2 => DomainEnums.DeliveryStatus.InTransit, // DELIVERY_SHIPPED + 3 => DomainEnums.DeliveryStatus.Delivered, // DELIVERY_DELIVERED + 4 => DomainEnums.DeliveryStatus.Cancelled, // DELIVERY_CANCELLED + _ => DomainEnums.DeliveryStatus.None // DELIVERY_PENDING (0) + }; } diff --git a/src/CMSMicroservice.WebApi/Services/UserOrderService.cs b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs index 24eeb5d..c780da0 100644 --- a/src/CMSMicroservice.WebApi/Services/UserOrderService.cs +++ b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs @@ -121,7 +121,9 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase TrackingCode = result.TrackingCode, DeliveryDescription = result.DeliveryDescription, UserFullName = result.UserFullName, - UserNationalCode = result.UserNationalCode + UserNationalCode = result.UserNationalCode, + PostalCode = result.PostalCode, + UserMobile = result.UserMobile }; // VAT Info @@ -789,7 +791,9 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase TrackingCode = result.TrackingCode, DeliveryDescription = result.DeliveryDescription, UserFullName = result.UserFullName, - UserNationalCode = result.UserNationalCode + UserNationalCode = result.UserNationalCode, + PostalCode = result.PostalCode, + UserMobile = result.UserMobile }; // VAT Info From 6c90e4caf091b320aab85c36526cb2cff8d9119d Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 7 Aug 2026 17:25:57 +0330 Subject: [PATCH 2/5] feat(order): enhance order status management and Protobuf definitions - Added AdminNotes handling in UpdateOrderStatusCommandHandler to include delivery descriptions. - Updated DeliveryStatus enum to include ReadyForOfficePickup. - Enhanced GetCustomerOrderHistoryQueryHandler and UserOrderService to support new delivery status. - Updated Protobuf definitions for DeliveryStatus to reflect changes. - Bumped Protobuf project version to accommodate new features. --- .../UpdateOrderStatusCommandHandler.cs | 5 +++ .../GetCustomerOrderHistoryQueryHandler.cs | 2 + .../Enums/DeliveryStatus.cs | 2 + .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/discountorder.proto | 2 + .../Protos/public_messages.proto | 4 ++ .../Services/DiscountOrderService.cs | 41 +++++++++++++++---- .../Services/UserOrderService.cs | 1 + 8 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/CMSMicroservice.Application/DiscountShopCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs b/src/CMSMicroservice.Application/DiscountShopCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs index 2016ba9..957b620 100644 --- a/src/CMSMicroservice.Application/DiscountShopCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs +++ b/src/CMSMicroservice.Application/DiscountShopCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs @@ -35,6 +35,11 @@ public class UpdateOrderStatusCommandHandler : IRequestHandler 4, DeliveryStatus.Cancelled => 5, DeliveryStatus.Returned => 6, + DeliveryStatus.ReadyForOfficePickup => 7, _ => 0 }; } @@ -127,6 +128,7 @@ public class GetCustomerOrderHistoryQueryHandler : IRequestHandler "تحویل داده شد", DeliveryStatus.Cancelled => "لغو شده", DeliveryStatus.Returned => "مرجوع شده", + DeliveryStatus.ReadyForOfficePickup => "آماده تحویل در دفتر", _ => "نامشخص" }; } diff --git a/src/CMSMicroservice.Domain/Enums/DeliveryStatus.cs b/src/CMSMicroservice.Domain/Enums/DeliveryStatus.cs index 86563db..e979c4d 100644 --- a/src/CMSMicroservice.Domain/Enums/DeliveryStatus.cs +++ b/src/CMSMicroservice.Domain/Enums/DeliveryStatus.cs @@ -15,5 +15,7 @@ public enum DeliveryStatus Returned = 4, // لغو شده Cancelled = 5, + // آماده تحویل حضوری در دفتر + ReadyForOfficePickup = 6, } diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index cff2532..80ec01a 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.206 + 0.0.207 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/discountorder.proto b/src/CMSMicroservice.Protobuf/Protos/discountorder.proto index 4edbcb8..72cd4cc 100644 --- a/src/CMSMicroservice.Protobuf/Protos/discountorder.proto +++ b/src/CMSMicroservice.Protobuf/Protos/discountorder.proto @@ -118,6 +118,8 @@ enum DeliveryStatus DELIVERY_SHIPPED = 2; DELIVERY_DELIVERED = 3; DELIVERY_CANCELLED = 4; + DELIVERY_READY_FOR_OFFICE = 5; + DELIVERY_RETURNED = 6; } // Get Order By Id diff --git a/src/CMSMicroservice.Protobuf/Protos/public_messages.proto b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto index 99fd260..b2d67d9 100644 --- a/src/CMSMicroservice.Protobuf/Protos/public_messages.proto +++ b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto @@ -102,6 +102,10 @@ enum DeliveryStatus DeliveryStatus_Delivered = 3; // مرجوع شده DeliveryStatus_Returned = 4; + // لغو شده + DeliveryStatus_Cancelled = 5; + // آماده تحویل حضوری در دفتر + DeliveryStatus_ReadyForOfficePickup = 6; } enum TransactionType { diff --git a/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs b/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs index 4249823..0af7f7b 100644 --- a/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs +++ b/src/CMSMicroservice.WebApi/Services/DiscountOrderService.cs @@ -99,7 +99,20 @@ public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractB public override async Task UpdateOrderStatus(UpdateOrderStatusRequest request, ServerCallContext context) { - return await _dispatchRequestToCQRS.Handle(request, context); + // Proto DeliveryStatus ≠ Domain DeliveryStatus — نگاشت صریح لازم است + var command = new UpdateOrderStatusCommand + { + OrderId = request.OrderId, + DeliveryStatus = MapProtoDeliveryToDomain(request.DeliveryStatus), + TrackingCode = request.TrackingCode, + AdminNotes = request.AdminNotes + }; + var result = await _sender.Send(command, context.CancellationToken); + return new UpdateOrderStatusResponse + { + Success = result.Success, + Message = result.Message ?? string.Empty + }; } public override async Task GetOrderById(GetOrderByIdRequest request, ServerCallContext context) @@ -466,8 +479,9 @@ public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractB DomainEnums.DeliveryStatus.Pending => DeliveryStatus.DeliveryProcessing, DomainEnums.DeliveryStatus.InTransit => DeliveryStatus.DeliveryShipped, DomainEnums.DeliveryStatus.Delivered => DeliveryStatus.DeliveryDelivered, - DomainEnums.DeliveryStatus.Returned => DeliveryStatus.DeliveryCancelled, DomainEnums.DeliveryStatus.Cancelled => DeliveryStatus.DeliveryCancelled, + DomainEnums.DeliveryStatus.ReadyForOfficePickup => DeliveryStatus.DeliveryReadyForOffice, + DomainEnums.DeliveryStatus.Returned => DeliveryStatus.DeliveryReturned, _ => DeliveryStatus.DeliveryPending }; @@ -476,10 +490,23 @@ public class DiscountOrderService : DiscountOrderContract.DiscountOrderContractB /// private static DomainEnums.DeliveryStatus MapProtoDeliveryFilterToDomain(int protoDeliveryStatus) => protoDeliveryStatus switch { - 1 => DomainEnums.DeliveryStatus.Pending, // DELIVERY_PROCESSING - 2 => DomainEnums.DeliveryStatus.InTransit, // DELIVERY_SHIPPED - 3 => DomainEnums.DeliveryStatus.Delivered, // DELIVERY_DELIVERED - 4 => DomainEnums.DeliveryStatus.Cancelled, // DELIVERY_CANCELLED - _ => DomainEnums.DeliveryStatus.None // DELIVERY_PENDING (0) + 1 => DomainEnums.DeliveryStatus.Pending, // DELIVERY_PROCESSING + 2 => DomainEnums.DeliveryStatus.InTransit, // DELIVERY_SHIPPED + 3 => DomainEnums.DeliveryStatus.Delivered, // DELIVERY_DELIVERED + 4 => DomainEnums.DeliveryStatus.Cancelled, // DELIVERY_CANCELLED + 5 => DomainEnums.DeliveryStatus.ReadyForOfficePickup, // DELIVERY_READY_FOR_OFFICE + 6 => DomainEnums.DeliveryStatus.Returned, // DELIVERY_RETURNED + _ => DomainEnums.DeliveryStatus.None // DELIVERY_PENDING (0) + }; + + private static DomainEnums.DeliveryStatus MapProtoDeliveryToDomain(DeliveryStatus status) => status switch + { + DeliveryStatus.DeliveryProcessing => DomainEnums.DeliveryStatus.Pending, + DeliveryStatus.DeliveryShipped => DomainEnums.DeliveryStatus.InTransit, + DeliveryStatus.DeliveryDelivered => DomainEnums.DeliveryStatus.Delivered, + DeliveryStatus.DeliveryCancelled => DomainEnums.DeliveryStatus.Cancelled, + DeliveryStatus.DeliveryReadyForOffice => DomainEnums.DeliveryStatus.ReadyForOfficePickup, + DeliveryStatus.DeliveryReturned => DomainEnums.DeliveryStatus.Returned, + _ => DomainEnums.DeliveryStatus.None }; } diff --git a/src/CMSMicroservice.WebApi/Services/UserOrderService.cs b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs index c780da0..e989209 100644 --- a/src/CMSMicroservice.WebApi/Services/UserOrderService.cs +++ b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs @@ -1058,6 +1058,7 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase Domain.Enums.DeliveryStatus.Delivered => "تحویل داده شده", Domain.Enums.DeliveryStatus.Returned => "مرجوع شده", Domain.Enums.DeliveryStatus.Cancelled => "لغو شده", + Domain.Enums.DeliveryStatus.ReadyForOfficePickup => "آماده تحویل در دفتر", _ => status.ToString() }; } From fb9e3d010976da5e3194a64cba78846457220003 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Fri, 7 Aug 2026 18:39:42 +0330 Subject: [PATCH 3/5] feat(order): refactor order data mapping for improved clarity and structure - Updated GetAllDiscountOrdersQueryHandler to enhance order data mapping by using a more structured approach with AdminOrderDto. - Refactored user full name construction in GetCustomerOrderQueryHandler and GetCustomerOrdersQueryHandler to utilize UserDisplayName for better readability. - Added necessary using directives for consistency across query handlers. --- .../Common/UserDisplayName.cs | 29 +++++++++ .../GetAllDiscountOrdersQueryHandler.cs | 60 +++++++++++++------ .../GetCustomerOrderQueryHandler.cs | 3 +- .../GetCustomerOrdersQueryHandler.cs | 3 +- 4 files changed, 75 insertions(+), 20 deletions(-) create mode 100644 src/CMSMicroservice.Application/Common/UserDisplayName.cs diff --git a/src/CMSMicroservice.Application/Common/UserDisplayName.cs b/src/CMSMicroservice.Application/Common/UserDisplayName.cs new file mode 100644 index 0000000..1c18ec8 --- /dev/null +++ b/src/CMSMicroservice.Application/Common/UserDisplayName.cs @@ -0,0 +1,29 @@ +namespace CMSMicroservice.Application.Common; + +/// +/// نام نمایشی کاربر برای گزارش‌ها؛ اگر نام خالی باشد موبایل یا شناسه. +/// +public static class UserDisplayName +{ + public static string From(string? firstName, string? lastName, string? mobile, long userId) + { + var name = string.Join(" ", + new[] { firstName, lastName }.Where(s => !string.IsNullOrWhiteSpace(s))); + + if (!string.IsNullOrWhiteSpace(name)) + return name; + + if (!string.IsNullOrWhiteSpace(mobile)) + return mobile.Trim(); + + return userId > 0 ? $"کاربر {userId}" : "—"; + } + + public static string From(Domain.Entities.User? user) + { + if (user is null) + return string.Empty; + + return From(user.FirstName, user.LastName, user.Mobile, user.Id); + } +} diff --git a/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQueryHandler.cs b/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQueryHandler.cs index fac1fde..f95415a 100644 --- a/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQueryHandler.cs +++ b/src/CMSMicroservice.Application/DiscountShopCQ/Queries/GetAllDiscountOrders/GetAllDiscountOrdersQueryHandler.cs @@ -1,3 +1,4 @@ +using CMSMicroservice.Application.Common; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Application.Common.Models; using MediatR; @@ -80,35 +81,58 @@ public class GetAllDiscountOrdersQueryHandler : IRequestHandler o.Created) .Skip((pagination.PageNumber - 1) * pagination.PageSize) .Take(pagination.PageSize) - .Select(o => new AdminOrderDto + .Select(o => new { - Id = o.Id, - UserId = o.UserId, - UserFullName = (o.User.FirstName ?? "") + " " + (o.User.LastName ?? ""), - UserMobile = o.User.Mobile, - TotalAmount = o.TotalAmount, - DiscountBalanceUsed = o.DiscountBalanceUsed, - GatewayAmountPaid = o.GatewayAmountPaid, - VatAmount = o.VatAmount, - PaymentStatus = o.PaymentStatus, - PaymentDate = o.PaymentDate, - DeliveryStatus = o.DeliveryStatus, - DeliveryDate = null, // TODO: Add DeliveryDate to DiscountOrder if needed + o.Id, + o.UserId, + FirstName = o.User.FirstName, + LastName = o.User.LastName, + Mobile = o.User.Mobile, + o.TotalAmount, + o.DiscountBalanceUsed, + o.GatewayAmountPaid, + o.VatAmount, + o.PaymentStatus, + o.PaymentDate, + o.DeliveryStatus, ShippingAddress = o.UserAddress.Address, ReceiverName = o.UserAddress.Title, - ReceiverMobile = o.User.Mobile, - TrackingCode = o.TrackingCode, + o.TrackingCode, AdminNote = o.DeliveryDescription, - Created = o.Created, - LastModified = o.LastModified, + o.Created, + o.LastModified, ItemsCount = o.OrderDetails.Count }) .ToListAsync(cancellationToken); + var orders = rows.Select(o => new AdminOrderDto + { + Id = o.Id, + UserId = o.UserId, + UserFullName = UserDisplayName.From(o.FirstName, o.LastName, o.Mobile, o.UserId), + UserMobile = o.Mobile, + TotalAmount = o.TotalAmount, + DiscountBalanceUsed = o.DiscountBalanceUsed, + GatewayAmountPaid = o.GatewayAmountPaid, + VatAmount = o.VatAmount, + PaymentStatus = o.PaymentStatus, + PaymentDate = o.PaymentDate, + DeliveryStatus = o.DeliveryStatus, + DeliveryDate = null, + ShippingAddress = o.ShippingAddress, + ReceiverName = o.ReceiverName, + ReceiverMobile = o.Mobile, + TrackingCode = o.TrackingCode, + AdminNote = o.AdminNote, + Created = o.Created, + LastModified = o.LastModified, + ItemsCount = o.ItemsCount + }).ToList(); + return new GetAllDiscountOrdersResponseDto { MetaData = new MetaData diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs index c43e133..c60945a 100644 --- a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetCustomerOrder/GetCustomerOrderQueryHandler.cs @@ -1,3 +1,4 @@ +using CMSMicroservice.Application.Common; using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Entities; @@ -50,7 +51,7 @@ public class GetCustomerOrderQueryHandler : IRequestHandler Date: Sat, 8 Aug 2026 21:59:14 +0330 Subject: [PATCH 4/5] feat(package): update package purchase methods and enhance Protobuf definitions - Changed package purchase method from DirectPurchase to Manual in multiple command handlers to reflect new business logic. - Added Manual purchase method to PackagePurchaseMethod enum for clarity. - Introduced new RPC method GetCustomerPackagePurchaseRollup in Protobuf for summarizing customer package purchases. - Updated UserPackagePurchaseProfile and UserPackagePurchaseService to support new rollup functionality. - Bumped Protobuf project version to accommodate new features. --- README.md | 2 +- .../ActivateClubMembershipCommandHandler.cs | 4 +- .../CreateManualPaymentCommandHandler.cs | 14 +- ...ssManualMembershipPaymentCommandHandler.cs | 2 +- .../GetCustomerPackagePurchaseRollupQuery.cs | 51 +++++++ ...stomerPackagePurchaseRollupQueryHandler.cs | 130 ++++++++++++++++++ .../Enums/PackagePurchaseMethod.cs | 7 +- .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/userpackagepurchase.proto | 53 +++++++ .../Mappings/UserPackagePurchaseProfile.cs | 37 +++++ .../Services/UserPackagePurchaseService.cs | 5 + 11 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQuery.cs create mode 100644 src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs diff --git a/README.md b/README.md index 9ef67cc..9fd7663 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # CMS Microservice Documentation moved to [totalDoc/INDEX.md](../totalDoc/INDEX.md). - \ No newline at end of file + \ No newline at end of file diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs index 0735b07..3d361e5 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs @@ -163,10 +163,10 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler +{ + public PaginationState? PaginationState { get; init; } + public GetCustomerPackagePurchaseRollupFilter? Filter { get; init; } +} + +public class GetCustomerPackagePurchaseRollupFilter +{ + public long? UserId { get; set; } + public PackagePurchaseMethod? PurchaseMethod { get; set; } + public DateTime? PurchasedFrom { get; set; } + public DateTime? PurchasedTo { get; set; } +} + +public class GetCustomerPackagePurchaseRollupResponseDto +{ + public MetaData MetaData { get; set; } = new(); + public List Models { get; set; } = new(); +} + +public class CustomerPackagePurchaseRollupModel +{ + public long UserId { get; set; } + public string UserName { get; set; } = string.Empty; + public string UserMobile { get; set; } = string.Empty; + + public long FirstPackageId { get; set; } + public string FirstPackageName { get; set; } = string.Empty; + public long FirstAmount { get; set; } + public DateTime FirstPurchasedAt { get; set; } + + public long LastPackageId { get; set; } + public string LastPackageName { get; set; } = string.Empty; + public long LastAmount { get; set; } + public DateTime LastPurchasedAt { get; set; } + public PackagePurchaseMethod LastPurchaseMethod { get; set; } + + public int PurchaseCount { get; set; } + public long TotalAmount { get; set; } + + public int DayaCount { get; set; } + public long DayaAmount { get; set; } + public int ManualCount { get; set; } + public long ManualAmount { get; set; } + public int GatewayCount { get; set; } + public long GatewayAmount { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs new file mode 100644 index 0000000..5fc0e91 --- /dev/null +++ b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs @@ -0,0 +1,130 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Application.Common.Models; +using CMSMicroservice.Domain.Enums; +using Microsoft.EntityFrameworkCore; + +namespace CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetCustomerPackagePurchaseRollup; + +public class GetCustomerPackagePurchaseRollupQueryHandler + : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetCustomerPackagePurchaseRollupQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle( + GetCustomerPackagePurchaseRollupQuery request, + CancellationToken cancellationToken) + { + var filter = request.Filter; + var pagination = request.PaginationState ?? new PaginationState { PageNumber = 1, PageSize = 20 }; + if (pagination.PageNumber < 1) pagination.PageNumber = 1; + if (pagination.PageSize < 1) pagination.PageSize = 20; + + // خرید معتبر: بدون تراکنش یا تراکنش موفق + var purchases = _context.UserPackagePurchases + .AsNoTracking() + .Include(x => x.User) + .Include(x => x.Package) + .Include(x => x.Transaction) + .Where(x => x.TransactionId == null + || (x.Transaction != null && x.Transaction.PaymentStatus == PaymentStatus.Success)); + + if (filter?.UserId is > 0) + purchases = purchases.Where(x => x.UserId == filter.UserId.Value); + + if (filter?.PurchaseMethod != null) + purchases = purchases.Where(x => x.PurchaseMethod == filter.PurchaseMethod.Value); + + if (filter?.PurchasedFrom != null) + purchases = purchases.Where(x => x.PurchasedAt >= filter.PurchasedFrom.Value); + + if (filter?.PurchasedTo != null) + purchases = purchases.Where(x => x.PurchasedAt <= filter.PurchasedTo.Value); + + var rows = await purchases + .Select(x => new + { + x.UserId, + FirstName = x.User != null ? x.User.FirstName : null, + LastName = x.User != null ? x.User.LastName : null, + Mobile = x.User != null ? x.User.Mobile : null, + x.PackageId, + PackageName = x.Package != null ? x.Package.Title : null, + x.Amount, + x.PurchasedAt, + x.PurchaseMethod + }) + .ToListAsync(cancellationToken); + + var grouped = rows + .GroupBy(x => x.UserId) + .Select(g => + { + var ordered = g.OrderBy(x => x.PurchasedAt).ThenBy(x => x.PackageId).ToList(); + var first = ordered.First(); + var last = ordered.Last(); + var userName = string.Join(" ", + new[] { first.FirstName, first.LastName }.Where(s => !string.IsNullOrWhiteSpace(s))).Trim(); + + return new CustomerPackagePurchaseRollupModel + { + UserId = g.Key, + UserName = string.IsNullOrWhiteSpace(userName) + ? (!string.IsNullOrWhiteSpace(first.Mobile) ? first.Mobile! : $"کاربر {g.Key}") + : userName, + UserMobile = first.Mobile ?? string.Empty, + + FirstPackageId = first.PackageId, + FirstPackageName = first.PackageName ?? string.Empty, + FirstAmount = first.Amount, + FirstPurchasedAt = first.PurchasedAt, + + LastPackageId = last.PackageId, + LastPackageName = last.PackageName ?? string.Empty, + LastAmount = last.Amount, + LastPurchasedAt = last.PurchasedAt, + LastPurchaseMethod = last.PurchaseMethod, + + PurchaseCount = ordered.Count, + TotalAmount = ordered.Sum(x => x.Amount), + + DayaCount = ordered.Count(x => x.PurchaseMethod == PackagePurchaseMethod.DayaLoan), + DayaAmount = ordered.Where(x => x.PurchaseMethod == PackagePurchaseMethod.DayaLoan).Sum(x => x.Amount), + ManualCount = ordered.Count(x => x.PurchaseMethod == PackagePurchaseMethod.Manual), + ManualAmount = ordered.Where(x => x.PurchaseMethod == PackagePurchaseMethod.Manual).Sum(x => x.Amount), + GatewayCount = ordered.Count(x => x.PurchaseMethod == PackagePurchaseMethod.DirectPurchase), + GatewayAmount = ordered.Where(x => x.PurchaseMethod == PackagePurchaseMethod.DirectPurchase).Sum(x => x.Amount) + }; + }) + .OrderByDescending(x => x.LastPurchasedAt) + .ToList(); + + var totalCount = grouped.Count; + var pageSize = pagination.PageSize; + var pageNumber = pagination.PageNumber; + var totalPage = pageSize > 0 ? (int)Math.Ceiling(totalCount / (double)pageSize) : 0; + + var pageModels = grouped + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToList(); + + return new GetCustomerPackagePurchaseRollupResponseDto + { + MetaData = new MetaData + { + CurrentPage = pageNumber, + PageSize = pageSize, + TotalCount = totalCount, + TotalPage = totalPage, + HasPrevious = pageNumber > 1, + HasNext = pageNumber < totalPage + }, + Models = pageModels + }; + } +} diff --git a/src/CMSMicroservice.Domain/Enums/PackagePurchaseMethod.cs b/src/CMSMicroservice.Domain/Enums/PackagePurchaseMethod.cs index 8ff177f..748f3ac 100644 --- a/src/CMSMicroservice.Domain/Enums/PackagePurchaseMethod.cs +++ b/src/CMSMicroservice.Domain/Enums/PackagePurchaseMethod.cs @@ -18,5 +18,10 @@ public enum PackagePurchaseMethod /// /// از طریق پرداخت مستقیم درگاه بانکی /// - DirectPurchase = 2 + DirectPurchase = 2, + + /// + /// ثبت دستی توسط ادمین + /// + Manual = 3 } diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index 80ec01a..6d7c475 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.207 + 0.0.208 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto b/src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto index 8a52aa4..ef35d9b 100644 --- a/src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto +++ b/src/CMSMicroservice.Protobuf/Protos/userpackagepurchase.proto @@ -21,6 +21,11 @@ service UserPackagePurchaseContract get: "/UserPackagePurchase/GetSummary" }; }; + rpc GetCustomerPackagePurchaseRollup(GetCustomerPackagePurchaseRollupRequest) returns (GetCustomerPackagePurchaseRollupResponse){ + option (google.api.http) = { + get: "/UserPackagePurchase/GetCustomerRollup" + }; + }; } message GetAllUserPackagePurchaseByFilterRequest @@ -73,3 +78,51 @@ message GetUserPackagePurchaseSummaryResponse int64 total_count = 1; int64 total_amount = 2; } + +message GetCustomerPackagePurchaseRollupRequest +{ + messages.PaginationState pagination_state = 1; + GetCustomerPackagePurchaseRollupFilter filter = 2; +} + +message GetCustomerPackagePurchaseRollupFilter +{ + google.protobuf.Int64Value user_id = 1; + google.protobuf.Int32Value purchase_method = 2; + google.protobuf.Timestamp purchased_from = 3; + google.protobuf.Timestamp purchased_to = 4; +} + +message GetCustomerPackagePurchaseRollupResponse +{ + messages.MetaData meta_data = 1; + repeated CustomerPackagePurchaseRollupModel models = 2; +} + +message CustomerPackagePurchaseRollupModel +{ + int64 user_id = 1; + string user_name = 2; + string user_mobile = 3; + + int64 first_package_id = 4; + string first_package_name = 5; + int64 first_amount = 6; + google.protobuf.Timestamp first_purchased_at = 7; + + int64 last_package_id = 8; + string last_package_name = 9; + int64 last_amount = 10; + google.protobuf.Timestamp last_purchased_at = 11; + int32 last_purchase_method = 12; + + int32 purchase_count = 13; + int64 total_amount = 14; + + int32 daya_count = 15; + int64 daya_amount = 16; + int32 manual_count = 17; + int64 manual_amount = 18; + int32 gateway_count = 19; + int64 gateway_amount = 20; +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs index ba02b15..a825884 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserPackagePurchaseProfile.cs @@ -3,6 +3,7 @@ using CMSMicroservice.Domain.Enums; using Mapster; using AppUp = CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; using AppUpSummary = CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; +using AppRollup = CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetCustomerPackagePurchaseRollup; using ProtoUp = CMSMicroservice.Protobuf.Protos.UserPackagePurchase; namespace CMSMicroservice.WebApi.Common.Mappings; @@ -49,5 +50,41 @@ public class UserPackagePurchaseProfile : IRegister config.NewConfig() .Map(dest => dest.TotalCount, src => src.TotalCount) .Map(dest => dest.TotalAmount, src => src.TotalAmount); + + config.NewConfig() + .Map(dest => dest.PaginationState, src => src.PaginationState) + .Map(dest => dest.Filter, src => src.Filter); + + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.PurchaseMethod, src => src.PurchaseMethod == null ? null : (PackagePurchaseMethod?)src.PurchaseMethod) + .Map(dest => dest.PurchasedFrom, src => src.PurchasedFrom != null ? src.PurchasedFrom.ToDateTime() : (DateTime?)null) + .Map(dest => dest.PurchasedTo, src => src.PurchasedTo != null ? src.PurchasedTo.ToDateTime() : (DateTime?)null); + + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData) + .Map(dest => dest.Models, src => src.Models); + + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.UserName, src => src.UserName) + .Map(dest => dest.UserMobile, src => src.UserMobile) + .Map(dest => dest.FirstPackageId, src => src.FirstPackageId) + .Map(dest => dest.FirstPackageName, src => src.FirstPackageName) + .Map(dest => dest.FirstAmount, src => src.FirstAmount) + .Map(dest => dest.FirstPurchasedAt, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.FirstPurchasedAt, DateTimeKind.Utc))) + .Map(dest => dest.LastPackageId, src => src.LastPackageId) + .Map(dest => dest.LastPackageName, src => src.LastPackageName) + .Map(dest => dest.LastAmount, src => src.LastAmount) + .Map(dest => dest.LastPurchasedAt, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.LastPurchasedAt, DateTimeKind.Utc))) + .Map(dest => dest.LastPurchaseMethod, src => (int)src.LastPurchaseMethod) + .Map(dest => dest.PurchaseCount, src => src.PurchaseCount) + .Map(dest => dest.TotalAmount, src => src.TotalAmount) + .Map(dest => dest.DayaCount, src => src.DayaCount) + .Map(dest => dest.DayaAmount, src => src.DayaAmount) + .Map(dest => dest.ManualCount, src => src.ManualCount) + .Map(dest => dest.ManualAmount, src => src.ManualAmount) + .Map(dest => dest.GatewayCount, src => src.GatewayCount) + .Map(dest => dest.GatewayAmount, src => src.GatewayAmount); } } diff --git a/src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs b/src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs index 239d7c8..2581b4c 100644 --- a/src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs +++ b/src/CMSMicroservice.WebApi/Services/UserPackagePurchaseService.cs @@ -2,6 +2,7 @@ using CMSMicroservice.Protobuf.Protos.UserPackagePurchase; using CMSMicroservice.WebApi.Common.Services; using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetAllUserPackagePurchaseByFilter; using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetUserPackagePurchaseSummary; +using CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetCustomerPackagePurchaseRollup; namespace CMSMicroservice.WebApi.Services; @@ -18,4 +19,8 @@ public class UserPackagePurchaseService : UserPackagePurchaseContract.UserPackag public override Task GetUserPackagePurchaseSummary( GetUserPackagePurchaseSummaryRequest request, ServerCallContext context) => _dispatch.Handle(request, context); + + public override Task GetCustomerPackagePurchaseRollup( + GetCustomerPackagePurchaseRollupRequest request, ServerCallContext context) => + _dispatch.Handle(request, context); } From 6a04a6a270bc8dcd5c1e140b77d3ac18193e870d Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sun, 9 Aug 2026 00:40:25 +0330 Subject: [PATCH 5/5] feat(package): enhance pagination logic in GetCustomerPackagePurchaseRollupQueryHandler - Updated pagination handling to allow for exporting all results when PageSize is set to 0. - Adjusted page size and number calculations to accommodate the new export functionality. - Improved clarity in pagination logic by distinguishing between export and paginated results. --- ...stomerPackagePurchaseRollupQueryHandler.cs | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs index 5fc0e91..ca2e401 100644 --- a/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs +++ b/src/CMSMicroservice.Application/UserPackagePurchaseCQ/Queries/GetCustomerPackagePurchaseRollup/GetCustomerPackagePurchaseRollupQueryHandler.cs @@ -22,7 +22,9 @@ public class GetCustomerPackagePurchaseRollupQueryHandler var filter = request.Filter; var pagination = request.PaginationState ?? new PaginationState { PageNumber = 1, PageSize = 20 }; if (pagination.PageNumber < 1) pagination.PageNumber = 1; - if (pagination.PageSize < 1) pagination.PageSize = 20; + // PageSize == 0 → خروجی کامل (بدون صفحه‌بندی)، مثلاً Excel + var exportAll = pagination.PageSize == 0; + if (!exportAll && pagination.PageSize < 1) pagination.PageSize = 20; // خرید معتبر: بدون تراکنش یا تراکنش موفق var purchases = _context.UserPackagePurchases @@ -104,14 +106,18 @@ public class GetCustomerPackagePurchaseRollupQueryHandler .ToList(); var totalCount = grouped.Count; - var pageSize = pagination.PageSize; - var pageNumber = pagination.PageNumber; - var totalPage = pageSize > 0 ? (int)Math.Ceiling(totalCount / (double)pageSize) : 0; + var pageNumber = exportAll ? 1 : pagination.PageNumber; + var pageSize = exportAll ? totalCount : pagination.PageSize; + var totalPage = exportAll || pageSize <= 0 + ? (totalCount > 0 ? 1 : 0) + : (int)Math.Ceiling(totalCount / (double)pageSize); - var pageModels = grouped - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize) - .ToList(); + var pageModels = exportAll + ? grouped + : grouped + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToList(); return new GetCustomerPackagePurchaseRollupResponseDto { @@ -121,8 +127,8 @@ public class GetCustomerPackagePurchaseRollupQueryHandler PageSize = pageSize, TotalCount = totalCount, TotalPage = totalPage, - HasPrevious = pageNumber > 1, - HasNext = pageNumber < totalPage + HasPrevious = !exportAll && pageNumber > 1, + HasNext = !exportAll && pageNumber < totalPage }, Models = pageModels };