This commit is contained in:
SamSys
2025-12-31 18:21:15 +03:30
20 changed files with 706 additions and 560 deletions

View File

@@ -85,7 +85,9 @@ public interface ISmsService
/// <param name="code1"></param>
/// <param name="code2"></param>
/// <returns></returns>
Task<(byte status, string message, int messaeId, bool isSucceded)> BlockMessageForElectronicContract(string number, string fullname, string amount, string code1, string code2)
Task<(byte status, string message, int messaeId, bool isSucceded)> BlockMessageForElectronicContract(string number,
string fullname,
string amount, string code1, string code2);
#endregion
#region AlarmMessage

View File

@@ -10,4 +10,6 @@ public interface IFinancialInvoiceRepository : IRepository<long, FinancialInvoic
EditFinancialInvoice GetDetails(long id);
List<FinancialInvoiceViewModel> Search(FinancialInvoiceSearchModel searchModel);
Task<FinancialInvoice> GetUnPaidByEntityId(long entityId, FinancialInvoiceItemType financialInvoiceItemType);
Task<FinancialInvoice> GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(long contractingPartyId,
double amount);
}

View File

@@ -190,4 +190,5 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
Task<InstitutionContractDiscountResponse> SetDiscountForCreation(InstitutionContractSetDiscountForCreationRequest request);
Task<InstitutionContractDiscountResponse> ResetDiscountForCreation(InstitutionContractResetDiscountForExtensionRequest request);
Task<OperationResult> CreationComplete(InstitutionContractExtensionCompleteRequest request);
Task<InstitutionContract> GetIncludeInstallments(long id);
}

View File

@@ -8,7 +8,7 @@ public class CreateFinancialInvoice
public double Amount { get; set; }
public long ContractingPartyId { get; set; }
public string Description { get; set; }
public List<CreateFinancialInvoiceItem>? Items { get; set; }
public List<CreateFinancialInvoiceItem> Items { get; set; }
}
public class CreateFinancialInvoiceItem

View File

@@ -10,7 +10,8 @@ public class EditFinancialInvoice
public double Amount { get; set; }
public FinancialInvoiceStatus Status { get; set; }
public List<EditFinancialInvoiceItem>? Items { get; set; }
public List<EditFinancialInvoiceItem> Items { get; set; }
public long ContractingPartyId { get; set; }
}
public class EditFinancialInvoiceItem

View File

@@ -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
/// <returns></returns>
Task<FinancialStatmentDetailsByContractingPartyViewModel> GetDetailsByContractingParty(long contractingPartyId,
FinancialStatementSearchModel searchModel);
/// <summary>
/// پردازش شارژ حساب از طریق درگاه پرداخت سپهر
/// </summary>
/// <param name="request"></param>
/// <param name="gateWayCallBackUrl">مسیر برگشت درگاه پرداخت</param>
///
Task<OperationResult<CreateSepehrPaymentGatewayResponse>> CreatePaymentGateWayAndCreateInvoice(
CreateFinancialPayRequest request, string gateWayCallBackUrl);
}
public record CreateFinancialPayRequest(long Id, string BaseUrl);
public class FinancialStatmentDetailsByContractingPartyViewModel
{

View File

@@ -0,0 +1,21 @@
using _0_Framework.Application;
using System.Threading;
using System.Threading.Tasks;
namespace CompanyManagment.App.Contracts.PaymentCallback;
/// <summary>
/// رابط برای مدیریت Callback درگاه‌های پرداخت
/// </summary>
public interface IPaymentCallbackHandler
{
/// <summary>
/// تأیید و پردازش callback درگاه پرداخت سپهر
/// </summary>
/// <param name="command">داده‌های callback درگاه</param>
/// <param name="cancellationToken">توکن لغو عملیات</param>
/// <returns>نتیجه عملیات</returns>
Task<OperationResult> VerifySepehrPaymentCallback(VerifyPaymentCallbackCommand command,
CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,53 @@
namespace CompanyManagment.App.Contracts.PaymentCallback;
/// <summary>
/// دستور تأیید callback درگاه پرداخت
/// </summary>
public class VerifyPaymentCallbackCommand
{
/// <summary>
/// کد پاسخ درگاه (0 = موفق)
/// </summary>
public int ResponseCode { get; set; }
/// <summary>
/// شناسه فاکتور/تراکنش
/// </summary>
public long InvoiceId { get; set; }
/// <summary>
/// داده‌های اضافی JSON
/// </summary>
public string Payload { get; set; }
/// <summary>
/// مبلغ تراکنش
/// </summary>
public long Amount { get; set; }
/// <summary>
/// شماره پیگیری درگاه
/// </summary>
public long TraceNumber { get; set; }
/// <summary>
/// شماره سند بانکی (RRN)
/// </summary>
public long Rrn { get; set; }
/// <summary>
/// رسید دیجیتال
/// </summary>
public string DigitalReceipt { get; set; }
/// <summary>
/// بانک صادر کننده کارت
/// </summary>
public string IssuerBank { get; set; }
/// <summary>
/// شماره کارت
/// </summary>
public string CardNumber { get; set; }
}

View File

@@ -0,0 +1,22 @@
namespace CompanyManagment.App.Contracts.SepehrPaymentGateway;
/// <summary>
/// پاسخ ایجاد درگاه پرداخت سپهر
/// </summary>
public class CreateSepehrPaymentGatewayResponse
{
/// <summary>
/// توکن درگاه
/// </summary>
public string Token { get; set; }
/// <summary>
/// شناسه تراکنش
/// </summary>
public long TransactionId { get; set; }
/// <summary>
/// URL درگاه پرداخت
/// </summary>
public string PaymentUrl { get; set; }
}

View File

@@ -0,0 +1,32 @@
using _0_Framework.Application;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace CompanyManagment.App.Contracts.SepehrPaymentGateway;
/// <summary>
/// رابط برای سرویس مشترک ایجاد درگاه پرداخت سپهر
/// </summary>
public interface ISepehrPaymentGatewayService
{
/// <summary>
/// ایجاد درگاه پرداخت سپهر برای یک تراکنش
/// </summary>
/// <param name="amount">مبلغ</param>
/// <param name="contractingPartyId">شناسه طرف قرارداد</param>
/// <param name="frontCallbackUrl">آدرس بازگشتی به فرانت برای نمایش نتیجه</param>
/// <param name="gatewayCallbackUrl">آدرس بازگشتی درگاه پرداخت</param>
/// <param name="financialInvoiceId">شناسه فاکتور مالی (اختیاری) - این پارامتر مستقیماً به درگاه فرستاده می‌شود</param>
/// <param name="extraData">داده‌های اضافی سفارشی برای payload (اختیاری)</param>
/// <param name="cancellationToken">توکن لغو</param>
/// <returns>شامل Token درگاه یا OperationResult با خطا</returns>
Task<OperationResult<CreateSepehrPaymentGatewayResponse>> CreateSepehrPaymentGateway(
double amount,
long contractingPartyId,
long financialInvoiceId,
string gatewayCallbackUrl,
string frontCallbackUrl="https://client.gozareshgir.ir",
Dictionary<string, object> extraData = null,
CancellationToken cancellationToken = default);
}

View File

@@ -9,15 +9,13 @@ using CompanyManagment.EFCore;
namespace CompanyManagment.Application;
public class FinancialInvoiceApplication : RepositoryBase<long, FinancialInvoice>, 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<long, FinancialInvoice
{
return _financialInvoiceRepository.Search(searchModel);
}
//public OperationResult Remove(long id)
//{

View File

@@ -3,9 +3,12 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using _0_Framework.Application;
using Company.Domain.ContarctingPartyAgg;
using Company.Domain.FinancialInvoiceAgg;
using Company.Domain.FinancialStatmentAgg;
using CompanyManagment.App.Contracts.FinancialInvoice;
using CompanyManagment.App.Contracts.FinancialStatment;
using CompanyManagment.App.Contracts.FinancilTransaction;
using CompanyManagment.App.Contracts.SepehrPaymentGateway;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Mvc;
@@ -16,12 +19,20 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication
private readonly IFinancialStatmentRepository _financialStatmentRepository;
private readonly IFinancialTransactionApplication _financialTransactionApplication;
private readonly IPersonalContractingPartyRepository _contractingPartyRepository;
private readonly IFinancialInvoiceRepository _financialInvoiceRepository;
private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService;
public FinancialStatmentApplication(IFinancialStatmentRepository financialStatmentRepository, IFinancialTransactionApplication financialTransactionApplication, IPersonalContractingPartyRepository contractingPartyRepository)
public FinancialStatmentApplication(IFinancialStatmentRepository financialStatmentRepository,
IFinancialTransactionApplication financialTransactionApplication,
IPersonalContractingPartyRepository contractingPartyRepository,
IFinancialInvoiceRepository financialInvoiceRepository,
ISepehrPaymentGatewayService sepehrPaymentGatewayService)
{
_financialStatmentRepository = financialStatmentRepository;
_financialTransactionApplication = financialTransactionApplication;
_contractingPartyRepository = contractingPartyRepository;
_financialInvoiceRepository = financialInvoiceRepository;
_sepehrPaymentGatewayService = sepehrPaymentGatewayService;
}
public OperationResult CreateFromBankGateway(CreateFinancialStatment command)
@@ -51,7 +62,6 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication
if (createTransaction.IsSuccedded)
return op.Succcedded();
return op.Failed("خطا در انجام عملیات");
}
else
{
@@ -71,8 +81,6 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication
Balance = 0,
TypeOfTransaction = command.TypeOfTransaction,
DescriptionOption = command.DescriptionOption
};
var createTransaction = _financialTransactionApplication.Create(transaction);
if (createTransaction.IsSuccedded)
@@ -98,22 +106,22 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication
{
debtor = 0;
creditor = command.CreditorString.MoneyToDouble();
}
else if (command.TypeOfTransaction == "debt")
{
creditor = 0;
debtor = command.DeptorString.MoneyToDouble();
}
if (!command.TdateFa.TryToGeorgianDateTime(out var tDateGr))
{
return op.Failed("تاریخ وارد شده صحیح نمی باشد");
}
if (_financialStatmentRepository.Exists(x => 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<FinancialStatmentViewModel> Search(FinancialStatmentSearchModel searchModel)
{
@@ -203,6 +200,45 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication
public async Task<FinancialStatmentDetailsByContractingPartyViewModel> GetDetailsByContractingParty(
long contractingPartyId, FinancialStatementSearchModel searchModel)
{
return await _financialStatmentRepository.GetDetailsByContractingParty(contractingPartyId,searchModel);
return await _financialStatmentRepository.GetDetailsByContractingParty(contractingPartyId, searchModel);
}
public async Task<OperationResult<CreateSepehrPaymentGatewayResponse>> CreatePaymentGateWayAndCreateInvoice(
CreateFinancialPayRequest request, string gateWayCallBackUrl)
{
var op = new OperationResult<CreateSepehrPaymentGatewayResponse>();
// گام 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;
}
}

View File

@@ -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<InstitutionContractWorkshopDetailViewModel> GetWorkshopInitialDetails(long workshopDetailsId)

View File

@@ -0,0 +1,237 @@
using _0_Framework.Application;
using Company.Domain.PaymentTransactionAgg;
using CompanyManagment.App.Contracts.FinancialInvoice;
using CompanyManagment.App.Contracts.FinancialStatment;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.PaymentCallback;
using CompanyManagment.App.Contracts.PaymentTransaction;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;
using _0_Framework.Application.PaymentGateway;
using Company.Domain.FinancialStatmentAgg;
using Company.Domain.FinancialTransactionAgg;
using Company.Domain.InstitutionContractAgg;
using CompanyManagment.EFCore.Migrations;
namespace CompanyManagment.Application;
public class PaymentCallbackHandler : IPaymentCallbackHandler
{
private readonly IPaymentTransactionApplication _paymentTransactionApplication;
private readonly IFinancialStatmentApplication _financialStatmentApplication;
private readonly IFinancialStatmentRepository _financialStatmentRepository;
private readonly IFinancialInvoiceApplication _financialInvoiceApplication;
private readonly IInstitutionContractApplication _institutionContractApplication;
private readonly IInstitutionContractRepository _institutionContractRepository;
private readonly IPaymentGateway _paymentGateway;
public PaymentCallbackHandler(
IPaymentTransactionApplication paymentTransactionApplication,
IFinancialStatmentApplication financialStatmentApplication,
IFinancialInvoiceApplication financialInvoiceApplication,
IInstitutionContractApplication institutionContractApplication,
IHttpClientFactory httpClientFactory, IInstitutionContractRepository institutionContractRepository,
IFinancialStatmentRepository financialStatmentRepository)
{
_paymentTransactionApplication = paymentTransactionApplication;
_financialStatmentApplication = financialStatmentApplication;
_financialInvoiceApplication = financialInvoiceApplication;
_institutionContractApplication = institutionContractApplication;
_institutionContractRepository = institutionContractRepository;
_financialStatmentRepository = financialStatmentRepository;
_paymentGateway = new SepehrPaymentGateway(httpClientFactory);
}
/// <summary>
/// تأیید و پردازش callback درگاه پرداخت سپهر
/// </summary>
public async Task<OperationResult> VerifySepehrPaymentCallback(VerifyPaymentCallbackCommand command,
CancellationToken cancellationToken = default)
{
var operation = new OperationResult();
try
{
await using var transactionScope =await _financialStatmentRepository.BeginTransactionAsync();
// گام 1: دریافت اطلاعات تراکنش
var transaction = await _paymentTransactionApplication.GetDetails(command.InvoiceId);
if (transaction == null)
return operation.Failed("تراکنش مورد نظر یافت نشد");
// گام 2: بررسی وضعیت قبلی تراکنش
if (transaction.Status != PaymentTransactionStatus.Pending)
return operation.Failed("این تراکنش قبلا پرداخت شده است");
// گام 3: بررسی کد پاسخ درگاه
if (command.ResponseCode != 0)
{
var failResult = _paymentTransactionApplication.SetFailed(command.InvoiceId);
return failResult.IsSuccedded
? operation.Failed("تراکنش توسط درگاه رد شد")
: operation.Failed("خطا در به‌روزرسانی وضعیت تراکنش");
}
// گام 4: استخراج اطلاعات فاکتور مالی
var extraData = JsonConvert.DeserializeObject<IDictionary<string, object>>(command.Payload ?? "{}");
extraData.TryGetValue("financialInvoiceId", out var financialInvoiceIdObj);
if (financialInvoiceIdObj == null ||
!long.TryParse(financialInvoiceIdObj.ToString(), out var financialInvoiceId))
return operation.Failed("فاکتور مالی نامعتبر است");
// گام 5: دریافت اطلاعات فاکتور مالی
var financialInvoice = _financialInvoiceApplication.GetDetails(financialInvoiceId);
if (financialInvoice == null)
return operation.Failed("فاکتور مالی نامعتبر است");
if (financialInvoice.Status != FinancialInvoiceStatus.Unpaid)
return operation.Failed("فاکتور مالی نامعتبر است");
// گام 6: بررسی تطابق مبلغ
if ((long)financialInvoice.Amount != command.Amount)
{
var failResult = _paymentTransactionApplication.SetFailed(command.InvoiceId);
return operation.Failed("مبلغ تراکنش با مبلغ فاکتور مطابقت ندارد");
}
// گام 7: به‌روزرسانی فاکتور مالی
var setPaidResult = _financialInvoiceApplication.SetPaid(financialInvoiceId, DateTime.Now);
if (!setPaidResult.IsSuccedded)
{
var failResult = _paymentTransactionApplication.SetFailed(command.InvoiceId);
return operation.Failed("خطا در به‌روزرسانی فاکتور مالی");
}
// گام 8: به‌روزرسانی وضعیت تراکنش
var setSuccessResult = _paymentTransactionApplication.SetSuccess(
command.InvoiceId,
command.CardNumber,
command.IssuerBank,
command.Rrn.ToString(),
command.DigitalReceipt);
if (!setSuccessResult.IsSuccedded)
{
return operation.Failed("خطا در به‌روزرسانی وضعیت تراکنش");
}
// گام 9: به‌روزرسانی وضعیت قرارداد‌های نهادی (اگر وجود داشته باشند)
var institutionContractItems = financialInvoice.Items.Where(x =>
x.Type is FinancialInvoiceItemType.BuyInstitutionContract
or FinancialInvoiceItemType.BuyInstitutionContractInstallment).ToList();
if (institutionContractItems.Any())
{
await HandleInstitutionContractItems(financialInvoice);
}
// گام 10: ایجاد سند مالی (Financial Statement)
var createCreditStatementCommand = new CreateFinancialStatment()
{
ContractingPartyId = transaction.ContractingPartyId,
Deptor = 0,
Creditor = command.Amount,
DeptorString = "0",
TypeOfTransaction = "credit",
DescriptionOption = (financialInvoice.Description ?? "") + " شماره فاکتور: " +
(financialInvoice.InvoiceNumber ?? ""),
Description = "درگاه بانکی",
};
var statementResult = _financialStatmentApplication.CreateFromBankGateway(createCreditStatementCommand);
if (!statementResult.IsSuccedded)
{
_paymentTransactionApplication.SetFailed(command.InvoiceId);
return operation.Failed("خطا در ایجاد سند مالی");
}
// گام 11: تأیید نهایی با درگاه پرداخت
var verifyCommand = new VerifyPaymentGateWayRequest()
{
Amount = transaction.Amount,
TransactionId = command.InvoiceId.ToString(),
DigitalReceipt = command.DigitalReceipt
};
var verifyRes = await _paymentGateway.Verify(verifyCommand, cancellationToken);
#if DEBUG
verifyRes.IsSuccess = true;
#endif
if (!verifyRes.IsSuccess)
{
return operation.Failed("خطا در تایید پرداخت از درگاه");
}
// تمام عملیات موفق - تایید transaction
await transactionScope.CommitAsync(cancellationToken);
return operation.Succcedded();
}
catch (Exception ex)
{
// در صورت بروز هرگونه خطا، transaction خودکار rollback می‌شود
return operation.Failed($"خطا در پردازش callback: {ex.Message}");
}
}
/// <summary>
/// مدیریت آپدیت قرارداد‌های نهادی
/// </summary>
private async Task HandleInstitutionContractItems(EditFinancialInvoice financialInvoice)
{
// قرارداد‌های خریداری مستقیم
var directContractItems = financialInvoice.Items
.Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContract);
var financialStatement =
await _financialStatmentRepository.GetByContractingPartyId(financialInvoice.ContractingPartyId);
var today = DateTime.Now;
foreach (var item in directContractItems)
{
var institutionContract = _institutionContractRepository.Get(item.EntityId);
await _institutionContractApplication.SetPendingWorkflow(item.EntityId,
InstitutionContractSigningType.OtpBased);
var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(),
"پرداخت کل سرویس", "debt", "بابت خدمات", institutionContract.TotalAmount, 0, 0);
financialStatement.AddFinancialTransaction(financialTransaction);
}
// قرارداد‌های خریداری با اقساط
var installmentItems = financialInvoice.Items
.Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContractInstallment);
foreach (var item in installmentItems)
{
var institutionContractId =await _institutionContractRepository.GetIdByInstallmentId(item.EntityId);
var institutionContract = _institutionContractRepository.Get(institutionContractId);
await _institutionContractApplication.SetPendingWorkflow(institutionContractId,
InstitutionContractSigningType.OtpBased);
var firstInstallment = institutionContract.Installments.First();
var firstInstallmentAmount = firstInstallment.Amount;
var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(),
"قسط اول سرویس", "debt", "بابت خدمات", firstInstallmentAmount, 0, 0);
financialStatement.AddFinancialTransaction(financialTransaction);
}
await _financialStatmentRepository.SaveChangesAsync();
}
}

View File

@@ -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;
/// <summary>
/// سرویس مشترک برای ایجاد درگاه پرداخت سپهر
/// </summary>
public class SepehrPaymentGatewayService : ISepehrPaymentGatewayService
{
private readonly IPaymentGateway _paymentGateway;
private readonly IPaymentTransactionApplication _paymentTransactionApplication;
public SepehrPaymentGatewayService(
IPaymentTransactionApplication paymentTransactionApplication,
IHttpClientFactory httpClientFactory)
{
_paymentGateway = new SepehrPaymentGateway(httpClientFactory);
_paymentTransactionApplication = paymentTransactionApplication;
}
/// <summary>
/// ایجاد درگاه پرداخت سپهر برای یک تراکنش
/// </summary>
/// <param name="amount">مبلغ</param>
/// <param name="contractingPartyId">شناسه طرف قرارداد</param>
/// <param name="frontCallbackUrl">آدرس بازگشتی به فرانت برای نمایش نتیجه</param>
/// <param name="gatewayCallbackUrl">آدرس بازگشتی درگاه پرداخت</param>
/// <param name="financialInvoiceId">شناسه فاکتور مالی (اختیاری)</param>
/// <param name="extraData">داده‌های اضافی (اختیاری)</param>
/// <param name="cancellationToken">توکن لغو</param>
/// <returns>شامل Token درگاه یا OperationResult با خطا</returns>
public async Task<OperationResult<CreateSepehrPaymentGatewayResponse>> CreateSepehrPaymentGateway(
double amount,
long contractingPartyId,
long financialInvoiceId,
string gatewayCallbackUrl,
string frontCallbackUrl="https://client.gozareshgir.ir",
Dictionary<string, object> extraData = null,
CancellationToken cancellationToken = default)
{
var op = new OperationResult<CreateSepehrPaymentGatewayResponse>();
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<string, object>();
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}");
}
}
}

View File

@@ -34,6 +34,7 @@ public class FinancialInvoiceRepository : RepositoryBase<long, FinancialInvoice>
Amount = financialInvoice.Amount,
Status = financialInvoice.Status,
InvoiceNumber = financialInvoice.InvoiceNumber,
ContractingPartyId = financialInvoice.ContractingPartyId,
Items = financialInvoice.Items?.Select(x => new EditFinancialInvoiceItem
{
Id = x.id,
@@ -100,4 +101,12 @@ public class FinancialInvoiceRepository : RepositoryBase<long, FinancialInvoice>
.Where(x => x.Status == FinancialInvoiceStatus.Unpaid).FirstOrDefaultAsync(x => x.Items
.Any(y => y.Type == financialInvoiceItemType && y.EntityId == entityId));
}
public async Task<FinancialInvoice> GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(long contractingPartyId,
double amount)
{
return await _context.FinancialInvoices.FirstOrDefaultAsync(x=>x.ContractingPartyId == contractingPartyId &&
x.Amount == amount &&
x.Status == FinancialInvoiceStatus.Unpaid);
}
}

View File

@@ -6178,6 +6178,12 @@ public class InstitutionContractRepository : RepositoryBase<long, InstitutionCon
return opration.Succcedded();
}
public Task<InstitutionContract> GetIncludeInstallments(long id)
{
return _context.InstitutionContractSet.Include(x => x.Installments)
.FirstOrDefaultAsync(x => x.id == id);
}
private async Task<OperationResult<PersonalContractingParty>> CreateLegalContractingPartyEntity(
InstitutionContractCreationTempLegalParty request, long representativeId, string address, string city,
string state)

View File

@@ -229,153 +229,15 @@ using CompanyManagment.Application;
using CompanyManagment.EFCore;
using CompanyManagment.EFCore._common;
using CompanyManagment.EFCore.Repository;
using CompanyManagment.EFCore.Repository;
using File.EfCore.Repository;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using P_TextManager.Domin.TextManagerAgg;
using CompanyManagment.App.Contracts.CrossJobItems;
using Company.Domain.CrossJobItemsAgg;
using Company.Domain.DateSalaryAgg;
using Company.Domain.DateSalaryItemAgg;
using Company.Domain.FinancialStatmentAgg;
using Company.Domain.FinancialTransactionAgg;
using Company.Domain.GroupPlanAgg;
using Company.Domain.GroupPlanJobItemAgg;
using Company.Domain.InstitutionContractAgg;
using Company.Domain.InstitutionContractContactInfoAgg;
using CompanyManagment.App.Contracts.Insurance;
using Company.Domain.InsuranceAgg;
using Company.Domain.InsuranceEmployeeInfoAgg;
using Company.Domain.InsuranceJobItemAgg;
using Company.Domain.InsuranceListAgg;
using Company.Domain.InsurancJobAgg;
using Company.Domain.InsurancWorkshopInfoAgg;
using Company.Domain.LeftWorkInsuranceAgg;
using Company.Domain.PaymentToEmployeeAgg;
using Company.Domain.PaymentToEmployeeItemAgg;
using Company.Domain.PercentageAgg;
using Company.Domain.PersonnelCodeAgg;
using Company.Domain.SmsResultAgg;
using Company.Domain.WorkingHoursTempAgg;
using Company.Domain.WorkingHoursTempItemAgg;
using Company.Domain.WorkshopPlanAgg;
using Company.Domain.WorkshopPlanEmployeeAgg;
using Company.Domain.ZoneAgg;
using CompanyManagment.App.Contracts.ClassifiedSalary;
using CompanyManagment.App.Contracts.DateSalary;
using CompanyManagment.App.Contracts.DateSalaryItem;
using CompanyManagment.App.Contracts.EmployeeInsurancListData;
using CompanyManagment.App.Contracts.FinancialStatment;
using CompanyManagment.App.Contracts.FinancilTransaction;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.InstitutionContractContactinfo;
using CompanyManagment.App.Contracts.InsuranceEmployeeInfo;
using CompanyManagment.App.Contracts.InsuranceJob;
using CompanyManagment.App.Contracts.InsuranceList;
using CompanyManagment.App.Contracts.InsuranceWorkshopInfo;
using CompanyManagment.App.Contracts.LeftWorkInsurance;
using CompanyManagment.App.Contracts.PaymentToEmployee;
using CompanyManagment.App.Contracts.Percentage;
using CompanyManagment.App.Contracts.PersonnleCode;
using CompanyManagment.App.Contracts.SmsResult;
using CompanyManagment.App.Contracts.WorkingHoursTemp;
using CompanyManagment.App.Contracts.WorkingHoursTempItem;
using CompanyManagment.App.Contracts.WorkshopPlan;
using CompanyManagment.App.Contracts.Zone;
using CompanyManagment.App.Contracts.EmployeeComputeOptions;
using Company.Domain.EmployeeComputeOptionsAgg;
using Company.Domain.InsuranceYearlySalaryAgg;
using Company.Domain.ReportAgg;
using Company.Domain.RollCallAgg;
using Company.Domain.RollCallEmployeeAgg;
using Company.Domain.RollCallPlanAgg;
using Company.Domain.RollCallServiceAgg;
using CompanyManagment.App.Contracts.InsuranceYearlySalary;
using CompanyManagment.App.Contracts.Report;
using CompanyManagment.App.Contracts.RollCall;
using CompanyManagment.App.Contracts.RollCallEmployee;
using CompanyManagment.App.Contracts.RollCallService;
using CompanyManagment.App.Contracts.RollCallPlan;
using Company.Domain.ReportClientAgg;
using Company.Domain.TaxJobCategoryAgg;
using Company.Domain.WorkshopAccountAgg;
using CompanyManagment.App.Contracts.ReportClient;
using CompanyManagment.App.Contracts.TaxJobCategory;
using Company.Domain.RollCallEmployeeStatusAgg;
using CompanyManagment.App.Contracts.RollCallEmployeeStatus;
using Company.Domain.CustomizeWorkshopEmployeeSettingsAgg;
using Company.Domain.CustomizeWorkshopGroupSettingsAgg;
using Company.Domain.CustomizeWorkshopSettingsAgg;
using Company.Domain.FineAgg;
using Company.Domain.LoanAgg;
using Company.Domain.RewardAgg;
using Company.Domain.SalaryAidAgg;
using CompanyManagment.App.Contracts.CustomizeWorkshopSettings;
using CompanyManagment.App.Contracts.Fine;
using CompanyManagment.App.Contracts.Loan;
using CompanyManagment.App.Contracts.Reward;
using CompanyManagment.App.Contracts.SalaryAid;
using Company.Domain.AndroidApkVersionAgg;
using Company.Domain.BankAgg;
using CompanyManagment.App.Contracts.AndroidApkVersion;
using Company.Domain.FineSubjectAgg;
using CompanyManagment.App.Contracts.FineSubject;
using Company.Domain.CustomizeCheckoutAgg;
using CompanyManagment.App.Contracts.CustomizeCheckout;
using Company.Domain.WorkshopSubAccountAgg;
using Company.Domain.CustomizeCheckoutTempAgg;
using Company.Domain.EmployeeBankInformationAgg;
using Company.Domain.RollCallAgg.DomainService;
using CompanyManagment.App.Contracts.Bank;
using CompanyManagment.App.Contracts.EmployeeBankInformation;
using Company.Domain.EmployeeDocumentItemAgg;
using Company.Domain.EmployeeDocumentsAdminSelectionAgg;
using Company.Domain.EmployeeDocumentsAgg;
using CompanyManagement.Infrastructure.Excel.SalaryAid;
using CompanyManagment.App.Contracts.EmployeeDocuments;
using CompanyManagment.App.Contracts.EmployeeDocumentsAdminSelection;
using Company.Domain.EmployeeClientTempAgg;
using Company.Domain.InstitutionPlanAgg;
using Company.Domain.LeftWorkTempAgg;
using Company.Domain.TemporaryClientRegistrationAgg;
using CompanyManagment.App.Contracts.EmployeeClientTemp;
using CompanyManagment.App.Contracts.InstitutionPlan;
using CompanyManagment.App.Contracts.LeftWorkTemp;
using CompanyManagment.App.Contracts.TemporaryClientRegistration;
using Company.Domain.ContactUsAgg;
using CompanyManagment.App.Contracts.ContactUs;
using Company.Domain.EmployeeAuthorizeTempAgg;
using Company.Domain.AdminMonthlyOverviewAgg;
using Company.Domain.AuthorizedBankDetailsAgg;
using Company.Domain.ContractingPartyBankAccountsAgg;
using Company.Domain.PaymentInstrumentAgg;
using Company.Domain.PaymentTransactionAgg;
using Company.Domain.FinancialInvoiceAgg;
using CompanyManagment.App.Contracts.AdminMonthlyOverview;
using CompanyManagment.App.Contracts.ContractingPartyBankAccounts;
using CompanyManagment.App.Contracts.PaymentInstrument;
using CompanyManagment.App.Contracts.PaymentTransaction;
using CompanyManagment.App.Contracts.AuthorizedPerson;
using Company.Domain.AuthorizedPersonAgg;
using Company.Domain.EmployeeFaceEmbeddingAgg;
using Company.Domain.InstitutionContractExtensionTempAgg;
using Company.Domain.LawAgg;
using CompanyManagement.Infrastructure.Mongo.EmployeeFaceEmbeddingRepo;
using CompanyManagement.Infrastructure.Mongo.InstitutionContractInsertTempRepo;
using CompanyManagment.App.Contracts.EmployeeFaceEmbedding;
using CompanyManagment.App.Contracts.Law;
using CompanyManagment.EFCore.Repository;
using CompanyManagment.App.Contracts.FinancialInvoice;
using _0_Framework.Application.FaceEmbedding;
using _0_Framework.Infrastructure;
using _0_Framework.InfraStructure;
using CompanyManagment.App.Contracts.PaymentCallback;
using CompanyManagment.App.Contracts.SepehrPaymentGateway;
using Company.Domain.CameraBugReportAgg;
using CompanyManagment.App.Contracts.CameraBugReport;
using CompanyManagement.Infrastructure.Mongo.CameraBugReportRepo;
using CameraBugReportRepository = CompanyManagement.Infrastructure.Mongo.CameraBugReportRepo.CameraBugReportRepository;
using Company.Domain._common;
using CompanyManagment.EFCore._common;
using CompanyManagment.EFCore.Services;
using Shared.Contracts.Holidays;
@@ -622,6 +484,8 @@ public class PersonalBootstrapper
services.AddTransient<IPaymentTransactionRepository, PaymentTransactionRepository>();
services.AddTransient<IPaymentTransactionApplication, PaymentTransactionApplication>();
services.AddTransient<IPaymentCallbackHandler, PaymentCallbackHandler>();
services.AddTransient<ISepehrPaymentGatewayService, SepehrPaymentGatewayService>();
services.AddTransient<IContractingPartyBankAccountsApplication, ContractingPartyBankAccountsApplication>();
services.AddTransient<IContractingPartyBankAccountsRepository, ContractingPartyBankAccountsRepository>();

View File

@@ -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<AppSettingConfiguration> appSetting)
public FinancialController(IFinancialStatmentApplication financialStatementApplication, IAuthHelper authHelper, ISepehrPaymentGatewayService sepehrPaymentGatewayService, IFinancialInvoiceApplication financialInvoiceApplication)
{
_financialStatementApplication = financialStatementApplication;
_authHelper = authHelper;
_paymentTransactionApplication = paymentTransactionApplication;
_paymentGateway = new AqayePardakhtPaymentGateway(httpClientFactory, appSetting);
_sepehrPaymentGatewayService = sepehrPaymentGatewayService;
_financialInvoiceApplication = financialInvoiceApplication;
}
[HttpGet]
@@ -45,64 +46,28 @@ public class FinancialController : ClientBaseController
return result;
}
/// <summary>
/// ساخت
/// ساخت درگاه پرداخت برای موجودی حساب کلاینت
/// </summary>
/// <param name="id"></param>
/// <param name="baseUrl"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
[HttpPost("CreatePay")]
[AllowAnonymous]
public async Task<ActionResult<OperationResult<string>>> CreatePay([FromForm] CreateFinancialPayRequest request, CancellationToken cancellationToken)
public async Task<ActionResult<OperationResult<string>>> CreatePay([FromForm] CreateFinancialPayRequest request)
{
var op = new OperationResult<string>();
var balanceAmount = await _financialStatementApplication.GetBalanceAmount(request.Id);
if (balanceAmount.Amount<=0)
{
return op.Failed("موجودی حساب شما صفر است");
}
var callbackUrl = Url.Action(
action: "OnGetCallBack",
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
};
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/10,
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);
}
}

View File

@@ -1,49 +1,25 @@
using _0_Framework.Application;
using _0_Framework.Application.PaymentGateway;
using Company.Domain.BankAgg;
using Company.Domain.PaymentTransactionAgg;
using CompanyManagment.App.Contracts.FinancialStatment;
using CompanyManagment.App.Contracts.FinancilTransaction;
using CompanyManagment.App.Contracts.PaymentCallback;
using CompanyManagment.App.Contracts.PaymentTransaction;
using CompanyManagment.App.Contracts.Workshop;
using CompanyManagment.EFCore.Migrations;
using Microsoft.AspNetCore.Authorization;
using GozareshgirProgramManager.Application._Common.Constants;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using NuGet.Protocol;
using Parbad;
using ServiceHost.BaseControllers;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading;
using CompanyManagment.App.Contracts.FinancialInvoice;
using CompanyManagment.App.Contracts.InstitutionContract;
using GozareshgirProgramManager.Application._Common.Constants;
using GozareshgirProgramManager.Infrastructure.Persistence.Context;
namespace ServiceHost.Controllers;
public class GeneralController : GeneralBaseController
{
private readonly IPaymentTransactionApplication _paymentTransactionApplication;
private readonly IPaymentGateway _paymentGateway;
private readonly IFinancialStatmentApplication _financialStatmentApplication;
private readonly IFinancialInvoiceApplication _financialInvoiceApplication;
private readonly IInstitutionContractApplication _institutionContractApplication;
private readonly IPaymentCallbackHandler _paymentCallbackHandler;
public GeneralController(IPaymentTransactionApplication paymentTransactionApplication,
IHttpClientFactory clientFactory, IFinancialStatmentApplication financialStatmentApplication,
IFinancialInvoiceApplication financialInvoiceApplication,
IInstitutionContractApplication institutionContractApplication)
IPaymentCallbackHandler paymentCallbackHandler)
{
_paymentTransactionApplication = paymentTransactionApplication;
_paymentGateway = new SepehrPaymentGateway(clientFactory);
_financialStatmentApplication = financialStatmentApplication;
_financialInvoiceApplication = financialInvoiceApplication;
_institutionContractApplication = institutionContractApplication;
_paymentCallbackHandler = paymentCallbackHandler;
}
/// <summary>
@@ -67,15 +43,15 @@ public class GeneralController : GeneralBaseController
});
}
[HttpGet("pm-permissions")]
public IActionResult GetPMPermissions()
{
var permissions = ProgramManagerPermissionCode.GetAllCodes();
return new JsonResult(permissions);
}
// [HttpGet("pm-permissions")]
// public IActionResult GetPMPermissions()
// {
// var permissions = ProgramManagerPermissionCode.GetAllCodes();
// return new JsonResult(permissions);
// }
[HttpGet("/api/callback"), HttpPost("/api/callback")]
public async Task<IActionResult> Verify([FromForm]SepehrGatewayPayResponse payResponse)
public async Task<IActionResult> Verify([FromForm] SepehrGatewayPayResponse payResponse)
{
if (!long.TryParse(payResponse.invoiceid, out var paymentTransactionId))
{
@@ -89,215 +65,29 @@ public class GeneralController : GeneralBaseController
return NotFound("Transaction not found");
}
if (transaction.Status != PaymentTransactionStatus.Pending)
// ایجاد command برای ارسال به PaymentCallbackHandler
var command = new VerifyPaymentCallbackCommand
{
return BadRequest("این تراکنش قبلا پرداخت شده است");
}
if (payResponse.respcode != 0)
{
return await HandleFailedTransaction(transaction);
}
var extraData = JsonConvert.DeserializeObject<IDictionary<string, object>>(payResponse.payload);
extraData.TryGetValue("financialInvoiceId", out var financialInvoiceIdObj);
if (financialInvoiceIdObj == null ||
!long.TryParse(financialInvoiceIdObj.ToString(), out var financialInvoiceId))
{
return BadRequest("فاکتور مالی نامعتبر است");
}
var financialInvoice = _financialInvoiceApplication.GetDetails(financialInvoiceId);
if (financialInvoice == null)
{
return BadRequest("فاکتور مالی نامعتبر است");
}
if (financialInvoice.Status != FinancialInvoiceStatus.Unpaid)
{
return BadRequest("فاکتور مالی نامعتبر است");
}
if (financialInvoice.Amount != transaction.Amount)
{
return await HandleFailedTransaction(transaction);
}
var verifyCommand = new VerifyPaymentGateWayRequest()
{
Amount = transaction.Amount,
TransactionId = payResponse.invoiceid,
DigitalReceipt = payResponse.digitalreceipt
ResponseCode = payResponse.respcode,
InvoiceId = paymentTransactionId,
Payload = payResponse.payload,
Amount = payResponse.amount,
TraceNumber = payResponse.tracenumber,
Rrn = payResponse.rrn,
DigitalReceipt = payResponse.digitalreceipt,
IssuerBank = payResponse.issuerbank,
CardNumber = payResponse.cardnumber
};
var verifyRes = await _paymentGateway.Verify(verifyCommand, CancellationToken.None);
#if DEBUG
verifyRes.IsSuccess = true;
#endif
// پردازش callback در Application Layer
var result = await _paymentCallbackHandler.VerifySepehrPaymentCallback(command, CancellationToken.None);
_financialInvoiceApplication.SetPaid(financialInvoiceId, DateTime.Now);
if (verifyRes.IsSuccess)
if (result.IsSuccedded)
{
var command = new CreateFinancialStatment()
{
ContractingPartyId = transaction.ContractingPartyId,
Deptor = 0,
Creditor = transaction.Amount,
DeptorString = "0",
TypeOfTransaction = "credit",
DescriptionOption = financialInvoice.Description + "شماره فاکتور" + financialInvoice.InvoiceNumber,
Description = "درگاه بانکی",
};
var statementResult = _financialStatmentApplication.CreateFromBankGateway(command);
if (!statementResult.IsSuccedded)
{
return new JsonResult(statementResult);
}
var setSuccessResult = _paymentTransactionApplication.SetSuccess(paymentTransactionId,
payResponse.cardnumber, payResponse.issuerbank, payResponse.rrn.ToString(),
payResponse.digitalreceipt);
if (financialInvoice.Items?.Any(x =>
x.Type is FinancialInvoiceItemType.BuyInstitutionContract
or FinancialInvoiceItemType.BuyInstitutionContractInstallment) ?? false)
{
var financialItems = financialInvoice.Items
.Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContract);
foreach (var editFinancialInvoiceItem in financialItems)
{
await _institutionContractApplication.SetPendingWorkflow(editFinancialInvoiceItem.EntityId,
InstitutionContractSigningType.OtpBased);
}
var financialInstallmentItems = financialInvoice.Items
.Where(x => x.Type == FinancialInvoiceItemType.BuyInstitutionContractInstallment);
foreach (var editFinancialInvoiceItem in financialInstallmentItems)
{
var institutionContractId =
await _institutionContractApplication.GetIdByInstallmentId(
editFinancialInvoiceItem.EntityId);
await _institutionContractApplication.SetPendingWorkflow(institutionContractId,
InstitutionContractSigningType.OtpBased);
}
}
if (!setSuccessResult.IsSuccedded)
{
return await HandleFailedTransaction(transaction);
}
return Redirect(BuildCallbackUrl(transaction.CallBackUrl, true, transaction.Id));
}
// در غیر این صورت تراکنش ناموفق است
return await HandleFailedTransaction(transaction);
//var data = JsonConvert.SerializeObject(invoice.AdditionalData);
//var statics =
//JsonConvert.SerializeObject(res);
//await _onlinePayment.CancelAsync(invoice);
//return new JsonResult(new
//{
// data,
// statics
//});
//// Check if the invoice is new, or it's already processed before.
//if (invoice.Status != PaymentFetchResultStatus.ReadyForVerifying)
//{
// // You can also see if the invoice is already verified before.
// var isAlreadyVerified = invoice.IsAlreadyVerified;
// return Content("The payment was not successful.");
//}
//// Note: Save the verifyResult.TransactionCode in your database.
}
[HttpPost("/api/callback3232")]
public async Task<IActionResult> OnGetCallBack(string? transid, string? cardnumber, string? tracking_number,
string bank, string invoice_id, string? status, CancellationToken cancellationToken)
{
if (!long.TryParse(invoice_id, out var paymentTransactionId))
{
return BadRequest("Invalid invoice_id");
}
var transaction = await _paymentTransactionApplication.GetDetails(paymentTransactionId);
if (transaction == null)
{
return NotFound("Transaction not found");
}
if (transaction.Status != PaymentTransactionStatus.Pending)
{
return BadRequest("این تراکنش قبلا پرداخت شده است");
}
// اگر شماره کارت یا شماره پیگیری خالی باشد، تراکنش ناموفق است
if (string.IsNullOrWhiteSpace(cardnumber) || string.IsNullOrWhiteSpace(tracking_number))
{
return await HandleFailedTransaction(transaction);
}
var verifyCommand = new VerifyPaymentGateWayRequest()
{
Amount = transaction.Amount / 10,
TransactionId = transid
};
var verifyRes = await _paymentGateway.Verify(verifyCommand, cancellationToken);
// اگر استاتوس 1 باشد، تراکنش موفق است
if (verifyRes.IsSuccess)
{
var command = new CreateFinancialStatment()
{
ContractingPartyId = transaction.ContractingPartyId,
Deptor = 0,
Creditor = transaction.Amount,
DeptorString = "0",
TypeOfTransaction = "credit",
DescriptionOption = "بابت قرارداد مابین (روابط کار)",
Description = "درگاه بانکی",
};
var statementResult = _financialStatmentApplication.CreateFromBankGateway(command);
if (!statementResult.IsSuccedded)
{
return await HandleFailedTransaction(transaction);
}
var setSuccessResult =
_paymentTransactionApplication.SetSuccess(paymentTransactionId, cardnumber, bank, null, null);
if (!setSuccessResult.IsSuccedded)
{
return new JsonResult(setSuccessResult);
}
return Redirect(BuildCallbackUrl(transaction.CallBackUrl, true, transaction.Id));
}
// در غیر این صورت تراکنش ناموفق است
return await HandleFailedTransaction(transaction);
}
private async Task<IActionResult> HandleFailedTransaction(PaymentTransactionDetailsViewModel transaction)
{
var result = _paymentTransactionApplication.SetFailed(transaction.Id);
if (!result.IsSuccedded)
{
return new JsonResult(result);
}
// در صورت ناموفق بودن
return Redirect(BuildCallbackUrl(transaction.CallBackUrl, false, transaction.Id));
}