From 0e9d0cad2f8f63c53048b5ac4c056d7f853b8566 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Wed, 11 Mar 2026 23:44:28 +0330 Subject: [PATCH] feat: manual payment package-based + StockMovement constraint fix - ManualPayment: add package_id to proto, handler selects package by ID - ManualPayment: remove manual amount input, use package price - ManualPayment: validator now checks PackageId instead of Amount - StockMovement: fix CHECK constraint (store negative qty for decreases) - StockMovement: Reserved/Released don't change physical Quantity - Proto NuGet bumped to 0.0.192 --- k8s/production/cms-config.yaml | 70 +++++++++++++++++-- .../CreateManualPaymentCommand.cs | 7 +- .../CreateManualPaymentCommandHandler.cs | 18 +++-- .../CreateManualPaymentCommandValidator.cs | 10 ++- .../CreateStockMovementCommandHandler.cs | 21 +++++- .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/manualpayment.proto | 3 +- 7 files changed, 113 insertions(+), 18 deletions(-) diff --git a/k8s/production/cms-config.yaml b/k8s/production/cms-config.yaml index 1dd737d..6ce28ee 100644 --- a/k8s/production/cms-config.yaml +++ b/k8s/production/cms-config.yaml @@ -19,28 +19,89 @@ type: Opaque stringData: appsettings.Production.json: | { + "PaymentProvider": "zarinpal", "ZarinPal": { "MerchantId": "4225d555-5fa9-4df0-9b61-1ce152cbbba8", "UseSandbox": false }, "CmsBaseUrl": "https://cms.kbs2.ir", "FrontOfficeBaseUrl": "https://kbs2.ir", + "JwtSecurityKey": "TvlZVx5TJaHs8e9HgUdGzhGP2CIidoI444nAj+8+g7c=", + "JwtIssuer": "https://localhost", + "JwtAudience": "https://localhost", + "JwtExpiryInDays": 5, "ConnectionStrings": { - "DefaultConnection": "Server=mssql-svc;Database=KBS;User Id=sa;Password=YourStrong@Passw0rd;TrustServerCertificate=True;" + "DefaultConnection": "Server=mssql-svc;Database=KBS;User Id=sa;Password=YourStrong@Passw0rd;TrustServerCertificate=True;", + "providerName": "System.Data.SqlClient" + }, + "Otp": { + "Secret": "K2w8k1h1mH2Qz1kqWk0c8kQ2Pq8q9H1eE2nqN1qQ8x7M=" + }, + "Monitoring": { + "SentryEnabled": false, + "SentryDsn": "", + "SlackEnabled": false, + "SlackWebhookUrl": "", + "EmailAlertsEnabled": false, + "AdminEmails": [ + "admin@example.com" + ], + "SmsNotificationsEnabled": false, + "SmsApiKey": "", + "SmsGatewayUrl": "" + }, + "Email": { + "Enabled": true, + "SmtpHost": "smtp.gmail.com", + "SmtpPort": 587, + "SmtpUsername": "your-email@gmail.com", + "SmtpPassword": "your-app-password", + "FromEmail": "noreply@foursat.com", + "FromName": "FourSat CMS", + "EnableSsl": true + }, + "Sms": { + "Enabled": true, + "Provider": "Kavenegar", + "KavenegarApiKey": "43676A4E786A6C50452F2F6252507939346A5145764B33566B456454374E657A614468706658656D6534593D", + "Sender": "1000001110100" + }, + "DayaPayment": { + "BaseUrl": "https://api.daya.ir", + "ApiKey": "YOUR_DAYA_API_KEY" + }, + "DayaApi": { + "UseMock": false, + "BaseAddress": "https://Dayadiamond.ir", + "MerchantPermissionKey": "56146364$04sXjethI5WxhItR1Q9xnmFdJzl2BB8Bclsq8dAy7YVSZp3vtt-wP7ivrcCvmKLq", + "CacheDurationMinutes": 20 + }, + "Chatika": { + "Enabled": true, + "BaseUrl": "https://api.chatika.ir", + "ApiKey": "tIukvL8dnV4cB3yVWcCD9Xyfbj8rBxm5wPt2mLyJCgTsBBoMTWjt6mFEqQwpw-er" + }, + "BackgroundJobs": { + "WeeklyCommissionCalculation": { + "Enabled": false, + "CronExpression": "5 0 * * 0" + } }, "SeedWorkers": { "MagicWalletCycleSeed": { "Enabled": true } }, - "FileStorage": { - "UploadPath": "/app/Uploads" - }, + "AllowedHosts": "*", "Kestrel": { "EndpointDefaults": { "Protocols": "Http2" } }, + "Authentication": { + "Authority": "https://ids.domain.com/", + "Audience": "domain_api" + }, "Seq": { "ServerUrl": "http://seq-svc:5341", "ApiKey": "oxpvpUzU1pZxMS4s3Fqq" @@ -52,3 +113,4 @@ stringData: } } } + diff --git a/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommand.cs b/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommand.cs index 6a65a49..d350f33 100644 --- a/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommand.cs +++ b/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommand.cs @@ -14,10 +14,15 @@ public class CreateManualPaymentCommand : IRequest public long UserId { get; set; } /// - /// مبلغ تراکنش (تومان) + /// مبلغ تراکنش (تومان) — [DEPRECATED] مبلغ از پکیج خوانده می‌شود /// public long Amount { get; set; } + /// + /// شناسه پکیج — اگر 0 باشد، پکیج پایه استفاده می‌شود + /// + public long PackageId { get; set; } + /// /// نوع تراکنش دستی /// diff --git a/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs b/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs index 41947ef..fa7fb68 100644 --- a/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs +++ b/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs @@ -70,10 +70,20 @@ public class CreateManualPaymentCommandHandler : IRequestHandler p.IsBasePackage && !p.IsDeleted, cancellationToken) - ?? throw new NotFoundException("پکیج پایه یافت نشد"); + // 4. بارگذاری پکیج انتخاب‌شده (یا پکیج پایه اگر PackageId=0) + Domain.Entities.Package package; + if (request.PackageId > 0) + { + package = await _context.Packages + .FirstOrDefaultAsync(p => p.Id == request.PackageId && !p.IsDeleted, cancellationToken) + ?? throw new NotFoundException($"پکیج با شناسه {request.PackageId} یافت نشد"); + } + else + { + package = await _context.Packages + .FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken) + ?? throw new NotFoundException("پکیج پایه یافت نشد"); + } var balanceAmount = package.Price; var discountBalanceAmount = (long)(package.Price * package.DiscountMultiplier); diff --git a/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandValidator.cs b/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandValidator.cs index 9dae429..2e16891 100644 --- a/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandValidator.cs +++ b/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandValidator.cs @@ -11,12 +11,10 @@ public class CreateManualPaymentCommandValidator : AbstractValidator x.Amount) - .GreaterThan(0) - .WithMessage("مبلغ باید بزرگتر از صفر باشد") - .LessThanOrEqualTo(SystemConstants.WalletMaxSafeAmount) - .WithMessage("مبلغ وارد شده بیش از حد مجاز است"); + // مبلغ از پکیج خوانده می‌شود — فیلد Amount دیگر اعتبارسنجی نمی‌شود + RuleFor(x => x.PackageId) + .GreaterThanOrEqualTo(0) + .WithMessage("شناسه پکیج نامعتبر است"); RuleFor(x => x.Type) .IsInEnum() diff --git a/src/CMSMicroservice.Application/StockMovementCQ/Commands/CreateStockMovement/CreateStockMovementCommandHandler.cs b/src/CMSMicroservice.Application/StockMovementCQ/Commands/CreateStockMovement/CreateStockMovementCommandHandler.cs index 8fac09f..2606931 100644 --- a/src/CMSMicroservice.Application/StockMovementCQ/Commands/CreateStockMovement/CreateStockMovementCommandHandler.cs +++ b/src/CMSMicroservice.Application/StockMovementCQ/Commands/CreateStockMovement/CreateStockMovementCommandHandler.cs @@ -61,7 +61,9 @@ public class CreateStockMovementCommandHandler : IRequestHandler -request.Quantity, + // رزرو و آزادسازی تأثیری روی Quantity فیزیکی ندارن + StockMovementType.Reserved or + StockMovementType.Released => 0, + _ => request.Quantity + }; + var entity = new StockMovement { InventoryItemId = request.InventoryItemId, MovementType = request.MovementType, - Quantity = request.Quantity, + Quantity = storedQuantity, QuantityBefore = quantityBefore, QuantityAfter = quantityAfter, Note = request.Note, diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index 040b722..67fffe5 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.190 + 0.0.192 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/manualpayment.proto b/src/CMSMicroservice.Protobuf/Protos/manualpayment.proto index edd0cab..66db59a 100644 --- a/src/CMSMicroservice.Protobuf/Protos/manualpayment.proto +++ b/src/CMSMicroservice.Protobuf/Protos/manualpayment.proto @@ -72,13 +72,14 @@ enum ManualPaymentStatus message CreateManualPaymentRequest { int64 user_id = 1; - int64 amount = 2; + int64 amount = 2; // [DEPRECATED] مبلغ از پکیج خوانده می‌شود — نادیده گرفته می‌شود ManualPaymentType type = 3; string description = 4; google.protobuf.StringValue reference_number = 5; google.protobuf.StringValue image_path = 6; google.protobuf.Int64Value image_document_id = 7; FileUploadModel image_file = 8; + int64 package_id = 9; // شناسه پکیج — اگر 0 باشد، پکیج پایه استفاده می‌شود } message CreateManualPaymentResponse