diff --git a/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs b/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs index 96edcc14..6f1812eb 100644 --- a/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs +++ b/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs @@ -10,4 +10,6 @@ public interface IFinancialInvoiceRepository : IRepository Search(FinancialInvoiceSearchModel searchModel); Task GetUnPaidByEntityId(long entityId, FinancialInvoiceItemType financialInvoiceItemType); + Task GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(long contractingPartyId, + double amount); } \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs b/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs index 0ce5a82b..6c28c66e 100644 --- a/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs +++ b/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs @@ -8,7 +8,7 @@ public class CreateFinancialInvoice public double Amount { get; set; } public long ContractingPartyId { get; set; } public string Description { get; set; } - public List? Items { get; set; } + public List Items { get; set; } } public class CreateFinancialInvoiceItem diff --git a/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs b/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs index 749a38a8..4cd5fd77 100644 --- a/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs +++ b/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; namespace CompanyManagment.App.Contracts.FinancialStatment; @@ -62,7 +63,17 @@ public interface IFinancialStatmentApplication /// Task GetDetailsByContractingParty(long contractingPartyId, FinancialStatementSearchModel searchModel); + + /// + /// پردازش شارژ حساب از طریق درگاه پرداخت سپهر + /// + /// + /// مسیر برگشت درگاه پرداخت + /// + Task> CreatePaymentGateWayAndCreateInvoice( + CreateFinancialPayRequest request, string gateWayCallBackUrl); } +public record CreateFinancialPayRequest(long Id, string BaseUrl); public class FinancialStatmentDetailsByContractingPartyViewModel { diff --git a/CompanyManagment.App.Contracts/SepehrPaymentGateway/CreateSepehrPaymentGatewayResponse.cs b/CompanyManagment.App.Contracts/SepehrPaymentGateway/CreateSepehrPaymentGatewayResponse.cs new file mode 100644 index 00000000..8e44123f --- /dev/null +++ b/CompanyManagment.App.Contracts/SepehrPaymentGateway/CreateSepehrPaymentGatewayResponse.cs @@ -0,0 +1,22 @@ +namespace CompanyManagment.App.Contracts.SepehrPaymentGateway; + +/// +/// پاسخ ایجاد درگاه پرداخت سپهر +/// +public class CreateSepehrPaymentGatewayResponse +{ + /// + /// توکن درگاه + /// + public string Token { get; set; } + + /// + /// شناسه تراکنش + /// + public long TransactionId { get; set; } + + /// + /// URL درگاه پرداخت + /// + public string PaymentUrl { get; set; } +} \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/SepehrPaymentGateway/ISepehrPaymentGatewayService.cs b/CompanyManagment.App.Contracts/SepehrPaymentGateway/ISepehrPaymentGatewayService.cs new file mode 100644 index 00000000..b5af2f4e --- /dev/null +++ b/CompanyManagment.App.Contracts/SepehrPaymentGateway/ISepehrPaymentGatewayService.cs @@ -0,0 +1,32 @@ +using _0_Framework.Application; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CompanyManagment.App.Contracts.SepehrPaymentGateway; + +/// +/// رابط برای سرویس مشترک ایجاد درگاه پرداخت سپهر +/// +public interface ISepehrPaymentGatewayService +{ + /// + /// ایجاد درگاه پرداخت سپهر برای یک تراکنش + /// + /// مبلغ + /// شناسه طرف قرارداد + /// آدرس بازگشتی به فرانت برای نمایش نتیجه + /// آدرس بازگشتی درگاه پرداخت + /// شناسه فاکتور مالی (اختیاری) - این پارامتر مستقیماً به درگاه فرستاده می‌شود + /// داده‌های اضافی سفارشی برای payload (اختیاری) + /// توکن لغو + /// شامل Token درگاه یا OperationResult با خطا + Task> CreateSepehrPaymentGateway( + double amount, + long contractingPartyId, + long financialInvoiceId, + string gatewayCallbackUrl, + string frontCallbackUrl="https://client.gozareshgir.ir", + Dictionary extraData = null, + CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/CompanyManagment.Application/FinancialInvoiceApplication.cs b/CompanyManagment.Application/FinancialInvoiceApplication.cs index 59a7fdd9..c2b6ffbf 100644 --- a/CompanyManagment.Application/FinancialInvoiceApplication.cs +++ b/CompanyManagment.Application/FinancialInvoiceApplication.cs @@ -9,15 +9,13 @@ using CompanyManagment.EFCore; namespace CompanyManagment.Application; -public class FinancialInvoiceApplication : RepositoryBase, IFinancialInvoiceApplication +public class FinancialInvoiceApplication : IFinancialInvoiceApplication { private readonly IFinancialInvoiceRepository _financialInvoiceRepository; - private readonly CompanyContext _context; - public FinancialInvoiceApplication(IFinancialInvoiceRepository financialInvoiceRepository, CompanyContext context) : base(context) + public FinancialInvoiceApplication(IFinancialInvoiceRepository financialInvoiceRepository) { _financialInvoiceRepository = financialInvoiceRepository; - _context = context; } public OperationResult Create(CreateFinancialInvoice command) @@ -185,6 +183,7 @@ public class FinancialInvoiceApplication : RepositoryBase x.ContractingPartyId == command.ContractingPartyId)) { - var financialStatment = _financialStatmentRepository.GetDetailsByContractingPartyId(command.ContractingPartyId); + var financialStatment = + _financialStatmentRepository.GetDetailsByContractingPartyId(command.ContractingPartyId); var transaction = new CreateFinancialTransaction() { FinancialStatementId = financialStatment.Id, @@ -124,20 +132,15 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication Creditor = creditor, TypeOfTransaction = command.TypeOfTransaction, DescriptionOption = command.DescriptionOption - - - }; - - var createTransaction = _financialTransactionApplication.Create(transaction); + + var createTransaction = _financialTransactionApplication.Create(transaction); if (createTransaction.IsSuccedded) return op.Succcedded(); return op.Failed("خطا در انجام عملیات"); - } else { - var statement = new FinancialStatment(command.ContractingPartyId, command.ContractingPartyName); _financialStatmentRepository.Create(statement); _financialStatmentRepository.SaveChanges(); @@ -153,20 +156,14 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication Balance = 0, TypeOfTransaction = command.TypeOfTransaction, DescriptionOption = command.DescriptionOption - - }; var createTransaction = _financialTransactionApplication.Create(transaction); if (createTransaction.IsSuccedded) return op.Succcedded(); return op.Failed("خطا در انجام عملیات"); - } - } - - public List Search(FinancialStatmentSearchModel searchModel) { @@ -203,6 +200,45 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication public async Task GetDetailsByContractingParty( long contractingPartyId, FinancialStatementSearchModel searchModel) { - return await _financialStatmentRepository.GetDetailsByContractingParty(contractingPartyId,searchModel); + return await _financialStatmentRepository.GetDetailsByContractingParty(contractingPartyId, searchModel); + } + + public async Task> CreatePaymentGateWayAndCreateInvoice( + CreateFinancialPayRequest request, string gateWayCallBackUrl) + { + var op = new OperationResult(); + // گام 1: دریافت موجودی حساب + var balanceAmount = await GetBalanceAmount(request.Id); + if (balanceAmount.Amount <= 0) + { + return op.Failed("موجودی حساب شما صفر است"); + } + // گام 2: ایجاد درگاه پرداخت سپهر + + var financialInvoice = await _financialInvoiceRepository + .GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(balanceAmount.ContractingPartyId, + balanceAmount.Amount); + + if (financialInvoice == null) + { + financialInvoice = new FinancialInvoice(balanceAmount.Amount, balanceAmount.ContractingPartyId, + "پرداخت بدهی صورت حساب مالی"); + + var items = new FinancialInvoiceItem("پرداخت بدهی صورت حساب مالی", balanceAmount.Amount, + financialInvoice.id, FinancialInvoiceItemType.PreviousDebt, 0); + financialInvoice.AddItem(items); + await _financialInvoiceRepository.CreateAsync(financialInvoice); + await _financialInvoiceRepository.SaveChangesAsync(); + } + + var gatewayResult = await _sepehrPaymentGatewayService.CreateSepehrPaymentGateway( + amount: balanceAmount.Amount, + contractingPartyId: balanceAmount.ContractingPartyId, + frontCallbackUrl: request.BaseUrl, + gatewayCallbackUrl: gateWayCallBackUrl, + financialInvoiceId: financialInvoice.id, + extraData: null); + + return gatewayResult; } } \ No newline at end of file diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index c4ea7ce4..e844c1ff 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -24,6 +24,7 @@ using CompanyManagment.App.Contracts.FinancialStatment; using CompanyManagment.App.Contracts.InstitutionContract; using CompanyManagment.App.Contracts.InstitutionContractContactinfo; using CompanyManagment.App.Contracts.PaymentTransaction; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; using CompanyManagment.App.Contracts.Workshop; using PersianTools.Core; using ConnectedPersonnelViewModel = CompanyManagment.App.Contracts.Workshop.ConnectedPersonnelViewModel; @@ -48,6 +49,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication private readonly IPaymentGateway _paymentGateway; private readonly IPaymentTransactionRepository _paymentTransactionRepository; private readonly IRollCallServiceRepository _rollCallServiceRepository; + private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService; public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository, @@ -58,7 +60,8 @@ public class InstitutionContractApplication : IInstitutionContractApplication IFinancialStatmentRepository financialStatmentRepository, IContactInfoApplication contactInfoApplication, IAccountApplication accountApplication, ISmsService smsService, IFinancialInvoiceRepository financialInvoiceRepository, IHttpClientFactory httpClientFactory, - IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository) + IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository, + ISepehrPaymentGatewayService sepehrPaymentGatewayService) { _institutionContractRepository = institutionContractRepository; _contractingPartyRepository = contractingPartyRepository; @@ -74,6 +77,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication _financialInvoiceRepository = financialInvoiceRepository; _paymentTransactionRepository = paymentTransactionRepository; _rollCallServiceRepository = rollCallServiceRepository; + _sepehrPaymentGatewayService = sepehrPaymentGatewayService; _paymentGateway = new SepehrPaymentGateway(httpClientFactory); } @@ -1258,119 +1262,93 @@ public class InstitutionContractApplication : IInstitutionContractApplication if (contractingParty == null) throw new NotFoundException("طرف قرارداد یافت نشد"); - if (institutionContract.VerifyCode != code) - return op.Failed("کد وارد شده صحیح نمی باشد"); - - var financialStatement =await _financialStatmentRepository.GetByContractingPartyId(contractingParty.id); + if (institutionContract.VerifyCode != code) + return op.Failed("کد وارد شده صحیح نمی باشد"); - var dbTransaction = await _institutionContractRepository.BeginTransactionAsync(); - FinancialInvoice financialInvoice; - FinancialInvoiceItem financialInvoiceItem; - var today = DateTime.Today; - double invoiceAmount = 0; - string invoiceItemDescription = string.Empty; - FinancialInvoiceItemType invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; - long invoiceItemEntityId = 0; + var financialStatement = await _financialStatmentRepository.GetByContractingPartyId(contractingParty.id); - if (institutionContract.IsInstallment) - { - var firstInstallment = institutionContract.Installments.First(); - var firstInstallmentAmount = firstInstallment.Amount; + var dbTransaction = await _institutionContractRepository.BeginTransactionAsync(); + FinancialInvoice financialInvoice; + FinancialInvoiceItem financialInvoiceItem; + var today = DateTime.Today; + double invoiceAmount = 0; + string invoiceItemDescription = string.Empty; + FinancialInvoiceItemType invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; + long invoiceItemEntityId = 0; - financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(firstInstallment.Id, FinancialInvoiceItemType.BuyInstitutionContractInstallment); - if (financialInvoice == null) - { - var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), - "قسط اول سرویس", "debt", "بابت خدمات", firstInstallmentAmount, 0, 0); - financialStatement.AddFinancialTransaction(financialTransaction); - invoiceAmount = firstInstallmentAmount; - invoiceItemDescription = $"پرداخت قسط اول قرارداد شماره {institutionContract.ContractNo}"; - invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContractInstallment; - invoiceItemEntityId = firstInstallment.Id; - } - else - { - invoiceAmount = financialInvoice.Amount; - invoiceItemDescription = financialInvoice.Items.First().Description; - invoiceItemType = financialInvoice.Items.First().Type; - invoiceItemEntityId = financialInvoice.Items.First().EntityId; - } - } - else - { - financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(institutionContract.id, FinancialInvoiceItemType.BuyInstitutionContract); - if (financialInvoice == null) - { - var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), - "پرداخت کل سرویس", "debt", "بابت خدمات", institutionContract.TotalAmount, 0, 0); - financialStatement.AddFinancialTransaction(financialTransaction); - invoiceAmount = institutionContract.TotalAmount; - invoiceItemDescription = $"پرداخت کل قرارداد شماره {institutionContract.ContractNo}"; - invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; - invoiceItemEntityId = institutionContract.id; - } - else - { - invoiceAmount = financialInvoice.Amount; - invoiceItemDescription = financialInvoice.Items.First().Description; - invoiceItemType = financialInvoice.Items.First().Type; - invoiceItemEntityId = financialInvoice.Items.First().EntityId; - } - } + if (institutionContract.IsInstallment) + { + var firstInstallment = institutionContract.Installments.First(); + var firstInstallmentAmount = firstInstallment.Amount; - if (financialInvoice == null) - { - financialInvoice = new FinancialInvoice(invoiceAmount, contractingParty.id, $"خرید قرارداد مالی شماره {institutionContract.ContractNo}"); - financialInvoiceItem = new FinancialInvoiceItem(invoiceItemDescription, invoiceAmount, 0, invoiceItemType, invoiceItemEntityId); - financialInvoice.AddItem(financialInvoiceItem); - await _financialInvoiceRepository.CreateAsync(financialInvoice); - } + financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(firstInstallment.Id, FinancialInvoiceItemType.BuyInstitutionContractInstallment); + if (financialInvoice == null) + { + var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), + "قسط اول سرویس", "debt", "بابت خدمات", firstInstallmentAmount, 0, 0); + financialStatement.AddFinancialTransaction(financialTransaction); + invoiceAmount = firstInstallmentAmount; + invoiceItemDescription = $"پرداخت قسط اول قرارداد شماره {institutionContract.ContractNo}"; + invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContractInstallment; + invoiceItemEntityId = firstInstallment.Id; + } + else + { + invoiceAmount = financialInvoice.Amount; + invoiceItemDescription = financialInvoice.Items.First().Description; + invoiceItemType = financialInvoice.Items.First().Type; + invoiceItemEntityId = financialInvoice.Items.First().EntityId; + } + } + else + { + financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(institutionContract.id, FinancialInvoiceItemType.BuyInstitutionContract); + if (financialInvoice == null) + { + var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), + "پرداخت کل سرویس", "debt", "بابت خدمات", institutionContract.TotalAmount, 0, 0); + financialStatement.AddFinancialTransaction(financialTransaction); + invoiceAmount = institutionContract.TotalAmount; + invoiceItemDescription = $"پرداخت کل قرارداد شماره {institutionContract.ContractNo}"; + invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; + invoiceItemEntityId = institutionContract.id; + } + else + { + invoiceAmount = financialInvoice.Amount; + invoiceItemDescription = financialInvoice.Items.First().Description; + invoiceItemType = financialInvoice.Items.First().Type; + invoiceItemEntityId = financialInvoice.Items.First().EntityId; + } + } - await _financialInvoiceRepository.SaveChangesAsync(); + if (financialInvoice == null) + { + financialInvoice = new FinancialInvoice(invoiceAmount, contractingParty.id, $"خرید قرارداد مالی شماره {institutionContract.ContractNo}"); + financialInvoiceItem = new FinancialInvoiceItem(invoiceItemDescription, invoiceAmount, 0, invoiceItemType, invoiceItemEntityId); + financialInvoice.AddItem(financialInvoiceItem); + await _financialInvoiceRepository.CreateAsync(financialInvoice); + } - var transaction = new PaymentTransaction(institutionContract.ContractingPartyId, invoiceAmount, - institutionContract.ContractingPartyName, "https://client.gozareshgir.ir", - PaymentTransactionGateWay.SepehrPay); - await _paymentTransactionRepository.CreateAsync(transaction); - await _financialInvoiceRepository.SaveChangesAsync(); + await _financialInvoiceRepository.SaveChangesAsync(); - var createPayment = new CreatePaymentGatewayRequest() - { - Amount = invoiceAmount, - TransactionId = transaction.id.ToString(), - CallBackUrl = callbackUrl, - FinancialInvoiceId = financialInvoice.id, - }; - var gatewayResponse = await _paymentGateway.Create(createPayment); - if (!gatewayResponse.IsSuccess) - return op.Failed("خطا در ایجاد درگاه پرداخت: " + gatewayResponse.Message + gatewayResponse.ErrorCode); + // استفاده از سرویس مشترک برای ایجاد درگاه پرداخت + var gatewayResult = await _sepehrPaymentGatewayService.CreateSepehrPaymentGateway( + amount: (long)invoiceAmount, + contractingPartyId: institutionContract.ContractingPartyId, + gatewayCallbackUrl: callbackUrl, + financialInvoiceId: financialInvoice.id, + extraData: null); - - // institutionContract.SetPendingWorkflow(); - // - // var phone = institutionContract.ContactInfoList.FirstOrDefault(x => - // x.SendSms && x.Position == "طرف قرارداد" && x.PhoneType == "شماره همراه"); - // if (phone !=null) - // { - // var userPass = contractingParty.IsLegal == "حقیقی" - // ? contractingParty.Nationalcode - // : contractingParty.NationalId; - // var createAcc = new RegisterAccount - // { - // Fullname = contractingParty.LName, - // Username = userPass, - // Password = userPass, - // Mobile = phone.PhoneNumber, - // NationalCode = userPass - // }; - // var res = _accountApplication.RegisterClient(createAcc); - // if (res.IsSuccedded) - // CreateContractingPartyAccount(contractingParty.id, res.SendId); - // } + if (!gatewayResult.IsSuccedded) + { + await dbTransaction.RollbackAsync(); + return op.Failed(gatewayResult.Message); + } await dbTransaction.CommitAsync(); await _institutionContractRepository.SaveChangesAsync(); - return op.Succcedded(gatewayResponse.Token); + return op.Succcedded(gatewayResult.Data.Token); } public async Task GetWorkshopInitialDetails(long workshopDetailsId) diff --git a/CompanyManagment.Application/SepehrPaymentGatewayService.cs b/CompanyManagment.Application/SepehrPaymentGatewayService.cs new file mode 100644 index 00000000..dc9749cf --- /dev/null +++ b/CompanyManagment.Application/SepehrPaymentGatewayService.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using _0_Framework.Application; +using _0_Framework.Application.PaymentGateway; +using CompanyManagment.App.Contracts.PaymentTransaction; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; + +namespace CompanyManagment.Application; + +/// +/// سرویس مشترک برای ایجاد درگاه پرداخت سپهر +/// +public class SepehrPaymentGatewayService : ISepehrPaymentGatewayService +{ + private readonly IPaymentGateway _paymentGateway; + private readonly IPaymentTransactionApplication _paymentTransactionApplication; + + public SepehrPaymentGatewayService( + IPaymentTransactionApplication paymentTransactionApplication, + IHttpClientFactory httpClientFactory) + { + _paymentGateway = new SepehrPaymentGateway(httpClientFactory); + _paymentTransactionApplication = paymentTransactionApplication; + } + + /// + /// ایجاد درگاه پرداخت سپهر برای یک تراکنش + /// + /// مبلغ + /// شناسه طرف قرارداد + /// آدرس بازگشتی به فرانت برای نمایش نتیجه + /// آدرس بازگشتی درگاه پرداخت + /// شناسه فاکتور مالی (اختیاری) + /// داده‌های اضافی (اختیاری) + /// توکن لغو + /// شامل Token درگاه یا OperationResult با خطا + public async Task> CreateSepehrPaymentGateway( + double amount, + long contractingPartyId, + long financialInvoiceId, + string gatewayCallbackUrl, + string frontCallbackUrl="https://client.gozareshgir.ir", + Dictionary extraData = null, + CancellationToken cancellationToken = default) + { + var op = new OperationResult(); + + try + { + // گام 1: ایجاد تراکنش پرداخت + var transactionCommand = new CreatePaymentTransaction() + { + Amount = amount, + ContractingPartyId = contractingPartyId, + CallBackUrl = frontCallbackUrl, + Gateway = PaymentTransactionGateWay.SepehrPay + }; + + var transactionResult = await _paymentTransactionApplication.Create(transactionCommand); + + if (!transactionResult.IsSuccedded) + { + return op.Failed(transactionResult.Message); + } + + // گام 2: ایجاد درخواست درگاه پرداخت + extraData ??= new Dictionary(); + + var createPaymentCommand = new CreatePaymentGatewayRequest() + { + Amount = amount, + TransactionId = transactionResult.SendId.ToString(), + CallBackUrl = gatewayCallbackUrl, + FinancialInvoiceId = financialInvoiceId, + ExtraData = extraData + }; + + // گام 3: ارسال درخواست به درگاه سپهر + var gatewayResponse = await _paymentGateway.Create(createPaymentCommand, cancellationToken); + +#if DEBUG + gatewayResponse.IsSuccess = true; +#endif + if (!gatewayResponse.IsSuccess) + { + return op.Failed($"خطا در ایجاد درگاه پرداخت: {gatewayResponse.Message ?? gatewayResponse.ErrorCode?.ToString()}"); + } + + // گام 4: ذخیره Token در تراکنش + var setTokenResult = await _paymentTransactionApplication.SetTransactionId( + transactionResult.SendId, + gatewayResponse.Token); + + if (!setTokenResult.IsSuccedded) + { + return op.Failed("خطا در ذخیره Token درگاه"); + } + + // گام 5: بازگشت اطلاعات درگاه پرداخت + var response = new CreateSepehrPaymentGatewayResponse + { + Token = gatewayResponse.Token, + TransactionId = transactionResult.SendId, + PaymentUrl = _paymentGateway.GetStartPayUrl(gatewayResponse.Token) + }; + + return op.Succcedded(response); + } + catch (Exception ex) + { + return op.Failed($"خطا در ایجاد درگاه پرداخت: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs b/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs index b2db131a..a5e65908 100644 --- a/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs +++ b/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs @@ -101,4 +101,12 @@ public class FinancialInvoiceRepository : RepositoryBase .Where(x => x.Status == FinancialInvoiceStatus.Unpaid).FirstOrDefaultAsync(x => x.Items .Any(y => y.Type == financialInvoiceItemType && y.EntityId == entityId)); } + + public async Task GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(long contractingPartyId, + double amount) + { + return await _context.FinancialInvoices.FirstOrDefaultAsync(x=>x.ContractingPartyId == contractingPartyId && + x.Amount == amount && + x.Status == FinancialInvoiceStatus.Unpaid); + } } \ No newline at end of file diff --git a/PersonalContractingParty.Config/PersonalBootstrapper.cs b/PersonalContractingParty.Config/PersonalBootstrapper.cs index e7256455..92e63a87 100644 --- a/PersonalContractingParty.Config/PersonalBootstrapper.cs +++ b/PersonalContractingParty.Config/PersonalBootstrapper.cs @@ -234,6 +234,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using P_TextManager.Domin.TextManagerAgg; using CompanyManagment.App.Contracts.PaymentCallback; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; using Company.Domain.CameraBugReportAgg; using CompanyManagment.App.Contracts.CameraBugReport; using CameraBugReportRepository = CompanyManagement.Infrastructure.Mongo.CameraBugReportRepo.CameraBugReportRepository; @@ -484,6 +485,7 @@ public class PersonalBootstrapper services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/ServiceHost/Areas/Client/Controllers/FinancialController.cs b/ServiceHost/Areas/Client/Controllers/FinancialController.cs index 8736c764..68d8d494 100644 --- a/ServiceHost/Areas/Client/Controllers/FinancialController.cs +++ b/ServiceHost/Areas/Client/Controllers/FinancialController.cs @@ -1,8 +1,10 @@ using _0_Framework.Application; using _0_Framework.Application.PaymentGateway; +using CompanyManagment.App.Contracts.FinancialInvoice; using CompanyManagment.App.Contracts.FinancialStatment; using CompanyManagment.App.Contracts.FinancilTransaction; using CompanyManagment.App.Contracts.PaymentTransaction; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; @@ -10,20 +12,19 @@ using ServiceHost.BaseControllers; namespace ServiceHost.Areas.Client.Controllers; -public record CreateFinancialPayRequest(long Id, string BaseUrl); public class FinancialController : ClientBaseController { private readonly IFinancialStatmentApplication _financialStatementApplication; private readonly IAuthHelper _authHelper; - private readonly IPaymentGateway _paymentGateway; - private readonly IPaymentTransactionApplication _paymentTransactionApplication; + private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService; + private readonly IFinancialInvoiceApplication _financialInvoiceApplication; - public FinancialController(IFinancialStatmentApplication financialStatementApplication, IAuthHelper authHelper,IHttpClientFactory httpClientFactory, IPaymentTransactionApplication paymentTransactionApplication,IOptions appSetting) + public FinancialController(IFinancialStatmentApplication financialStatementApplication, IAuthHelper authHelper, ISepehrPaymentGatewayService sepehrPaymentGatewayService, IFinancialInvoiceApplication financialInvoiceApplication) { _financialStatementApplication = financialStatementApplication; _authHelper = authHelper; - _paymentTransactionApplication = paymentTransactionApplication; - _paymentGateway = new SepehrPaymentGateway(httpClientFactory); + _sepehrPaymentGatewayService = sepehrPaymentGatewayService; + _financialInvoiceApplication = financialInvoiceApplication; } [HttpGet] @@ -45,65 +46,28 @@ public class FinancialController : ClientBaseController return result; } /// - /// ساخت + /// ساخت درگاه پرداخت برای موجودی حساب کلاینت /// - /// - /// - /// - /// [HttpPost("CreatePay")] [AllowAnonymous] - public async Task>> CreatePay([FromForm] CreateFinancialPayRequest request, CancellationToken cancellationToken) + public async Task>> CreatePay([FromForm] CreateFinancialPayRequest request) { var op = new OperationResult(); - var balanceAmount = await _financialStatementApplication.GetBalanceAmount(request.Id); - if (balanceAmount.Amount<=0) - { - return op.Failed("موجودی حساب شما صفر است"); - } - var callbackUrl = Url.Action( + var gateWayCallBackUrl = Url.Action( action: "Verify", controller: "General", // نام کنترلر بدون کلمه‌ی "Controller" values: null, protocol: Request.Scheme); // http یا https + // گام 2: ایجاد درگاه پرداخت سپهر - var transactionCommand = new CreatePaymentTransaction() + var gatewayResult = await _financialStatementApplication.CreatePaymentGateWayAndCreateInvoice(request, gateWayCallBackUrl); + if (!gatewayResult.IsSuccedded) { - Amount = balanceAmount.Amount, - ContractingPartyId = balanceAmount.ContractingPartyId, - CallBackUrl = request.BaseUrl, - Gateway = PaymentTransactionGateWay.SepehrPay - }; - - var transaction = await _paymentTransactionApplication.Create(transactionCommand); - - if (!transaction.IsSuccedded) - { - return op.Failed(transaction.Message); + return op.Failed(gatewayResult.Message); } - var command = new CreatePaymentGatewayRequest() - { - CallBackUrl = callbackUrl, - Amount = balanceAmount.Amount, - TransactionId = transaction.SendId.ToString(), - }; - - var gatewayResponse = await _paymentGateway.Create(command, cancellationToken); - - if (gatewayResponse.IsSuccess) - { - _ = await _paymentTransactionApplication.SetTransactionId(transaction.SendId, gatewayResponse.Token); - return Redirect(_paymentGateway.GetStartPayUrl(gatewayResponse.Token)); - } - - if (gatewayResponse.ErrorCode.HasValue) - { - return op.Failed($"خطا در ایجاد درگاه پرداخت: {gatewayResponse.ErrorCode.Value}"); - } - - return op.Failed("خطا در ایجاد درگاه پرداخت"); - + // گام 3: بازگشتی به درگاه پرداخت + return Redirect(gatewayResult.Data.PaymentUrl); } } \ No newline at end of file