# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
This commit is contained in:
2026-01-01 12:30:38 +03:30
36 changed files with 1984 additions and 1003 deletions

View File

@@ -4,6 +4,7 @@ using System.Net.Http;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace _0_Framework.Application.PaymentGateway;
@@ -12,18 +13,24 @@ public class SepehrPaymentGateway:IPaymentGateway
{
private readonly HttpClient _httpClient;
private const long TerminalId = 99213700;
private readonly ILogger<SepehrPaymentGateway> _logger;
public SepehrPaymentGateway(IHttpClientFactory httpClient)
public SepehrPaymentGateway(IHttpClientFactory httpClient, ILogger<SepehrPaymentGateway> logger)
{
_logger = logger;
_httpClient = httpClient.CreateClient();
_httpClient.BaseAddress = new Uri("https://sepehr.shaparak.ir/Rest/V1/PeymentApi/");
}
public async Task<PaymentGatewayResponse> Create(CreatePaymentGatewayRequest command, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Create payment started. TransactionId: {TransactionId}, Amount: {Amount}", command.TransactionId, command.Amount);
command.ExtraData ??= new Dictionary<string, object>();
_logger.LogInformation("Initializing extra data with FinancialInvoiceId: {FinancialInvoiceId}", command.FinancialInvoiceId);
command.ExtraData.Add("financialInvoiceId", command.FinancialInvoiceId);
var extraData = JsonConvert.SerializeObject(command.ExtraData);
_logger.LogInformation("Serialized extra data payload: {Payload}", extraData);
var res = await _httpClient.PostAsJsonAsync("GetToken", new
{
TerminalID = TerminalId,
@@ -32,21 +39,25 @@ public class SepehrPaymentGateway:IPaymentGateway
callbackURL = command.CallBackUrl,
payload = extraData
}, cancellationToken: cancellationToken);
_logger.LogInformation("Create payment request sent. StatusCode: {StatusCode}", res.StatusCode);
// خواندن محتوای پاسخ
var content = await res.Content.ReadAsStringAsync(cancellationToken);
_logger.LogInformation("Create payment response content: {Content}", content);
// تبدیل پاسخ JSON به آبجکت دات‌نت
var json = System.Text.Json.JsonDocument.Parse(content);
_logger.LogInformation("Create payment JSON parsed successfully.");
// گرفتن مقدار AccessToken
var accessToken = json.RootElement.GetProperty("Accesstoken").ToString();
var status = json.RootElement.GetProperty("Status").ToString();
_logger.LogInformation("Create payment parsed values. Status: {Status}, AccessToken: {AccessToken}", status, accessToken);
return new PaymentGatewayResponse
{
Status = status,
IsSuccess = status == "0",
Token = accessToken
Token = accessToken,
};
}
@@ -55,21 +66,24 @@ public class SepehrPaymentGateway:IPaymentGateway
public async Task<PaymentGatewayResponse> Verify(VerifyPaymentGateWayRequest command, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Verify payment started. DigitalReceipt: {DigitalReceipt}", command.DigitalReceipt);
var res = await _httpClient.PostAsJsonAsync("Advice", new
{
digitalreceipt = command.DigitalReceipt,
Tid = TerminalId,
}, cancellationToken: cancellationToken);
_logger.LogInformation("Verify payment request sent. StatusCode: {StatusCode}", res.StatusCode);
// خواندن محتوای پاسخ
var content = await res.Content.ReadAsStringAsync(cancellationToken);
_logger.LogInformation("Verify payment response content: {Content}", content);
// تبدیل پاسخ JSON به آبجکت دات‌نت
var json = System.Text.Json.JsonDocument.Parse(content);
_logger.LogInformation("Verify payment JSON parsed successfully.");
var message = json.RootElement.GetProperty("Message").GetString();
var status = json.RootElement.GetProperty("Status").GetString();
_logger.LogInformation("Verify payment parsed values. Status: {Status}, Message: {Message}", status, message);
return new PaymentGatewayResponse
{
Status = status,

View File

@@ -64,6 +64,7 @@ public interface ISmsService
/// <summary>
/// پیامک مسدودی طرف حساب
/// قراردادهای قدیم
/// </summary>
/// <param name="number"></param>
/// <param name="fullname"></param>
@@ -74,6 +75,19 @@ public interface ISmsService
/// <returns></returns>
Task<(byte status, string message, int messaeId, bool isSucceded)> BlockMessage(string number, string fullname, string amount, string accountType, string id, string aprove);
/// <summary>
/// پیامک مسدودی طرف حساب
/// قرارداد های جدید
/// </summary>
/// <param name="number"></param>
/// <param name="fullname"></param>
/// <param name="amount"></param>
/// <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);
#endregion
#region AlarmMessage

View File

@@ -75,7 +75,6 @@ public interface IAccountApplication
void CameraLogin(CameraLoginRequest request);
Task<GetPmUserDto> GetPmUserAsync(long accountId);
}
public class CameraLoginRequest

View File

@@ -1024,4 +1024,5 @@ public class AccountApplication : IAccountApplication
{
return await _pmUserQueryService.GetPmUserDataByAccountId(accountId);
}
}

View File

@@ -57,6 +57,18 @@ public class JobSchedulerRegistrator
() => SendInstitutionContractConfirmSms(),
"*/1 * * * *" // هر 1 دقیقه یکبار چک کن
);
//RecurringJob.AddOrUpdate(
// "InstitutionContract.SendWarningSms",
// () => SendWarningSms(),
// "*/1 * * * *" // هر 1 دقیقه یکبار چک کن
//);
//RecurringJob.AddOrUpdate(
// "InstitutionContract.SendLegalActionSms",
// () => SendLegalActionSms(),
// "*/1 * * * *" // هر 1 دقیقه یکبار چک کن
//);
}
@@ -170,4 +182,22 @@ public class JobSchedulerRegistrator
await _institutionContractRepository.SendInstitutionContractConfirmSmsTask();
}
/// <summary>
/// ارسال پیامک هشدار
/// </summary>
/// <returns></returns>
[DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task SendWarningSms()
{
_logger.LogInformation("SendWarningSms job run");
await _institutionContractRepository.SendWarningSmsTask();
}
[DisableConcurrentExecution(timeoutInSeconds: 100)]
public async System.Threading.Tasks.Task SendLegalActionSms()
{
_logger.LogInformation("SendWarningSms job run");
await _institutionContractRepository.SendLegalActionSmsTask();
}
}

View File

@@ -1,4 +1,5 @@
using CompanyManagment.App.Contracts.PersonalContractingParty;
using System;
using CompanyManagment.App.Contracts.PersonalContractingParty;
using System.Collections.Generic;
using _0_Framework.Application;
using _0_Framework.Domain;
@@ -32,7 +33,9 @@ public interface IPersonalContractingPartyRepository :IRepository<long, Personal
List<PersonalContractingPartyViewModel> SearchForMain(PersonalContractingPartySearchModel searchModel2);
OperationResult DeletePersonalContractingParties(long id);
bool GetHasContract(long id);
[Obsolete("از متدهای async استفاده کنید")]
OperationResult DeActiveAll(long id);
[Obsolete("از متدهای async استفاده کنید")]
OperationResult ActiveAll(long id);
#endregion
@@ -76,4 +79,9 @@ public interface IPersonalContractingPartyRepository :IRepository<long, Personal
Task<PersonalContractingParty> GetByNationalCode(string nationalCode);
Task<PersonalContractingParty> GetByNationalId(string registerId);
Task<OperationResult> DeActiveAllAsync(long id);
Task<OperationResult> ActiveAllAsync(long id);
}

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

@@ -12,7 +12,7 @@ namespace Company.Domain.InstitutionContractAgg;
public interface IInstitutionContractRepository : IRepository<long, InstitutionContract>
{
EditInstitutionContract GetDetails(long id);
EditInstitutionContract GetFirstContract(long contractingPartyId, string typeOfContract);
List<InstitutionContractViewModel> InstitutionContractsWithoutAccount();
@@ -55,12 +55,12 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
void UpdateStatusIfNeeded(long institutionContractId);
Task<GetInstitutionVerificationDetailsViewModel> GetVerificationDetails(Guid id);
Task<InstitutionContract> GetByPublicIdAsync(Guid id);
InstitutionContractDiscountResponse CalculateDiscount(InstitutionContractSetDiscountRequest request,string contractStart = null);
InstitutionContractDiscountResponse CalculateDiscount(InstitutionContractSetDiscountRequest request, string contractStart = null);
InstitutionContractDiscountResponse ResetDiscountCreate(InstitutionContractResetDiscountForCreateRequest request);
#region Creation
#endregion
#region Extension
@@ -72,19 +72,19 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
Task<InstitutionContractDiscountResponse> SetDiscountForExtension(
InstitutionContractSetDiscountForExtensionRequest request);
Task<InstitutionContractDiscountResponse> ResetDiscountForExtension(InstitutionContractResetDiscountForExtensionRequest request);
Task<OperationResult> ExtensionComplete(InstitutionContractExtensionCompleteRequest request);
#endregion
#region Upgrade(Amendment)
Task<InstitutionContractAmendmentWorkshopsResponse> GetAmendmentWorkshops(long institutionContractId);
Task<InsitutionContractAmendmentPaymentResponse> GetAmendmentPaymentDetails(InsitutionContractAmendmentPaymentRequest request);
Task<InstitutionContractAmendmentWorkshopsResponse> GetAmendmentWorkshops(long institutionContractId);
Task<InsitutionContractAmendmentPaymentResponse> GetAmendmentPaymentDetails(InsitutionContractAmendmentPaymentRequest request);
Task<InsertAmendmentTempWorkshopResponse> InsertAmendmentTempWorkshops(InstitutionContractAmendmentTempWorkshopViewModel request);
Task RemoveAmendmentWorkshops(Guid workshopTempId);
#endregion
Task<InsertAmendmentTempWorkshopResponse> InsertAmendmentTempWorkshops(InstitutionContractAmendmentTempWorkshopViewModel request);
Task RemoveAmendmentWorkshops(Guid workshopTempId);
#endregion
Task<List<InstitutionContractSelectListViewModel>> GetInstitutionContractSelectList(string search, string selected);
Task<List<InstitutionContractPrintViewModel>> PrintAllAsync(List<long> ids);
@@ -162,6 +162,25 @@ public interface IInstitutionContractRepository : IRepository<long, InstitutionC
Task CreateTransactionForInstitutionContracts(DateTime endOfMonthGr, string endOfMonthFa, string description);
#endregion
#region WarningSms
/// <summary>
/// پیامک های هشدار
/// </summary>
/// <returns></returns>
Task SendWarningSmsTask();
#endregion
#region legalAction
/// <summary>
/// پیامک اقدام قضائی
/// </summary>
/// <returns></returns>
Task SendLegalActionSmsTask();
#endregion
Task<long> GetIdByInstallmentId(long installmentId);
@@ -173,4 +192,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

@@ -94,4 +94,29 @@ public class BlockSmsListData
/// آی دی صورت حساب مالی
/// </summary>
public string AproveId { get; set; }
/// <summary>
/// آیا قرداد مالی قدیمی است
/// </summary>
public bool IsElectronicContract { get; set; }
/// <summary>
/// پابلیک آی دی بخش یک
/// </summary>
public string Code1 { get; set; }
/// <summary>
/// پابلیک آی دی بخش دو
/// </summary>
public string Code2 { get; set; }
}
/// <summary>
/// لیست قراداد های آبی
/// جهت ارسال هشدار یا اقدام قضائی
/// </summary>
public class BlueWarningSmsData
{
}

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

@@ -1,40 +1,32 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using _0_Framework.Application;
using _0_Framework.Application.Enums;
using _0_Framework.Application.PaymentGateway;
using _0_Framework.Application.Sms;
using _0_Framework.Application.UID;
using _0_Framework.Exceptions;
using AccountManagement.Application.Contracts.Account;
using Company.Domain.ContarctingPartyAgg;
using Company.Domain.EmployeeAgg;
using Company.Domain.empolyerAgg;
using Company.Domain.FinancialInvoiceAgg;
using Company.Domain.FinancialStatmentAgg;
using Company.Domain.FinancialTransactionAgg;
using Company.Domain.InstitutionContractAgg;
using Company.Domain.LeftWorkAgg;
using Company.Domain.PaymentTransactionAgg;
using Company.Domain.RepresentativeAgg;
using Company.Domain.RollCallServiceAgg;
using Company.Domain.TemporaryClientRegistrationAgg;
using Company.Domain.WorkshopAgg;
using CompanyManagment.App.Contracts.FinancialInvoice;
using CompanyManagment.App.Contracts.FinancialStatment;
using CompanyManagment.App.Contracts.InstitutionContract;
using CompanyManagment.App.Contracts.InstitutionContractContactinfo;
using CompanyManagment.App.Contracts.PaymentTransaction;
using CompanyManagment.App.Contracts.PersonalContractingParty;
using CompanyManagment.App.Contracts.SepehrPaymentGateway;
using CompanyManagment.App.Contracts.Workshop;
using CompanyManagment.EFCore.Migrations;
using Microsoft.AspNetCore.Mvc;
using OfficeOpenXml.Packaging.Ionic.Zip;
using Microsoft.Extensions.Logging;
using PersianTools.Core;
using ConnectedPersonnelViewModel = CompanyManagment.App.Contracts.Workshop.ConnectedPersonnelViewModel;
using FinancialStatment = Company.Domain.FinancialStatmentAgg.FinancialStatment;
@@ -49,49 +41,45 @@ public class InstitutionContractApplication : IInstitutionContractApplication
private readonly IFinancialStatmentApplication _financialStatmentApplication;
private readonly IEmployerRepository _employerRepository;
private readonly IWorkshopRepository _workshopRepository;
private readonly ILeftWorkRepository _leftWorkRepository;
private readonly IWorkshopApplication _workshopApplication;
private readonly IContractingPartyTempRepository _contractingPartyTempRepository;
private readonly IFinancialStatmentRepository _financialStatmentRepository;
private readonly IContactInfoApplication _contactInfoApplication;
private readonly IAccountApplication _accountApplication;
private readonly ISmsService _smsService;
private readonly IUidService _uidService;
private readonly IFinancialInvoiceRepository _financialInvoiceRepository;
private readonly IPaymentGateway _paymentGateway;
private readonly IPaymentTransactionRepository _paymentTransactionRepository;
private readonly IRollCallServiceRepository _rollCallServiceRepository;
private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService;
public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository,
IPersonalContractingPartyRepository contractingPartyRepository,
IRepresentativeRepository representativeRepository, IEmployerRepository employerRepository,
IWorkshopRepository workshopRepository, ILeftWorkRepository leftWorkRepository,
IWorkshopRepository workshopRepository,
IFinancialStatmentApplication financialStatmentApplication, IWorkshopApplication workshopApplication,
IContractingPartyTempRepository contractingPartyTempRepository,
IFinancialStatmentRepository financialStatmentRepository, IContactInfoApplication contactInfoApplication,
IAccountApplication accountApplication, ISmsService smsService, IUidService uidService,
IAccountApplication accountApplication, ISmsService smsService,
IFinancialInvoiceRepository financialInvoiceRepository, IHttpClientFactory httpClientFactory,
IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository)
IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository,
ISepehrPaymentGatewayService sepehrPaymentGatewayService,ILogger<SepehrPaymentGateway> sepehrGatewayLogger)
{
_institutionContractRepository = institutionContractRepository;
_contractingPartyRepository = contractingPartyRepository;
_representativeRepository = representativeRepository;
_employerRepository = employerRepository;
_workshopRepository = workshopRepository;
_leftWorkRepository = leftWorkRepository;
_financialStatmentApplication = financialStatmentApplication;
_workshopApplication = workshopApplication;
_contractingPartyTempRepository = contractingPartyTempRepository;
_financialStatmentRepository = financialStatmentRepository;
_contactInfoApplication = contactInfoApplication;
_accountApplication = accountApplication;
_smsService = smsService;
_uidService = uidService;
_financialInvoiceRepository = financialInvoiceRepository;
_paymentTransactionRepository = paymentTransactionRepository;
_rollCallServiceRepository = rollCallServiceRepository;
_paymentGateway = new SepehrPaymentGateway(httpClientFactory);
_sepehrPaymentGatewayService = sepehrPaymentGatewayService;
_paymentGateway = new SepehrPaymentGateway(httpClientFactory,sepehrGatewayLogger);
}
public OperationResult Create(CreateInstitutionContract command)
@@ -817,20 +805,11 @@ public class InstitutionContractApplication : IInstitutionContractApplication
var contractingParty = _contractingPartyRepository.Get(institutionContract.ContractingPartyId);
if (contractingParty != null)
{
contractingParty.DeActive();
_contractingPartyRepository.SaveChanges();
var employers =
_employerRepository.GetEmployerByContracrtingPartyID(institutionContract.ContractingPartyId);
//var employersIdList = employers.Select(x => x.Id).ToList();
//var workshops = _workshopApplication.GetWorkshopsByEmployerId(employersIdList);
//foreach (var workshop in workshops)
//{
// var res = _workshopApplication.DeActive(workshop.Id);
//}
foreach (var employer in employers)
{
var res = _employerRepository.DeActiveAll(employer.Id);
}
var accountsDeActiveRes = _contractingPartyRepository.DeActiveAllAsync(contractingParty.id)
.GetAwaiter().GetResult();
if (!accountsDeActiveRes.IsSuccedded)
return opration.Failed(accountsDeActiveRes.Message);
}
return opration.Succcedded();
@@ -847,20 +826,10 @@ public class InstitutionContractApplication : IInstitutionContractApplication
var contractingParty = _contractingPartyRepository.Get(institutionContract.ContractingPartyId);
if (contractingParty != null)
{
contractingParty.Active();
_contractingPartyRepository.SaveChanges();
var employers =
_employerRepository.GetEmployerByContracrtingPartyID(institutionContract.ContractingPartyId);
//var employersIdList = employers.Select(x => x.Id).ToList();
//var workshops = _workshopApplication.GetWorkshopsByEmployerId(employersIdList);
//foreach (var workshop in workshops)
//{
// var res = _workshopApplication.DeActive(workshop.Id);
//}
foreach (var employer in employers)
{
var res = _employerRepository.ActiveAll(employer.Id);
}
var activeRes = _contractingPartyRepository.ActiveAllAsync(contractingParty.id).GetAwaiter()
.GetResult();
if (!activeRes.IsSuccedded)
return opration.Failed(activeRes.Message);
}
return opration.Succcedded();
@@ -1294,119 +1263,87 @@ 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)
{
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)
{
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,239 @@
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;
using Microsoft.Extensions.Logging;
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,
ILogger<SepehrPaymentGateway> sepehrGatewayLogger)
{
_paymentTransactionApplication = paymentTransactionApplication;
_financialStatmentApplication = financialStatmentApplication;
_financialInvoiceApplication = financialInvoiceApplication;
_institutionContractApplication = institutionContractApplication;
_institutionContractRepository = institutionContractRepository;
_financialStatmentRepository = financialStatmentRepository;
_paymentGateway = new SepehrPaymentGateway(httpClientFactory, sepehrGatewayLogger);
}
/// <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,119 @@
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;
using Microsoft.Extensions.Logging;
namespace CompanyManagment.Application;
/// <summary>
/// سرویس مشترک برای ایجاد درگاه پرداخت سپهر
/// </summary>
public class SepehrPaymentGatewayService : ISepehrPaymentGatewayService
{
private readonly IPaymentGateway _paymentGateway;
private readonly IPaymentTransactionApplication _paymentTransactionApplication;
public SepehrPaymentGatewayService(
IPaymentTransactionApplication paymentTransactionApplication,
IHttpClientFactory httpClientFactory,
ILogger<SepehrPaymentGateway> sepehrGatewayLogger)
{
_paymentGateway = new SepehrPaymentGateway(httpClientFactory, sepehrGatewayLogger);
_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

@@ -210,6 +210,7 @@ public class FinancialStatmentRepository : RepositoryBase<long, FinancialStatmen
}
return new FinancialTransactionDetailViewModel()
{
Id = t.id,
DateTimeGr = t.TdateGr,
DateFa = t.TdateGr.ToFarsi(),
TimeFa = $"{t.TdateGr:HH:mm}",

View File

@@ -773,6 +773,137 @@ public class PersonalContractingPartyRepository : RepositoryBase<long, PersonalC
return await _context.PersonalContractingParties.FirstOrDefaultAsync(x => x.NationalId == nationalId);
}
public async Task<OperationResult> DeActiveAllAsync(long id)
{
OperationResult result = new OperationResult();
await using var transaction = await _context.Database.BeginTransactionAsync();
await using var accountTransaction = await _accountContext.Database.BeginTransactionAsync();
try
{
var contractingParty = _context.PersonalContractingParties
.FirstOrDefault(x => x.id == id);
if (contractingParty == null)
return result.Failed("طرف حساب یافت نشد");
contractingParty.DeActive();
var employers = _context.Employers
.Where(x => x.ContractingPartyId == id).ToList();
employers.ForEach(x => x.DeActive());
var employerIds = employers.Select(x => x.id).ToList();
var workshopIds = _context.WorkshopEmployers
.Where(x => employerIds.Contains(x.EmployerId))
.Select(x => x.WorkshopId).ToList();
var workshops = _context.Workshops
.Where(x => workshopIds.Contains(x.id)).ToList();
workshops.ForEach(x => x.DeActive(x.ArchiveCode));
var contracts = _context.Contracts
.Where(x => workshopIds.Contains(x.WorkshopIds)).ToList();
contracts.ForEach(x => x.DeActive());
var contractIds = contracts.Select(x => x.id).ToList();
var checkouts = _context.CheckoutSet
.Where(x => contractIds.Contains(x.ContractId)).ToList();
checkouts.ForEach(x => x.DeActive());
var contractingPartyAccount =await _context.ContractingPartyAccounts
.FirstOrDefaultAsync(x => x.PersonalContractingPartyId == id);
if (contractingPartyAccount != null)
{
var account = await _accountContext.Accounts
.FirstOrDefaultAsync(x => x.id == contractingPartyAccount.AccountId);
account?.DeActive();
var cameraAccount =await _accountContext.CameraAccounts
.FirstOrDefaultAsync(x=>x.AccountId==account.id);
cameraAccount?.DeActive();
await _accountContext.SaveChangesAsync();
}
await _context.SaveChangesAsync();
await transaction.CommitAsync();
await accountTransaction.CommitAsync();
result.Succcedded();
}
catch (Exception)
{
result.Failed("غیرفعال کردن طرف حساب با خطا مواجه شد");
await transaction.RollbackAsync();
await accountTransaction.RollbackAsync();
}
return result;
}
public async Task<OperationResult> ActiveAllAsync(long id)
{
OperationResult result = new OperationResult();
await using var transaction =await _context.Database.BeginTransactionAsync();
await using var accountTransaction = await _accountContext.Database.BeginTransactionAsync();
try
{
var personel = _context.PersonalContractingParties
.FirstOrDefault(x => x.id == id);
if (personel == null)
return result.Failed("طرف حساب یافت نشد");
personel.Active();
var employers = _context.Employers.Where(x => x.ContractingPartyId == id).ToList();
employers.ForEach(x => x.Active());
var employerIds = employers.Select(x => x.id).ToList();
var workshopIds = _context.WorkshopEmployers.Where(x => employerIds.Contains(x.EmployerId))
.Select(x => x.WorkshopId).ToList();
var workshops = _context.Workshops.Where(x => workshopIds.Contains(x.id)).ToList();
workshops.ForEach(x => x.Active(x.ArchiveCode));
var contracts = _context.Contracts.Where(x => workshopIds.Contains(x.WorkshopIds)).ToList();
contracts.ForEach(x => x.Active());
var contractIds = contracts.Select(x => x.id).ToList();
var checkouts = _context.CheckoutSet.Where(x => contractIds.Contains(x.ContractId)).ToList();
checkouts.ForEach(x => x.Active());
var contractingPartyAccount =await _context.ContractingPartyAccounts
.FirstOrDefaultAsync(x => x.PersonalContractingPartyId == id);
if (contractingPartyAccount != null)
{
var account = await _accountContext.Accounts
.FirstOrDefaultAsync(x => x.id == contractingPartyAccount.AccountId);
account?.Active();
var cameraAccount =await _accountContext.CameraAccounts
.FirstOrDefaultAsync(x=>x.AccountId==account.id);
cameraAccount?.Active();
await _accountContext.SaveChangesAsync();
}
await _context.SaveChangesAsync();
await transaction.CommitAsync();
await accountTransaction.CommitAsync();
result.Succcedded();
}
catch (Exception)
{
result.Failed("فعال کردن طرف حساب با خطا مواجه شد");
await transaction.RollbackAsync();
await accountTransaction.RollbackAsync();
}
return result;
}
#endregion
}

View File

@@ -518,6 +518,31 @@ public class SmsService : ISmsService
return result;
}
public async Task<(byte status, string message, int messaeId, bool isSucceded)> BlockMessageForElectronicContract(string number, string fullname, string amount,string code1, string code2)
{
var tamplateId = 117685;
var result = new ValueTuple<byte, string, int, bool>();
var smsIr = new SmsIr("Og5M562igmzJRhQPnq0GdtieYdLgtfikjzxOmeQBPxJjZtyge5Klc046Lfw1mxSa");
var sendResult = await smsIr.VerifySendAsync(number, tamplateId,
new VerifySendParameter[]
{
new("FULLNAME", fullname), new("AMOUNT", amount), new("CODE1", code1), new("CODE2", code2)
});
Thread.Sleep(500);
if (sendResult.Message == "موفق")
{
result = (sendResult.Status, sendResult.Message, sendResult.Data.MessageId, true);
return result;
}
result = (sendResult.Status, sendResult.Message, sendResult.Data.MessageId, false);
return result;
}
#endregion

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

@@ -48,7 +48,8 @@ public class institutionContractController : AdminBaseController
IPersonalContractingPartyApp contractingPartyApplication, IContactInfoApplication contactInfoApplication,
IAccountApplication accountApplication, IEmployerApplication employerApplication,
IWorkshopApplication workshopApplication, ITemporaryClientRegistrationApplication temporaryClientRegistration,
ITemporaryClientRegistrationApplication clientRegistrationApplication, IHttpClientFactory httpClientFactory)
ITemporaryClientRegistrationApplication clientRegistrationApplication, IHttpClientFactory httpClientFactory
,ILogger<SepehrPaymentGateway> sepehrGatewayLogger)
{
_institutionContractApplication = institutionContractApplication;
_contractingPartyApplication = contractingPartyApplication;
@@ -58,7 +59,7 @@ public class institutionContractController : AdminBaseController
_workshopApplication = workshopApplication;
_temporaryClientRegistration = temporaryClientRegistration;
_clientRegistrationApplication = clientRegistrationApplication;
_paymentGateway = new SepehrPaymentGateway(httpClientFactory);
_paymentGateway = new SepehrPaymentGateway(httpClientFactory, sepehrGatewayLogger);
}
/// <summary>
@@ -241,7 +242,8 @@ public class institutionContractController : AdminBaseController
if (balance == "0")
{
result = _institutionContractApplication.DeActive(id);
if (result.IsSuccedded) result = _institutionContractApplication.DeActiveAllConnections(id);
if (result.IsSuccedded)
result = _institutionContractApplication.DeActiveAllConnections(id);
}
else
{
@@ -338,21 +340,6 @@ public class institutionContractController : AdminBaseController
});
}
/// <summary>
/// دانلود اکسل
/// </summary>
/// <returns></returns>
[HttpGet("excel")]
public IActionResult OnGetDownloadExcel()
{
var institutionContractViewModels =
_institutionContractApplication.NewSearch(new() { IsActiveString = "both", TypeOfContract = "both" });
var bytes = InstitutionContractExcelGenerator.GenerateExcel(new List<InstitutionContractExcelViewModel>());
return File(bytes,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
$"قرارداد های مالی.xlsx");
}
[HttpPost("create/inquiry")]
public async Task<ActionResult<OperationResult<ContractingPartyTempViewModel>>> CreateInquiry(
[FromBody] InstitutionContractCreationInquiryRequest request)
@@ -548,7 +535,7 @@ public class institutionContractController : AdminBaseController
return res;
}
[HttpPost("creation/set-contracting-party")]
[HttpGet("creation/get-representative")]
public async Task<ActionResult<InstitutionContractCreationGetRepresentativeIdResponse>> GetRepresentatives(string nationalCode)
{
var res = await _contractingPartyApplication.GetRepresentativeIdByNationalCode(nationalCode);

View File

@@ -89,7 +89,8 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
CompanyContext context, AccountContext accountContext, IHttpClientFactory httpClientFactory,
IOptions<AppSettingConfiguration> appSetting,
ITemporaryClientRegistrationApplication clientRegistrationApplication, IOnlinePayment onlinePayment,
IFaceEmbeddingService faceEmbeddingService, IAuthHelper authHelper, IInstitutionContractApplication institutionContractApplication)
IFaceEmbeddingService faceEmbeddingService, IAuthHelper authHelper, IInstitutionContractApplication institutionContractApplication
,ILogger<SepehrPaymentGateway> sepehrGatewayLogger)
{
_application = application;
_rollCallDomainService = rollCallDomainService;
@@ -101,7 +102,7 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk
_faceEmbeddingService = faceEmbeddingService;
_authHelper = authHelper;
_institutionContractApplication = institutionContractApplication;
_paymentGateway = new SepehrPaymentGateway(httpClientFactory);
_paymentGateway = new SepehrPaymentGateway(httpClientFactory, sepehrGatewayLogger);
}
public void OnGet()

View File

@@ -219,7 +219,7 @@
</div>
<div class="Rtable-cell--content">
<div class="d-flex align-items-center justify-content-end">
<a href="@Url.Page("./Index", "DownloadFile", new { path = @item.FullPath, fileName = @item.FileName })" class="btn-delete1">
<a href="@Url.Page("./Index", "DownloadFileLog", new { path = @item.FullPath, fileName = @item.FileName })" class="btn-delete1">
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3" />
</svg>

View File

@@ -1,4 +1,4 @@
using _0_Framework.Application;
using _0_Framework.Application;
using _0_Framework.Infrastructure;
using _0_Framework.InfraStructure;
using backService;
@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration.UserSecrets;
using System.IO;
namespace ServiceHost.Areas.AdminNew.Pages.Company.FileBackup
{
@@ -68,8 +69,8 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.FileBackup
{
FileName = Path.GetFileName(x),
FullPath = x,
CreationDate = Path.GetFileName(x).ExtractTimeFromInsurancebackup(),
}).OrderByDescending(x => x.CreationDate).ToList();
CreationDate = new DateTime(),
}).ToList();
#endregion
@@ -89,5 +90,22 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.FileBackup
byte[] fileContent = System.IO.File.ReadAllBytes(path);
return File(fileContent, "application/zip", fileName);
}
}
public IActionResult OnGetDownloadFileLog(string path, string fileName)
{
if (!System.IO.File.Exists(path))
return NotFound();
var stream = new FileStream(
path,
FileMode.Open,
FileAccess.Read,
FileShare.ReadWrite // 🔑 کلید حل مشکل
);
return File(stream, "text/plain", fileName);
}
}
}

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));
}

View File

@@ -32,6 +32,8 @@ using GozareshgirProgramManager.Application.Modules.Users.Commands.CreateUser;
using GozareshgirProgramManager.Infrastructure;
using GozareshgirProgramManager.Infrastructure.Persistence.Seed;
using Microsoft.OpenApi;
using Serilog;
using Serilog.Events;
using ServiceHost.Hubs.ProgramManager;
using ServiceHost.Notifications.ProgramManager;
using ServiceHost.Conventions;
@@ -53,7 +55,36 @@ builder.Services.AddHttpClient("holidayApi", c => c.BaseAddress = new System.Uri
var connectionString = builder.Configuration.GetConnectionString("MesbahDb");
var connectionStringTestDb = builder.Configuration.GetConnectionString("TestDb");
#region Serilog
var logDirectory = @"C:\Logs\Gozareshgir\";
if (!Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
Log.Logger = new LoggerConfiguration()
//NO EF Core log
.MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
//NO DbCommand log
.MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Warning)
//NO Microsoft Public log
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
//.MinimumLevel.Information()
.WriteTo.File(
path: Path.Combine(logDirectory, "gozareshgir_log.txt"),
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 30,
shared: true,
outputTemplate:
"{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}"
).CreateLogger();
#endregion
builder.Services.AddProgramManagerApplication();
builder.Services.AddProgramManagerInfrastructure(builder.Configuration);
@@ -348,7 +379,8 @@ builder.Services.AddParbad().ConfigureGateways(gateways =>
});
builder.Host.UseSerilog();
Log.Information("SERILOG STARTED SUCCESSFULLY");
var app = builder.Build();
app.UseCors("AllowSpecificOrigins");

View File

@@ -94,11 +94,16 @@
<PackageReference Include="MongoDB.Driver" Version="3.5.2" />
<PackageReference Include="Parbad.AspNetCore" Version="1.5.0" />
<PackageReference Include="Parbad.Storage.Cache" Version="1.5.0" />
<PackageReference Include="Serilog" Version="4.3.0" />
<PackageReference Include="SocialExplorer.FastDBF" Version="1.0.0" />
<PackageReference Include="System.Data.OleDb" Version="10.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.0.1" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Storage\Task\" />

View File

@@ -22,7 +22,7 @@
"DbName": "mesbah_db",
"DbBackupZipPath": "c://EveryHourBackupList//",
"FastDbBackupZipPath": "c://FastBackupZipList//",
"InsuranceListZipPath": "c://InsuranceListZipPath//"
"InsuranceListZipPath": "c://Logs//Gozareshgir//"
},
"faceModels": {
"Faces": "c://labels//20//"