feat: add PaymentTransaction table for gateway-level tracking
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 9m6s
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 9m6s
- New PaymentTransaction entity (Domain/Entities/Payment/) with all gateway fields: GatewayProvider, MerchantId, Authority, CardPan, CardHash, RefId, VerificationStatusCode, etc. - New PaymentTransactionConfiguration with indexes on Authority, GatewayProvider, UserId, TransactionId, RefId - Added DbSet<PaymentTransaction> to IApplicationDbContext and ApplicationDbContext - Extended PaymentVerificationResult DTO with CardPan, CardHash, VerificationCode - Updated ZarinPalPaymentService.VerifyPayment to return CardPan/CardHash/VerificationCode - Updated all 5 payment consumers to create/update PaymentTransaction: * PlaceOrderCommandHandler — creates PaymentTransaction after InitiatePayment * PaymentCallbackController — updates PaymentTransaction after VerifyPayment * ChargeDiscountWalletCommandHandler — creates PaymentTransaction + fixed callback URL * VerifyDiscountWalletChargeCommandHandler — updates PaymentTransaction after verify * TransactionsService.CustomerPaymentRequest/Verification — create/update PaymentTransaction * PackageService.CustomerPurchasePackage/Verify — create/update PaymentTransaction - Transaction table untouched — PaymentTransaction is a separate table - Pattern inspired by PYMS: create row before gateway → update after verify - EF migration: AddPaymentTransactionTable
This commit is contained in:
@@ -14,6 +14,7 @@ using CMSMicroservice.Application.PackageCQ.Queries.GetCustomerPackages;
|
||||
using CMSMicroservice.Application.PackageCQ.Queries.GetCustomerPackageDetails;
|
||||
using CMSMicroservice.Application.PackageCQ.Queries.GetCustomerPurchaseHistory;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities.Payment;
|
||||
using AppModels = CMSMicroservice.Application.Common.Models;
|
||||
using Grpc.Core;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
@@ -23,6 +24,7 @@ using CMSMicroservice.Protobuf.Protos;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MediatR;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
public class PackageService : PackageContract.PackageContractBase
|
||||
@@ -32,19 +34,22 @@ public class PackageService : PackageContract.PackageContractBase
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
private readonly IPaymentGatewayService _paymentGateway;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public PackageService(
|
||||
IDispatchRequestToCQRS dispatchRequestToCQRS,
|
||||
ISender sender,
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUserService,
|
||||
IPaymentGatewayService paymentGateway)
|
||||
IPaymentGatewayService paymentGateway,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
_sender = sender;
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
_paymentGateway = paymentGateway;
|
||||
_configuration = configuration;
|
||||
}
|
||||
public override async Task<CreateNewPackageResponse> CreateNewPackage(CreateNewPackageRequest request, ServerCallContext context)
|
||||
{
|
||||
@@ -225,6 +230,25 @@ public class PackageService : PackageContract.PackageContractBase
|
||||
|
||||
// Save RefId
|
||||
transaction.RefId = paymentResult.RefId;
|
||||
|
||||
// ثبت PaymentTransaction
|
||||
var paymentTx = new PaymentTransaction
|
||||
{
|
||||
GatewayProvider = _configuration["PaymentProvider"] ?? "zarinpal",
|
||||
MerchantId = _configuration["ZarinPal:MerchantId"] ?? "",
|
||||
Amount = package.Price,
|
||||
CallbackUrl = request.CallbackUrl,
|
||||
Description = $"خرید پکیج {package.Title}",
|
||||
Mobile = user?.Mobile,
|
||||
UserId = userId,
|
||||
RequestStatusCode = 100,
|
||||
RequestStatusMessage = "Success",
|
||||
Authority = paymentResult.RefId,
|
||||
PaymentStatus = false,
|
||||
TransactionId = transaction.Id,
|
||||
OrderId = purchase.Id.ToString()
|
||||
};
|
||||
_context.PaymentTransactions.Add(paymentTx);
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
return new CustomerPurchasePackageResponse
|
||||
@@ -275,6 +299,19 @@ public class PackageService : PackageContract.PackageContractBase
|
||||
var verifyResult = await _paymentGateway.VerifyPaymentAsync(
|
||||
request.Authority, request.Status, context.CancellationToken);
|
||||
|
||||
// آپدیت PaymentTransaction
|
||||
var paymentTx = await _context.PaymentTransactions
|
||||
.FirstOrDefaultAsync(pt => pt.Authority == request.Authority, context.CancellationToken);
|
||||
if (paymentTx != null)
|
||||
{
|
||||
paymentTx.PaymentStatus = verifyResult.IsSuccess;
|
||||
paymentTx.VerificationStatusCode = verifyResult.VerificationCode;
|
||||
paymentTx.VerificationStatusMessage = verifyResult.Message;
|
||||
paymentTx.CardPan = verifyResult.CardPan;
|
||||
paymentTx.CardHash = verifyResult.CardHash;
|
||||
paymentTx.RefId = verifyResult.TrackingCode;
|
||||
}
|
||||
|
||||
if (verifyResult.IsSuccess && transaction != null)
|
||||
{
|
||||
transaction.PaymentStatus = Domain.Enums.PaymentStatus.Success;
|
||||
|
||||
@@ -10,11 +10,13 @@ using CMSMicroservice.Application.TransactionsCQ.Commands.RefundTransaction;
|
||||
using CMSMicroservice.Application.TransactionsCQ.Queries.GetCustomerTransaction;
|
||||
using CMSMicroservice.Application.TransactionsCQ.Queries.GetCustomerTransactionsByFilter;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities.Payment;
|
||||
using AppModels = CMSMicroservice.Application.Common.Models;
|
||||
using Grpc.Core;
|
||||
using MediatR;
|
||||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace CMSMicroservice.WebApi.Services;
|
||||
@@ -25,19 +27,22 @@ public class TransactionsService : TransactionsContract.TransactionsContractBase
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
private readonly IPaymentGatewayService _paymentGateway;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public TransactionsService(
|
||||
IDispatchRequestToCQRS dispatchRequestToCQRS,
|
||||
ISender sender,
|
||||
IApplicationDbContext context,
|
||||
ICurrentUserService currentUserService,
|
||||
IPaymentGatewayService paymentGateway)
|
||||
IPaymentGatewayService paymentGateway,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||
_sender = sender;
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
_paymentGateway = paymentGateway;
|
||||
_configuration = configuration;
|
||||
}
|
||||
public override async Task<CreateNewTransactionsResponse> CreateNewTransactions(CreateNewTransactionsRequest request, ServerCallContext context)
|
||||
{
|
||||
@@ -179,6 +184,24 @@ public class TransactionsService : TransactionsContract.TransactionsContractBase
|
||||
|
||||
// Save RefId from gateway
|
||||
transaction.RefId = paymentResult.RefId;
|
||||
|
||||
// ثبت PaymentTransaction
|
||||
var paymentTx = new PaymentTransaction
|
||||
{
|
||||
GatewayProvider = _configuration["PaymentProvider"] ?? "zarinpal",
|
||||
MerchantId = _configuration["ZarinPal:MerchantId"] ?? "",
|
||||
Amount = request.Amount,
|
||||
CallbackUrl = request.CallbackUrl,
|
||||
Description = request.Description ?? "پرداخت آنلاین",
|
||||
Mobile = request.Mobile ?? user?.Mobile,
|
||||
UserId = userId,
|
||||
RequestStatusCode = 100,
|
||||
RequestStatusMessage = "Success",
|
||||
Authority = paymentResult.RefId,
|
||||
PaymentStatus = false,
|
||||
TransactionId = transaction.Id
|
||||
};
|
||||
_context.PaymentTransactions.Add(paymentTx);
|
||||
await _context.SaveChangesAsync(context.CancellationToken);
|
||||
|
||||
return new CustomerPaymentRequestResponse
|
||||
@@ -216,6 +239,19 @@ public class TransactionsService : TransactionsContract.TransactionsContractBase
|
||||
var verifyResult = await _paymentGateway.VerifyPaymentAsync(
|
||||
request.Authority, request.Status, context.CancellationToken);
|
||||
|
||||
// آپدیت PaymentTransaction
|
||||
var paymentTx = await _context.PaymentTransactions
|
||||
.FirstOrDefaultAsync(pt => pt.Authority == request.Authority, context.CancellationToken);
|
||||
if (paymentTx != null)
|
||||
{
|
||||
paymentTx.PaymentStatus = verifyResult.IsSuccess;
|
||||
paymentTx.VerificationStatusCode = verifyResult.VerificationCode;
|
||||
paymentTx.VerificationStatusMessage = verifyResult.Message;
|
||||
paymentTx.CardPan = verifyResult.CardPan;
|
||||
paymentTx.CardHash = verifyResult.CardHash;
|
||||
paymentTx.RefId = verifyResult.TrackingCode;
|
||||
}
|
||||
|
||||
if (verifyResult.IsSuccess)
|
||||
{
|
||||
transaction.PaymentStatus = Domain.Enums.PaymentStatus.Success;
|
||||
|
||||
Reference in New Issue
Block a user