From ba6d74fe35d6cac144c5b8b87778705a13afc78d Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Thu, 4 Dec 2025 03:43:19 +0330 Subject: [PATCH] feat: Implement Public Message Management Commands and Queries - Add GetUserPackageStatusQueryValidator for user package status validation. - Create ArchiveMessageCommand and ArchiveMessageCommandHandler for archiving public messages. - Implement ArchiveMessageCommandValidator to validate message ID. - Introduce PublishMessageCommand and PublishMessageCommandHandler for publishing messages. - Add PublishMessageCommandValidator for validating publish message requests. - Implement GetPublicMessageQuery and GetPublicMessageQueryHandler for retrieving public messages. - Create GetPublicMessageQueryValidator for validating public message requests. - Add ApplyDiscountToOrderCommand and ApplyDiscountToOrderCommandHandler for applying discounts to orders. - Implement ApplyDiscountToOrderCommandValidator for validating discount application requests. - Create UpdateOrderStatusCommand and UpdateOrderStatusCommandHandler for changing order statuses. - Implement UpdateOrderStatusCommandValidator for validating order status updates. - Add CalculateOrderPVQuery and CalculateOrderPVQueryHandler for calculating order PV. - Implement CalculateOrderPVQueryValidator for validating PV calculation requests. - Create GetOrdersByDateRangeQuery and GetOrdersByDateRangeQueryHandler for retrieving orders by date range. - Implement GetOrdersByDateRangeQueryValidator for validating date range queries. - Add PublicMessage entity to represent public messages in the system. - Implement PublicMessageService for handling public message operations via gRPC. --- .../Interfaces/IApplicationDbContext.cs | 1 - .../PurchaseGoldenPackageCommand.cs | 22 ++ .../PurchaseGoldenPackageCommandHandler.cs | 88 ++++++++ .../PurchaseGoldenPackageCommandValidator.cs | 23 ++ .../VerifyGoldenPackagePurchaseCommand.cs | 23 ++ ...rifyGoldenPackagePurchaseCommandHandler.cs | 115 ++++++++++ ...fyGoldenPackagePurchaseCommandValidator.cs | 23 ++ .../GetUserPackageStatusQuery.cs | 24 +++ .../GetUserPackageStatusQueryHandler.cs | 61 ++++++ .../GetUserPackageStatusQueryValidator.cs | 13 ++ .../ArchiveMessage/ArchiveMessageCommand.cs | 16 ++ .../ArchiveMessageCommandHandler.cs | 52 +++++ .../ArchiveMessageCommandValidator.cs | 11 + .../CreatePublicMessageCommandHandler.cs | 2 +- .../PublishMessage/PublishMessageCommand.cs | 16 ++ .../PublishMessageCommandHandler.cs | 56 +++++ .../PublishMessageCommandValidator.cs | 11 + .../GetActiveMessages/PublicMessageDto.cs | 4 +- .../GetAllMessages/AdminPublicMessageDto.cs | 6 +- .../GetPublicMessage/GetPublicMessageQuery.cs | 25 +++ .../GetPublicMessageQueryHandler.cs | 46 ++++ .../GetPublicMessageQueryValidator.cs | 11 + .../ApplyDiscountToOrderCommand.cs | 39 ++++ .../ApplyDiscountToOrderCommandHandler.cs | 74 +++++++ .../ApplyDiscountToOrderCommandValidator.cs | 21 ++ .../UpdateOrderStatusCommand.cs | 34 +++ .../UpdateOrderStatusCommandHandler.cs | 53 +++++ .../UpdateOrderStatusCommandValidator.cs | 17 ++ .../CalculateOrderPV/CalculateOrderPVQuery.cs | 46 ++++ .../CalculateOrderPVQueryHandler.cs | 62 ++++++ .../CalculateOrderPVQueryValidator.cs | 11 + .../GetOrdersByDateRangeQuery.cs | 66 ++++++ .../GetOrdersByDateRangeQueryHandler.cs | 80 +++++++ .../GetOrdersByDateRangeQueryValidator.cs | 28 +++ .../Entities/{Message => }/PublicMessage.cs | 47 +++- .../Persistence/ApplicationDbContext.cs | 2 +- .../PublicMessageConfiguration.cs | 2 +- .../Protos/package.proto | 71 ++++++ .../Protos/public_messages.proto | 202 +++++++++++++++++- .../Protos/userorder.proto | 106 +++++++++ .../Common/Mappings/PackageProfile.cs | 52 ++++- .../Common/Mappings/UserOrderProfile.cs | 32 +++ .../Services/PackageService.cs | 18 ++ .../Services/PublicMessageService.cs | 63 ++++++ .../Services/UserOrderService.cs | 24 +++ 45 files changed, 1777 insertions(+), 22 deletions(-) create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommand.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommand.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQuery.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryValidator.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommand.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommand.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQuery.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryValidator.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommand.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommand.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQuery.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryValidator.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQuery.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryHandler.cs create mode 100644 src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryValidator.cs rename src/CMSMicroservice.Domain/Entities/{Message => }/PublicMessage.cs (56%) create mode 100644 src/CMSMicroservice.WebApi/Services/PublicMessageService.cs diff --git a/src/CMSMicroservice.Application/Common/Interfaces/IApplicationDbContext.cs b/src/CMSMicroservice.Application/Common/Interfaces/IApplicationDbContext.cs index 76f973a..0677b7d 100644 --- a/src/CMSMicroservice.Application/Common/Interfaces/IApplicationDbContext.cs +++ b/src/CMSMicroservice.Application/Common/Interfaces/IApplicationDbContext.cs @@ -1,5 +1,4 @@ using CMSMicroservice.Domain.Entities.Payment; -using CMSMicroservice.Domain.Entities.Message; using CMSMicroservice.Domain.Entities.Order; using CMSMicroservice.Domain.Entities.DiscountShop; diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommand.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommand.cs new file mode 100644 index 0000000..e05e252 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommand.cs @@ -0,0 +1,22 @@ +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage; + +/// +/// خرید پکیج طلایی (شروع فرآیند پرداخت) +/// +public record PurchaseGoldenPackageCommand : IRequest +{ + public long UserId { get; init; } + public long PackageId { get; init; } + public string ReturnUrl { get; init; } = string.Empty; +} + +public class PurchaseGoldenPackageResponseDto +{ + public bool Success { get; set; } + public string Message { get; set; } = string.Empty; + public long OrderId { get; set; } + public string PaymentGatewayUrl { get; set; } = string.Empty; + public string TrackingCode { get; set; } = string.Empty; +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandHandler.cs new file mode 100644 index 0000000..9e7c7bd --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandHandler.cs @@ -0,0 +1,88 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Enums; +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage; + +public class PurchaseGoldenPackageCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IPaymentGatewayService _paymentGateway; + private readonly ILogger _logger; + + public PurchaseGoldenPackageCommandHandler( + IApplicationDbContext context, + IPaymentGatewayService paymentGateway, + ILogger logger) + { + _context = context; + _paymentGateway = paymentGateway; + _logger = logger; + } + + public async Task Handle(PurchaseGoldenPackageCommand request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی خرید پکیج طلایی + // + // 1. پیدا کردن کاربر و بررسی شرایط: + // - var user = await _context.Users + // .Include(u => u.UserOrders) + // .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken) + // - if (user == null) throw new NotFoundException("کاربر یافت نشد") + // - if (user.PackagePurchaseMethod != PackagePurchaseMethod.None) + // throw new InvalidOperationException("شما قبلاً پکیج طلایی خریداری کرده‌اید") + // + // 2. پیدا کردن پکیج: + // - var package = await _context.Packages + // .FirstOrDefaultAsync(p => p.Id == request.PackageId && p.IsAvailable, cancellationToken) + // - if (package == null) throw new NotFoundException("پکیج یافت نشد") + // - if (package.Name != "طلایی") + // throw new InvalidOperationException("فقط پکیج طلایی قابل خرید است") + // + // 3. ایجاد سفارش: + // - var order = new UserOrder { + // UserId = user.Id, + // OrderNumber = GenerateOrderNumber(), // مثلاً "ORD" + DateTime.UtcNow.Ticks + // TotalPrice = package.Price, // 56,000,000 + // Status = OrderStatus.Pending, + // PaymentMethod = PaymentMethod.IPG, + // OrderType = OrderType.PackagePurchase, // enum جدید + // PackageId = package.Id + // } + // - _context.UserOrders.Add(order) + // - await _context.SaveChangesAsync(cancellationToken) + // + // 4. شروع پرداخت با درگاه: + // - var paymentResult = await _paymentGateway.InitiatePaymentAsync( + // orderId: order.Id, + // amount: order.TotalPrice, + // description: $"خرید پکیج {package.Name}", + // returnUrl: request.ReturnUrl, + // cancellationToken: cancellationToken + // ) + // - if (!paymentResult.Success) + // throw new InvalidOperationException($"خطا در اتصال به درگاه: {paymentResult.ErrorMessage}") + // + // 5. ذخیره اطلاعات پرداخت: + // - order.TrackingCode = paymentResult.TrackingCode + // - order.PaymentGatewayToken = paymentResult.Token + // - await _context.SaveChangesAsync(cancellationToken) + // + // 6. برگشت نتیجه: + // - _logger.LogInformation("Golden package purchase initiated for user {UserId}, order {OrderId}", user.Id, order.Id) + // - return new PurchaseGoldenPackageResponseDto { + // Success = true, + // Message = "لطفاً به درگاه پرداخت منتقل شوید", + // OrderId = order.Id, + // PaymentGatewayUrl = paymentResult.PaymentUrl, + // TrackingCode = paymentResult.TrackingCode + // } + // + // نکته 1: OrderType.PackagePurchase را به OrderType enum اضافه کنید + // نکته 2: PackageId nullable است در UserOrder - مطمئن شوید می‌توانید set کنید + // نکته 3: کاربر به صفحه paymentResult.PaymentUrl redirect می‌شود + // نکته 4: پس از پرداخت موفق، VerifyGoldenPackagePurchase فراخوانی می‌شود + + throw new NotImplementedException("PurchaseGoldenPackage needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandValidator.cs new file mode 100644 index 0000000..b9f4411 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/PurchaseGoldenPackage/PurchaseGoldenPackageCommandValidator.cs @@ -0,0 +1,23 @@ +using FluentValidation; + +namespace CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage; + +public class PurchaseGoldenPackageCommandValidator : AbstractValidator +{ + public PurchaseGoldenPackageCommandValidator() + { + RuleFor(x => x.UserId) + .GreaterThan(0) + .WithMessage("شناسه کاربر باید بزرگتر از 0 باشد"); + + RuleFor(x => x.PackageId) + .GreaterThan(0) + .WithMessage("شناسه پکیج باید بزرگتر از 0 باشد"); + + RuleFor(x => x.ReturnUrl) + .NotEmpty() + .WithMessage("آدرس بازگشت الزامی است") + .Must(url => Uri.TryCreate(url, UriKind.Absolute, out _)) + .WithMessage("آدرس بازگشت معتبر نیست"); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommand.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommand.cs new file mode 100644 index 0000000..d2ec876 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommand.cs @@ -0,0 +1,23 @@ +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyGoldenPackagePurchase; + +/// +/// تایید پرداخت پکیج طلایی (پس از بازگشت از درگاه) +/// +public record VerifyGoldenPackagePurchaseCommand : IRequest +{ + public long OrderId { get; init; } + public string Authority { get; init; } = string.Empty; + public string Status { get; init; } = string.Empty; // OK یا NOK +} + +public class VerifyGoldenPackagePurchaseResponseDto +{ + public bool Success { get; set; } + public string Message { get; set; } = string.Empty; + public long OrderId { get; set; } + public long TransactionId { get; set; } + public string ReferenceCode { get; set; } = string.Empty; + public long WalletBalance { get; set; } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandHandler.cs new file mode 100644 index 0000000..df9fe85 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandHandler.cs @@ -0,0 +1,115 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Enums; +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyGoldenPackagePurchase; + +public class VerifyGoldenPackagePurchaseCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly IPaymentGatewayService _paymentGateway; + private readonly ILogger _logger; + + public VerifyGoldenPackagePurchaseCommandHandler( + IApplicationDbContext context, + IPaymentGatewayService paymentGateway, + ILogger logger) + { + _context = context; + _paymentGateway = paymentGateway; + _logger = logger; + } + + public async Task Handle(VerifyGoldenPackagePurchaseCommand request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی تایید پرداخت پکیج طلایی + // + // 1. بررسی Status از درگاه: + // - if (request.Status != "OK") + // throw new InvalidOperationException("پرداخت توسط کاربر لغو شد") + // + // 2. پیدا کردن سفارش: + // - var order = await _context.UserOrders + // .Include(o => o.User) + // .ThenInclude(u => u.UserWallet) + // .FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken) + // - if (order == null) throw new NotFoundException("سفارش یافت نشد") + // - if (order.Status != OrderStatus.Pending) + // throw new InvalidOperationException("این سفارش قبلاً پردازش شده است") + // + // 3. Verify با درگاه پرداخت: + // - var verifyResult = await _paymentGateway.VerifyPaymentAsync( + // authority: request.Authority, + // amount: order.TotalPrice, + // cancellationToken: cancellationToken + // ) + // - if (!verifyResult.Success) { + // order.Status = OrderStatus.PaymentFailed + // order.PaymentFailureReason = verifyResult.ErrorMessage + // await _context.SaveChangesAsync(cancellationToken) + // throw new InvalidOperationException($"تایید پرداخت ناموفق: {verifyResult.ErrorMessage}") + // } + // + // 4. شارژ کیف پول: + // - var wallet = order.User.UserWallet + // - if (wallet == null) { + // wallet = new UserWallet { UserId = order.UserId, Balance = 0, DiscountBalance = 0 } + // _context.UserWallets.Add(wallet) + // } + // - wallet.Balance += order.TotalPrice // اضافه شدن 56,000,000 + // + // 5. ثبت Transaction: + // - var transaction = new Transaction { + // UserId = order.UserId, + // Amount = order.TotalPrice, + // Type = TransactionType.DepositIpg, + // Status = TransactionStatus.Completed, + // Description = $"شارژ کیف پول از خرید پکیج طلایی - سفارش {order.OrderNumber}", + // ReferenceCode = verifyResult.ReferenceCode, + // OrderId = order.Id + // } + // - _context.Transactions.Add(transaction) + // + // 6. ثبت UserWalletChangeLog: + // - var changeLog = new UserWalletChangeLog { + // UserId = order.UserId, + // ChangeValue = order.TotalPrice, + // ChangeType = ChangeType.Deposit, + // CurrentBalance = wallet.Balance, + // Description = $"شارژ از خرید پکیج طلایی", + // TransactionId = transaction.Id + // } + // - _context.UserWalletChangeLogs.Add(changeLog) + // + // 7. Set PackagePurchaseMethod: + // - order.User.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase + // + // 8. به‌روزرسانی سفارش: + // - order.Status = OrderStatus.Processing // یا Completed + // - order.PaymentStatus = PaymentStatus.Paid + // - order.PaidAt = DateTime.UtcNow + // - order.BankReferenceId = verifyResult.ReferenceCode + // + // 9. ذخیره همه تغییرات: + // - await _context.SaveChangesAsync(cancellationToken) + // + // 10. Log و برگشت: + // - _logger.LogInformation("Golden package verified for user {UserId}, order {OrderId}, wallet charged {Amount}", + // order.UserId, order.Id, order.TotalPrice) + // - return new VerifyGoldenPackagePurchaseResponseDto { + // Success = true, + // Message = "پرداخت با موفقیت تایید شد. کیف پول شما شارژ گردید", + // OrderId = order.Id, + // TransactionId = transaction.Id, + // ReferenceCode = verifyResult.ReferenceCode, + // WalletBalance = wallet.Balance + // } + // + // نکته 1: کاربر هنوز عضو باشگاه نشده - باید ActivateClubMembership صدا بزند + // نکته 2: TransactionType.DepositIpg را بررسی کنید موجود باشد + // نکته 3: در صورت خطا، سفارش به PaymentFailed تغییر وضعیت می‌دهد + // نکته 4: این فرآیند idempotent نیست - باید بررسی شود سفارش Pending باشد + + throw new NotImplementedException("VerifyGoldenPackagePurchase needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandValidator.cs new file mode 100644 index 0000000..8442702 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyGoldenPackagePurchase/VerifyGoldenPackagePurchaseCommandValidator.cs @@ -0,0 +1,23 @@ +using FluentValidation; + +namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyGoldenPackagePurchase; + +public class VerifyGoldenPackagePurchaseCommandValidator : AbstractValidator +{ + public VerifyGoldenPackagePurchaseCommandValidator() + { + RuleFor(x => x.OrderId) + .GreaterThan(0) + .WithMessage("شناسه سفارش باید بزرگتر از 0 باشد"); + + RuleFor(x => x.Authority) + .NotEmpty() + .WithMessage("کد Authority الزامی است"); + + RuleFor(x => x.Status) + .NotEmpty() + .WithMessage("وضعیت پرداخت الزامی است") + .Must(s => s == "OK" || s == "NOK") + .WithMessage("وضعیت باید OK یا NOK باشد"); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQuery.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQuery.cs new file mode 100644 index 0000000..6d359c5 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQuery.cs @@ -0,0 +1,24 @@ +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus; + +/// +/// دریافت وضعیت خرید پکیج کاربر +/// +public record GetUserPackageStatusQuery : IRequest +{ + public long UserId { get; init; } +} + +public class UserPackageStatusDto +{ + public long UserId { get; set; } + public string PackagePurchaseMethod { get; set; } = string.Empty; // None, DayaLoan, DirectPurchase + public bool HasPurchasedPackage { get; set; } + public bool IsClubMemberActive { get; set; } + public long WalletBalance { get; set; } + public long DiscountBalance { get; set; } + public bool CanActivateClubMembership { get; set; } + public string? LastOrderNumber { get; set; } + public DateTime? LastPurchaseDate { get; set; } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs new file mode 100644 index 0000000..daf2885 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryHandler.cs @@ -0,0 +1,61 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Enums; +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus; + +public class GetUserPackageStatusQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetUserPackageStatusQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetUserPackageStatusQuery request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی دریافت وضعیت پکیج کاربر + // + // 1. دریافت اطلاعات کاربر: + // - var user = await _context.Users + // .Include(u => u.UserWallet) + // .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken) + // - if (user == null) throw new NotFoundException("کاربر یافت نشد") + // + // 2. دریافت عضویت باشگاه: + // - var clubMembership = await _context.ClubMemberships + // .FirstOrDefaultAsync(c => c.UserId == user.Id && c.IsActive, cancellationToken) + // + // 3. دریافت آخرین سفارش پکیج: + // - var lastPackageOrder = await _context.UserOrders + // .Where(o => o.UserId == user.Id && o.PackageId != null) + // .OrderByDescending(o => o.Created) + // .FirstOrDefaultAsync(cancellationToken) + // + // 4. بررسی شرایط فعالسازی باشگاه: + // - var wallet = user.UserWallet + // - bool canActivate = + // user.PackagePurchaseMethod != PackagePurchaseMethod.None && + // clubMembership == null && + // wallet != null && + // wallet.Balance >= 56_000_000 + // + // 5. برگشت DTO: + // - return new UserPackageStatusDto { + // UserId = user.Id, + // PackagePurchaseMethod = user.PackagePurchaseMethod.ToString(), + // HasPurchasedPackage = user.PackagePurchaseMethod != PackagePurchaseMethod.None, + // IsClubMemberActive = clubMembership != null, + // WalletBalance = wallet?.Balance ?? 0, + // DiscountBalance = wallet?.DiscountBalance ?? 0, + // CanActivateClubMembership = canActivate, + // LastOrderNumber = lastPackageOrder?.OrderNumber, + // LastPurchaseDate = lastPackageOrder?.Created + // } + // + // نکته: این query برای UI مفید است تا وضعیت کاربر را نمایش دهد + + throw new NotImplementedException("GetUserPackageStatus needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryValidator.cs new file mode 100644 index 0000000..9016f86 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Queries/GetUserPackageStatus/GetUserPackageStatusQueryValidator.cs @@ -0,0 +1,13 @@ +using FluentValidation; + +namespace CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus; + +public class GetUserPackageStatusQueryValidator : AbstractValidator +{ + public GetUserPackageStatusQueryValidator() + { + RuleFor(x => x.UserId) + .GreaterThan(0) + .WithMessage("شناسه کاربر باید بزرگتر از 0 باشد"); + } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommand.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommand.cs new file mode 100644 index 0000000..2829800 --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommand.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.PublicMessageCQ.Commands.ArchiveMessage; + +/// +/// آرشیو پیام عمومی (غیرفعال و بایگانی) +/// +public record ArchiveMessageCommand : IRequest +{ + public long MessageId { get; init; } +} + +public class ArchiveMessageResponseDto +{ + public bool Success { get; set; } + public string Message { get; set; } = string.Empty; + public DateTime? ArchivedAt { get; set; } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandHandler.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandHandler.cs new file mode 100644 index 0000000..ce79ce1 --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandHandler.cs @@ -0,0 +1,52 @@ +using CMSMicroservice.Application.Common.Interfaces; + +namespace CMSMicroservice.Application.PublicMessageCQ.Commands.ArchiveMessage; + +public class ArchiveMessageCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + public ArchiveMessageCommandHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(ArchiveMessageCommand request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی آرشیو پیام + // 1. پیدا کردن پیام: + // - var message = await _context.PublicMessages + // .FirstOrDefaultAsync(m => m.Id == request.MessageId, cancellationToken) + // - بررسی null و پرتاب NotFoundException + // + // 2. بررسی وضعیت: + // - اگر قبلاً آرشیو شده: + // if (message.IsArchived) + // return موفقیت با پیام "این پیام قبلاً آرشیو شده است" + // + // 3. آرشیو کردن: + // - message.IsArchived = true + // - message.IsActive = false // غیرفعال هم می‌شود + // - message.ArchivedAt = DateTime.UtcNow + // + // 4. ذخیره و Log: + // - await _context.SaveChangesAsync(cancellationToken) + // - _logger.LogInformation("Public message {MessageId} archived: {Title}", message.Id, message.Title) + // + // 5. برگشت Response: + // - return new ArchiveMessageResponseDto { + // Success = true, + // Message = "پیام با موفقیت آرشیو شد", + // ArchivedAt = message.ArchivedAt + // } + // + // نکته: پیام‌های آرشیو شده دیگر در GetActiveMessages نمایش داده نمی‌شوند + // نکته: می‌توان پیام‌های آرشیو شده را در یک query جداگانه GetArchivedMessages دریافت کرد + + throw new NotImplementedException("ArchiveMessage needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandValidator.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandValidator.cs new file mode 100644 index 0000000..3193164 --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/ArchiveMessage/ArchiveMessageCommandValidator.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.PublicMessageCQ.Commands.ArchiveMessage; + +public class ArchiveMessageCommandValidator : AbstractValidator +{ + public ArchiveMessageCommandValidator() + { + RuleFor(x => x.MessageId) + .GreaterThan(0) + .WithMessage("شناسه پیام باید بزرگتر از 0 باشد"); + } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/CreatePublicMessage/CreatePublicMessageCommandHandler.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/CreatePublicMessage/CreatePublicMessageCommandHandler.cs index 56a4157..2f24849 100644 --- a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/CreatePublicMessage/CreatePublicMessageCommandHandler.cs +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/CreatePublicMessage/CreatePublicMessageCommandHandler.cs @@ -1,5 +1,5 @@ using CMSMicroservice.Application.Common.Interfaces; -using CMSMicroservice.Domain.Entities.Message; +using CMSMicroservice.Domain.Entities; using MediatR; using Microsoft.Extensions.Logging; diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommand.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommand.cs new file mode 100644 index 0000000..7c3a8c4 --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommand.cs @@ -0,0 +1,16 @@ +namespace CMSMicroservice.Application.PublicMessageCQ.Commands.PublishMessage; + +/// +/// انتشار پیام عمومی (فعال‌سازی) +/// +public record PublishMessageCommand : IRequest +{ + public long MessageId { get; init; } +} + +public class PublishMessageResponseDto +{ + public bool Success { get; set; } + public string Message { get; set; } = string.Empty; + public DateTime? PublishedAt { get; set; } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs new file mode 100644 index 0000000..e83458a --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandHandler.cs @@ -0,0 +1,56 @@ +using CMSMicroservice.Application.Common.Interfaces; + +namespace CMSMicroservice.Application.PublicMessageCQ.Commands.PublishMessage; + +public class PublishMessageCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + public PublishMessageCommandHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(PublishMessageCommand request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی انتشار پیام + // 1. پیدا کردن پیام: + // - var message = await _context.PublicMessages + // .FirstOrDefaultAsync(m => m.Id == request.MessageId, cancellationToken) + // - بررسی null و پرتاب NotFoundException + // + // 2. بررسی شرایط انتشار: + // - اگر قبلاً منتشر شده: + // if (message.IsActive && message.PublishedAt.HasValue) + // return موفقیت با پیام "این پیام قبلاً منتشر شده است" + // - اگر آرشیو شده: + // if (message.IsArchived) + // throw new InvalidOperationException("پیام آرشیو شده قابل انتشار نیست") + // + // 3. فعال‌سازی پیام: + // - message.IsActive = true + // - message.PublishedAt = DateTime.UtcNow + // - اگر StartDate خالی است، از الان شروع کن: + // if (!message.StartDate.HasValue) + // message.StartDate = DateTime.UtcNow + // + // 4. ذخیره و Log: + // - await _context.SaveChangesAsync(cancellationToken) + // - _logger.LogInformation("Public message {MessageId} published: {Title}", message.Id, message.Title) + // + // 5. برگشت Response: + // - return new PublishMessageResponseDto { + // Success = true, + // Message = "پیام با موفقیت منتشر شد", + // PublishedAt = message.PublishedAt + // } + // + // نکته: پس از publish، پیام برای کاربران قابل مشاهده می‌شود (GetActiveMessages) + + throw new NotImplementedException("PublishMessage needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandValidator.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandValidator.cs new file mode 100644 index 0000000..20ac2ad --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Commands/PublishMessage/PublishMessageCommandValidator.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.PublicMessageCQ.Commands.PublishMessage; + +public class PublishMessageCommandValidator : AbstractValidator +{ + public PublishMessageCommandValidator() + { + RuleFor(x => x.MessageId) + .GreaterThan(0) + .WithMessage("شناسه پیام باید بزرگتر از 0 باشد"); + } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetActiveMessages/PublicMessageDto.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetActiveMessages/PublicMessageDto.cs index ffe35cd..3d2375f 100644 --- a/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetActiveMessages/PublicMessageDto.cs +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetActiveMessages/PublicMessageDto.cs @@ -14,8 +14,8 @@ public class PublicMessageDto public string TypeName { get; set; } = string.Empty; public MessagePriority Priority { get; set; } public string PriorityName { get; set; } = string.Empty; - public DateTime StartsAt { get; set; } - public DateTime ExpiresAt { get; set; } + public DateTime? StartsAt { get; set; } + public DateTime? ExpiresAt { get; set; } public string? LinkUrl { get; set; } public string? LinkText { get; set; } public DateTime Created { get; set; } diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetAllMessages/AdminPublicMessageDto.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetAllMessages/AdminPublicMessageDto.cs index cd2a9d0..734b105 100644 --- a/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetAllMessages/AdminPublicMessageDto.cs +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetAllMessages/AdminPublicMessageDto.cs @@ -15,9 +15,9 @@ public class AdminPublicMessageDto public MessagePriority Priority { get; set; } public string PriorityName { get; set; } = string.Empty; public bool IsActive { get; set; } - public DateTime StartsAt { get; set; } - public DateTime ExpiresAt { get; set; } - public long CreatedByUserId { get; set; } + public DateTime? StartsAt { get; set; } + public DateTime? ExpiresAt { get; set; } + public long? CreatedByUserId { get; set; } public int ViewCount { get; set; } public string? LinkUrl { get; set; } public string? LinkText { get; set; } diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQuery.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQuery.cs new file mode 100644 index 0000000..a158917 --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQuery.cs @@ -0,0 +1,25 @@ +namespace CMSMicroservice.Application.PublicMessageCQ.Queries.GetPublicMessage; + +/// +/// دریافت یک پیام عمومی با شناسه +/// +public record GetPublicMessageQuery : IRequest +{ + public long MessageId { get; init; } +} + +public class PublicMessageDto +{ + public long Id { get; set; } + public string Title { get; set; } = string.Empty; + public string Content { get; set; } = string.Empty; + public MessageType MessageType { get; set; } + public bool IsActive { get; set; } + public bool IsArchived { get; set; } + public DateTime? StartDate { get; set; } + public DateTime? EndDate { get; set; } + public DateTime? PublishedAt { get; set; } + public DateTime? ArchivedAt { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? LastModifiedAt { get; set; } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryHandler.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryHandler.cs new file mode 100644 index 0000000..dc8638c --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryHandler.cs @@ -0,0 +1,46 @@ +using CMSMicroservice.Application.Common.Interfaces; + +namespace CMSMicroservice.Application.PublicMessageCQ.Queries.GetPublicMessage; + +public class GetPublicMessageQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + + public GetPublicMessageQueryHandler(IApplicationDbContext context) + { + _context = context; + } + + public async Task Handle(GetPublicMessageQuery request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی دریافت پیام + // 1. پیدا کردن پیام: + // - var message = await _context.PublicMessages + // .AsNoTracking() + // .FirstOrDefaultAsync(m => m.Id == request.MessageId, cancellationToken) + // + // 2. چک null: + // - if (message == null) return null + // + // 3. Map به DTO: + // - return new PublicMessageDto { + // Id = message.Id, + // Title = message.Title, + // Content = message.Content, + // MessageType = message.MessageType, + // IsActive = message.IsActive, + // IsArchived = message.IsArchived, + // StartDate = message.StartDate, + // EndDate = message.EndDate, + // PublishedAt = message.PublishedAt, + // ArchivedAt = message.ArchivedAt, + // CreatedAt = message.CreatedAt, + // LastModifiedAt = message.LastModifiedAt + // } + // + // نکته: این query برای Admin است و همه پیام‌ها (حتی آرشیو شده) را برمی‌گرداند + // نکته: برای کاربران عادی از GetActiveMessages استفاده می‌شود + + throw new NotImplementedException("GetPublicMessage needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryValidator.cs b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryValidator.cs new file mode 100644 index 0000000..4aac3c2 --- /dev/null +++ b/src/CMSMicroservice.Application/PublicMessageCQ/Queries/GetPublicMessage/GetPublicMessageQueryValidator.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.PublicMessageCQ.Queries.GetPublicMessage; + +public class GetPublicMessageQueryValidator : AbstractValidator +{ + public GetPublicMessageQueryValidator() + { + RuleFor(x => x.MessageId) + .GreaterThan(0) + .WithMessage("شناسه پیام باید بزرگتر از 0 باشد"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommand.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommand.cs new file mode 100644 index 0000000..61d04f8 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommand.cs @@ -0,0 +1,39 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder; + +/// +/// اعمال تخفیف به سفارش +/// +public record ApplyDiscountToOrderCommand : IRequest +{ + /// + /// شناسه سفارش + /// + public long OrderId { get; init; } + + /// + /// مبلغ تخفیف (ریال) + /// + public long DiscountAmount { get; init; } + + /// + /// دلیل تخفیف + /// + public string Reason { get; init; } = string.Empty; + + /// + /// کد تخفیف (اختیاری) + /// + public string? DiscountCode { get; init; } +} + +/// +/// پاسخ اعمال تخفیف +/// +public class ApplyDiscountToOrderResponseDto +{ + public bool Success { get; set; } + public string Message { get; set; } = string.Empty; + public long OriginalAmount { get; set; } + public long DiscountAmount { get; set; } + public long FinalAmount { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandHandler.cs new file mode 100644 index 0000000..cfe6519 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandHandler.cs @@ -0,0 +1,74 @@ +using CMSMicroservice.Application.Common.Interfaces; + +namespace CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder; + +public class ApplyDiscountToOrderCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + public ApplyDiscountToOrderCommandHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(ApplyDiscountToOrderCommand request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی اعمال تخفیف به سفارش + // 1. پیدا کردن سفارش: + // - var order = await _context.UserOrders.FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken) + // - بررسی null و پرتاب NotFoundException + // + // 2. بررسی شرایط اعمال تخفیف: + // - سفارش نباید Delivered یا Cancelled باشد + // - مبلغ تخفیف نباید بیشتر از Amount باشد + // - if (order.DeliveryStatus == DeliveryStatus.Delivered || order.DeliveryStatus == DeliveryStatus.Cancelled) + // throw new InvalidOperationException("نمی‌توان به این سفارش تخفیف اعمال کرد") + // - if (request.DiscountAmount > order.Amount) + // throw new InvalidOperationException("مبلغ تخفیف نمی‌تواند بیشتر از مبلغ سفارش باشد") + // + // 3. محاسبه مبلغ نهایی: + // - var originalAmount = order.Amount + // - var newDiscountedPrice = order.Amount - request.DiscountAmount + // - مطمئن شوید که منفی نشود: newDiscountedPrice = Math.Max(0, newDiscountedPrice) + // + // 4. به‌روزرسانی سفارش: + // - order.DiscountedPrice = newDiscountedPrice + // - اگر فیلد OrderDiscountAmount وجود دارد، آن را هم به‌روز کنید + // - order.OrderDiscountAmount = request.DiscountAmount + // - اضافه کردن به توضیحات: + // order.DeliveryDescription = (order.DeliveryDescription ?? "") + + // $"\nتخفیف اعمال شده: {request.DiscountAmount} ریال - دلیل: {request.Reason}" + // + // 5. ذخیره Log تخفیف (اختیاری - اگر جدول OrderDiscountLog دارید): + // - var discountLog = new OrderDiscountLog { + // OrderId = order.Id, + // DiscountAmount = request.DiscountAmount, + // Reason = request.Reason, + // DiscountCode = request.DiscountCode, + // AppliedAt = DateTime.UtcNow + // } + // - await _context.OrderDiscountLogs.AddAsync(discountLog, cancellationToken) + // + // 6. ذخیره و Log: + // - await _context.SaveChangesAsync(cancellationToken) + // - _logger.LogInformation("Discount {Amount} applied to order {OrderId}: {Reason}", + // request.DiscountAmount, request.OrderId, request.Reason) + // + // 7. برگشت Response: + // - return new ApplyDiscountToOrderResponseDto { + // Success = true, + // Message = "تخفیف با موفقیت اعمال شد", + // OriginalAmount = originalAmount, + // DiscountAmount = request.DiscountAmount, + // FinalAmount = newDiscountedPrice + // } + // + // نکته: این تخفیف برای تخفیفات دستی Admin است و جدا از تخفیف‌های محصول + + throw new NotImplementedException("ApplyDiscountToOrder needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandValidator.cs new file mode 100644 index 0000000..6c0fcfb --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/ApplyDiscountToOrder/ApplyDiscountToOrderCommandValidator.cs @@ -0,0 +1,21 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder; + +public class ApplyDiscountToOrderCommandValidator : AbstractValidator +{ + public ApplyDiscountToOrderCommandValidator() + { + RuleFor(x => x.OrderId) + .GreaterThan(0) + .WithMessage("شناسه سفارش باید بزرگتر از 0 باشد"); + + RuleFor(x => x.DiscountAmount) + .GreaterThan(0) + .WithMessage("مبلغ تخفیف باید بزرگتر از 0 باشد"); + + RuleFor(x => x.Reason) + .NotEmpty() + .WithMessage("دلیل تخفیف الزامی است") + .MaximumLength(500) + .WithMessage("دلیل تخفیف نمی‌تواند بیشتر از 500 کاراکتر باشد"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommand.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommand.cs new file mode 100644 index 0000000..5ebc317 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommand.cs @@ -0,0 +1,34 @@ +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus; + +/// +/// تغییر وضعیت سفارش +/// +public record UpdateOrderStatusCommand : IRequest +{ + /// + /// شناسه سفارش + /// + public long OrderId { get; init; } + + /// + /// وضعیت تحویل جدید + /// + public DeliveryStatus NewStatus { get; init; } + + /// + /// توضیحات (اختیاری) + /// + public string? Description { get; init; } +} + +/// +/// پاسخ تغییر وضعیت سفارش +/// +public class UpdateOrderStatusResponseDto +{ + public bool Success { get; set; } + public string Message { get; set; } = string.Empty; + public DeliveryStatus CurrentStatus { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs new file mode 100644 index 0000000..96279e7 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandHandler.cs @@ -0,0 +1,53 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus; + +public class UpdateOrderStatusCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + public UpdateOrderStatusCommandHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(UpdateOrderStatusCommand request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی تغییر وضعیت سفارش + // 1. پیدا کردن سفارش: + // - await _context.UserOrders.FirstOrDefaultAsync(o => o.Id == request.OrderId) + // - بررسی null و پرتاب NotFoundException + // + // 2. بررسی‌های انتقال وضعیت (State Transition Validation): + // - نمی‌توان از Delivered به Cancelled رفت + // - نمی‌توان از Cancelled به سایر وضعیت‌ها رفت + // - الگوی معمول: Pending → Processing → Shipped → Delivered + // - Cancelled می‌تواند از Pending, Processing, Shipped باشد + // + // 3. تغییر وضعیت: + // - order.DeliveryStatus = request.NewStatus + // - اگر Description داریم: order.DeliveryDescription = request.Description + // - تنظیم تاریخ‌های مربوطه: + // * اگر NewStatus == Delivered → order.DeliveredAt = DateTime.UtcNow + // * اگر NewStatus == Shipped → order.ShippedAt = DateTime.UtcNow + // * اگر NewStatus == Processing → order.ProcessedAt = DateTime.UtcNow + // + // 4. ذخیره و Log: + // - await _context.SaveChangesAsync(cancellationToken) + // - _logger.LogInformation("Order {OrderId} status changed to {NewStatus}", request.OrderId, request.NewStatus) + // + // 5. برگشت Response: + // - Success = true + // - Message = "وضعیت سفارش با موفقیت تغییر کرد" + // - CurrentStatus = order.DeliveryStatus + // + // نکته: برای validation دقیق‌تر، می‌توان یک State Machine برای انتقال‌های مجاز تعریف کرد + + throw new NotImplementedException("UpdateOrderStatus needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandValidator.cs new file mode 100644 index 0000000..d4ebd11 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Commands/UpdateOrderStatus/UpdateOrderStatusCommandValidator.cs @@ -0,0 +1,17 @@ +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus; + +public class UpdateOrderStatusCommandValidator : AbstractValidator +{ + public UpdateOrderStatusCommandValidator() + { + RuleFor(x => x.OrderId) + .GreaterThan(0) + .WithMessage("شناسه سفارش باید بزرگتر از 0 باشد"); + + RuleFor(x => x.NewStatus) + .IsInEnum() + .WithMessage("وضعیت تحویل نامعتبر است"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQuery.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQuery.cs new file mode 100644 index 0000000..c29b1f8 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQuery.cs @@ -0,0 +1,46 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV; + +/// +/// محاسبه امتیاز PV سفارش +/// +public record CalculateOrderPVQuery : IRequest +{ + /// + /// شناسه سفارش + /// + public long OrderId { get; init; } +} + +/// +/// پاسخ محاسبه PV سفارش +/// +public class CalculateOrderPVResponseDto +{ + /// + /// مجموع امتیاز PV سفارش + /// + public decimal TotalPV { get; set; } + + /// + /// جزئیات PV هر محصول + /// + public List ProductPVs { get; set; } = new(); + + /// + /// مبلغ قابل پرداخت + /// + public long PayableAmount { get; set; } +} + +/// +/// جزئیات PV یک محصول در سفارش +/// +public class ProductPVDto +{ + public long ProductId { get; set; } + public string ProductTitle { get; set; } = string.Empty; + public int Quantity { get; set; } + public decimal UnitPV { get; set; } + public decimal TotalPV { get; set; } + public long UnitPrice { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryHandler.cs new file mode 100644 index 0000000..54ffe48 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryHandler.cs @@ -0,0 +1,62 @@ +using CMSMicroservice.Application.Common.Interfaces; + +namespace CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV; + +public class CalculateOrderPVQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + public CalculateOrderPVQueryHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(CalculateOrderPVQuery request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی محاسبه PV سفارش + // 1. پیدا کردن سفارش و جزئیات: + // - var order = await _context.UserOrders + // .Include(o => o.FactorDetails) + // .ThenInclude(fd => fd.Product) + // .FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken) + // - بررسی null و پرتاب NotFoundException + // + // 2. محاسبه PV هر محصول: + // - var productPVs = new List() + // - decimal totalPV = 0 + // - foreach (var detail in order.FactorDetails): + // * محاسبه PV واحد محصول (فرض: قیمت / 10000 یا از فیلد Product.PV اگر وجود دارد): + // decimal unitPV = detail.Product.PV ?? (detail.Product.Price / 10000m) + // * محاسبه PV کل این آیتم: + // decimal itemTotalPV = unitPV * detail.Count + // * اضافه به لیست: + // productPVs.Add(new ProductPVDto { + // ProductId = detail.ProductId, + // ProductTitle = detail.Product.Title, + // Quantity = detail.Count, + // UnitPV = unitPV, + // TotalPV = itemTotalPV, + // UnitPrice = detail.Product.Price + // }) + // * اضافه به مجموع: + // totalPV += itemTotalPV + // + // 3. برگشت Response: + // - _logger.LogInformation("Calculated PV for order {OrderId}: {TotalPV}", request.OrderId, totalPV) + // - return new CalculateOrderPVResponseDto { + // TotalPV = totalPV, + // ProductPVs = productPVs, + // PayableAmount = order.DiscountedPrice + // } + // + // نکته: PV (Point Value) معمولاً برای سیستم‌های MLM و کمیسیون شبکه استفاده می‌شود + // نکته: فرمول محاسبه PV باید بر اساس business logic شما باشد (قیمت/10000 فقط مثال است) + // نکته: اگر entity Product فیلد PV ندارد، باید اضافه شود یا از Configuration استفاده کنید + + throw new NotImplementedException("CalculateOrderPV needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryValidator.cs new file mode 100644 index 0000000..671348a --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/CalculateOrderPV/CalculateOrderPVQueryValidator.cs @@ -0,0 +1,11 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV; + +public class CalculateOrderPVQueryValidator : AbstractValidator +{ + public CalculateOrderPVQueryValidator() + { + RuleFor(x => x.OrderId) + .GreaterThan(0) + .WithMessage("شناسه سفارش باید بزرگتر از 0 باشد"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQuery.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQuery.cs new file mode 100644 index 0000000..67cba45 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQuery.cs @@ -0,0 +1,66 @@ +using CMSMicroservice.Application.Common.Models; +using CMSMicroservice.Domain.Enums; + +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange; + +/// +/// دریافت سفارشات بر اساس بازه زمانی +/// +public record GetOrdersByDateRangeQuery : IRequest +{ + /// + /// تاریخ شروع (UTC) + /// + public DateTime StartDate { get; init; } + + /// + /// تاریخ پایان (UTC) + /// + public DateTime EndDate { get; init; } + + /// + /// فیلتر وضعیت تحویل (اختیاری) + /// + public DeliveryStatus? Status { get; init; } + + /// + /// شناسه کاربر (اختیاری - برای فیلتر بر اساس کاربر) + /// + public long? UserId { get; init; } + + /// + /// شماره صفحه + /// + public int PageIndex { get; init; } = 1; + + /// + /// تعداد در صفحه + /// + public int PageSize { get; init; } = 20; +} + +/// +/// پاسخ لیست سفارشات +/// +public class GetOrdersByDateRangeResponseDto +{ + public MetaData MetaData { get; set; } = new(); + public List Orders { get; set; } = new(); +} + +/// +/// خلاصه اطلاعات سفارش +/// +public class OrderSummaryDto +{ + public long Id { get; set; } + public long UserId { get; set; } + public string UserFullName { get; set; } = string.Empty; + public long Amount { get; set; } + public long DiscountedPrice { get; set; } + public DeliveryStatus Status { get; set; } + public DateTime Created { get; set; } + public DateTime? ShippedAt { get; set; } + public DateTime? DeliveredAt { get; set; } + public int ItemsCount { get; set; } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryHandler.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryHandler.cs new file mode 100644 index 0000000..f7bcf95 --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryHandler.cs @@ -0,0 +1,80 @@ +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Application.Common.Models; + +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange; + +public class GetOrdersByDateRangeQueryHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + public GetOrdersByDateRangeQueryHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle(GetOrdersByDateRangeQuery request, CancellationToken cancellationToken) + { + // TODO: پیاده‌سازی دریافت سفارشات بر اساس بازه زمانی + // 1. شروع Query: + // - var query = _context.UserOrders.AsQueryable() + // - Include User برای نام کاربر: .Include(o => o.User) + // - Include FactorDetails برای شمارش تعداد آیتم‌ها: .Include(o => o.FactorDetails) + // + // 2. اعمال فیلتر بازه زمانی: + // - query = query.Where(o => o.Created >= request.StartDate && o.Created <= request.EndDate) + // + // 3. اعمال فیلترهای اختیاری: + // - اگر request.Status.HasValue: + // query = query.Where(o => o.DeliveryStatus == request.Status.Value) + // - اگر request.UserId.HasValue: + // query = query.Where(o => o.UserId == request.UserId.Value) + // + // 4. محاسبه تعداد کل: + // - var totalCount = await query.CountAsync(cancellationToken) + // + // 5. مرتب‌سازی و Pagination: + // - query = query.OrderByDescending(o => o.Created) + // - query = query.Skip((request.PageIndex - 1) * request.PageSize) + // - query = query.Take(request.PageSize) + // + // 6. دریافت داده‌ها: + // - var orders = await query.ToListAsync(cancellationToken) + // + // 7. Mapping به DTO: + // - var orderDtos = orders.Select(o => new OrderSummaryDto { + // Id = o.Id, + // UserId = o.UserId, + // UserFullName = $"{o.User.Firstname} {o.User.Lastname}", + // Amount = o.Amount, + // DiscountedPrice = o.DiscountedPrice, + // Status = o.DeliveryStatus, + // Created = o.Created, + // ShippedAt = o.ShippedAt, + // DeliveredAt = o.DeliveredAt, + // ItemsCount = o.FactorDetails.Count + // }).ToList() + // + // 8. ساخت MetaData: + // - var totalPages = (int)Math.Ceiling(totalCount / (double)request.PageSize) + // - MetaData = new MetaData { + // CurrentPage = request.PageIndex, + // TotalPage = totalPages, + // PageSize = request.PageSize, + // TotalCount = totalCount, + // HasNext = request.PageIndex < totalPages, + // HasPrevious = request.PageIndex > 1 + // } + // + // 9. Log و برگشت: + // - _logger.LogInformation("Retrieved {Count} orders for date range {Start} to {End}", orders.Count, request.StartDate, request.EndDate) + // - return new GetOrdersByDateRangeResponseDto { MetaData = metaData, Orders = orderDtos } + // + // نکته: برای performance بهتر، می‌توان از AsNoTracking() استفاده کرد + + throw new NotImplementedException("GetOrdersByDateRange needs implementation"); + } +} diff --git a/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryValidator.cs b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryValidator.cs new file mode 100644 index 0000000..f11541f --- /dev/null +++ b/src/CMSMicroservice.Application/UserOrderCQ/Queries/GetOrdersByDateRange/GetOrdersByDateRangeQueryValidator.cs @@ -0,0 +1,28 @@ +namespace CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange; + +public class GetOrdersByDateRangeQueryValidator : AbstractValidator +{ + public GetOrdersByDateRangeQueryValidator() + { + RuleFor(x => x.StartDate) + .LessThanOrEqualTo(x => x.EndDate) + .WithMessage("تاریخ شروع باید کوچکتر یا مساوی تاریخ پایان باشد"); + + RuleFor(x => x.EndDate) + .LessThanOrEqualTo(DateTime.UtcNow.AddDays(1)) + .WithMessage("تاریخ پایان نمی‌تواند در آینده باشد"); + + RuleFor(x => x.PageIndex) + .GreaterThan(0) + .WithMessage("شماره صفحه باید بزرگتر از 0 باشد"); + + RuleFor(x => x.PageSize) + .InclusiveBetween(1, 100) + .WithMessage("تعداد در صفحه باید بین 1 تا 100 باشد"); + + // بازه زمانی نباید بیش از 1 سال باشد + RuleFor(x => x) + .Must(x => (x.EndDate - x.StartDate).TotalDays <= 365) + .WithMessage("بازه زمانی نمی‌تواند بیش از 1 سال باشد"); + } +} diff --git a/src/CMSMicroservice.Domain/Entities/Message/PublicMessage.cs b/src/CMSMicroservice.Domain/Entities/PublicMessage.cs similarity index 56% rename from src/CMSMicroservice.Domain/Entities/Message/PublicMessage.cs rename to src/CMSMicroservice.Domain/Entities/PublicMessage.cs index cd516d6..bab99fd 100644 --- a/src/CMSMicroservice.Domain/Entities/Message/PublicMessage.cs +++ b/src/CMSMicroservice.Domain/Entities/PublicMessage.cs @@ -1,11 +1,10 @@ using CMSMicroservice.Domain.Common; using CMSMicroservice.Domain.Enums; -namespace CMSMicroservice.Domain.Entities.Message; +namespace CMSMicroservice.Domain.Entities; /// -/// پیام‌های عمومی سیستم -/// Admin می‌تواند پیام‌های عمومی برای نمایش در داشبورد کاربران ارسال کند +/// پیام عمومی برای نمایش در سیستم /// public class PublicMessage : BaseAuditableEntity { @@ -22,37 +21,52 @@ public class PublicMessage : BaseAuditableEntity /// /// نوع پیام (Announcement, News, Warning, Promotion, SystemUpdate, Event) /// - public MessageType Type { get; set; } + public MessageType Type { get; set; } = MessageType.Announcement; /// /// اولویت پیام (Low, Medium, High, Urgent) /// - public MessagePriority Priority { get; set; } + public MessagePriority Priority { get; set; } = MessagePriority.Medium; /// /// وضعیت فعال/غیرفعال /// - public bool IsActive { get; set; } + public bool IsActive { get; set; } = false; + + /// + /// آیا آرشیو شده است؟ + /// + public bool IsArchived { get; set; } = false; /// /// تاریخ شروع نمایش پیام /// - public DateTime StartsAt { get; set; } + public DateTime? StartDate { get; set; } /// /// تاریخ پایان نمایش پیام /// - public DateTime ExpiresAt { get; set; } + public DateTime? EndDate { get; set; } + + /// + /// تاریخ انتشار + /// + public DateTime? PublishedAt { get; set; } + + /// + /// تاریخ آرشیو + /// + public DateTime? ArchivedAt { get; set; } /// /// شناسه Admin ایجادکننده /// - public long CreatedByUserId { get; set; } + public long? CreatedByUserId { get; set; } /// /// تعداد بازدید (اختیاری - برای آمار) /// - public int ViewCount { get; set; } + public int ViewCount { get; set; } = 0; /// /// لینک اختیاری (برای اطلاعات بیشتر) @@ -63,4 +77,17 @@ public class PublicMessage : BaseAuditableEntity /// متن دکمه لینک (مثلاً "اطلاعات بیشتر") /// public string? LinkText { get; set; } + + // Backward compatibility properties (map to StartDate/EndDate) + public DateTime? StartsAt + { + get => StartDate; + set => StartDate = value; + } + + public DateTime? ExpiresAt + { + get => EndDate; + set => EndDate = value; + } } diff --git a/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs b/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs index ebc1e6c..7f2d668 100644 --- a/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs +++ b/src/CMSMicroservice.Infrastructure/Persistence/ApplicationDbContext.cs @@ -2,7 +2,7 @@ using System.Reflection; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Entities.Payment; -using CMSMicroservice.Domain.Entities.Message; + using CMSMicroservice.Domain.Entities.Order; using CMSMicroservice.Domain.Entities.DiscountShop; using CMSMicroservice.Infrastructure.Persistence.Interceptors; diff --git a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/PublicMessageConfiguration.cs b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/PublicMessageConfiguration.cs index 4983607..c4906ce 100644 --- a/src/CMSMicroservice.Infrastructure/Persistence/Configurations/PublicMessageConfiguration.cs +++ b/src/CMSMicroservice.Infrastructure/Persistence/Configurations/PublicMessageConfiguration.cs @@ -1,4 +1,4 @@ -using CMSMicroservice.Domain.Entities.Message; +using CMSMicroservice.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/src/CMSMicroservice.Protobuf/Protos/package.proto b/src/CMSMicroservice.Protobuf/Protos/package.proto index 6424de0..43c0ebd 100644 --- a/src/CMSMicroservice.Protobuf/Protos/package.proto +++ b/src/CMSMicroservice.Protobuf/Protos/package.proto @@ -43,6 +43,25 @@ service PackageContract }; }; + + // Package Purchase System + rpc PurchaseGoldenPackage(PurchaseGoldenPackageRequest) returns (PurchaseGoldenPackageResponse){ + option (google.api.http) = { + post: "/PurchaseGoldenPackage" + body: "*" + }; + }; + rpc VerifyGoldenPackagePurchase(VerifyGoldenPackagePurchaseRequest) returns (VerifyGoldenPackagePurchaseResponse){ + option (google.api.http) = { + post: "/VerifyGoldenPackagePurchase" + body: "*" + }; + }; + rpc GetUserPackageStatus(GetUserPackageStatusRequest) returns (GetUserPackageStatusResponse){ + option (google.api.http) = { + get: "/GetUserPackageStatus" + }; + }; } message CreateNewPackageRequest { @@ -106,3 +125,55 @@ message GetAllPackageByFilterResponseModel string image_path = 4; int64 price = 5; } + +// Package Purchase Messages +message PurchaseGoldenPackageRequest +{ + int64 user_id = 1; + int64 package_id = 2; + string return_url = 3; +} + +message PurchaseGoldenPackageResponse +{ + bool success = 1; + string message = 2; + int64 order_id = 3; + string payment_gateway_url = 4; + string tracking_code = 5; +} + +message VerifyGoldenPackagePurchaseRequest +{ + int64 order_id = 1; + string authority = 2; + string status = 3; +} + +message VerifyGoldenPackagePurchaseResponse +{ + bool success = 1; + string message = 2; + int64 order_id = 3; + int64 transaction_id = 4; + string reference_code = 5; + int64 wallet_balance = 6; +} + +message GetUserPackageStatusRequest +{ + int64 user_id = 1; +} + +message GetUserPackageStatusResponse +{ + int64 user_id = 1; + string package_purchase_method = 2; + bool has_purchased_package = 3; + bool is_club_member_active = 4; + int64 wallet_balance = 5; + int64 discount_balance = 6; + bool can_activate_club_membership = 7; + google.protobuf.StringValue last_order_number = 8; + google.protobuf.Timestamp last_purchase_date = 9; +} diff --git a/src/CMSMicroservice.Protobuf/Protos/public_messages.proto b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto index c78db04..095918c 100644 --- a/src/CMSMicroservice.Protobuf/Protos/public_messages.proto +++ b/src/CMSMicroservice.Protobuf/Protos/public_messages.proto @@ -2,8 +2,60 @@ syntax = "proto3"; package messages; +import "google/protobuf/empty.proto"; +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; +import "google/api/annotations.proto"; + option csharp_namespace = "CMSMicroservice.Protobuf.Protos"; -service PublicMessageContract{} + +service PublicMessageContract{ + rpc CreatePublicMessage(CreatePublicMessageRequest) returns (CreatePublicMessageResponse){ + option (google.api.http) = { + post: "/CreatePublicMessage" + body: "*" + }; + }; + rpc UpdatePublicMessage(UpdatePublicMessageRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + put: "/UpdatePublicMessage" + body: "*" + }; + }; + rpc DeletePublicMessage(DeletePublicMessageRequest) returns (google.protobuf.Empty){ + option (google.api.http) = { + delete: "/DeletePublicMessage" + body: "*" + }; + }; + rpc PublishMessage(PublishMessageRequest) returns (PublishMessageResponse){ + option (google.api.http) = { + post: "/PublishMessage" + body: "*" + }; + }; + rpc ArchiveMessage(ArchiveMessageRequest) returns (ArchiveMessageResponse){ + option (google.api.http) = { + post: "/ArchiveMessage" + body: "*" + }; + }; + rpc GetAllMessages(GetAllMessagesRequest) returns (GetAllMessagesResponse){ + option (google.api.http) = { + get: "/GetAllMessages" + }; + }; + rpc GetActiveMessages(GetActiveMessagesRequest) returns (GetActiveMessagesResponse){ + option (google.api.http) = { + get: "/GetActiveMessages" + }; + }; + rpc GetPublicMessage(GetPublicMessageRequest) returns (GetPublicMessageResponse){ + option (google.api.http) = { + get: "/GetPublicMessage" + }; + }; +} message PaginationState { int32 page_number = 1; @@ -68,3 +120,151 @@ enum PaymentMethod IPG = 0; Wallet = 1; } + +// Public Message Types +message CreatePublicMessageRequest +{ + string title = 1; + string content = 2; + int32 type = 3; + int32 priority = 4; + google.protobuf.Timestamp start_date = 5; + google.protobuf.Timestamp end_date = 6; + google.protobuf.StringValue link_url = 7; + google.protobuf.StringValue link_text = 8; +} + +message CreatePublicMessageResponse +{ + int64 id = 1; +} + +message UpdatePublicMessageRequest +{ + int64 id = 1; + string title = 2; + string content = 3; + int32 type = 4; + int32 priority = 5; + google.protobuf.Timestamp start_date = 6; + google.protobuf.Timestamp end_date = 7; + google.protobuf.StringValue link_url = 8; + google.protobuf.StringValue link_text = 9; +} + +message DeletePublicMessageRequest +{ + int64 message_id = 1; +} + +message PublishMessageRequest +{ + int64 message_id = 1; +} + +message PublishMessageResponse +{ + bool success = 1; + string message = 2; + google.protobuf.Timestamp published_at = 3; +} + +message ArchiveMessageRequest +{ + int64 message_id = 1; +} + +message ArchiveMessageResponse +{ + bool success = 1; + string message = 2; + google.protobuf.Timestamp archived_at = 3; +} + +message GetAllMessagesRequest +{ + int32 page_number = 1; + int32 page_size = 2; + google.protobuf.BoolValue is_active = 3; + google.protobuf.Int32Value type = 4; + google.protobuf.Int32Value priority = 5; +} + +message GetAllMessagesResponse +{ + MetaData meta_data = 1; + repeated AdminPublicMessageDto messages = 2; +} + +message AdminPublicMessageDto +{ + int64 id = 1; + string title = 2; + string content = 3; + int32 type = 4; + string type_name = 5; + int32 priority = 6; + string priority_name = 7; + bool is_active = 8; + google.protobuf.Timestamp starts_at = 9; + google.protobuf.Timestamp expires_at = 10; + int64 created_by_user_id = 11; + int32 view_count = 12; + google.protobuf.StringValue link_url = 13; + google.protobuf.StringValue link_text = 14; + google.protobuf.Timestamp created = 15; + google.protobuf.Timestamp last_modified = 16; + bool is_expired = 17; +} + +message GetActiveMessagesRequest +{ +} + +message GetActiveMessagesResponse +{ + repeated PublicMessageDto messages = 1; +} + +message PublicMessageDto +{ + int64 id = 1; + string title = 2; + string content = 3; + int32 type = 4; + string type_name = 5; + int32 priority = 6; + string priority_name = 7; + google.protobuf.Timestamp starts_at = 8; + google.protobuf.Timestamp expires_at = 9; + google.protobuf.StringValue link_url = 10; + google.protobuf.StringValue link_text = 11; + google.protobuf.Timestamp created = 12; +} + +message GetPublicMessageRequest +{ + int64 message_id = 1; +} + +message GetPublicMessageResponse +{ + int64 id = 1; + string title = 2; + string content = 3; + int32 type = 4; + int32 priority = 5; + bool is_active = 6; + bool is_archived = 7; + google.protobuf.Timestamp start_date = 8; + google.protobuf.Timestamp end_date = 9; + google.protobuf.Timestamp published_at = 10; + google.protobuf.Timestamp archived_at = 11; + int64 created_by_user_id = 12; + int32 view_count = 13; + google.protobuf.StringValue link_url = 14; + google.protobuf.StringValue link_text = 15; + google.protobuf.Timestamp created_at = 16; + google.protobuf.Timestamp last_modified_at = 17; +} + diff --git a/src/CMSMicroservice.Protobuf/Protos/userorder.proto b/src/CMSMicroservice.Protobuf/Protos/userorder.proto index f594b63..eba196b 100644 --- a/src/CMSMicroservice.Protobuf/Protos/userorder.proto +++ b/src/CMSMicroservice.Protobuf/Protos/userorder.proto @@ -55,6 +55,30 @@ service UserOrderContract body: "*" }; }; + + // Order Management + rpc UpdateOrderStatus(UpdateOrderStatusRequest) returns (UpdateOrderStatusResponse){ + option (google.api.http) = { + post: "/UpdateOrderStatus" + body: "*" + }; + }; + rpc GetOrdersByDateRange(GetOrdersByDateRangeRequest) returns (GetOrdersByDateRangeResponse){ + option (google.api.http) = { + get: "/GetOrdersByDateRange" + }; + }; + rpc ApplyDiscountToOrder(ApplyDiscountToOrderRequest) returns (ApplyDiscountToOrderResponse){ + option (google.api.http) = { + post: "/ApplyDiscountToOrder" + body: "*" + }; + }; + rpc CalculateOrderPV(CalculateOrderPVRequest) returns (CalculateOrderPVResponse){ + option (google.api.http) = { + get: "/CalculateOrderPV" + }; + }; } message CreateNewUserOrderRequest { @@ -247,3 +271,85 @@ message CancelOrderResponse string message = 3; bool refund_processed = 4; } + +// Order Management Messages +message UpdateOrderStatusRequest +{ + int64 order_id = 1; + int32 new_status = 2; +} + +message UpdateOrderStatusResponse +{ + bool success = 1; + string message = 2; + int32 old_status = 3; + int32 new_status = 4; +} + +message GetOrdersByDateRangeRequest +{ + google.protobuf.Timestamp start_date = 1; + google.protobuf.Timestamp end_date = 2; + google.protobuf.Int32Value status = 3; + google.protobuf.Int64Value user_id = 4; + int32 page_number = 5; + int32 page_size = 6; +} + +message GetOrdersByDateRangeResponse +{ + messages.MetaData meta_data = 1; + repeated OrderSummaryDto orders = 2; +} + +message OrderSummaryDto +{ + int64 order_id = 1; + string order_number = 2; + int64 user_id = 3; + string user_full_name = 4; + int64 total_amount = 5; + int32 status = 6; + string status_name = 7; + int32 items_count = 8; + google.protobuf.Timestamp created_at = 9; +} + +message ApplyDiscountToOrderRequest +{ + int64 order_id = 1; + int64 discount_amount = 2; + string reason = 3; +} + +message ApplyDiscountToOrderResponse +{ + bool success = 1; + string message = 2; + int64 original_amount = 3; + int64 discount_amount = 4; + int64 final_amount = 5; +} + +message CalculateOrderPVRequest +{ + int64 order_id = 1; +} + +message CalculateOrderPVResponse +{ + int64 order_id = 1; + int64 total_pv = 2; + repeated ProductPVDto products = 3; +} + +message ProductPVDto +{ + int64 product_id = 1; + string product_title = 2; + int32 quantity = 3; + int64 unit_pv = 4; + int64 total_pv = 5; +} + diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs index 9e8a8f8..8611951 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs @@ -1,10 +1,58 @@ +using CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage; +using CMSMicroservice.Application.PackageCQ.Commands.VerifyGoldenPackagePurchase; +using CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus; +using CMSMicroservice.Protobuf.Protos.Package; +using Google.Protobuf.WellKnownTypes; + namespace CMSMicroservice.WebApi.Common.Mappings; public class PackageProfile : IRegister { void IRegister.Register(TypeAdapterConfig config) { - //config.NewConfig() - // .Map(dest => dest.FullName, src => $"{src.Firstname} {src.Lastname}"); + // PurchaseGoldenPackage + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.PackageId, src => src.PackageId) + .Map(dest => dest.ReturnUrl, src => src.ReturnUrl); + + config.NewConfig() + .Map(dest => dest.Success, src => src.Success) + .Map(dest => dest.Message, src => src.Message) + .Map(dest => dest.OrderId, src => src.OrderId) + .Map(dest => dest.PaymentGatewayUrl, src => src.PaymentGatewayUrl) + .Map(dest => dest.TrackingCode, src => src.TrackingCode); + + // VerifyGoldenPackagePurchase + config.NewConfig() + .Map(dest => dest.OrderId, src => src.OrderId) + .Map(dest => dest.Authority, src => src.Authority) + .Map(dest => dest.Status, src => src.Status); + + config.NewConfig() + .Map(dest => dest.Success, src => src.Success) + .Map(dest => dest.Message, src => src.Message) + .Map(dest => dest.OrderId, src => src.OrderId) + .Map(dest => dest.TransactionId, src => src.TransactionId) + .Map(dest => dest.ReferenceCode, src => src.ReferenceCode) + .Map(dest => dest.WalletBalance, src => src.WalletBalance); + + // GetUserPackageStatus + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId); + + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId) + .Map(dest => dest.PackagePurchaseMethod, src => src.PackagePurchaseMethod) + .Map(dest => dest.HasPurchasedPackage, src => src.HasPurchasedPackage) + .Map(dest => dest.IsClubMemberActive, src => src.IsClubMemberActive) + .Map(dest => dest.WalletBalance, src => src.WalletBalance) + .Map(dest => dest.DiscountBalance, src => src.DiscountBalance) + .Map(dest => dest.CanActivateClubMembership, src => src.CanActivateClubMembership) + .Map(dest => dest.LastOrderNumber, src => src.LastOrderNumber != null ? src.LastOrderNumber : null) + .Map(dest => dest.LastPurchaseDate, src => src.LastPurchaseDate.HasValue + ? Timestamp.FromDateTime(src.LastPurchaseDate.Value.ToUniversalTime()) + : null); } } + diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/UserOrderProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/UserOrderProfile.cs index 89e2a90..6164a65 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/UserOrderProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/UserOrderProfile.cs @@ -1,3 +1,9 @@ +using CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus; +using CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder; +using CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange; +using CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV; +using Google.Protobuf.WellKnownTypes; + namespace CMSMicroservice.WebApi.Common.Mappings; public class UserOrderProfile : IRegister @@ -8,5 +14,31 @@ public class UserOrderProfile : IRegister .IgnoreIf((src, dest) => src.Filter == null || !src.Filter.HasPaymentStatus, dest => dest.Filter.PaymentStatus) .IgnoreIf((src, dest) => src.Filter == null || !src.Filter.HasPaymentMethod, dest => dest.Filter.PaymentMethod) .IgnoreIf((src, dest) => src.Filter == null || !src.Filter.HasDeliveryStatus, dest => dest.Filter.DeliveryStatus); + + // UpdateOrderStatus + config.NewConfig(); + config.NewConfig(); + + // GetOrdersByDateRange + config.NewConfig() + .Map(dest => dest.StartDate, src => src.StartDate.ToDateTime()) + .Map(dest => dest.EndDate, src => src.EndDate.ToDateTime()) + .Map(dest => dest.Status, src => src.Status != null ? (int?)src.Status.Value : null) + .Map(dest => dest.UserId, src => src.UserId != null ? (long?)src.UserId.Value : null); + + config.NewConfig() + .Map(dest => dest.Orders, src => src.Orders); + + config.NewConfig() + .Map(dest => dest.CreatedAt, src => Timestamp.FromDateTime(src.Created.ToUniversalTime())); + + // ApplyDiscountToOrder + config.NewConfig(); + config.NewConfig(); + + // CalculateOrderPV + config.NewConfig(); + config.NewConfig(); + config.NewConfig(); } } diff --git a/src/CMSMicroservice.WebApi/Services/PackageService.cs b/src/CMSMicroservice.WebApi/Services/PackageService.cs index cfb27ea..93ed127 100644 --- a/src/CMSMicroservice.WebApi/Services/PackageService.cs +++ b/src/CMSMicroservice.WebApi/Services/PackageService.cs @@ -3,8 +3,11 @@ using CMSMicroservice.WebApi.Common.Services; using CMSMicroservice.Application.PackageCQ.Commands.CreateNewPackage; using CMSMicroservice.Application.PackageCQ.Commands.UpdatePackage; using CMSMicroservice.Application.PackageCQ.Commands.DeletePackage; +using CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage; +using CMSMicroservice.Application.PackageCQ.Commands.VerifyGoldenPackagePurchase; using CMSMicroservice.Application.PackageCQ.Queries.GetPackage; using CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter; +using CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus; namespace CMSMicroservice.WebApi.Services; public class PackageService : PackageContract.PackageContractBase { @@ -34,4 +37,19 @@ public class PackageService : PackageContract.PackageContractBase { return await _dispatchRequestToCQRS.Handle(request, context); } + + public override async Task PurchaseGoldenPackage(PurchaseGoldenPackageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task VerifyGoldenPackagePurchase(VerifyGoldenPackagePurchaseRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task GetUserPackageStatus(GetUserPackageStatusRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } } diff --git a/src/CMSMicroservice.WebApi/Services/PublicMessageService.cs b/src/CMSMicroservice.WebApi/Services/PublicMessageService.cs new file mode 100644 index 0000000..0672b71 --- /dev/null +++ b/src/CMSMicroservice.WebApi/Services/PublicMessageService.cs @@ -0,0 +1,63 @@ +using CMSMicroservice.Protobuf.Protos; +using CMSMicroservice.WebApi.Common.Services; +using CMSMicroservice.Application.PublicMessageCQ.Commands.CreatePublicMessage; +using CMSMicroservice.Application.PublicMessageCQ.Commands.UpdatePublicMessage; +using CMSMicroservice.Application.PublicMessageCQ.Commands.DeletePublicMessage; +using CMSMicroservice.Application.PublicMessageCQ.Commands.PublishMessage; +using CMSMicroservice.Application.PublicMessageCQ.Commands.ArchiveMessage; +using CMSMicroservice.Application.PublicMessageCQ.Queries.GetAllMessages; +using CMSMicroservice.Application.PublicMessageCQ.Queries.GetActiveMessages; +using CMSMicroservice.Application.PublicMessageCQ.Queries.GetPublicMessage; +using Google.Protobuf.WellKnownTypes; + +namespace CMSMicroservice.WebApi.Services; + +public class PublicMessageService : PublicMessageContract.PublicMessageContractBase +{ + private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + + public PublicMessageService(IDispatchRequestToCQRS dispatchRequestToCQRS) + { + _dispatchRequestToCQRS = dispatchRequestToCQRS; + } + + public override async Task CreatePublicMessage(CreatePublicMessageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task UpdatePublicMessage(UpdatePublicMessageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task DeletePublicMessage(DeletePublicMessageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task PublishMessage(PublishMessageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task ArchiveMessage(ArchiveMessageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task GetAllMessages(GetAllMessagesRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task GetActiveMessages(GetActiveMessagesRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task GetPublicMessage(GetPublicMessageRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } +} diff --git a/src/CMSMicroservice.WebApi/Services/UserOrderService.cs b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs index 96984af..9cf8b31 100644 --- a/src/CMSMicroservice.WebApi/Services/UserOrderService.cs +++ b/src/CMSMicroservice.WebApi/Services/UserOrderService.cs @@ -3,8 +3,12 @@ using CMSMicroservice.WebApi.Common.Services; using CMSMicroservice.Application.UserOrderCQ.Commands.CreateNewUserOrder; using CMSMicroservice.Application.UserOrderCQ.Commands.UpdateUserOrder; using CMSMicroservice.Application.UserOrderCQ.Commands.DeleteUserOrder; +using CMSMicroservice.Application.UserOrderCQ.Commands.UpdateOrderStatus; +using CMSMicroservice.Application.UserOrderCQ.Commands.ApplyDiscountToOrder; using CMSMicroservice.Application.UserOrderCQ.Queries.GetUserOrder; using CMSMicroservice.Application.UserOrderCQ.Queries.GetAllUserOrderByFilter; +using CMSMicroservice.Application.UserOrderCQ.Queries.GetOrdersByDateRange; +using CMSMicroservice.Application.UserOrderCQ.Queries.CalculateOrderPV; using CMSMicroservice.Application.UserOrderCQ.Commands.SubmitShopBuyOrder; using CMSMicroservice.Application.UserOrderCQ.Commands.CancelOrder; @@ -46,4 +50,24 @@ public class UserOrderService : UserOrderContract.UserOrderContractBase { return await _dispatchRequestToCQRS.Handle(request, context); } + + public override async Task UpdateOrderStatus(UpdateOrderStatusRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task GetOrdersByDateRange(GetOrdersByDateRangeRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task ApplyDiscountToOrder(ApplyDiscountToOrderRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task CalculateOrderPV(CalculateOrderPVRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } }