From 26e1243cfe02eba68a5b9199ed7f76e69dd52fab Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Tue, 16 Dec 2025 02:34:57 +0330 Subject: [PATCH] feat: add base package payment initiation and verification --- .../VerifyOtpTokenCommandHandler.cs | 14 +- .../InitiateBasePackagePaymentCommand.cs | 43 ++++ ...nitiateBasePackagePaymentCommandHandler.cs | 173 +++++++++++++++ ...tiateBasePackagePaymentCommandValidator.cs | 13 ++ .../VerifyBasePackagePaymentCommand.cs | 72 ++++++ .../VerifyBasePackagePaymentCommandHandler.cs | 209 ++++++++++++++++++ ...erifyBasePackagePaymentCommandValidator.cs | 17 ++ .../AdminGetJwtTokenQueryHandler.cs | 2 +- .../GetJwtToken/GetJwtTokenQueryHandler.cs | 1 + .../Services/DayaLoanApiService.cs | 7 +- .../Services/GenerateJwtTokenService.cs | 16 ++ .../Protos/package.proto | 49 ++++ .../Common/Mappings/PackageProfile.cs | 30 +++ .../Services/PackageService.cs | 13 ++ 14 files changed, 654 insertions(+), 5 deletions(-) create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommand.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandValidator.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommand.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandHandler.cs create mode 100644 src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandValidator.cs diff --git a/src/CMSMicroservice.Application/OtpTokenCQ/Commands/VerifyOtpToken/VerifyOtpTokenCommandHandler.cs b/src/CMSMicroservice.Application/OtpTokenCQ/Commands/VerifyOtpToken/VerifyOtpTokenCommandHandler.cs index c82bf7a..6bf7605 100644 --- a/src/CMSMicroservice.Application/OtpTokenCQ/Commands/VerifyOtpToken/VerifyOtpTokenCommandHandler.cs +++ b/src/CMSMicroservice.Application/OtpTokenCQ/Commands/VerifyOtpToken/VerifyOtpTokenCommandHandler.cs @@ -57,11 +57,21 @@ public class VerifyOtpTokenCommandHandler : IRequestHandler u.ReferralCode == request.ParentReferralCode, - cancellationToken: cancellationToken); + var parent = await _context.Users + .Include(u => u.ClubMembership) + .FirstOrDefaultAsync(u => u.ReferralCode == request.ParentReferralCode, + cancellationToken: cancellationToken); if (parent == null) return new VerifyOtpTokenResponseDto() { Success = false, Message = "معرف وجود ندارد." }; + // بررسی فعالیت باشگاه معرف + if (parent.ClubMembership == null || !parent.ClubMembership.IsActive) + return new VerifyOtpTokenResponseDto() + { + Success = false, + Message = "لینک دعوت معرف فعال نیست. لطفاً از کد دعوت معتبر دیگری استفاده کنید." + }; + if (await _context.Users.CountAsync(x => x.NetworkParentId == parent.Id, cancellationToken: cancellationToken) > 1) return new VerifyOtpTokenResponseDto() { Success = false, Message = "ظرفیت معرف تکمیل است!!" }; diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommand.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommand.cs new file mode 100644 index 0000000..29449f7 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommand.cs @@ -0,0 +1,43 @@ +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Commands.InitiateBasePackagePayment; + +/// +/// ثبت اولیه تراکنش و سفارش پکیج پایه (56 میلیون تومان) +/// این Command توسط BFF فراخوانی می‌شود قبل از ارسال کاربر به درگاه +/// +public record InitiateBasePackagePaymentCommand : IRequest +{ + /// + /// شناسه کاربر + /// + public long UserId { get; init; } +} + +public class InitiateBasePackagePaymentResponseDto +{ + /// + /// موفقیت عملیات + /// + public bool Success { get; set; } + + /// + /// پیام + /// + public string Message { get; set; } = string.Empty; + + /// + /// شناسه سفارش + /// + public long OrderId { get; set; } + + /// + /// شناسه تراکنش CMS + /// + public long TransactionId { get; set; } + + /// + /// مبلغ پکیج + /// + public long Amount { get; set; } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandHandler.cs new file mode 100644 index 0000000..fbc87cc --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandHandler.cs @@ -0,0 +1,173 @@ +using CMSMicroservice.Application.Common.Exceptions; +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Entities; +using CMSMicroservice.Domain.Enums; +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using ValidationException = FluentValidation.ValidationException; + +namespace CMSMicroservice.Application.PackageCQ.Commands.InitiateBasePackagePayment; + +/// +/// Handler برای ثبت اولیه تراکنش و سفارش پکیج پایه +/// این Handler فقط Transaction و Order را با وضعیت Pending ایجاد می‌کند +/// BFF سپس کاربر را به درگاه PYMS هدایت می‌کند +/// +public class InitiateBasePackagePaymentCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + /// + /// مبلغ پکیج پایه (56 میلیون تومان) + /// + private const long BasePackageAmount = 56_000_000; + + /// + /// شناسه پکیج پایه در دیتابیس + /// + private const long BasePackageId = 4; + + public InitiateBasePackagePaymentCommandHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle( + InitiateBasePackagePaymentCommand request, + CancellationToken cancellationToken) + { + try + { + _logger.LogInformation( + "Initiating base package payment for UserId: {UserId}", + request.UserId); + + // 1. پیدا کردن کاربر + var user = await _context.Users + .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken); + + if (user == null) + { + _logger.LogWarning("User not found. UserId: {UserId}", request.UserId); + throw new NotFoundException(nameof(User), request.UserId); + } + + // 2. بررسی عدم خرید قبلی پکیج پایه + if (user.PackagePurchaseMethod != PackagePurchaseMethod.None) + { + _logger.LogWarning( + "User {UserId} has already purchased base package via {Method}", + request.UserId, + user.PackagePurchaseMethod); + + return new InitiateBasePackagePaymentResponseDto + { + Success = false, + Message = "شما قبلاً پکیج پایه را خریداری کرده‌اید." + }; + } + + // 3. بررسی عدم وجود سفارش Pending + var pendingOrder = await _context.UserOrders + .FirstOrDefaultAsync(o => + o.UserId == request.UserId && + o.PaymentStatus == PaymentStatus.Pending && + o.PackageId == BasePackageId, + cancellationToken); + + if (pendingOrder != null) + { + _logger.LogWarning( + "User {UserId} has pending order {OrderId}", + request.UserId, + pendingOrder.Id); + + // برگرداندن سفارش موجود برای ادامه پرداخت + var existingTransaction = await _context.Transactions + .FirstOrDefaultAsync(t => t.Id == pendingOrder.TransactionId, cancellationToken); + + return new InitiateBasePackagePaymentResponseDto + { + Success = true, + Message = "سفارش قبلی در انتظار پرداخت یافت شد.", + OrderId = pendingOrder.Id, + TransactionId = existingTransaction?.Id ?? 0, + Amount = BasePackageAmount + }; + } + + // 4. پیدا کردن آدرس پیش‌فرض کاربر + var defaultAddress = await _context.UserAddresses + .Where(a => a.UserId == request.UserId) + .OrderByDescending(a => a.Created) + .FirstOrDefaultAsync(cancellationToken); + + if (defaultAddress == null) + { + _logger.LogWarning("No address found for user {UserId}", request.UserId); + throw new ValidationException("لطفاً ابتدا یک آدرس برای خود ثبت کنید."); + } + + // 5. ایجاد Transaction با وضعیت Pending + var transaction = new Transaction + { + Amount = BasePackageAmount, + Description = $"خرید پکیج پایه ۵۶ میلیونی - کاربر #{user.Id}", + PaymentStatus = PaymentStatus.Pending, + Type = TransactionType.DepositIpg + }; + + _context.Transactions.Add(transaction); + await _context.SaveChangesAsync(cancellationToken); + + _logger.LogInformation( + "Created Transaction {TransactionId} with Pending status for UserId {UserId}", + transaction.Id, + request.UserId); + + // 6. ایجاد UserOrder با وضعیت Pending + var order = new UserOrder + { + UserId = user.Id, + PackageId = BasePackageId, + Amount = BasePackageAmount, + PaymentStatus = PaymentStatus.Pending, + DeliveryStatus = DeliveryStatus.None, + UserAddressId = defaultAddress.Id, + PaymentMethod = PaymentMethod.IPG, + TransactionId = transaction.Id + }; + + _context.UserOrders.Add(order); + await _context.SaveChangesAsync(cancellationToken); + + _logger.LogInformation( + "Created UserOrder {OrderId} for UserId {UserId}, TransactionId: {TransactionId}", + order.Id, + request.UserId, + transaction.Id); + + return new InitiateBasePackagePaymentResponseDto + { + Success = true, + Message = "تراکنش و سفارش با موفقیت ثبت شد.", + OrderId = order.Id, + TransactionId = transaction.Id, + Amount = BasePackageAmount + }; + } + catch (Exception ex) + { + _logger.LogError( + ex, + "Error in InitiateBasePackagePaymentCommand for UserId: {UserId}", + request.UserId); + throw; + } + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandValidator.cs new file mode 100644 index 0000000..6639b26 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/InitiateBasePackagePayment/InitiateBasePackagePaymentCommandValidator.cs @@ -0,0 +1,13 @@ +using FluentValidation; + +namespace CMSMicroservice.Application.PackageCQ.Commands.InitiateBasePackagePayment; + +public class InitiateBasePackagePaymentCommandValidator : AbstractValidator +{ + public InitiateBasePackagePaymentCommandValidator() + { + RuleFor(x => x.UserId) + .GreaterThan(0) + .WithMessage("شناسه کاربر معتبر نیست."); + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommand.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommand.cs new file mode 100644 index 0000000..9de3357 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommand.cs @@ -0,0 +1,72 @@ +using MediatR; + +namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyBasePackagePayment; + +/// +/// تکمیل یا رد پرداخت پکیج پایه (فراخوانی توسط BFF بعد از Callback) +/// +public record VerifyBasePackagePaymentCommand : IRequest +{ + /// + /// شناسه سفارش CMS + /// + public long OrderId { get; init; } + + /// + /// شناسه تراکنش CMS + /// + public long TransactionId { get; init; } + + /// + /// آیا پرداخت موفق بوده؟ (نتیجه Verify از BFF) + /// + public bool PaymentSuccess { get; init; } + + /// + /// کد پیگیری بانکی (در صورت موفقیت) + /// + public string? RefId { get; init; } + + /// + /// پیام از درگاه + /// + public string? Message { get; init; } +} + +public class VerifyBasePackagePaymentResponseDto +{ + /// + /// موفقیت عملیات + /// + 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; } + + /// + /// موجودی کیف پول بعد از شارژ + /// + public long WalletBalance { get; set; } + + /// + /// موجودی تخفیف بعد از شارژ + /// + public long DiscountBalance { get; set; } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandHandler.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandHandler.cs new file mode 100644 index 0000000..2fbf1b5 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandHandler.cs @@ -0,0 +1,209 @@ +using CMSMicroservice.Application.Common.Exceptions; +using CMSMicroservice.Application.Common.Interfaces; +using CMSMicroservice.Domain.Entities; +using CMSMicroservice.Domain.Enums; +using MediatR; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; + +namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyBasePackagePayment; + +/// +/// Handler برای تکمیل یا رد پرداخت پکیج پایه +/// فراخوانی توسط BFF بعد از اینکه نتیجه Verify از PYMS مشخص شد +/// +/// اگر PaymentSuccess = true: +/// - شارژ کیف پول (Balance + DiscountBalance) +/// - ثبت لاگ تغییر کیف پول +/// - به‌روزرسانی سفارش و کاربر +/// +/// اگر PaymentSuccess = false: +/// - فقط آپدیت وضعیت تراکنش و سفارش به Reject +/// +public class VerifyBasePackagePaymentCommandHandler : IRequestHandler +{ + private readonly IApplicationDbContext _context; + private readonly ILogger _logger; + + /// + /// مبلغ پکیج پایه (56 میلیون تومان) + /// + private const long BasePackageAmount = 56_000_000; + + public VerifyBasePackagePaymentCommandHandler( + IApplicationDbContext context, + ILogger logger) + { + _context = context; + _logger = logger; + } + + public async Task Handle( + VerifyBasePackagePaymentCommand request, + CancellationToken cancellationToken) + { + try + { + _logger.LogInformation( + "Processing base package payment result. OrderId: {OrderId}, TransactionId: {TransactionId}, PaymentSuccess: {PaymentSuccess}", + request.OrderId, + request.TransactionId, + request.PaymentSuccess); + + // 1. پیدا کردن سفارش با کاربر + var order = await _context.UserOrders + .Include(o => o.User) + .FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken); + + if (order == null) + { + _logger.LogWarning("Order not found. OrderId: {OrderId}", request.OrderId); + throw new NotFoundException(nameof(UserOrder), request.OrderId); + } + + // 2. پیدا کردن تراکنش + var transaction = await _context.Transactions + .FirstOrDefaultAsync(t => t.Id == request.TransactionId, cancellationToken); + + if (transaction == null) + { + _logger.LogWarning("Transaction not found. TransactionId: {TransactionId}", request.TransactionId); + throw new NotFoundException(nameof(Transaction), request.TransactionId); + } + + // 3. بررسی Idempotency - اگر قبلاً تایید شده باشد + if (order.PaymentStatus == PaymentStatus.Success) + { + _logger.LogInformation( + "Order {OrderId} already verified successfully", + request.OrderId); + + var existingWallet = await _context.UserWallets + .FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken); + + return new VerifyBasePackagePaymentResponseDto + { + Success = true, + Message = "پرداخت قبلاً با موفقیت تایید شده است.", + OrderId = order.Id, + TransactionId = transaction.Id, + ReferenceCode = transaction.RefId, + WalletBalance = existingWallet?.Balance ?? 0, + DiscountBalance = existingWallet?.DiscountBalance ?? 0 + }; + } + + // 4. اگر پرداخت ناموفق بود - فقط وضعیت را Reject می‌کنیم + if (!request.PaymentSuccess) + { + _logger.LogWarning( + "Payment failed. OrderId: {OrderId}, Message: {Message}", + request.OrderId, + request.Message); + + transaction.PaymentStatus = PaymentStatus.Reject; + order.PaymentStatus = PaymentStatus.Reject; + await _context.SaveChangesAsync(cancellationToken); + + return new VerifyBasePackagePaymentResponseDto + { + Success = false, + Message = request.Message ?? "پرداخت ناموفق بود.", + OrderId = order.Id, + TransactionId = transaction.Id + }; + } + + // 5. پرداخت موفق - پیدا کردن یا ایجاد کیف پول + var userWallet = await _context.UserWallets + .FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken); + + if (userWallet == null) + { + _logger.LogInformation("Creating new wallet for UserId: {UserId}", order.UserId); + userWallet = new UserWallet + { + UserId = order.UserId, + Balance = 0, + DiscountBalance = 0, + NetworkBalance = 0 + }; + _context.UserWallets.Add(userWallet); + await _context.SaveChangesAsync(cancellationToken); + } + + // 6. شارژ کیف پول (هم Balance و هم DiscountBalance) + var oldBalance = userWallet.Balance; + var oldDiscountBalance = userWallet.DiscountBalance; + + userWallet.Balance += BasePackageAmount; + userWallet.DiscountBalance += BasePackageAmount; + + _logger.LogInformation( + "Charging wallet for user {UserId}. Balance: {OldBalance} -> {NewBalance}, DiscountBalance: {OldDiscount} -> {NewDiscount}", + order.UserId, + oldBalance, + userWallet.Balance, + oldDiscountBalance, + userWallet.DiscountBalance); + + // 7. به‌روزرسانی Transaction + transaction.PaymentStatus = PaymentStatus.Success; + transaction.PaymentDate = DateTime.Now; + transaction.RefId = request.RefId; + + // 8. ثبت لاگ تغییر کیف پول + var changeLog = new UserWalletChangeLog + { + WalletId = userWallet.Id, + CurrentBalance = userWallet.Balance, + ChangeValue = BasePackageAmount, + CurrentNetworkBalance = userWallet.NetworkBalance, + ChangeNerworkValue = 0, + CurrentDiscountBalance = userWallet.DiscountBalance, + ChangeDiscountValue = BasePackageAmount, + IsIncrease = true, + RefrenceId = transaction.Id + }; + + await _context.UserWalletChangeLogs.AddAsync(changeLog, cancellationToken); + + // 9. به‌روزرسانی Order + order.TransactionId = transaction.Id; + order.PaymentStatus = PaymentStatus.Success; + order.PaymentDate = DateTime.Now; + order.PaymentMethod = PaymentMethod.IPG; + + // 10. به‌روزرسانی User + order.User.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase; + + await _context.SaveChangesAsync(cancellationToken); + + _logger.LogInformation( + "Base package payment completed successfully. OrderId: {OrderId}, UserId: {UserId}, TransactionId: {TransactionId}, RefId: {RefId}", + order.Id, + order.UserId, + transaction.Id, + request.RefId); + + return new VerifyBasePackagePaymentResponseDto + { + Success = true, + Message = "پرداخت با موفقیت تایید شد. کیف پول شما شارژ گردید.", + OrderId = order.Id, + TransactionId = transaction.Id, + ReferenceCode = request.RefId, + WalletBalance = userWallet.Balance, + DiscountBalance = userWallet.DiscountBalance + }; + } + catch (Exception ex) + { + _logger.LogError( + ex, + "Error in VerifyBasePackagePaymentCommand. OrderId: {OrderId}", + request.OrderId); + throw; + } + } +} diff --git a/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandValidator.cs b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandValidator.cs new file mode 100644 index 0000000..52e03a3 --- /dev/null +++ b/src/CMSMicroservice.Application/PackageCQ/Commands/VerifyBasePackagePayment/VerifyBasePackagePaymentCommandValidator.cs @@ -0,0 +1,17 @@ +using FluentValidation; + +namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyBasePackagePayment; + +public class VerifyBasePackagePaymentCommandValidator : AbstractValidator +{ + public VerifyBasePackagePaymentCommandValidator() + { + RuleFor(x => x.OrderId) + .GreaterThan(0) + .WithMessage("شناسه سفارش معتبر نیست."); + + RuleFor(x => x.TransactionId) + .GreaterThan(0) + .WithMessage("شناسه تراکنش معتبر نیست."); + } +} diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/AdminGetJwtToken/AdminGetJwtTokenQueryHandler.cs b/src/CMSMicroservice.Application/UserCQ/Queries/AdminGetJwtToken/AdminGetJwtTokenQueryHandler.cs index e97fcb9..a7ffabd 100644 --- a/src/CMSMicroservice.Application/UserCQ/Queries/AdminGetJwtToken/AdminGetJwtTokenQueryHandler.cs +++ b/src/CMSMicroservice.Application/UserCQ/Queries/AdminGetJwtToken/AdminGetJwtTokenQueryHandler.cs @@ -22,7 +22,7 @@ public class AdminGetJwtTokenQueryHandler : IRequestHandler u.Contract) .Include(u => u.UserRoles) .ThenInclude(ur => ur.Role) - + .Include(u => u.ClubMembership) .FirstOrDefaultAsync(f => f.Mobile == request.Username, cancellationToken); if (user == null) throw new Exception("Invalid username or password."); diff --git a/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs index 848f4fc..0de8bcf 100644 --- a/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs +++ b/src/CMSMicroservice.Application/UserCQ/Queries/GetJwtToken/GetJwtTokenQueryHandler.cs @@ -17,6 +17,7 @@ public class GetJwtTokenQueryHandler : IRequestHandler u.Contract) .Include(u => u.UserRoles) .ThenInclude(ur => ur.Role) + .Include(u => u.ClubMembership) .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken) ?? throw new NotFoundException(nameof(User), request.Id); return new GetJwtTokenResponseDto() { diff --git a/src/CMSMicroservice.Infrastructure/Services/DayaLoanApiService.cs b/src/CMSMicroservice.Infrastructure/Services/DayaLoanApiService.cs index 3ac0f97..6c46051 100644 --- a/src/CMSMicroservice.Infrastructure/Services/DayaLoanApiService.cs +++ b/src/CMSMicroservice.Infrastructure/Services/DayaLoanApiService.cs @@ -101,9 +101,13 @@ public class DayaLoanApiService : IDayaLoanApiService // تنظیم merchant-permission-key از Configuration var permissionKey = _configuration["DayaApi:MerchantPermissionKey"]; - if (!string.IsNullOrEmpty(permissionKey)) + if (!string.IsNullOrEmpty(permissionKey) && _httpClient.DefaultRequestHeaders.TryGetValues("merchant-permission-key", out var values)) { + if (values== null || !values.Any()) + { + _httpClient.DefaultRequestHeaders.Add("merchant-permission-key", permissionKey); + } } else { @@ -125,7 +129,6 @@ public class DayaLoanApiService : IDayaLoanApiService NationalCodes = nationalCodes }; - // فراخوانی API var response = await _httpClient.PostAsJsonAsync( "/api/merchant/contracts", requestBody, diff --git a/src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs b/src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs index 8bc133c..5a6533b 100644 --- a/src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs +++ b/src/CMSMicroservice.Infrastructure/Services/GenerateJwtTokenService.cs @@ -42,6 +42,22 @@ public class GenerateJwtTokenService : IGenerateJwtToken else claims.Add(new Claim("IsSignMainContract", false.ToString())); + // ClubMembership Claims + if (user.ClubMembership != null) + { + claims.Add(new Claim("IsClubMemberActive", user.ClubMembership.IsActive.ToString())); + if (user.ClubMembership.LastModified.HasValue && user.ClubMembership.LastModified.Value > lastModified) + lastModified = user.ClubMembership.LastModified.Value; + } + else + { + claims.Add(new Claim("IsClubMemberActive", "false")); + } + + // Package Purchase Status + claims.Add(new Claim("HasPurchasedPackage", + (user.PackagePurchaseMethod != PackagePurchaseMethod.None).ToString())); + if (user.UserRoles != null && user.UserRoles.Any()) { foreach (var userRole in user.UserRoles) diff --git a/src/CMSMicroservice.Protobuf/Protos/package.proto b/src/CMSMicroservice.Protobuf/Protos/package.proto index 43c0ebd..2dc3d24 100644 --- a/src/CMSMicroservice.Protobuf/Protos/package.proto +++ b/src/CMSMicroservice.Protobuf/Protos/package.proto @@ -62,6 +62,20 @@ service PackageContract get: "/GetUserPackageStatus" }; }; + + // Base Package Payment (56M) + rpc InitiateBasePackagePayment(InitiateBasePackagePaymentRequest) returns (InitiateBasePackagePaymentResponse){ + option (google.api.http) = { + post: "/InitiateBasePackagePayment" + body: "*" + }; + }; + rpc VerifyBasePackagePayment(VerifyBasePackagePaymentRequest) returns (VerifyBasePackagePaymentResponse){ + option (google.api.http) = { + post: "/VerifyBasePackagePayment" + body: "*" + }; + }; } message CreateNewPackageRequest { @@ -177,3 +191,38 @@ message GetUserPackageStatusResponse google.protobuf.StringValue last_order_number = 8; google.protobuf.Timestamp last_purchase_date = 9; } + +// Base Package Payment Messages +message InitiateBasePackagePaymentRequest +{ + int64 user_id = 1; +} + +message InitiateBasePackagePaymentResponse +{ + bool success = 1; + string message = 2; + int64 order_id = 3; + int64 transaction_id = 4; + int64 amount = 5; +} + +message VerifyBasePackagePaymentRequest +{ + int64 order_id = 1; + int64 transaction_id = 2; + bool payment_success = 3; + google.protobuf.StringValue ref_id = 4; + google.protobuf.StringValue message = 5; +} + +message VerifyBasePackagePaymentResponse +{ + bool success = 1; + string message = 2; + int64 order_id = 3; + int64 transaction_id = 4; + google.protobuf.StringValue reference_code = 5; + int64 wallet_balance = 6; + int64 discount_balance = 7; +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs index 8611951..915d1c5 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/PackageProfile.cs @@ -1,5 +1,7 @@ using CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage; using CMSMicroservice.Application.PackageCQ.Commands.VerifyGoldenPackagePurchase; +using CMSMicroservice.Application.PackageCQ.Commands.InitiateBasePackagePayment; +using CMSMicroservice.Application.PackageCQ.Commands.VerifyBasePackagePayment; using CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus; using CMSMicroservice.Protobuf.Protos.Package; using Google.Protobuf.WellKnownTypes; @@ -53,6 +55,34 @@ public class PackageProfile : IRegister .Map(dest => dest.LastPurchaseDate, src => src.LastPurchaseDate.HasValue ? Timestamp.FromDateTime(src.LastPurchaseDate.Value.ToUniversalTime()) : null); + + // InitiateBasePackagePayment (56M پکیج پایه) + config.NewConfig() + .Map(dest => dest.UserId, src => src.UserId); + + 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.Amount, src => src.Amount); + + // VerifyBasePackagePayment (تأیید پرداخت پکیج پایه) + config.NewConfig() + .Map(dest => dest.OrderId, src => src.OrderId) + .Map(dest => dest.TransactionId, src => src.TransactionId) + .Map(dest => dest.PaymentSuccess, src => src.PaymentSuccess) + .Map(dest => dest.RefId, src => src.RefId) + .Map(dest => dest.Message, src => src.Message); + + 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) + .Map(dest => dest.DiscountBalance, src => src.DiscountBalance); } } diff --git a/src/CMSMicroservice.WebApi/Services/PackageService.cs b/src/CMSMicroservice.WebApi/Services/PackageService.cs index 93ed127..c5d5de0 100644 --- a/src/CMSMicroservice.WebApi/Services/PackageService.cs +++ b/src/CMSMicroservice.WebApi/Services/PackageService.cs @@ -5,6 +5,8 @@ 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.Commands.InitiateBasePackagePayment; +using CMSMicroservice.Application.PackageCQ.Commands.VerifyBasePackagePayment; using CMSMicroservice.Application.PackageCQ.Queries.GetPackage; using CMSMicroservice.Application.PackageCQ.Queries.GetAllPackageByFilter; using CMSMicroservice.Application.PackageCQ.Queries.GetUserPackageStatus; @@ -52,4 +54,15 @@ public class PackageService : PackageContract.PackageContractBase { return await _dispatchRequestToCQRS.Handle(request, context); } + + // Base Package Payment (56M) + public override async Task InitiateBasePackagePayment(InitiateBasePackagePaymentRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } + + public override async Task VerifyBasePackagePayment(VerifyBasePackagePaymentRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } }