From cf3f0564f9c527c44ee19fb611f9492b741d8d63 Mon Sep 17 00:00:00 2001 From: mahan Date: Tue, 30 Dec 2025 12:13:57 +0330 Subject: [PATCH 01/21] feat: remove Excel download endpoint from institution contract controller --- .../Controllers/institutionContractController.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs b/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs index c2a21119..bbcf6af0 100644 --- a/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs +++ b/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs @@ -332,21 +332,6 @@ public class institutionContractController : AdminBaseController }); } - /// - /// دانلود اکسل - /// - /// - [HttpGet("excel")] - public IActionResult OnGetDownloadExcel() - { - var institutionContractViewModels = - _institutionContractApplication.NewSearch(new() { IsActiveString = "both", TypeOfContract = "both" }); - var bytes = InstitutionContractExcelGenerator.GenerateExcel(new List()); - return File(bytes, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - $"قرارداد های مالی.xlsx"); - } - [HttpPost("create/inquiry")] public async Task>> CreateInquiry( [FromBody] CreateInquiryRequest request) From 16c1ae04a9721998a67975e72eaa17e508094264 Mon Sep 17 00:00:00 2001 From: mahan Date: Tue, 30 Dec 2025 12:44:55 +0330 Subject: [PATCH 02/21] remove some injections --- .../InstitutionContractApplication.cs | 13 +++---------- .../Controllers/institutionContractController.cs | 3 ++- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index 82373502..fdd2e6a7 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -49,28 +49,23 @@ 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; - 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) { @@ -79,15 +74,12 @@ public class InstitutionContractApplication : IInstitutionContractApplication _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; @@ -831,6 +823,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication { var res = _employerRepository.DeActiveAll(employer.Id); } + } return opration.Succcedded(); diff --git a/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs b/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs index bbcf6af0..06bfab75 100644 --- a/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs +++ b/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs @@ -235,7 +235,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 { From eb9a3e52fe5906e9c82dc783cc3efdacf5ebc3a2 Mon Sep 17 00:00:00 2001 From: mahan Date: Tue, 30 Dec 2025 13:50:09 +0330 Subject: [PATCH 03/21] feat: implement async methods for activating and deactivating personal contracting parties --- .../Account/IAccountApplication.cs | 1 - .../AccountApplication.cs | 1 + .../IPersonalContractingPartyRepository.cs | 10 +- .../InstitutionContractApplication.cs | 47 ++----- .../PersonalContractingPartyRepository.cs | 131 ++++++++++++++++++ 5 files changed, 150 insertions(+), 40 deletions(-) diff --git a/AccountManagement.Application.Contracts/Account/IAccountApplication.cs b/AccountManagement.Application.Contracts/Account/IAccountApplication.cs index b1da0153..4d82946d 100644 --- a/AccountManagement.Application.Contracts/Account/IAccountApplication.cs +++ b/AccountManagement.Application.Contracts/Account/IAccountApplication.cs @@ -75,7 +75,6 @@ public interface IAccountApplication void CameraLogin(CameraLoginRequest request); Task GetPmUserAsync(long accountId); - } public class CameraLoginRequest diff --git a/AccountManagement.Application/AccountApplication.cs b/AccountManagement.Application/AccountApplication.cs index ff2fd102..64e05681 100644 --- a/AccountManagement.Application/AccountApplication.cs +++ b/AccountManagement.Application/AccountApplication.cs @@ -1024,4 +1024,5 @@ public class AccountApplication : IAccountApplication { return await _pmUserQueryService.GetPmUserDataByAccountId(accountId); } + } \ No newline at end of file diff --git a/Company.Domain/ContarctingPartyAgg/IPersonalContractingPartyRepository.cs b/Company.Domain/ContarctingPartyAgg/IPersonalContractingPartyRepository.cs index 068625ad..25178955 100644 --- a/Company.Domain/ContarctingPartyAgg/IPersonalContractingPartyRepository.cs +++ b/Company.Domain/ContarctingPartyAgg/IPersonalContractingPartyRepository.cs @@ -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 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 GetByNationalCode(string nationalCode); Task GetByNationalId(string registerId); + + Task DeActiveAllAsync(long id); + Task ActiveAllAsync(long id); + + } \ No newline at end of file diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index fdd2e6a7..0eed6616 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -1,40 +1,30 @@ 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.Workshop; -using CompanyManagment.EFCore.Migrations; -using Microsoft.AspNetCore.Mvc; -using OfficeOpenXml.Packaging.Ionic.Zip; using PersianTools.Core; using ConnectedPersonnelViewModel = CompanyManagment.App.Contracts.Workshop.ConnectedPersonnelViewModel; using FinancialStatment = Company.Domain.FinancialStatmentAgg.FinancialStatment; @@ -59,6 +49,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication private readonly IPaymentTransactionRepository _paymentTransactionRepository; private readonly IRollCallServiceRepository _rollCallServiceRepository; + public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository, IPersonalContractingPartyRepository contractingPartyRepository, IRepresentativeRepository representativeRepository, IEmployerRepository employerRepository, @@ -809,21 +800,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(); @@ -840,20 +821,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(); diff --git a/CompanyManagment.EFCore/Repository/PersonalContractingPartyRepository.cs b/CompanyManagment.EFCore/Repository/PersonalContractingPartyRepository.cs index ba888dc6..e0225194 100644 --- a/CompanyManagment.EFCore/Repository/PersonalContractingPartyRepository.cs +++ b/CompanyManagment.EFCore/Repository/PersonalContractingPartyRepository.cs @@ -773,6 +773,137 @@ public class PersonalContractingPartyRepository : RepositoryBase x.NationalId == nationalId); } + public async Task 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 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 } From 4d326b1983b57745786ba21aee2b625137a45bcf Mon Sep 17 00:00:00 2001 From: SamSys Date: Tue, 30 Dec 2025 18:38:08 +0330 Subject: [PATCH 04/21] reminderSms Change to electronicInstitutionContract --- .../InstitutionContractRepository.cs | 282 +++++++++--------- 1 file changed, 149 insertions(+), 133 deletions(-) diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index f15189ca..58bcae8a 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -35,6 +35,8 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Company.Domain.FinancialInvoiceAgg; +using CompanyManagment.App.Contracts.FinancialInvoice; using ContractingPartyAccount = Company.Domain.ContractingPartyAccountAgg.ContractingPartyAccount; using FinancialStatment = Company.Domain.FinancialStatmentAgg.FinancialStatment; using String = System.String; @@ -3828,7 +3830,9 @@ public class InstitutionContractRepository : RepositoryBase x.StartService.Date <= previusMonthStart.Date && x.EndService.Date >= previusMonthEnd.Date).ToList(); - var institutionContracts = await _context.InstitutionContractSet.AsSplitQuery().Select(x => + var institutionContracts = await _context.InstitutionContractSet.AsSplitQuery() + .Include(x => x.Installments) + .Select(x => new InstitutionContractViewModel { Id = x.id, @@ -3840,11 +3844,24 @@ public class InstitutionContractRepository : RepositoryBase new InstitutionContractInstallmentViewModel + { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) + .OrderBy(ins => ins.InstallmentDateGr).Skip(1).ToList(), }).Where(x => x.ContractStartGr < checkDate && x.ContractEndGr >= checkDate && - x.ContractAmountDouble > 0).GroupBy(x => x.ContractingPartyId).Select(x => x.First()) + x.ContractAmountDouble > 0 && x.VerificationStatus != InstitutionContractVerificationStatus.PendingForVerify) + .GroupBy(x => x.ContractingPartyId).Select(x => x.First()) .ToListAsync(); + // قرارداد هایی که بطور یکجا پرداخت شده اند + var paidInFull = institutionContracts.Where(x => + x.SigningType != InstitutionContractSigningType.Legacy && x.IsInstallment == false && x.SigningType != null).ToList(); + //حذف قراداد هایی که یکجا پرداخت شده اند از لیست ایجاد سند ماهانه + institutionContracts = institutionContracts.Except(paidInFull).ToList(); var contractingPartyList = await _context.PersonalContractingParties .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.id)).ToListAsync(); @@ -3861,7 +3878,15 @@ public class InstitutionContractRepository : RepositoryBase x.IsInstallment == false).ToList(); + var electronicInstitutionContract = institutionContracts.Where(x => x.IsInstallment == true).ToList(); + foreach (var item in oldInstitutionContract) { try { @@ -3913,6 +3938,8 @@ public class InstitutionContractRepository : RepositoryBase 0) // اگر بدهکار بود { //var employers = _context.Employers.Where(x => x.ContractingPartyId == item.ContractingPartyId) @@ -3954,37 +3981,7 @@ public class InstitutionContractRepository : RepositoryBase x.id == item.ContractingPartyId); + if (!string.IsNullOrWhiteSpace(contractingParty.LName)) + { + var partyName = contractingParty.IsLegal == "حقیقی" + ? $"{contractingParty.FName} {contractingParty.LName}" + : $"{contractingParty.LName}"; + if (!string.IsNullOrWhiteSpace(contractingParty.SureName)) + partyName = $"{partyName} ({contractingParty.SureName})"; + + if (partyName.Length > 25) partyName = $"{partyName.Substring(0, 25)}"; + + var isLegal = contractingParty.IsLegal == "حقوقی" ? true : false; + var isBlock = contractingParty.IsBlock == "true" ? true : false; + var isActive = contractingParty.IsActiveString == "true" ? true : false; + + if (!string.IsNullOrWhiteSpace(contractingParty.IsActiveString) && isActive) + { + var hasFinancialStatement = + financialStatmentList.Any(x => x.ContractingPartyId == item.ContractingPartyId); + + + var hasPhonNumber = phoneNumberList.Any(x => x.InstitutionContractId == item.Id); + + if (hasFinancialStatement && hasPhonNumber) + { + var phoneNumbers = phoneNumberList.Where(x => x.InstitutionContractId == item.Id) + .Select(x => new CreateContactInfo + { + PhoneType = x.PhoneType, + PhoneNumber = x.PhoneNumber, + + InstitutionContractId = x.InstitutionContractId, + SendSms = x.SendSms + }).Where(x => x.PhoneNumber.Length == 11).ToList(); + + var transactions = financialStatmentList.FirstOrDefault(x => + x.ContractingPartyId == item.ContractingPartyId); + + var debtor = transactions.FinancialTransactionList.Sum(x => x.Deptor); + var creditor = transactions.FinancialTransactionList.Sum(x => x.Creditor); + + + var id = $"{item.ContractingPartyId}"; + var aprove = $"{transactions.id}"; + var balance = debtor - creditor; + int templateId = 0; + //انتخاب قالب پیامک بر اساس حقیق/حقوقی + if (isLegal) + { + templateId = 789638; + if (typeOfSmsSetting == + TypeOfSmsSetting.MonthlyInstitutionContract) + { + templateId = 983035; + } + } + else + { + templateId = 768277; + if (typeOfSmsSetting == + TypeOfSmsSetting.MonthlyInstitutionContract) + { + templateId = 479624; + } + } + + if (balance > 0) // اگر بدهکار بود + { + var balanceToMoney = balance.ToMoney(); + + foreach (var number in phoneNumbers) + { + string publicId = transactions.PublicIdStr; + string code1 = publicId.Substring(0, 25); + string code2 = publicId.Substring(25); + + + smsList.Add(new SmsListData() + { + PhoneNumber = number.PhoneNumber, + TemplateId = templateId, + PartyName = partyName, + Amount = balanceToMoney, + ContractingPartyId = contractingParty.id, + AproveId = aprove, + TypeOfSmsMethod = "MonthlyBillNew", + Code1 = code1, + Code2 = code2, + InstitutionContractId = item.Id + }); + + } + } + } + } + } + + } + catch (Exception e) + { + _logger.LogError($"ContractingPartyId : {item.ContractingPartyId} - ContractingPartyName : {item.ContractingPartyName} - InstitutionContractId : {item.Id} خطای دریافت لیست بدهکاران "); + throw; + } + } + + #endregion Console.WriteLine("SmsListData: " + watch.Elapsed); From 147621de34b6e5a769500581f8599486de6249c1 Mon Sep 17 00:00:00 2001 From: mahan Date: Tue, 30 Dec 2025 20:53:44 +0330 Subject: [PATCH 05/21] feat: update institution contract creation to retrieve representatives and set contracting party info --- .../InstitutionContractRepository.cs | 39 +++++++++++++++++++ .../institutionContractController.cs | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index a8b26a99..882849df 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -5316,6 +5316,45 @@ public class InstitutionContractRepository : RepositoryBase> GetRepresentatives(string nationalCode) { var res = await _contractingPartyApplication.GetRepresentativeIdByNationalCode(nationalCode); From b03a806dfbf574893b759df28002372a8ceb261a Mon Sep 17 00:00:00 2001 From: SamSys Date: Wed, 31 Dec 2025 14:11:10 +0330 Subject: [PATCH 06/21] BackgroundTask change for new institutionContract sms --- 0_Framework/Application/Sms/ISmsService.cs | 12 + .../Jobs/JobSchedulerRegistrator.cs | 30 + .../IInstitutionContractRepository.cs | 37 +- .../InstitutionContract/SmsListData.cs | 15 + .../InstitutionContractRepository.cs | 722 ++++++++++++------ .../Services/SmsService.cs | 25 + 6 files changed, 594 insertions(+), 247 deletions(-) diff --git a/0_Framework/Application/Sms/ISmsService.cs b/0_Framework/Application/Sms/ISmsService.cs index 94e31299..53137858 100644 --- a/0_Framework/Application/Sms/ISmsService.cs +++ b/0_Framework/Application/Sms/ISmsService.cs @@ -64,6 +64,7 @@ public interface ISmsService /// /// پیامک مسدودی طرف حساب + /// قراردادهای قدیم /// /// /// @@ -74,6 +75,17 @@ public interface ISmsService /// Task<(byte status, string message, int messaeId, bool isSucceded)> BlockMessage(string number, string fullname, string amount, string accountType, string id, string aprove); + /// + /// پیامک مسدودی طرف حساب + /// قرارداد های جدید + /// + /// + /// + /// + /// + /// + /// + Task<(byte status, string message, int messaeId, bool isSucceded)> BlockMessageForElectronicContract(string number, string fullname, string amount, string code1, string code2) #endregion #region AlarmMessage diff --git a/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs b/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs index b4a0c823..7eaab611 100644 --- a/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs +++ b/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs @@ -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(); } + /// + /// ارسال پیامک هشدار + /// + /// + [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(); + } + } \ No newline at end of file diff --git a/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs b/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs index c578d7be..03f2e3ad 100644 --- a/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs +++ b/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs @@ -13,7 +13,7 @@ namespace Company.Domain.InstitutionContractAgg; public interface IInstitutionContractRepository : IRepository { - + EditInstitutionContract GetDetails(long id); EditInstitutionContract GetFirstContract(long contractingPartyId, string typeOfContract); List InstitutionContractsWithoutAccount(); @@ -56,12 +56,12 @@ public interface IInstitutionContractRepository : IRepository GetVerificationDetails(Guid id); Task 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 @@ -73,19 +73,19 @@ public interface IInstitutionContractRepository : IRepository SetDiscountForExtension( InstitutionContractSetDiscountForExtensionRequest request); Task ResetDiscountForExtension(InstitutionContractResetDiscountForExtensionRequest request); - + Task ExtensionComplete(InstitutionContractExtensionCompleteRequest request); #endregion #region Upgrade(Amendment) - Task GetAmendmentWorkshops(long institutionContractId); - Task GetAmendmentPaymentDetails(InsitutionContractAmendmentPaymentRequest request); + Task GetAmendmentWorkshops(long institutionContractId); + Task GetAmendmentPaymentDetails(InsitutionContractAmendmentPaymentRequest request); - Task InsertAmendmentTempWorkshops(InstitutionContractAmendmentTempWorkshopViewModel request); - Task RemoveAmendmentWorkshops(Guid workshopTempId); - #endregion + Task InsertAmendmentTempWorkshops(InstitutionContractAmendmentTempWorkshopViewModel request); + Task RemoveAmendmentWorkshops(Guid workshopTempId); + #endregion Task> GetInstitutionContractSelectList(string search, string selected); Task> PrintAllAsync(List ids); @@ -160,6 +160,25 @@ public interface IInstitutionContractRepository : IRepository + /// پیامک های هشدار + /// + /// + Task SendWarningSmsTask(); + + #endregion + + + #region legalAction + /// + /// پیامک اقدام قضائی + /// + /// + Task SendLegalActionSmsTask(); + #endregion Task GetIdByInstallmentId(long installmentId); diff --git a/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs b/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs index 35a89e68..538c7906 100644 --- a/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs +++ b/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs @@ -94,4 +94,19 @@ public class BlockSmsListData /// آی دی صورت حساب مالی /// public string AproveId { get; set; } + + /// + /// آیا قرداد مالی قدیمی است + /// + public bool IsElectronicContract { get; set; } + + /// + /// پابلیک آی دی بخش یک + /// + public string Code1 { get; set; } + + /// + /// پابلیک آی دی بخش دو + /// + public string Code2 { get; set; } } \ No newline at end of file diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index e2197ae7..268728cc 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -119,69 +119,69 @@ public class InstitutionContractRepository : RepositoryBase new EditInstitutionContract() - { - Id = x.id, - ContractNo = x.ContractNo, - ContractStartGr = x.ContractStartGr, - ContractStartFa = x.ContractStartFa, - ContractEndGr = x.ContractEndGr, - ContractEndFa = x.ContractEndFa, - RepresentativeName = x.RepresentativeName, - ContractingPartyName = x.ContractingPartyName, - RepresentativeId = x.RepresentativeId, - ContractingPartyId = x.ContractingPartyId, - ContractDateFa = x.ContractDateFa, - State = x.State, - City = x.City, - Address = x.Address, - Description = x.Description, - WorkshopManualCount = x.WorkshopManualCount, - EmployeeManualCount = x.EmployeeManualCount, - ContractAmountString = x.ContractAmount.ToMoney(), - ContractAmount = x.ContractAmount, - DailyCompenseationString = x.DailyCompenseation.ToMoney(), - ObligationString = x.Obligation.ToMoney(), - TotalAmountString = x.TotalAmount.ToMoney(), - ExtensionNo = x.ExtensionNo, - OfficialCompany = x.OfficialCompany, - TypeOfContract = x.TypeOfContract, - Signature = x.Signature, - HasValueAddedTax = x.HasValueAddedTax, - ValueAddedTax = x.ValueAddedTax, - }) + { + Id = x.id, + ContractNo = x.ContractNo, + ContractStartGr = x.ContractStartGr, + ContractStartFa = x.ContractStartFa, + ContractEndGr = x.ContractEndGr, + ContractEndFa = x.ContractEndFa, + RepresentativeName = x.RepresentativeName, + ContractingPartyName = x.ContractingPartyName, + RepresentativeId = x.RepresentativeId, + ContractingPartyId = x.ContractingPartyId, + ContractDateFa = x.ContractDateFa, + State = x.State, + City = x.City, + Address = x.Address, + Description = x.Description, + WorkshopManualCount = x.WorkshopManualCount, + EmployeeManualCount = x.EmployeeManualCount, + ContractAmountString = x.ContractAmount.ToMoney(), + ContractAmount = x.ContractAmount, + DailyCompenseationString = x.DailyCompenseation.ToMoney(), + ObligationString = x.Obligation.ToMoney(), + TotalAmountString = x.TotalAmount.ToMoney(), + ExtensionNo = x.ExtensionNo, + OfficialCompany = x.OfficialCompany, + TypeOfContract = x.TypeOfContract, + Signature = x.Signature, + HasValueAddedTax = x.HasValueAddedTax, + ValueAddedTax = x.ValueAddedTax, + }) .FirstOrDefault(x => x.Id == id); } public EditInstitutionContract GetFirstContract(long contractingPartyId, string typeOfContract) { return _context.InstitutionContractSet.Select(x => new EditInstitutionContract() - { - Id = x.id, - ContractNo = x.ContractNo, - ContractStartGr = x.ContractStartGr, - ContractStartFa = x.ContractStartFa, - ContractEndGr = x.ContractEndGr, - ContractEndFa = x.ContractEndFa, - RepresentativeName = x.RepresentativeName, - ContractingPartyName = x.ContractingPartyName, - RepresentativeId = x.RepresentativeId, - ContractingPartyId = x.ContractingPartyId, - ContractDateFa = x.ContractDateFa, - State = x.State, - City = x.City, - Address = x.Address, - Description = x.Description, - WorkshopManualCount = x.WorkshopManualCount, - EmployeeManualCount = x.EmployeeManualCount, - ContractAmountString = x.ContractAmount.ToMoney(), - DailyCompenseationString = x.DailyCompenseation.ToMoney(), - ObligationString = x.Obligation.ToMoney(), - TotalAmountString = x.TotalAmount.ToMoney(), - ExtensionNo = x.ExtensionNo, - OfficialCompany = x.OfficialCompany, - TypeOfContract = x.TypeOfContract, - Signature = x.Signature - }) + { + Id = x.id, + ContractNo = x.ContractNo, + ContractStartGr = x.ContractStartGr, + ContractStartFa = x.ContractStartFa, + ContractEndGr = x.ContractEndGr, + ContractEndFa = x.ContractEndFa, + RepresentativeName = x.RepresentativeName, + ContractingPartyName = x.ContractingPartyName, + RepresentativeId = x.RepresentativeId, + ContractingPartyId = x.ContractingPartyId, + ContractDateFa = x.ContractDateFa, + State = x.State, + City = x.City, + Address = x.Address, + Description = x.Description, + WorkshopManualCount = x.WorkshopManualCount, + EmployeeManualCount = x.EmployeeManualCount, + ContractAmountString = x.ContractAmount.ToMoney(), + DailyCompenseationString = x.DailyCompenseation.ToMoney(), + ObligationString = x.Obligation.ToMoney(), + TotalAmountString = x.TotalAmount.ToMoney(), + ExtensionNo = x.ExtensionNo, + OfficialCompany = x.OfficialCompany, + TypeOfContract = x.TypeOfContract, + Signature = x.Signature + }) .Where(x => x.ContractingPartyId == contractingPartyId && x.TypeOfContract == typeOfContract) .OrderBy(x => x.ExtensionNo).FirstOrDefault(); } @@ -599,40 +599,40 @@ public class InstitutionContractRepository : RepositoryBase new InstitutionContractViewModel() - { - Id = x.Id, - ContractNo = x.ContractNo, - ContractStartGr = x.ContractStartGr, - ContractStartFa = x.ContractStartFa, - ContractEndGr = x.ContractEndGr, - ContractEndFa = x.ContractEndFa, - RepresentativeId = x.RepresentativeId, - RepresentativeName = x.RepresentativeName, - ContractingPartyName = x.ContractingPartyName, - ContractingPartyId = x.ContractingPartyId, - ContractAmount = x.ContractAmount, - TotalAmount = x.TotalAmount, - SearchAmount = x.SearchAmount, - IsActiveString = x.IsActiveString, - OfficialCompany = x.OfficialCompany, - TypeOfContract = x.TypeOfContract, - Signature = x.Signature, - ExpireColor = x.ExpireColor, - IsExpier = x.IsExpier, - BalanceDouble = x.BalanceDouble, - BalanceStr = x.BalanceStr, - EmployerViewModels = x.EmployerViewModels, - EmployerNo = x.EmployerNo, - EmployerName = x.EmployerViewModels.Select(n => n.FullName).FirstOrDefault(), - WorkshopViewModels = x.WorkshopViewModels, - WorkshopCount = x.WorkshopCount, - IsContractingPartyBlock = x.IsContractingPartyBlock, - BlockTimes = x.BlockTimes, - EmployeeCount = + { + Id = x.Id, + ContractNo = x.ContractNo, + ContractStartGr = x.ContractStartGr, + ContractStartFa = x.ContractStartFa, + ContractEndGr = x.ContractEndGr, + ContractEndFa = x.ContractEndFa, + RepresentativeId = x.RepresentativeId, + RepresentativeName = x.RepresentativeName, + ContractingPartyName = x.ContractingPartyName, + ContractingPartyId = x.ContractingPartyId, + ContractAmount = x.ContractAmount, + TotalAmount = x.TotalAmount, + SearchAmount = x.SearchAmount, + IsActiveString = x.IsActiveString, + OfficialCompany = x.OfficialCompany, + TypeOfContract = x.TypeOfContract, + Signature = x.Signature, + ExpireColor = x.ExpireColor, + IsExpier = x.IsExpier, + BalanceDouble = x.BalanceDouble, + BalanceStr = x.BalanceStr, + EmployerViewModels = x.EmployerViewModels, + EmployerNo = x.EmployerNo, + EmployerName = x.EmployerViewModels.Select(n => n.FullName).FirstOrDefault(), + WorkshopViewModels = x.WorkshopViewModels, + WorkshopCount = x.WorkshopCount, + IsContractingPartyBlock = x.IsContractingPartyBlock, + BlockTimes = x.BlockTimes, + EmployeeCount = ((x.WorkshopViewModels.Sum(w => w.LeftWorkIds.Count)) + (x.WorkshopViewModels.Sum(w => w.InsuranceLeftWorkIds.Count(c => !w.LeftWorkIds.Contains(c))))).ToString(), - ArchiveCode = x.WorkshopViewModels.Count > 0 ? ArchiveCodeFinder(x.WorkshopViewModels) : 0, - }).OrderBy(x => x.WorkshopCount != "0" && string.IsNullOrWhiteSpace(x.ExpireColor)) + ArchiveCode = x.WorkshopViewModels.Count > 0 ? ArchiveCodeFinder(x.WorkshopViewModels) : 0, + }).OrderBy(x => x.WorkshopCount != "0" && string.IsNullOrWhiteSpace(x.ExpireColor)) .ThenBy(x => x.WorkshopCount == "0" && string.IsNullOrWhiteSpace(x.ExpireColor)) .ThenBy(x => x.IsExpier == "true") .ThenBy(x => x.ExpireColor == "purple") @@ -3550,7 +3550,7 @@ public class InstitutionContractRepository : RepositoryBase @@ -3617,8 +3617,9 @@ public class InstitutionContractRepository : RepositoryBase @@ -3640,6 +3641,7 @@ public class InstitutionContractRepository : RepositoryBase @@ -3707,7 +3709,9 @@ public class InstitutionContractRepository : RepositoryBase(); - var institutionContracts = await _context.InstitutionContractSet.Select(x => new InstitutionContractViewModel + var institutionContracts = await _context.InstitutionContractSet + .Include(x => x.Installments) + .Select(x => new InstitutionContractViewModel { Id = x.id, ContractingPartyId = x.ContractingPartyId, @@ -3718,11 +3722,24 @@ public class InstitutionContractRepository : RepositoryBase new InstitutionContractInstallmentViewModel + { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) + .OrderBy(ins => ins.InstallmentDateGr).Skip(1).ToList(), }).Where(x => x.ContractStartGr < checkDate && x.ContractEndGr >= checkDate && - x.ContractAmountDouble > 0).GroupBy(x => x.ContractingPartyId).Select(x => x.First()) + x.ContractAmountDouble > 0 && x.VerificationStatus != InstitutionContractVerificationStatus.PendingForVerify).GroupBy(x => x.ContractingPartyId).Select(x => x.First()) .ToListAsync(); + // قرارداد هایی که بطور یکجا پرداخت شده اند + var paidInFull = institutionContracts.Where(x => + x.SigningType != InstitutionContractSigningType.Legacy && x.IsInstallment == false && x.SigningType != null).ToList(); + + //حذف قراداد هایی که یکجا پرداخت شده اند از لیست ایجاد سند ماهانه + institutionContracts = institutionContracts.Except(paidInFull).ToList(); var contractingPartyList = await _context.PersonalContractingParties .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.id)).ToListAsync(); @@ -3735,8 +3752,9 @@ public class InstitutionContractRepository : RepositoryBase institutionContracts.Select(ins => ins.Id).Contains(x.InstitutionContractId)) .Where(x => x.SendSms && x.PhoneType == "شماره همراه" && !string.IsNullOrWhiteSpace(x.PhoneNumber) && x.PhoneNumber.Length == 11).ToListAsync(); - - foreach (var item in institutionContracts) + var oldInstitutionContract = institutionContracts.Where(x => x.IsInstallment == false).ToList(); + var electronicInstitutionContract = institutionContracts.Where(x => x.IsInstallment == true).ToList(); + foreach (var item in oldInstitutionContract) { try { @@ -3820,7 +3838,11 @@ public class InstitutionContractRepository : RepositoryBase x.id == item.ContractingPartyId); + if (contractingParty != null && contractingParty.IsBlock == "true") + { + var partyName = contractingParty.IsLegal == "حقیقی" + ? $"{contractingParty.FName} {contractingParty.LName}" + : $"{contractingParty.LName}"; + if (!string.IsNullOrWhiteSpace(contractingParty.SureName)) + partyName = $"{partyName} ({contractingParty.SureName})"; + if (partyName.Length > 25) partyName = $"{partyName.Substring(0, 25)}"; + + var isLegal = contractingParty.IsLegal == "حقوقی" ? true : false; + + var hasFinancialStatment = + financialStatmentList.Any(x => + x.ContractingPartyId == item.ContractingPartyId & x.FinancialTransactionList.Count > 0); + + + var hasPhonNumber = phoneNumberList.Any(x => x.InstitutionContractId == item.Id); + + + if (hasFinancialStatment && hasPhonNumber) + { + var transactions = + financialStatmentList.FirstOrDefault(x => x.ContractingPartyId == item.ContractingPartyId); + + var debtor = transactions.FinancialTransactionList.Sum(x => x.Deptor); + var creditor = transactions.FinancialTransactionList.Sum(x => x.Creditor); + + + var id = $"{item.ContractingPartyId}"; + var aprove = $"{transactions.id}"; + var balance = debtor - creditor; + if (balance > 0) + { + + var instalment = item.InstallmentList + .FirstOrDefault().AmountDouble; + + var sumOfAmounts = instalment * 2; + if (balance >= sumOfAmounts) + { + var phoneNumbers = new List(); + phoneNumbers = phoneNumberList.Where(x => x.InstitutionContractId == item.Id) + .Select(x => new CreateContactInfo + { + PhoneType = x.PhoneType, + PhoneNumber = x.PhoneNumber, + + InstitutionContractId = x.InstitutionContractId, + SendSms = x.SendSms + }).Where(x => x.PhoneNumber.Length == 11).ToList(); + + + var accountType = item.OfficialCompany == "Official" ? "ol" : "nol"; + + var balanceToMoney = balance.ToMoney(); + var amount = balanceToMoney + " " + "ریال" + " "; + string publicId = transactions.PublicIdStr; + string code1 = publicId.Substring(0, 25); + string code2 = publicId.Substring(25); + foreach (var number in phoneNumbers) + { + + smsList.Add(new BlockSmsListData() + { + PhoneNumber = number.PhoneNumber, + PartyName = partyName, + AccountType = accountType, + Amount = amount, + ContractingPartyId = contractingParty.id, + InstitutionContractId = item.Id, + AproveId = aprove, + IsElectronicContract = true, + Code1 = code1, + Code2 = code2 + }); + } + } + } + } + } + } + catch (Exception e) + { + string name = item.ContractingPartyName.Length > 18 + ? item.ContractingPartyName.Substring(0, 18) + : item.ContractingPartyName; + string errMess = $"{name}-خطا"; + await _smsService.Alarm("09114221321", errMess); + } + } return smsList; } + public async Task SendBlockSmsToContractingParties(List smsListData, string typeOfSms, + string sendMessStart, string sendMessEnd) + { + if (smsListData.Any()) + { + await _smsService.Alarm("09114221321", sendMessStart); + Thread.Sleep(1000); + await _smsService.Alarm("09111485044", sendMessStart); + Thread.Sleep(1000); + int successProcess = 1; + int countList = smsListData.Count; + foreach (var item in smsListData) + { + try + { + if (item.IsElectronicContract) + { + var smsResult = await _smsService.BlockMessageForElectronicContract(item.PhoneNumber, item.PartyName, + item.Amount, item.Code1, $"{item.Code2}"); + Thread.Sleep(1000); + var createSmsResult = new Company.Domain.SmsResultAgg.SmsResult(smsResult.messaeId, + smsResult.message, typeOfSms, + item.PartyName, item.PhoneNumber, item.ContractingPartyId, item.InstitutionContractId); + await _smsResultRepository.CreateAsync(createSmsResult); + await _smsResultRepository.SaveChangesAsync(); + } + else + { + var smsResult = await _smsService.BlockMessage(item.PhoneNumber, item.PartyName, + item.Amount, item.AccountType, $"{item.ContractingPartyId}", item.AproveId); + Thread.Sleep(1000); + var createSmsResult = new Company.Domain.SmsResultAgg.SmsResult(smsResult.messaeId, + smsResult.message, typeOfSms, + item.PartyName, item.PhoneNumber, item.ContractingPartyId, item.InstitutionContractId); + await _smsResultRepository.CreateAsync(createSmsResult); + await _smsResultRepository.SaveChangesAsync(); + } + + } + catch (Exception e) + { + string name = item.PartyName.Length > 18 ? item.PartyName.Substring(0, 18) : item.PartyName; + string errMess = $"{name}-خطا"; + await _smsService.Alarm("09114221321", errMess); + } + + Thread.Sleep(600); + var percent = (successProcess / (double)countList) * 100; + await _hubContext.Clients.Group(SendSmsHub.GetGroupName(10)) + .SendAsync("showStatus", (int)percent); + + successProcess += 1; + } + + + await _smsService.Alarm("09114221321", sendMessEnd); + Thread.Sleep(1000); + await _smsService.Alarm("09111485044", sendMessEnd); + } + } #endregion + //دریافت لیست بدهکاران و ارسال پیامک + #region GetListAndSendSmsMethods /// ///دریافت لیست بدهکارن @@ -3884,7 +4063,7 @@ public class InstitutionContractRepository : RepositoryBase new InstitutionContractInstallmentViewModel - { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) + { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) .OrderBy(ins => ins.InstallmentDateGr).Skip(1).ToList(), }).Where(x => x.ContractStartGr < checkDate && x.ContractEndGr >= checkDate && x.ContractAmountDouble > 0 && x.VerificationStatus != InstitutionContractVerificationStatus.PendingForVerify) @@ -3972,7 +4151,7 @@ public class InstitutionContractRepository : RepositoryBase 0) // اگر بدهکار بود { @@ -4015,28 +4194,28 @@ public class InstitutionContractRepository : RepositoryBase 0) // اگر بدهکار بود { var balanceToMoney = balance.ToMoney(); @@ -4243,7 +4422,7 @@ public class InstitutionContractRepository : RepositoryBase smsListData, string typeOfSms, - string sendMessStart, string sendMessEnd) - { - if (smsListData.Any()) - { - await _smsService.Alarm("09114221321", sendMessStart); - Thread.Sleep(1000); - await _smsService.Alarm("09111485044", sendMessStart); - Thread.Sleep(1000); - int successProcess = 1; - int countList = smsListData.Count; - foreach (var item in smsListData) - { - try - { - var smsResult = await _smsService.BlockMessage(item.PhoneNumber, item.PartyName, - item.Amount, item.AccountType, $"{item.ContractingPartyId}", item.AproveId); - Thread.Sleep(1000); - var createSmsResult = new Company.Domain.SmsResultAgg.SmsResult(smsResult.messaeId, - smsResult.message, typeOfSms, - item.PartyName, item.PhoneNumber, item.ContractingPartyId, item.InstitutionContractId); - await _smsResultRepository.CreateAsync(createSmsResult); - await _smsResultRepository.SaveChangesAsync(); - } - catch (Exception e) - { - string name = item.PartyName.Length > 18 ? item.PartyName.Substring(0, 18) : item.PartyName; - string errMess = $"{name}-خطا"; - await _smsService.Alarm("09114221321", errMess); - } - - Thread.Sleep(600); - var percent = (successProcess / (double)countList) * 100; - await _hubContext.Clients.Group(SendSmsHub.GetGroupName(10)) - .SendAsync("showStatus", (int)percent); - - successProcess += 1; - } - - - await _smsService.Alarm("09114221321", sendMessEnd); - Thread.Sleep(1000); - await _smsService.Alarm("09111485044", sendMessEnd); - } - } /// /// ارسال پیامک های یاد آور بدهی @@ -4410,6 +4544,7 @@ public class InstitutionContractRepository : RepositoryBase @@ -4581,7 +4716,7 @@ public class InstitutionContractRepository : RepositoryBase new InstitutionContractInstallmentViewModel - { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) + { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) .OrderBy(ins => ins.InstallmentDateGr).Skip(1).ToList(), }).Where(x => x.ContractStartGr < endOfMonthGr && x.ContractEndGr >= endOfMonthGr && x.ContractAmountDouble > 0 && @@ -4628,7 +4763,7 @@ public class InstitutionContractRepository : RepositoryBase new InstitutionContractInstallmentViewModel - { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) + { AmountDouble = ins.Amount, InstallmentDateGr = ins.InstallmentDateGr }) .OrderBy(ins => ins.InstallmentDateGr).Skip(1).ToList(), }).ToListAsync(); @@ -4932,6 +5067,9 @@ public class InstitutionContractRepository : RepositoryBase GetIdByInstallmentId(long installmentId) { return await _context.InstitutionContractSet.Include(x => x.Installments) @@ -5285,7 +5423,7 @@ public class InstitutionContractRepository : RepositoryBase x.Id == request.TempId) .FirstOrDefaultAsync(); - // creationTemp.SetContractingPartyInfo(request.LegalType,request.RealParty,request.LegalParty); + // creationTemp.SetContractingPartyInfo(request.LegalType,request.RealParty,request.LegalParty); if (creationTemp == null) { @@ -5367,9 +5505,9 @@ public class InstitutionContractRepository : RepositoryBase + x.DayOfMonth >= dayOfMonth && + x.TimeOfDay.Hours == hour && + x.TimeOfDay.Minutes == minute && + x.TypeOfSmsSetting == TypeOfSmsSetting.Warning && + x.IsActive + ); + } + else + { + checkAnyToExecute = await _context.SmsSettings + .AnyAsync(x => + x.DayOfMonth == dayOfMonth && + x.TimeOfDay.Hours == hour && + x.TimeOfDay.Minutes == minute && + x.TypeOfSmsSetting == TypeOfSmsSetting.Warning && + x.IsActive + ); + } + + + if (checkAnyToExecute) + { + //اجرای تسک + _logger.LogInformation("اجرای تسک ارسال پیامک هشدار SendWarningSms" + + persianNow + " - " + hour + ":" + minute); + + + } + } + + #endregion + + + #region LegalActionSms + + + public async Task SendLegalActionSmsTask() + { + var now = DateTime.Now; + + + // تبدیل تاریخ میلادی به شمسی + var persianNow = now.ToFarsi(); + var persianEndOfMonth = int.Parse(persianNow.FindeEndOfMonth().Substring(8, 2)); + var dayOfMonth = int.Parse(persianNow.Substring(8, 2)); + var hour = now.Hour; + var minute = now.Minute; + var checkAnyToExecute = false; + + //اگر آخرین روز ماه باشد + //اگر روز مثلا عدد روز 31 بود ولی آخرین روز ماه 30 بود + if (dayOfMonth == persianEndOfMonth) + { + checkAnyToExecute = await _context.SmsSettings + .AnyAsync(x => + x.DayOfMonth >= dayOfMonth && + x.TimeOfDay.Hours == hour && + x.TimeOfDay.Minutes == minute && + x.TypeOfSmsSetting == TypeOfSmsSetting.LegalAction && + x.IsActive + ); + } + else + { + checkAnyToExecute = await _context.SmsSettings + .AnyAsync(x => + x.DayOfMonth == dayOfMonth && + x.TimeOfDay.Hours == hour && + x.TimeOfDay.Minutes == minute && + x.TypeOfSmsSetting == TypeOfSmsSetting.LegalAction && + x.IsActive + ); + } + + if (checkAnyToExecute) + { + //اجرای تسک + _logger.LogInformation("اجرای تسک ارسال پیامک اقدام قضائی SendLegalActionSms" + + persianNow + " - " + hour + ":" + minute); + + + } + + } + #endregion + #region CustomViewModels public class WorkshopsAndEmployeeViewModel diff --git a/CompanyManagment.EFCore/Services/SmsService.cs b/CompanyManagment.EFCore/Services/SmsService.cs index 5f2da288..82cf6917 100644 --- a/CompanyManagment.EFCore/Services/SmsService.cs +++ b/CompanyManagment.EFCore/Services/SmsService.cs @@ -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(); + 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 From 66a6c411d667aa3aade72209dc1c94550fdc15ab Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 15:49:44 +0330 Subject: [PATCH 07/21] add: implement payment callback handling and enhance financial invoice structure --- .../IInstitutionContractRepository.cs | 1 + .../FinancialInvoice/EditFinancialInvoice.cs | 3 +- .../IPaymentCallbackHandler.cs | 21 ++ .../VerifyPaymentCallbackCommand.cs | 53 ++++ .../PaymentCallbackHandler.cs | 233 ++++++++++++++++ .../Repository/FinancialInvoiceRepository.cs | 1 + .../InstitutionContractRepository.cs | 6 + .../PersonalBootstrapper.cs | 142 +--------- ServiceHost/Controllers/GeneralController.cs | 264 ++---------------- 9 files changed, 346 insertions(+), 378 deletions(-) create mode 100644 CompanyManagment.App.Contracts/PaymentCallback/IPaymentCallbackHandler.cs create mode 100644 CompanyManagment.App.Contracts/PaymentCallback/VerifyPaymentCallbackCommand.cs create mode 100644 CompanyManagment.Application/PaymentCallbackHandler.cs diff --git a/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs b/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs index c578d7be..be22916f 100644 --- a/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs +++ b/Company.Domain/InstitutionContractAgg/IInstitutionContractRepository.cs @@ -171,4 +171,5 @@ public interface IInstitutionContractRepository : IRepository SetDiscountForCreation(InstitutionContractSetDiscountForCreationRequest request); Task ResetDiscountForCreation(InstitutionContractResetDiscountForExtensionRequest request); Task CreationComplete(InstitutionContractExtensionCompleteRequest request); + Task GetIncludeInstallments(long id); } \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/FinancialInvoice/EditFinancialInvoice.cs b/CompanyManagment.App.Contracts/FinancialInvoice/EditFinancialInvoice.cs index 1975c32a..a24b49f3 100644 --- a/CompanyManagment.App.Contracts/FinancialInvoice/EditFinancialInvoice.cs +++ b/CompanyManagment.App.Contracts/FinancialInvoice/EditFinancialInvoice.cs @@ -10,7 +10,8 @@ public class EditFinancialInvoice public double Amount { get; set; } public FinancialInvoiceStatus Status { get; set; } - public List? Items { get; set; } + public List Items { get; set; } + public long ContractingPartyId { get; set; } } public class EditFinancialInvoiceItem diff --git a/CompanyManagment.App.Contracts/PaymentCallback/IPaymentCallbackHandler.cs b/CompanyManagment.App.Contracts/PaymentCallback/IPaymentCallbackHandler.cs new file mode 100644 index 00000000..c435cf5f --- /dev/null +++ b/CompanyManagment.App.Contracts/PaymentCallback/IPaymentCallbackHandler.cs @@ -0,0 +1,21 @@ +using _0_Framework.Application; +using System.Threading; +using System.Threading.Tasks; + +namespace CompanyManagment.App.Contracts.PaymentCallback; + +/// +/// رابط برای مدیریت Callback درگاه‌های پرداخت +/// +public interface IPaymentCallbackHandler +{ + /// + /// تأیید و پردازش callback درگاه پرداخت سپهر + /// + /// داده‌های callback درگاه + /// توکن لغو عملیات + /// نتیجه عملیات + Task VerifySepehrPaymentCallback(VerifyPaymentCallbackCommand command, + CancellationToken cancellationToken = default); +} + diff --git a/CompanyManagment.App.Contracts/PaymentCallback/VerifyPaymentCallbackCommand.cs b/CompanyManagment.App.Contracts/PaymentCallback/VerifyPaymentCallbackCommand.cs new file mode 100644 index 00000000..9dbe583c --- /dev/null +++ b/CompanyManagment.App.Contracts/PaymentCallback/VerifyPaymentCallbackCommand.cs @@ -0,0 +1,53 @@ +namespace CompanyManagment.App.Contracts.PaymentCallback; + +/// +/// دستور تأیید callback درگاه پرداخت +/// +public class VerifyPaymentCallbackCommand +{ + /// + /// کد پاسخ درگاه (0 = موفق) + /// + public int ResponseCode { get; set; } + + /// + /// شناسه فاکتور/تراکنش + /// + public long InvoiceId { get; set; } + + /// + /// داده‌های اضافی JSON + /// + public string Payload { get; set; } + + /// + /// مبلغ تراکنش + /// + public long Amount { get; set; } + + /// + /// شماره پیگیری درگاه + /// + public long TraceNumber { get; set; } + + /// + /// شماره سند بانکی (RRN) + /// + public long Rrn { get; set; } + + /// + /// رسید دیجیتال + /// + public string DigitalReceipt { get; set; } + + /// + /// بانک صادر کننده کارت + /// + public string IssuerBank { get; set; } + + /// + /// شماره کارت + /// + public string CardNumber { get; set; } +} + diff --git a/CompanyManagment.Application/PaymentCallbackHandler.cs b/CompanyManagment.Application/PaymentCallbackHandler.cs new file mode 100644 index 00000000..8e327201 --- /dev/null +++ b/CompanyManagment.Application/PaymentCallbackHandler.cs @@ -0,0 +1,233 @@ +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); + } + + /// + /// تأیید و پردازش callback درگاه پرداخت سپهر + /// + public async Task 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>(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: ایجاد سند مالی (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) + { + var failResult = _paymentTransactionApplication.SetFailed(command.InvoiceId); + return operation.Failed("خطا در ایجاد سند مالی"); + } + + // گام 9: به‌روزرسانی وضعیت تراکنش + var setSuccessResult = _paymentTransactionApplication.SetSuccess( + command.InvoiceId, + command.CardNumber, + command.IssuerBank, + command.Rrn.ToString(), + command.DigitalReceipt); + + if (!setSuccessResult.IsSuccedded) + { + return operation.Failed("خطا در به‌روزرسانی وضعیت تراکنش"); + } + + // گام 10: به‌روزرسانی وضعیت قرارداد‌های نهادی (اگر وجود داشته باشند) + if (financialInvoice.Items?.Any(x => + x.Type is FinancialInvoiceItemType.BuyInstitutionContract + or FinancialInvoiceItemType.BuyInstitutionContractInstallment) ?? false) + { + await HandleInstitutionContractItems(financialInvoice); + } + + // گام 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}"); + } + } + + /// + /// مدیریت آپدیت قرارداد‌های نهادی + /// + 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(); + } +} \ No newline at end of file diff --git a/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs b/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs index 66b05f02..b2db131a 100644 --- a/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs +++ b/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs @@ -34,6 +34,7 @@ public class FinancialInvoiceRepository : RepositoryBase Amount = financialInvoice.Amount, Status = financialInvoice.Status, InvoiceNumber = financialInvoice.InvoiceNumber, + ContractingPartyId = financialInvoice.ContractingPartyId, Items = financialInvoice.Items?.Select(x => new EditFinancialInvoiceItem { Id = x.id, diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index e2197ae7..1a105585 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -6040,6 +6040,12 @@ public class InstitutionContractRepository : RepositoryBase GetIncludeInstallments(long id) + { + return _context.InstitutionContractSet.Include(x => x.Installments) + .FirstOrDefaultAsync(x => x.id == id); + } + private async Task> CreateLegalContractingPartyEntity( InstitutionContractCreationTempLegalParty request, long representativeId, string address, string city, string state) diff --git a/PersonalContractingParty.Config/PersonalBootstrapper.cs b/PersonalContractingParty.Config/PersonalBootstrapper.cs index ebb0e49f..e7256455 100644 --- a/PersonalContractingParty.Config/PersonalBootstrapper.cs +++ b/PersonalContractingParty.Config/PersonalBootstrapper.cs @@ -229,153 +229,14 @@ 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 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 +483,7 @@ public class PersonalBootstrapper services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/ServiceHost/Controllers/GeneralController.cs b/ServiceHost/Controllers/GeneralController.cs index 4854bd4c..7871eef9 100644 --- a/ServiceHost/Controllers/GeneralController.cs +++ b/ServiceHost/Controllers/GeneralController.cs @@ -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; } /// @@ -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 Verify([FromForm]SepehrGatewayPayResponse payResponse) + public async Task 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>(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 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 HandleFailedTransaction(PaymentTransactionDetailsViewModel transaction) - { - var result = _paymentTransactionApplication.SetFailed(transaction.Id); - if (!result.IsSuccedded) - { - return new JsonResult(result); - } - + // در صورت ناموفق بودن return Redirect(BuildCallbackUrl(transaction.CallBackUrl, false, transaction.Id)); } From 7e3ea39d5b96dd9dc4d5796147a323d8534094a9 Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 16:08:52 +0330 Subject: [PATCH 08/21] add: update payment gateway integration and enhance transaction handling in callback --- .../PaymentCallbackHandler.cs | 52 ++++++++++--------- .../Client/Controllers/FinancialController.cs | 9 ++-- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/CompanyManagment.Application/PaymentCallbackHandler.cs b/CompanyManagment.Application/PaymentCallbackHandler.cs index 8e327201..5bd85425 100644 --- a/CompanyManagment.Application/PaymentCallbackHandler.cs +++ b/CompanyManagment.Application/PaymentCallbackHandler.cs @@ -112,7 +112,33 @@ public class PaymentCallbackHandler : IPaymentCallbackHandler return operation.Failed("خطا در به‌روزرسانی فاکتور مالی"); } - // گام 8: ایجاد سند مالی (Financial Statement) + + + // گام 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, @@ -128,31 +154,9 @@ public class PaymentCallbackHandler : IPaymentCallbackHandler var statementResult = _financialStatmentApplication.CreateFromBankGateway(createCreditStatementCommand); if (!statementResult.IsSuccedded) { - var failResult = _paymentTransactionApplication.SetFailed(command.InvoiceId); + _paymentTransactionApplication.SetFailed(command.InvoiceId); return operation.Failed("خطا در ایجاد سند مالی"); } - - // گام 9: به‌روزرسانی وضعیت تراکنش - var setSuccessResult = _paymentTransactionApplication.SetSuccess( - command.InvoiceId, - command.CardNumber, - command.IssuerBank, - command.Rrn.ToString(), - command.DigitalReceipt); - - if (!setSuccessResult.IsSuccedded) - { - return operation.Failed("خطا در به‌روزرسانی وضعیت تراکنش"); - } - - // گام 10: به‌روزرسانی وضعیت قرارداد‌های نهادی (اگر وجود داشته باشند) - if (financialInvoice.Items?.Any(x => - x.Type is FinancialInvoiceItemType.BuyInstitutionContract - or FinancialInvoiceItemType.BuyInstitutionContractInstallment) ?? false) - { - await HandleInstitutionContractItems(financialInvoice); - } - // گام 11: تأیید نهایی با درگاه پرداخت var verifyCommand = new VerifyPaymentGateWayRequest() { diff --git a/ServiceHost/Areas/Client/Controllers/FinancialController.cs b/ServiceHost/Areas/Client/Controllers/FinancialController.cs index 96b001be..8736c764 100644 --- a/ServiceHost/Areas/Client/Controllers/FinancialController.cs +++ b/ServiceHost/Areas/Client/Controllers/FinancialController.cs @@ -23,7 +23,7 @@ public class FinancialController : ClientBaseController _financialStatementApplication = financialStatementApplication; _authHelper = authHelper; _paymentTransactionApplication = paymentTransactionApplication; - _paymentGateway = new AqayePardakhtPaymentGateway(httpClientFactory, appSetting); + _paymentGateway = new SepehrPaymentGateway(httpClientFactory); } [HttpGet] @@ -63,7 +63,7 @@ public class FinancialController : ClientBaseController } var callbackUrl = Url.Action( - action: "OnGetCallBack", + action: "Verify", controller: "General", // نام کنترلر بدون کلمه‌ی "Controller" values: null, protocol: Request.Scheme); // http یا https @@ -72,7 +72,8 @@ public class FinancialController : ClientBaseController { Amount = balanceAmount.Amount, ContractingPartyId = balanceAmount.ContractingPartyId, - CallBackUrl = request.BaseUrl + CallBackUrl = request.BaseUrl, + Gateway = PaymentTransactionGateWay.SepehrPay }; var transaction = await _paymentTransactionApplication.Create(transactionCommand); @@ -85,7 +86,7 @@ public class FinancialController : ClientBaseController var command = new CreatePaymentGatewayRequest() { CallBackUrl = callbackUrl, - Amount = balanceAmount.Amount/10, + Amount = balanceAmount.Amount, TransactionId = transaction.SendId.ToString(), }; From 490a1a69d54bacf4615a36a0dc9cc39b8cf9dd47 Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 18:12:27 +0330 Subject: [PATCH 09/21] add: implement Sepehr payment gateway integration and enhance financial invoice handling --- .../IFinancialInvoiceRepository.cs | 2 + .../CreateFinancialInvoice.cs | 2 +- .../IFinancialStatmentApplication.cs | 11 ++ .../CreateSepehrPaymentGatewayResponse.cs | 22 +++ .../ISepehrPaymentGatewayService.cs | 32 +++ .../FinancialInvoiceApplication.cs | 7 +- .../FinancialStatmentApplication.cs | 78 ++++++-- .../InstitutionContractApplication.cs | 184 ++++++++---------- .../SepehrPaymentGatewayService.cs | 117 +++++++++++ .../Repository/FinancialInvoiceRepository.cs | 8 + .../PersonalBootstrapper.cs | 2 + .../Client/Controllers/FinancialController.cs | 68 ++----- 12 files changed, 352 insertions(+), 181 deletions(-) create mode 100644 CompanyManagment.App.Contracts/SepehrPaymentGateway/CreateSepehrPaymentGatewayResponse.cs create mode 100644 CompanyManagment.App.Contracts/SepehrPaymentGateway/ISepehrPaymentGatewayService.cs create mode 100644 CompanyManagment.Application/SepehrPaymentGatewayService.cs diff --git a/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs b/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs index 96edcc14..6f1812eb 100644 --- a/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs +++ b/Company.Domain/FinancialInvoiceAgg/IFinancialInvoiceRepository.cs @@ -10,4 +10,6 @@ public interface IFinancialInvoiceRepository : IRepository Search(FinancialInvoiceSearchModel searchModel); Task GetUnPaidByEntityId(long entityId, FinancialInvoiceItemType financialInvoiceItemType); + Task GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(long contractingPartyId, + double amount); } \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs b/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs index 0ce5a82b..6c28c66e 100644 --- a/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs +++ b/CompanyManagment.App.Contracts/FinancialInvoice/CreateFinancialInvoice.cs @@ -8,7 +8,7 @@ public class CreateFinancialInvoice public double Amount { get; set; } public long ContractingPartyId { get; set; } public string Description { get; set; } - public List? Items { get; set; } + public List Items { get; set; } } public class CreateFinancialInvoiceItem diff --git a/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs b/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs index 749a38a8..4cd5fd77 100644 --- a/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs +++ b/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; namespace CompanyManagment.App.Contracts.FinancialStatment; @@ -62,7 +63,17 @@ public interface IFinancialStatmentApplication /// Task GetDetailsByContractingParty(long contractingPartyId, FinancialStatementSearchModel searchModel); + + /// + /// پردازش شارژ حساب از طریق درگاه پرداخت سپهر + /// + /// + /// مسیر برگشت درگاه پرداخت + /// + Task> CreatePaymentGateWayAndCreateInvoice( + CreateFinancialPayRequest request, string gateWayCallBackUrl); } +public record CreateFinancialPayRequest(long Id, string BaseUrl); public class FinancialStatmentDetailsByContractingPartyViewModel { diff --git a/CompanyManagment.App.Contracts/SepehrPaymentGateway/CreateSepehrPaymentGatewayResponse.cs b/CompanyManagment.App.Contracts/SepehrPaymentGateway/CreateSepehrPaymentGatewayResponse.cs new file mode 100644 index 00000000..8e44123f --- /dev/null +++ b/CompanyManagment.App.Contracts/SepehrPaymentGateway/CreateSepehrPaymentGatewayResponse.cs @@ -0,0 +1,22 @@ +namespace CompanyManagment.App.Contracts.SepehrPaymentGateway; + +/// +/// پاسخ ایجاد درگاه پرداخت سپهر +/// +public class CreateSepehrPaymentGatewayResponse +{ + /// + /// توکن درگاه + /// + public string Token { get; set; } + + /// + /// شناسه تراکنش + /// + public long TransactionId { get; set; } + + /// + /// URL درگاه پرداخت + /// + public string PaymentUrl { get; set; } +} \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/SepehrPaymentGateway/ISepehrPaymentGatewayService.cs b/CompanyManagment.App.Contracts/SepehrPaymentGateway/ISepehrPaymentGatewayService.cs new file mode 100644 index 00000000..b5af2f4e --- /dev/null +++ b/CompanyManagment.App.Contracts/SepehrPaymentGateway/ISepehrPaymentGatewayService.cs @@ -0,0 +1,32 @@ +using _0_Framework.Application; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CompanyManagment.App.Contracts.SepehrPaymentGateway; + +/// +/// رابط برای سرویس مشترک ایجاد درگاه پرداخت سپهر +/// +public interface ISepehrPaymentGatewayService +{ + /// + /// ایجاد درگاه پرداخت سپهر برای یک تراکنش + /// + /// مبلغ + /// شناسه طرف قرارداد + /// آدرس بازگشتی به فرانت برای نمایش نتیجه + /// آدرس بازگشتی درگاه پرداخت + /// شناسه فاکتور مالی (اختیاری) - این پارامتر مستقیماً به درگاه فرستاده می‌شود + /// داده‌های اضافی سفارشی برای payload (اختیاری) + /// توکن لغو + /// شامل Token درگاه یا OperationResult با خطا + Task> CreateSepehrPaymentGateway( + double amount, + long contractingPartyId, + long financialInvoiceId, + string gatewayCallbackUrl, + string frontCallbackUrl="https://client.gozareshgir.ir", + Dictionary extraData = null, + CancellationToken cancellationToken = default); +} \ No newline at end of file diff --git a/CompanyManagment.Application/FinancialInvoiceApplication.cs b/CompanyManagment.Application/FinancialInvoiceApplication.cs index 59a7fdd9..c2b6ffbf 100644 --- a/CompanyManagment.Application/FinancialInvoiceApplication.cs +++ b/CompanyManagment.Application/FinancialInvoiceApplication.cs @@ -9,15 +9,13 @@ using CompanyManagment.EFCore; namespace CompanyManagment.Application; -public class FinancialInvoiceApplication : RepositoryBase, IFinancialInvoiceApplication +public class FinancialInvoiceApplication : IFinancialInvoiceApplication { private readonly IFinancialInvoiceRepository _financialInvoiceRepository; - private readonly CompanyContext _context; - public FinancialInvoiceApplication(IFinancialInvoiceRepository financialInvoiceRepository, CompanyContext context) : base(context) + public FinancialInvoiceApplication(IFinancialInvoiceRepository financialInvoiceRepository) { _financialInvoiceRepository = financialInvoiceRepository; - _context = context; } public OperationResult Create(CreateFinancialInvoice command) @@ -185,6 +183,7 @@ public class FinancialInvoiceApplication : RepositoryBase x.ContractingPartyId == command.ContractingPartyId)) { - var financialStatment = _financialStatmentRepository.GetDetailsByContractingPartyId(command.ContractingPartyId); + var financialStatment = + _financialStatmentRepository.GetDetailsByContractingPartyId(command.ContractingPartyId); var transaction = new CreateFinancialTransaction() { FinancialStatementId = financialStatment.Id, @@ -124,20 +132,15 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication Creditor = creditor, TypeOfTransaction = command.TypeOfTransaction, DescriptionOption = command.DescriptionOption - - - }; - - var createTransaction = _financialTransactionApplication.Create(transaction); + + var createTransaction = _financialTransactionApplication.Create(transaction); if (createTransaction.IsSuccedded) return op.Succcedded(); return op.Failed("خطا در انجام عملیات"); - } else { - var statement = new FinancialStatment(command.ContractingPartyId, command.ContractingPartyName); _financialStatmentRepository.Create(statement); _financialStatmentRepository.SaveChanges(); @@ -153,20 +156,14 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication Balance = 0, TypeOfTransaction = command.TypeOfTransaction, DescriptionOption = command.DescriptionOption - - }; var createTransaction = _financialTransactionApplication.Create(transaction); if (createTransaction.IsSuccedded) return op.Succcedded(); return op.Failed("خطا در انجام عملیات"); - } - } - - public List Search(FinancialStatmentSearchModel searchModel) { @@ -203,6 +200,45 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication public async Task GetDetailsByContractingParty( long contractingPartyId, FinancialStatementSearchModel searchModel) { - return await _financialStatmentRepository.GetDetailsByContractingParty(contractingPartyId,searchModel); + return await _financialStatmentRepository.GetDetailsByContractingParty(contractingPartyId, searchModel); + } + + public async Task> CreatePaymentGateWayAndCreateInvoice( + CreateFinancialPayRequest request, string gateWayCallBackUrl) + { + var op = new OperationResult(); + // گام 1: دریافت موجودی حساب + var balanceAmount = await GetBalanceAmount(request.Id); + if (balanceAmount.Amount <= 0) + { + return op.Failed("موجودی حساب شما صفر است"); + } + // گام 2: ایجاد درگاه پرداخت سپهر + + var financialInvoice = await _financialInvoiceRepository + .GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(balanceAmount.ContractingPartyId, + balanceAmount.Amount); + + if (financialInvoice == null) + { + financialInvoice = new FinancialInvoice(balanceAmount.Amount, balanceAmount.ContractingPartyId, + "پرداخت بدهی صورت حساب مالی"); + + var items = new FinancialInvoiceItem("پرداخت بدهی صورت حساب مالی", balanceAmount.Amount, + financialInvoice.id, FinancialInvoiceItemType.PreviousDebt, 0); + financialInvoice.AddItem(items); + await _financialInvoiceRepository.CreateAsync(financialInvoice); + await _financialInvoiceRepository.SaveChangesAsync(); + } + + var gatewayResult = await _sepehrPaymentGatewayService.CreateSepehrPaymentGateway( + amount: balanceAmount.Amount, + contractingPartyId: balanceAmount.ContractingPartyId, + frontCallbackUrl: request.BaseUrl, + gatewayCallbackUrl: gateWayCallBackUrl, + financialInvoiceId: financialInvoice.id, + extraData: null); + + return gatewayResult; } } \ No newline at end of file diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index c4ea7ce4..e844c1ff 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -24,6 +24,7 @@ using CompanyManagment.App.Contracts.FinancialStatment; using CompanyManagment.App.Contracts.InstitutionContract; using CompanyManagment.App.Contracts.InstitutionContractContactinfo; using CompanyManagment.App.Contracts.PaymentTransaction; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; using CompanyManagment.App.Contracts.Workshop; using PersianTools.Core; using ConnectedPersonnelViewModel = CompanyManagment.App.Contracts.Workshop.ConnectedPersonnelViewModel; @@ -48,6 +49,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication private readonly IPaymentGateway _paymentGateway; private readonly IPaymentTransactionRepository _paymentTransactionRepository; private readonly IRollCallServiceRepository _rollCallServiceRepository; + private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService; public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository, @@ -58,7 +60,8 @@ public class InstitutionContractApplication : IInstitutionContractApplication IFinancialStatmentRepository financialStatmentRepository, IContactInfoApplication contactInfoApplication, IAccountApplication accountApplication, ISmsService smsService, IFinancialInvoiceRepository financialInvoiceRepository, IHttpClientFactory httpClientFactory, - IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository) + IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository, + ISepehrPaymentGatewayService sepehrPaymentGatewayService) { _institutionContractRepository = institutionContractRepository; _contractingPartyRepository = contractingPartyRepository; @@ -74,6 +77,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication _financialInvoiceRepository = financialInvoiceRepository; _paymentTransactionRepository = paymentTransactionRepository; _rollCallServiceRepository = rollCallServiceRepository; + _sepehrPaymentGatewayService = sepehrPaymentGatewayService; _paymentGateway = new SepehrPaymentGateway(httpClientFactory); } @@ -1258,119 +1262,93 @@ public class InstitutionContractApplication : IInstitutionContractApplication if (contractingParty == null) throw new NotFoundException("طرف قرارداد یافت نشد"); - if (institutionContract.VerifyCode != code) - return op.Failed("کد وارد شده صحیح نمی باشد"); - - var financialStatement =await _financialStatmentRepository.GetByContractingPartyId(contractingParty.id); + if (institutionContract.VerifyCode != code) + return op.Failed("کد وارد شده صحیح نمی باشد"); - var dbTransaction = await _institutionContractRepository.BeginTransactionAsync(); - FinancialInvoice financialInvoice; - FinancialInvoiceItem financialInvoiceItem; - var today = DateTime.Today; - double invoiceAmount = 0; - string invoiceItemDescription = string.Empty; - FinancialInvoiceItemType invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; - long invoiceItemEntityId = 0; + var financialStatement = await _financialStatmentRepository.GetByContractingPartyId(contractingParty.id); - if (institutionContract.IsInstallment) - { - var firstInstallment = institutionContract.Installments.First(); - var firstInstallmentAmount = firstInstallment.Amount; + var dbTransaction = await _institutionContractRepository.BeginTransactionAsync(); + FinancialInvoice financialInvoice; + FinancialInvoiceItem financialInvoiceItem; + var today = DateTime.Today; + double invoiceAmount = 0; + string invoiceItemDescription = string.Empty; + FinancialInvoiceItemType invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; + long invoiceItemEntityId = 0; - financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(firstInstallment.Id, FinancialInvoiceItemType.BuyInstitutionContractInstallment); - if (financialInvoice == null) - { - var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), - "قسط اول سرویس", "debt", "بابت خدمات", firstInstallmentAmount, 0, 0); - financialStatement.AddFinancialTransaction(financialTransaction); - invoiceAmount = firstInstallmentAmount; - invoiceItemDescription = $"پرداخت قسط اول قرارداد شماره {institutionContract.ContractNo}"; - invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContractInstallment; - invoiceItemEntityId = firstInstallment.Id; - } - else - { - invoiceAmount = financialInvoice.Amount; - invoiceItemDescription = financialInvoice.Items.First().Description; - invoiceItemType = financialInvoice.Items.First().Type; - invoiceItemEntityId = financialInvoice.Items.First().EntityId; - } - } - else - { - financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(institutionContract.id, FinancialInvoiceItemType.BuyInstitutionContract); - if (financialInvoice == null) - { - var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), - "پرداخت کل سرویس", "debt", "بابت خدمات", institutionContract.TotalAmount, 0, 0); - financialStatement.AddFinancialTransaction(financialTransaction); - invoiceAmount = institutionContract.TotalAmount; - invoiceItemDescription = $"پرداخت کل قرارداد شماره {institutionContract.ContractNo}"; - invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; - invoiceItemEntityId = institutionContract.id; - } - else - { - invoiceAmount = financialInvoice.Amount; - invoiceItemDescription = financialInvoice.Items.First().Description; - invoiceItemType = financialInvoice.Items.First().Type; - invoiceItemEntityId = financialInvoice.Items.First().EntityId; - } - } + if (institutionContract.IsInstallment) + { + var firstInstallment = institutionContract.Installments.First(); + var firstInstallmentAmount = firstInstallment.Amount; - if (financialInvoice == null) - { - financialInvoice = new FinancialInvoice(invoiceAmount, contractingParty.id, $"خرید قرارداد مالی شماره {institutionContract.ContractNo}"); - financialInvoiceItem = new FinancialInvoiceItem(invoiceItemDescription, invoiceAmount, 0, invoiceItemType, invoiceItemEntityId); - financialInvoice.AddItem(financialInvoiceItem); - await _financialInvoiceRepository.CreateAsync(financialInvoice); - } + financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(firstInstallment.Id, FinancialInvoiceItemType.BuyInstitutionContractInstallment); + if (financialInvoice == null) + { + var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), + "قسط اول سرویس", "debt", "بابت خدمات", firstInstallmentAmount, 0, 0); + financialStatement.AddFinancialTransaction(financialTransaction); + invoiceAmount = firstInstallmentAmount; + invoiceItemDescription = $"پرداخت قسط اول قرارداد شماره {institutionContract.ContractNo}"; + invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContractInstallment; + invoiceItemEntityId = firstInstallment.Id; + } + else + { + invoiceAmount = financialInvoice.Amount; + invoiceItemDescription = financialInvoice.Items.First().Description; + invoiceItemType = financialInvoice.Items.First().Type; + invoiceItemEntityId = financialInvoice.Items.First().EntityId; + } + } + else + { + financialInvoice = await _financialInvoiceRepository.GetUnPaidByEntityId(institutionContract.id, FinancialInvoiceItemType.BuyInstitutionContract); + if (financialInvoice == null) + { + var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), + "پرداخت کل سرویس", "debt", "بابت خدمات", institutionContract.TotalAmount, 0, 0); + financialStatement.AddFinancialTransaction(financialTransaction); + invoiceAmount = institutionContract.TotalAmount; + invoiceItemDescription = $"پرداخت کل قرارداد شماره {institutionContract.ContractNo}"; + invoiceItemType = FinancialInvoiceItemType.BuyInstitutionContract; + invoiceItemEntityId = institutionContract.id; + } + else + { + invoiceAmount = financialInvoice.Amount; + invoiceItemDescription = financialInvoice.Items.First().Description; + invoiceItemType = financialInvoice.Items.First().Type; + invoiceItemEntityId = financialInvoice.Items.First().EntityId; + } + } - await _financialInvoiceRepository.SaveChangesAsync(); + if (financialInvoice == null) + { + financialInvoice = new FinancialInvoice(invoiceAmount, contractingParty.id, $"خرید قرارداد مالی شماره {institutionContract.ContractNo}"); + financialInvoiceItem = new FinancialInvoiceItem(invoiceItemDescription, invoiceAmount, 0, invoiceItemType, invoiceItemEntityId); + financialInvoice.AddItem(financialInvoiceItem); + await _financialInvoiceRepository.CreateAsync(financialInvoice); + } - var transaction = new PaymentTransaction(institutionContract.ContractingPartyId, invoiceAmount, - institutionContract.ContractingPartyName, "https://client.gozareshgir.ir", - PaymentTransactionGateWay.SepehrPay); - await _paymentTransactionRepository.CreateAsync(transaction); - await _financialInvoiceRepository.SaveChangesAsync(); + await _financialInvoiceRepository.SaveChangesAsync(); - var createPayment = new CreatePaymentGatewayRequest() - { - Amount = invoiceAmount, - TransactionId = transaction.id.ToString(), - CallBackUrl = callbackUrl, - FinancialInvoiceId = financialInvoice.id, - }; - var gatewayResponse = await _paymentGateway.Create(createPayment); - if (!gatewayResponse.IsSuccess) - return op.Failed("خطا در ایجاد درگاه پرداخت: " + gatewayResponse.Message + gatewayResponse.ErrorCode); + // استفاده از سرویس مشترک برای ایجاد درگاه پرداخت + var gatewayResult = await _sepehrPaymentGatewayService.CreateSepehrPaymentGateway( + amount: (long)invoiceAmount, + contractingPartyId: institutionContract.ContractingPartyId, + gatewayCallbackUrl: callbackUrl, + financialInvoiceId: financialInvoice.id, + extraData: null); - - // institutionContract.SetPendingWorkflow(); - // - // var phone = institutionContract.ContactInfoList.FirstOrDefault(x => - // x.SendSms && x.Position == "طرف قرارداد" && x.PhoneType == "شماره همراه"); - // if (phone !=null) - // { - // var userPass = contractingParty.IsLegal == "حقیقی" - // ? contractingParty.Nationalcode - // : contractingParty.NationalId; - // var createAcc = new RegisterAccount - // { - // Fullname = contractingParty.LName, - // Username = userPass, - // Password = userPass, - // Mobile = phone.PhoneNumber, - // NationalCode = userPass - // }; - // var res = _accountApplication.RegisterClient(createAcc); - // if (res.IsSuccedded) - // CreateContractingPartyAccount(contractingParty.id, res.SendId); - // } + if (!gatewayResult.IsSuccedded) + { + await dbTransaction.RollbackAsync(); + return op.Failed(gatewayResult.Message); + } await dbTransaction.CommitAsync(); await _institutionContractRepository.SaveChangesAsync(); - return op.Succcedded(gatewayResponse.Token); + return op.Succcedded(gatewayResult.Data.Token); } public async Task GetWorkshopInitialDetails(long workshopDetailsId) diff --git a/CompanyManagment.Application/SepehrPaymentGatewayService.cs b/CompanyManagment.Application/SepehrPaymentGatewayService.cs new file mode 100644 index 00000000..dc9749cf --- /dev/null +++ b/CompanyManagment.Application/SepehrPaymentGatewayService.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using _0_Framework.Application; +using _0_Framework.Application.PaymentGateway; +using CompanyManagment.App.Contracts.PaymentTransaction; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; + +namespace CompanyManagment.Application; + +/// +/// سرویس مشترک برای ایجاد درگاه پرداخت سپهر +/// +public class SepehrPaymentGatewayService : ISepehrPaymentGatewayService +{ + private readonly IPaymentGateway _paymentGateway; + private readonly IPaymentTransactionApplication _paymentTransactionApplication; + + public SepehrPaymentGatewayService( + IPaymentTransactionApplication paymentTransactionApplication, + IHttpClientFactory httpClientFactory) + { + _paymentGateway = new SepehrPaymentGateway(httpClientFactory); + _paymentTransactionApplication = paymentTransactionApplication; + } + + /// + /// ایجاد درگاه پرداخت سپهر برای یک تراکنش + /// + /// مبلغ + /// شناسه طرف قرارداد + /// آدرس بازگشتی به فرانت برای نمایش نتیجه + /// آدرس بازگشتی درگاه پرداخت + /// شناسه فاکتور مالی (اختیاری) + /// داده‌های اضافی (اختیاری) + /// توکن لغو + /// شامل Token درگاه یا OperationResult با خطا + public async Task> CreateSepehrPaymentGateway( + double amount, + long contractingPartyId, + long financialInvoiceId, + string gatewayCallbackUrl, + string frontCallbackUrl="https://client.gozareshgir.ir", + Dictionary extraData = null, + CancellationToken cancellationToken = default) + { + var op = new OperationResult(); + + try + { + // گام 1: ایجاد تراکنش پرداخت + var transactionCommand = new CreatePaymentTransaction() + { + Amount = amount, + ContractingPartyId = contractingPartyId, + CallBackUrl = frontCallbackUrl, + Gateway = PaymentTransactionGateWay.SepehrPay + }; + + var transactionResult = await _paymentTransactionApplication.Create(transactionCommand); + + if (!transactionResult.IsSuccedded) + { + return op.Failed(transactionResult.Message); + } + + // گام 2: ایجاد درخواست درگاه پرداخت + extraData ??= new Dictionary(); + + var createPaymentCommand = new CreatePaymentGatewayRequest() + { + Amount = amount, + TransactionId = transactionResult.SendId.ToString(), + CallBackUrl = gatewayCallbackUrl, + FinancialInvoiceId = financialInvoiceId, + ExtraData = extraData + }; + + // گام 3: ارسال درخواست به درگاه سپهر + var gatewayResponse = await _paymentGateway.Create(createPaymentCommand, cancellationToken); + +#if DEBUG + gatewayResponse.IsSuccess = true; +#endif + if (!gatewayResponse.IsSuccess) + { + return op.Failed($"خطا در ایجاد درگاه پرداخت: {gatewayResponse.Message ?? gatewayResponse.ErrorCode?.ToString()}"); + } + + // گام 4: ذخیره Token در تراکنش + var setTokenResult = await _paymentTransactionApplication.SetTransactionId( + transactionResult.SendId, + gatewayResponse.Token); + + if (!setTokenResult.IsSuccedded) + { + return op.Failed("خطا در ذخیره Token درگاه"); + } + + // گام 5: بازگشت اطلاعات درگاه پرداخت + var response = new CreateSepehrPaymentGatewayResponse + { + Token = gatewayResponse.Token, + TransactionId = transactionResult.SendId, + PaymentUrl = _paymentGateway.GetStartPayUrl(gatewayResponse.Token) + }; + + return op.Succcedded(response); + } + catch (Exception ex) + { + return op.Failed($"خطا در ایجاد درگاه پرداخت: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs b/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs index b2db131a..a5e65908 100644 --- a/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs +++ b/CompanyManagment.EFCore/Repository/FinancialInvoiceRepository.cs @@ -101,4 +101,12 @@ public class FinancialInvoiceRepository : RepositoryBase .Where(x => x.Status == FinancialInvoiceStatus.Unpaid).FirstOrDefaultAsync(x => x.Items .Any(y => y.Type == financialInvoiceItemType && y.EntityId == entityId)); } + + public async Task GetUnPaidFinancialInvoiceByContractingPartyIdAndAmount(long contractingPartyId, + double amount) + { + return await _context.FinancialInvoices.FirstOrDefaultAsync(x=>x.ContractingPartyId == contractingPartyId && + x.Amount == amount && + x.Status == FinancialInvoiceStatus.Unpaid); + } } \ No newline at end of file diff --git a/PersonalContractingParty.Config/PersonalBootstrapper.cs b/PersonalContractingParty.Config/PersonalBootstrapper.cs index e7256455..92e63a87 100644 --- a/PersonalContractingParty.Config/PersonalBootstrapper.cs +++ b/PersonalContractingParty.Config/PersonalBootstrapper.cs @@ -234,6 +234,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using P_TextManager.Domin.TextManagerAgg; using CompanyManagment.App.Contracts.PaymentCallback; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; using Company.Domain.CameraBugReportAgg; using CompanyManagment.App.Contracts.CameraBugReport; using CameraBugReportRepository = CompanyManagement.Infrastructure.Mongo.CameraBugReportRepo.CameraBugReportRepository; @@ -484,6 +485,7 @@ public class PersonalBootstrapper services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/ServiceHost/Areas/Client/Controllers/FinancialController.cs b/ServiceHost/Areas/Client/Controllers/FinancialController.cs index 8736c764..68d8d494 100644 --- a/ServiceHost/Areas/Client/Controllers/FinancialController.cs +++ b/ServiceHost/Areas/Client/Controllers/FinancialController.cs @@ -1,8 +1,10 @@ using _0_Framework.Application; using _0_Framework.Application.PaymentGateway; +using CompanyManagment.App.Contracts.FinancialInvoice; using CompanyManagment.App.Contracts.FinancialStatment; using CompanyManagment.App.Contracts.FinancilTransaction; using CompanyManagment.App.Contracts.PaymentTransaction; +using CompanyManagment.App.Contracts.SepehrPaymentGateway; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; @@ -10,20 +12,19 @@ using ServiceHost.BaseControllers; namespace ServiceHost.Areas.Client.Controllers; -public record CreateFinancialPayRequest(long Id, string BaseUrl); public class FinancialController : ClientBaseController { private readonly IFinancialStatmentApplication _financialStatementApplication; private readonly IAuthHelper _authHelper; - private readonly IPaymentGateway _paymentGateway; - private readonly IPaymentTransactionApplication _paymentTransactionApplication; + private readonly ISepehrPaymentGatewayService _sepehrPaymentGatewayService; + private readonly IFinancialInvoiceApplication _financialInvoiceApplication; - public FinancialController(IFinancialStatmentApplication financialStatementApplication, IAuthHelper authHelper,IHttpClientFactory httpClientFactory, IPaymentTransactionApplication paymentTransactionApplication,IOptions appSetting) + public FinancialController(IFinancialStatmentApplication financialStatementApplication, IAuthHelper authHelper, ISepehrPaymentGatewayService sepehrPaymentGatewayService, IFinancialInvoiceApplication financialInvoiceApplication) { _financialStatementApplication = financialStatementApplication; _authHelper = authHelper; - _paymentTransactionApplication = paymentTransactionApplication; - _paymentGateway = new SepehrPaymentGateway(httpClientFactory); + _sepehrPaymentGatewayService = sepehrPaymentGatewayService; + _financialInvoiceApplication = financialInvoiceApplication; } [HttpGet] @@ -45,65 +46,28 @@ public class FinancialController : ClientBaseController return result; } /// - /// ساخت + /// ساخت درگاه پرداخت برای موجودی حساب کلاینت /// - /// - /// - /// - /// [HttpPost("CreatePay")] [AllowAnonymous] - public async Task>> CreatePay([FromForm] CreateFinancialPayRequest request, CancellationToken cancellationToken) + public async Task>> CreatePay([FromForm] CreateFinancialPayRequest request) { var op = new OperationResult(); - var balanceAmount = await _financialStatementApplication.GetBalanceAmount(request.Id); - if (balanceAmount.Amount<=0) - { - return op.Failed("موجودی حساب شما صفر است"); - } - var callbackUrl = Url.Action( + var gateWayCallBackUrl = Url.Action( action: "Verify", controller: "General", // نام کنترلر بدون کلمه‌ی "Controller" values: null, protocol: Request.Scheme); // http یا https + // گام 2: ایجاد درگاه پرداخت سپهر - var transactionCommand = new CreatePaymentTransaction() + var gatewayResult = await _financialStatementApplication.CreatePaymentGateWayAndCreateInvoice(request, gateWayCallBackUrl); + if (!gatewayResult.IsSuccedded) { - Amount = balanceAmount.Amount, - ContractingPartyId = balanceAmount.ContractingPartyId, - CallBackUrl = request.BaseUrl, - Gateway = PaymentTransactionGateWay.SepehrPay - }; - - var transaction = await _paymentTransactionApplication.Create(transactionCommand); - - if (!transaction.IsSuccedded) - { - return op.Failed(transaction.Message); + return op.Failed(gatewayResult.Message); } - var command = new CreatePaymentGatewayRequest() - { - CallBackUrl = callbackUrl, - Amount = balanceAmount.Amount, - TransactionId = transaction.SendId.ToString(), - }; - - var gatewayResponse = await _paymentGateway.Create(command, cancellationToken); - - if (gatewayResponse.IsSuccess) - { - _ = await _paymentTransactionApplication.SetTransactionId(transaction.SendId, gatewayResponse.Token); - return Redirect(_paymentGateway.GetStartPayUrl(gatewayResponse.Token)); - } - - if (gatewayResponse.ErrorCode.HasValue) - { - return op.Failed($"خطا در ایجاد درگاه پرداخت: {gatewayResponse.ErrorCode.Value}"); - } - - return op.Failed("خطا در ایجاد درگاه پرداخت"); - + // گام 3: بازگشتی به درگاه پرداخت + return Redirect(gatewayResult.Data.PaymentUrl); } } \ No newline at end of file From 8e72b56758bf7f893dd6d4535bc434a6d530945c Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 18:16:51 +0330 Subject: [PATCH 10/21] refactor: format BlockMessageForElectronicContract method parameters for improved readability --- 0_Framework/Application/Sms/ISmsService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/0_Framework/Application/Sms/ISmsService.cs b/0_Framework/Application/Sms/ISmsService.cs index 53137858..9590bf27 100644 --- a/0_Framework/Application/Sms/ISmsService.cs +++ b/0_Framework/Application/Sms/ISmsService.cs @@ -85,7 +85,9 @@ public interface ISmsService /// /// /// - 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 From 8f37d9f3882648ca48e06a5a39de836acc18ac4d Mon Sep 17 00:00:00 2001 From: SamSys Date: Wed, 31 Dec 2025 18:21:01 +0330 Subject: [PATCH 11/21] init SendWarningSms and LegalActionSms --- .../InstitutionContract/SmsListData.cs | 10 + .../InstitutionContractRepository.cs | 265 +++++++++++++++++- 2 files changed, 274 insertions(+), 1 deletion(-) diff --git a/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs b/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs index 538c7906..e81a8ecf 100644 --- a/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs +++ b/CompanyManagment.App.Contracts/InstitutionContract/SmsListData.cs @@ -109,4 +109,14 @@ public class BlockSmsListData /// پابلیک آی دی بخش دو /// public string Code2 { get; set; } +} + + +/// +/// لیست قراداد های آبی +/// جهت ارسال هشدار یا اقدام قضائی +/// +public class BlueWarningSmsData +{ + } \ No newline at end of file diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index 268728cc..9e7e7cac 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -3561,7 +3561,7 @@ public class InstitutionContractRepository : RepositoryBase SendReminderSmsForBackgroundTask() { var now = DateTime.Now; - _logger.LogInformation("================>> SendReminderSmsForBackgroundTask job run"); + // تبدیل تاریخ میلادی به شمسی var persianNow = now.ToFarsi(); @@ -6327,6 +6327,269 @@ public class InstitutionContractRepository : RepositoryBase + ///دریافت لیست پیامک قرادا های آبی بدهکار + /// + /// + public async Task> GetBlueSmsListData() + { + + var institutionContracts = await _context.InstitutionContractSet.AsQueryable().Select(x => new InstitutionContractViewModel + { + Id = x.id, + ContractingPartyId = x.ContractingPartyId, + ContractingPartyName = x.ContractingPartyName, + ContractStartGr = x.ContractStartGr, + ContractStartFa = x.ContractStartFa, + ContractEndGr = x.ContractEndGr, + ContractEndFa = x.ContractEndFa, + IsActiveString = x.IsActiveString, + ContractAmountDouble = x.ContractAmount, + OfficialCompany = x.OfficialCompany, + IsInstallment = x.IsInstallment, + VerificationStatus = x.VerificationStatus, + SigningType = x.SigningType, + }).Where(x => x.IsActiveString == "blue" && + x.ContractAmountDouble > 0).GroupBy(x => x.ContractingPartyId).Select(x => x.First()).ToListAsync(); + + // قرارداد هایی که بطور یکجا پرداخت شده اند + var paidInFull = institutionContracts.Where(x => + x.SigningType != InstitutionContractSigningType.Legacy && x.IsInstallment == false && x.SigningType != null).ToList(); + + //حذف قراداد هایی که یکجا پرداخت شده اند از لیست ایجاد سند ماهانه + institutionContracts = institutionContracts.Except(paidInFull).ToList(); + + var contractingPartyList = await _context.PersonalContractingParties + .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.id)).ToListAsync(); + + var financialStatmentList = await _context.FinancialStatments.AsSplitQuery() + .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.ContractingPartyId)) + .Include(x => x.FinancialTransactionList).Where(x => x.FinancialTransactionList.Count > 0).ToListAsync(); + + var phoneNumberList = await _context.InstitutionContractContactInfos + .Where(x => institutionContracts.Select(ins => ins.Id).Contains(x.InstitutionContractId)) + .Where(x => x.SendSms && x.PhoneType == "شماره همراه" && !string.IsNullOrWhiteSpace(x.PhoneNumber) && + x.PhoneNumber.Length == 11).ToListAsync(); + var legalActionSentSms =await _context.SmsResults + .Where(x => x.TypeOfSms == "اقدام قضایی").ToListAsync(); + var warningSentSms = await _context.SmsResults.Where(x => x.TypeOfSms.Contains("هشدار")).ToListAsync(); + + var oldInstitutionContract = institutionContracts.Where(x => x.IsInstallment == false).ToList(); + var electronicInstitutionContract = institutionContracts.Where(x => x.IsInstallment == true).ToList(); + + foreach (var item in oldInstitutionContract) + { + try + { + var contractingParty = GetDetails(item.ContractingPartyId); + bool hasLegalActionSentSms = legalActionSentSms.Any(x => x.InstitutionContractId == item.Id); + + if (!string.IsNullOrWhiteSpace(contractingParty.LName) && !hasLegalActionSentSms) + { + //Thread.Sleep(500); + var partyName = contractingParty.LName; + + if (partyName.Length > 25) partyName = $"{partyName.Substring(0, 25)}"; + + var isLegal = contractingParty.IsLegal == "حقوقی" ? true : false; + var isBlock = contractingParty.IsBlock == "true" ? true : false; + var isActive = contractingParty.IsActiveString == "true" ? true : false; + if (!string.IsNullOrWhiteSpace(contractingParty.IsActiveString)) + { + var hasFinancialStatement = + financialStatmentList.Any(x => x.ContractingPartyId == item.ContractingPartyId); + + var hasPhonNumber = phoneNumberList.Any(x => x.InstitutionContractId == item.Id); + + if (hasFinancialStatement && hasPhonNumber) + { + var phoneNumbers = phoneNumberList.Where(x => x.InstitutionContractId == item.Id) + .Select(x => new CreateContactInfo + { + PhoneType = x.PhoneType, + PhoneNumber = x.PhoneNumber, + + InstitutionContractId = x.InstitutionContractId, + SendSms = x.SendSms + }).Where(x => x.PhoneNumber.Length == 11).ToList(); + + var transactions = financialStatmentList.FirstOrDefault(x => + x.ContractingPartyId == item.ContractingPartyId); + + + var debtor = transactions.FinancialTransactionViewModels.Sum(x => x.Deptor); + var creditor = transactions.FinancialTransactionViewModels.Sum(x => x.Creditor); + + + var id = $"{item.ContractingPartyId}"; + var aprove = $"{transactions.Id}"; + var balance = debtor - creditor; + + if (balance > 0) // اگر بدهکار بود + { + + if (isLegal) + { + if (item.OfficialCompany == "Official") // حقوقی بدهکار رسمی + { + var balanceToMoney = balance.ToMoney(); + + foreach (var number in phoneNumbers) + { + + var isLastAlarmSend = _context.SmsResults.Any(x => ( + x.ContractingPatyId == contractingParty.Id && + x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + + if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + { + + var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 608443, + partyName, + balanceToMoney, id, aprove); + Thread.Sleep(1000); + if (smsResult.IsSuccedded) + { + var createSmsResult = new SmsResult(smsResult.MessageId, + smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + item.ContractingPartyId, item.Id); + _smsResultRepository.Create(createSmsResult); + _smsResultRepository.SaveChanges(); + Thread.Sleep(1000); + } + + } + } + + + + } + else if (item.OfficialCompany == "NotOfficial") // حقوقی بدهکار غیر رسمی + { + var balanceToMoney = balance.ToMoney(); + foreach (var number in phoneNumbers) + { + var isSend = _context.SmsResults.Any(x => + x.ContractingPatyId == contractingParty.Id && + x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); + var isLastAlarmSend = _context.SmsResults.Any(x => ( + x.ContractingPatyId == contractingParty.Id && + x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + { + + var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 351691, + partyName, + balanceToMoney, id, aprove); + Thread.Sleep(1000); + if (smsResult.IsSuccedded) + { + var createSmsResult = new SmsResult(smsResult.MessageId, + smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + item.ContractingPartyId, item.Id); + _smsResultRepository.Create(createSmsResult); + _smsResultRepository.SaveChanges(); + Thread.Sleep(1000); + } + + + + } + } + + + } + } + else + { + if (item.OfficialCompany == "Official") // حقیقی بدهکار رسمی + { + var balanceToMoney = balance.ToMoney(); + + foreach (var number in phoneNumbers) + { + var isSend = _context.SmsResults.Any(x => + x.ContractingPatyId == contractingParty.Id && + x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); + var isLastAlarmSend = _context.SmsResults.Any(x => ( + x.ContractingPatyId == contractingParty.Id && + x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + { + + var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 190430, + partyName, + balanceToMoney, id, aprove); + Thread.Sleep(1000); + if (smsResult.IsSuccedded) + { + var createSmsResult = new SmsResult(smsResult.MessageId, + smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + item.ContractingPartyId, item.Id); + _smsResultRepository.Create(createSmsResult); + _smsResultRepository.SaveChanges(); + Thread.Sleep(1000); + } + } + } + + + } + else if (item.OfficialCompany == "NotOfficial") // حقیقی بدهکار غیر رسمی + { + var balanceToMoney = balance.ToMoney(); + + foreach (var number in phoneNumbers) + { + var isSend = _context.SmsResults.Any(x => + x.ContractingPatyId == contractingParty.Id && + x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); + var isLastAlarmSend = _context.SmsResults.Any(x => ( + x.ContractingPatyId == contractingParty.Id && + x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + { + var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 412829, + partyName, + balanceToMoney, id, aprove); + Thread.Sleep(1000); + if (smsResult.IsSuccedded) + { + var createSmsResult = new SmsResult(smsResult.MessageId, + smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + item.ContractingPartyId, item.Id); + _smsResultRepository.Create(createSmsResult); + _smsResultRepository.SaveChanges(); + Thread.Sleep(1000); + } + + + } + } + + + } + } + } + } + } + } + } + catch (Exception e) + { + + + string name = item.ContractingPartyName.Length > 18 ? item.ContractingPartyName.Substring(0, 18) : item.ContractingPartyName; + string errMess = $"{name}-خطا"; + _smsService.Alarm("09114221321", errMess); + _logger.LogError(e, "BlueWarningSms"); + } + } + } #endregion From cf62d75f0ed566c1224d225b4abf76d81f52a549 Mon Sep 17 00:00:00 2001 From: SamSys Date: Wed, 31 Dec 2025 18:23:07 +0330 Subject: [PATCH 12/21] change --- .../Jobs/JobSchedulerRegistrator.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs b/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs index 7eaab611..f368cb3e 100644 --- a/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs +++ b/BackgroundInstitutionContract/BackgroundInstitutionContract.Task/Jobs/JobSchedulerRegistrator.cs @@ -58,17 +58,17 @@ public class JobSchedulerRegistrator "*/1 * * * *" // هر 1 دقیقه یکبار چک کن ); - RecurringJob.AddOrUpdate( - "InstitutionContract.SendWarningSms", - () => SendWarningSms(), - "*/1 * * * *" // هر 1 دقیقه یکبار چک کن - ); + //RecurringJob.AddOrUpdate( + // "InstitutionContract.SendWarningSms", + // () => SendWarningSms(), + // "*/1 * * * *" // هر 1 دقیقه یکبار چک کن + //); - RecurringJob.AddOrUpdate( - "InstitutionContract.SendLegalActionSms", - () => SendLegalActionSms(), - "*/1 * * * *" // هر 1 دقیقه یکبار چک کن - ); + //RecurringJob.AddOrUpdate( + // "InstitutionContract.SendLegalActionSms", + // () => SendLegalActionSms(), + // "*/1 * * * *" // هر 1 دقیقه یکبار چک کن + //); } From f8126b4000af9143b9e1c76b4b8a5b136b8542b2 Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 18:31:00 +0330 Subject: [PATCH 13/21] set transaction id on get --- .../Repository/FinancialStatmentRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs b/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs index fbf7ef74..c25ecca1 100644 --- a/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs +++ b/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs @@ -210,6 +210,7 @@ public class FinancialStatmentRepository : RepositoryBase Date: Wed, 31 Dec 2025 18:34:42 +0330 Subject: [PATCH 14/21] change --- .../InstitutionContractRepository.cs | 426 +++++++++--------- 1 file changed, 213 insertions(+), 213 deletions(-) diff --git a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs index d240d0e7..b4d18f77 100644 --- a/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs +++ b/CompanyManagment.EFCore/Repository/InstitutionContractRepository.cs @@ -6337,265 +6337,265 @@ public class InstitutionContractRepository : RepositoryBase /// - public async Task> GetBlueSmsListData() - { + //public async Task> GetBlueSmsListData() + //{ - var institutionContracts = await _context.InstitutionContractSet.AsQueryable().Select(x => new InstitutionContractViewModel - { - Id = x.id, - ContractingPartyId = x.ContractingPartyId, - ContractingPartyName = x.ContractingPartyName, - ContractStartGr = x.ContractStartGr, - ContractStartFa = x.ContractStartFa, - ContractEndGr = x.ContractEndGr, - ContractEndFa = x.ContractEndFa, - IsActiveString = x.IsActiveString, - ContractAmountDouble = x.ContractAmount, - OfficialCompany = x.OfficialCompany, - IsInstallment = x.IsInstallment, - VerificationStatus = x.VerificationStatus, - SigningType = x.SigningType, - }).Where(x => x.IsActiveString == "blue" && - x.ContractAmountDouble > 0).GroupBy(x => x.ContractingPartyId).Select(x => x.First()).ToListAsync(); + // var institutionContracts = await _context.InstitutionContractSet.AsQueryable().Select(x => new InstitutionContractViewModel + // { + // Id = x.id, + // ContractingPartyId = x.ContractingPartyId, + // ContractingPartyName = x.ContractingPartyName, + // ContractStartGr = x.ContractStartGr, + // ContractStartFa = x.ContractStartFa, + // ContractEndGr = x.ContractEndGr, + // ContractEndFa = x.ContractEndFa, + // IsActiveString = x.IsActiveString, + // ContractAmountDouble = x.ContractAmount, + // OfficialCompany = x.OfficialCompany, + // IsInstallment = x.IsInstallment, + // VerificationStatus = x.VerificationStatus, + // SigningType = x.SigningType, + // }).Where(x => x.IsActiveString == "blue" && + // x.ContractAmountDouble > 0).GroupBy(x => x.ContractingPartyId).Select(x => x.First()).ToListAsync(); - // قرارداد هایی که بطور یکجا پرداخت شده اند - var paidInFull = institutionContracts.Where(x => - x.SigningType != InstitutionContractSigningType.Legacy && x.IsInstallment == false && x.SigningType != null).ToList(); + // // قرارداد هایی که بطور یکجا پرداخت شده اند + // var paidInFull = institutionContracts.Where(x => + // x.SigningType != InstitutionContractSigningType.Legacy && x.IsInstallment == false && x.SigningType != null).ToList(); - //حذف قراداد هایی که یکجا پرداخت شده اند از لیست ایجاد سند ماهانه - institutionContracts = institutionContracts.Except(paidInFull).ToList(); + // //حذف قراداد هایی که یکجا پرداخت شده اند از لیست ایجاد سند ماهانه + // institutionContracts = institutionContracts.Except(paidInFull).ToList(); - var contractingPartyList = await _context.PersonalContractingParties - .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.id)).ToListAsync(); + // var contractingPartyList = await _context.PersonalContractingParties + // .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.id)).ToListAsync(); - var financialStatmentList = await _context.FinancialStatments.AsSplitQuery() - .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.ContractingPartyId)) - .Include(x => x.FinancialTransactionList).Where(x => x.FinancialTransactionList.Count > 0).ToListAsync(); + // var financialStatmentList = await _context.FinancialStatments.AsSplitQuery() + // .Where(x => institutionContracts.Select(ins => ins.ContractingPartyId).Contains(x.ContractingPartyId)) + // .Include(x => x.FinancialTransactionList).Where(x => x.FinancialTransactionList.Count > 0).ToListAsync(); - var phoneNumberList = await _context.InstitutionContractContactInfos - .Where(x => institutionContracts.Select(ins => ins.Id).Contains(x.InstitutionContractId)) - .Where(x => x.SendSms && x.PhoneType == "شماره همراه" && !string.IsNullOrWhiteSpace(x.PhoneNumber) && - x.PhoneNumber.Length == 11).ToListAsync(); - var legalActionSentSms =await _context.SmsResults - .Where(x => x.TypeOfSms == "اقدام قضایی").ToListAsync(); - var warningSentSms = await _context.SmsResults.Where(x => x.TypeOfSms.Contains("هشدار")).ToListAsync(); + // var phoneNumberList = await _context.InstitutionContractContactInfos + // .Where(x => institutionContracts.Select(ins => ins.Id).Contains(x.InstitutionContractId)) + // .Where(x => x.SendSms && x.PhoneType == "شماره همراه" && !string.IsNullOrWhiteSpace(x.PhoneNumber) && + // x.PhoneNumber.Length == 11).ToListAsync(); + // var legalActionSentSms =await _context.SmsResults + // .Where(x => x.TypeOfSms == "اقدام قضایی").ToListAsync(); + // var warningSentSms = await _context.SmsResults.Where(x => x.TypeOfSms.Contains("هشدار")).ToListAsync(); - var oldInstitutionContract = institutionContracts.Where(x => x.IsInstallment == false).ToList(); - var electronicInstitutionContract = institutionContracts.Where(x => x.IsInstallment == true).ToList(); + // var oldInstitutionContract = institutionContracts.Where(x => x.IsInstallment == false).ToList(); + // var electronicInstitutionContract = institutionContracts.Where(x => x.IsInstallment == true).ToList(); - foreach (var item in oldInstitutionContract) - { - try - { - var contractingParty = GetDetails(item.ContractingPartyId); - bool hasLegalActionSentSms = legalActionSentSms.Any(x => x.InstitutionContractId == item.Id); + // foreach (var item in oldInstitutionContract) + // { + // try + // { + // var contractingParty = GetDetails(item.ContractingPartyId); + // bool hasLegalActionSentSms = legalActionSentSms.Any(x => x.InstitutionContractId == item.Id); - if (!string.IsNullOrWhiteSpace(contractingParty.LName) && !hasLegalActionSentSms) - { - //Thread.Sleep(500); - var partyName = contractingParty.LName; + // if (!string.IsNullOrWhiteSpace(contractingParty.LName) && !hasLegalActionSentSms) + // { + // //Thread.Sleep(500); + // var partyName = contractingParty.LName; - if (partyName.Length > 25) partyName = $"{partyName.Substring(0, 25)}"; + // if (partyName.Length > 25) partyName = $"{partyName.Substring(0, 25)}"; - var isLegal = contractingParty.IsLegal == "حقوقی" ? true : false; - var isBlock = contractingParty.IsBlock == "true" ? true : false; - var isActive = contractingParty.IsActiveString == "true" ? true : false; - if (!string.IsNullOrWhiteSpace(contractingParty.IsActiveString)) - { - var hasFinancialStatement = - financialStatmentList.Any(x => x.ContractingPartyId == item.ContractingPartyId); + // var isLegal = contractingParty.IsLegal == "حقوقی" ? true : false; + // var isBlock = contractingParty.IsBlock == "true" ? true : false; + // var isActive = contractingParty.IsActiveString == "true" ? true : false; + // if (!string.IsNullOrWhiteSpace(contractingParty.IsActiveString)) + // { + // var hasFinancialStatement = + // financialStatmentList.Any(x => x.ContractingPartyId == item.ContractingPartyId); - var hasPhonNumber = phoneNumberList.Any(x => x.InstitutionContractId == item.Id); + // var hasPhonNumber = phoneNumberList.Any(x => x.InstitutionContractId == item.Id); - if (hasFinancialStatement && hasPhonNumber) - { - var phoneNumbers = phoneNumberList.Where(x => x.InstitutionContractId == item.Id) - .Select(x => new CreateContactInfo - { - PhoneType = x.PhoneType, - PhoneNumber = x.PhoneNumber, + // if (hasFinancialStatement && hasPhonNumber) + // { + // var phoneNumbers = phoneNumberList.Where(x => x.InstitutionContractId == item.Id) + // .Select(x => new CreateContactInfo + // { + // PhoneType = x.PhoneType, + // PhoneNumber = x.PhoneNumber, - InstitutionContractId = x.InstitutionContractId, - SendSms = x.SendSms - }).Where(x => x.PhoneNumber.Length == 11).ToList(); + // InstitutionContractId = x.InstitutionContractId, + // SendSms = x.SendSms + // }).Where(x => x.PhoneNumber.Length == 11).ToList(); - var transactions = financialStatmentList.FirstOrDefault(x => - x.ContractingPartyId == item.ContractingPartyId); + // var transactions = financialStatmentList.FirstOrDefault(x => + // x.ContractingPartyId == item.ContractingPartyId); - var debtor = transactions.FinancialTransactionViewModels.Sum(x => x.Deptor); - var creditor = transactions.FinancialTransactionViewModels.Sum(x => x.Creditor); + // var debtor = transactions.FinancialTransactionViewModels.Sum(x => x.Deptor); + // var creditor = transactions.FinancialTransactionViewModels.Sum(x => x.Creditor); - var id = $"{item.ContractingPartyId}"; - var aprove = $"{transactions.Id}"; - var balance = debtor - creditor; + // var id = $"{item.ContractingPartyId}"; + // var aprove = $"{transactions.Id}"; + // var balance = debtor - creditor; - if (balance > 0) // اگر بدهکار بود - { + // if (balance > 0) // اگر بدهکار بود + // { - if (isLegal) - { - if (item.OfficialCompany == "Official") // حقوقی بدهکار رسمی - { - var balanceToMoney = balance.ToMoney(); + // if (isLegal) + // { + // if (item.OfficialCompany == "Official") // حقوقی بدهکار رسمی + // { + // var balanceToMoney = balance.ToMoney(); - foreach (var number in phoneNumbers) - { + // foreach (var number in phoneNumbers) + // { - var isLastAlarmSend = _context.SmsResults.Any(x => ( - x.ContractingPatyId == contractingParty.Id && - x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + // var isLastAlarmSend = _context.SmsResults.Any(x => ( + // x.ContractingPatyId == contractingParty.Id && + // x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); - if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && - number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) - { + // if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + // number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + // { - var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 608443, - partyName, - balanceToMoney, id, aprove); - Thread.Sleep(1000); - if (smsResult.IsSuccedded) - { - var createSmsResult = new SmsResult(smsResult.MessageId, - smsResult.Message, typeOfSms, partyName, number.PhoneNumber, - item.ContractingPartyId, item.Id); - _smsResultRepository.Create(createSmsResult); - _smsResultRepository.SaveChanges(); - Thread.Sleep(1000); - } + // var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 608443, + // partyName, + // balanceToMoney, id, aprove); + // Thread.Sleep(1000); + // if (smsResult.IsSuccedded) + // { + // var createSmsResult = new SmsResult(smsResult.MessageId, + // smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + // item.ContractingPartyId, item.Id); + // _smsResultRepository.Create(createSmsResult); + // _smsResultRepository.SaveChanges(); + // Thread.Sleep(1000); + // } - } - } + // } + // } - } - else if (item.OfficialCompany == "NotOfficial") // حقوقی بدهکار غیر رسمی - { - var balanceToMoney = balance.ToMoney(); - foreach (var number in phoneNumbers) - { - var isSend = _context.SmsResults.Any(x => - x.ContractingPatyId == contractingParty.Id && - x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); - var isLastAlarmSend = _context.SmsResults.Any(x => ( - x.ContractingPatyId == contractingParty.Id && - x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); - if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && - number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) - { + // } + // else if (item.OfficialCompany == "NotOfficial") // حقوقی بدهکار غیر رسمی + // { + // var balanceToMoney = balance.ToMoney(); + // foreach (var number in phoneNumbers) + // { + // var isSend = _context.SmsResults.Any(x => + // x.ContractingPatyId == contractingParty.Id && + // x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); + // var isLastAlarmSend = _context.SmsResults.Any(x => ( + // x.ContractingPatyId == contractingParty.Id && + // x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + // if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + // number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + // { - var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 351691, - partyName, - balanceToMoney, id, aprove); - Thread.Sleep(1000); - if (smsResult.IsSuccedded) - { - var createSmsResult = new SmsResult(smsResult.MessageId, - smsResult.Message, typeOfSms, partyName, number.PhoneNumber, - item.ContractingPartyId, item.Id); - _smsResultRepository.Create(createSmsResult); - _smsResultRepository.SaveChanges(); - Thread.Sleep(1000); - } + // var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 351691, + // partyName, + // balanceToMoney, id, aprove); + // Thread.Sleep(1000); + // if (smsResult.IsSuccedded) + // { + // var createSmsResult = new SmsResult(smsResult.MessageId, + // smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + // item.ContractingPartyId, item.Id); + // _smsResultRepository.Create(createSmsResult); + // _smsResultRepository.SaveChanges(); + // Thread.Sleep(1000); + // } - } - } + // } + // } - } - } - else - { - if (item.OfficialCompany == "Official") // حقیقی بدهکار رسمی - { - var balanceToMoney = balance.ToMoney(); + // } + // } + // else + // { + // if (item.OfficialCompany == "Official") // حقیقی بدهکار رسمی + // { + // var balanceToMoney = balance.ToMoney(); - foreach (var number in phoneNumbers) - { - var isSend = _context.SmsResults.Any(x => - x.ContractingPatyId == contractingParty.Id && - x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); - var isLastAlarmSend = _context.SmsResults.Any(x => ( - x.ContractingPatyId == contractingParty.Id && - x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); - if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && - number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) - { + // foreach (var number in phoneNumbers) + // { + // var isSend = _context.SmsResults.Any(x => + // x.ContractingPatyId == contractingParty.Id && + // x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); + // var isLastAlarmSend = _context.SmsResults.Any(x => ( + // x.ContractingPatyId == contractingParty.Id && + // x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + // if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + // number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + // { - var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 190430, - partyName, - balanceToMoney, id, aprove); - Thread.Sleep(1000); - if (smsResult.IsSuccedded) - { - var createSmsResult = new SmsResult(smsResult.MessageId, - smsResult.Message, typeOfSms, partyName, number.PhoneNumber, - item.ContractingPartyId, item.Id); - _smsResultRepository.Create(createSmsResult); - _smsResultRepository.SaveChanges(); - Thread.Sleep(1000); - } - } - } + // var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 190430, + // partyName, + // balanceToMoney, id, aprove); + // Thread.Sleep(1000); + // if (smsResult.IsSuccedded) + // { + // var createSmsResult = new SmsResult(smsResult.MessageId, + // smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + // item.ContractingPartyId, item.Id); + // _smsResultRepository.Create(createSmsResult); + // _smsResultRepository.SaveChanges(); + // Thread.Sleep(1000); + // } + // } + // } - } - else if (item.OfficialCompany == "NotOfficial") // حقیقی بدهکار غیر رسمی - { - var balanceToMoney = balance.ToMoney(); + // } + // else if (item.OfficialCompany == "NotOfficial") // حقیقی بدهکار غیر رسمی + // { + // var balanceToMoney = balance.ToMoney(); - foreach (var number in phoneNumbers) - { - var isSend = _context.SmsResults.Any(x => - x.ContractingPatyId == contractingParty.Id && - x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); - var isLastAlarmSend = _context.SmsResults.Any(x => ( - x.ContractingPatyId == contractingParty.Id && - x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); - if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && - number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) - { - var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 412829, - partyName, - balanceToMoney, id, aprove); - Thread.Sleep(1000); - if (smsResult.IsSuccedded) - { - var createSmsResult = new SmsResult(smsResult.MessageId, - smsResult.Message, typeOfSms, partyName, number.PhoneNumber, - item.ContractingPartyId, item.Id); - _smsResultRepository.Create(createSmsResult); - _smsResultRepository.SaveChanges(); - Thread.Sleep(1000); - } + // foreach (var number in phoneNumbers) + // { + // var isSend = _context.SmsResults.Any(x => + // x.ContractingPatyId == contractingParty.Id && + // x.Mobile == number.PhoneNumber && x.TypeOfSms == typeOfSms); + // var isLastAlarmSend = _context.SmsResults.Any(x => ( + // x.ContractingPatyId == contractingParty.Id && + // x.Mobile == number.PhoneNumber) && (x.TypeOfSms == "اقدام قضایی" || x.TypeOfSms == "هشدار دوم")); + // if (!string.IsNullOrWhiteSpace(number.PhoneNumber) && + // number.PhoneNumber.Length == 11 && !isSend && !isLastAlarmSend) + // { + // var smsResult = _smsService.MonthlyBill(number.PhoneNumber, 412829, + // partyName, + // balanceToMoney, id, aprove); + // Thread.Sleep(1000); + // if (smsResult.IsSuccedded) + // { + // var createSmsResult = new SmsResult(smsResult.MessageId, + // smsResult.Message, typeOfSms, partyName, number.PhoneNumber, + // item.ContractingPartyId, item.Id); + // _smsResultRepository.Create(createSmsResult); + // _smsResultRepository.SaveChanges(); + // Thread.Sleep(1000); + // } - } - } + // } + // } - } - } - } - } - } - } - } - catch (Exception e) - { + // } + // } + // } + // } + // } + // } + // } + // catch (Exception e) + // { - string name = item.ContractingPartyName.Length > 18 ? item.ContractingPartyName.Substring(0, 18) : item.ContractingPartyName; - string errMess = $"{name}-خطا"; - _smsService.Alarm("09114221321", errMess); - _logger.LogError(e, "BlueWarningSms"); - } - } - } + // string name = item.ContractingPartyName.Length > 18 ? item.ContractingPartyName.Substring(0, 18) : item.ContractingPartyName; + // string errMess = $"{name}-خطا"; + // _smsService.Alarm("09114221321", errMess); + // _logger.LogError(e, "BlueWarningSms"); + // } + // } + //} #endregion From fb62523a23a54dc879d79cda07bc7ab293e50081 Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 19:06:56 +0330 Subject: [PATCH 15/21] add: integrate Serilog for enhanced logging and monitoring --- .../PaymentGateway/SepehrPaymentGateway.cs | 12 +++++-- ServiceHost/Program.cs | 34 ++++++++++++++++++- ServiceHost/ServiceHost.csproj | 5 +++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs b/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs index 792df36b..874df523 100644 --- a/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs +++ b/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs @@ -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,9 +13,11 @@ public class SepehrPaymentGateway:IPaymentGateway { private readonly HttpClient _httpClient; private const long TerminalId = 99213700; + private readonly ILogger _logger; - public SepehrPaymentGateway(IHttpClientFactory httpClient) + public SepehrPaymentGateway(IHttpClientFactory httpClient, ILogger logger) { + _logger = logger; _httpClient = httpClient.CreateClient(); _httpClient.BaseAddress = new Uri("https://sepehr.shaparak.ir/Rest/V1/PeymentApi/"); } @@ -35,6 +38,7 @@ public class SepehrPaymentGateway:IPaymentGateway // خواندن محتوای پاسخ var content = await res.Content.ReadAsStringAsync(cancellationToken); + // تبدیل پاسخ JSON به آبجکت دات‌نت var json = System.Text.Json.JsonDocument.Parse(content); @@ -46,7 +50,7 @@ public class SepehrPaymentGateway:IPaymentGateway { Status = status, IsSuccess = status == "0", - Token = accessToken + Token = accessToken, }; } @@ -63,7 +67,9 @@ public class SepehrPaymentGateway:IPaymentGateway // خواندن محتوای پاسخ var content = await res.Content.ReadAsStringAsync(cancellationToken); - + + _logger.LogInformation(content); + // تبدیل پاسخ JSON به آبجکت دات‌نت var json = System.Text.Json.JsonDocument.Parse(content); diff --git a/ServiceHost/Program.cs b/ServiceHost/Program.cs index 53ed6274..921656cd 100644 --- a/ServiceHost/Program.cs +++ b/ServiceHost/Program.cs @@ -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"); diff --git a/ServiceHost/ServiceHost.csproj b/ServiceHost/ServiceHost.csproj index 744e0213..8eb8a743 100644 --- a/ServiceHost/ServiceHost.csproj +++ b/ServiceHost/ServiceHost.csproj @@ -94,11 +94,16 @@ + + + + + From ce305edac47b841ee79bc0cf755c98da66422825 Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 19:12:12 +0330 Subject: [PATCH 16/21] add: integrate ILogger for SepehrPaymentGateway logging --- .../InstitutionContractApplication.cs | 5 +++-- CompanyManagment.Application/PaymentCallbackHandler.cs | 6 ++++-- CompanyManagment.Application/SepehrPaymentGatewayService.cs | 6 ++++-- .../Admin/Controllers/institutionContractController.cs | 5 +++-- .../Areas/AdminNew/Pages/Company/AndroidApk/Index.cshtml.cs | 5 +++-- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index e844c1ff..35a0159a 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -26,6 +26,7 @@ using CompanyManagment.App.Contracts.InstitutionContractContactinfo; using CompanyManagment.App.Contracts.PaymentTransaction; using CompanyManagment.App.Contracts.SepehrPaymentGateway; using CompanyManagment.App.Contracts.Workshop; +using Microsoft.Extensions.Logging; using PersianTools.Core; using ConnectedPersonnelViewModel = CompanyManagment.App.Contracts.Workshop.ConnectedPersonnelViewModel; using FinancialStatment = Company.Domain.FinancialStatmentAgg.FinancialStatment; @@ -61,7 +62,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication IAccountApplication accountApplication, ISmsService smsService, IFinancialInvoiceRepository financialInvoiceRepository, IHttpClientFactory httpClientFactory, IPaymentTransactionRepository paymentTransactionRepository, IRollCallServiceRepository rollCallServiceRepository, - ISepehrPaymentGatewayService sepehrPaymentGatewayService) + ISepehrPaymentGatewayService sepehrPaymentGatewayService,ILogger sepehrGatewayLogger) { _institutionContractRepository = institutionContractRepository; _contractingPartyRepository = contractingPartyRepository; @@ -78,7 +79,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication _paymentTransactionRepository = paymentTransactionRepository; _rollCallServiceRepository = rollCallServiceRepository; _sepehrPaymentGatewayService = sepehrPaymentGatewayService; - _paymentGateway = new SepehrPaymentGateway(httpClientFactory); + _paymentGateway = new SepehrPaymentGateway(httpClientFactory,sepehrGatewayLogger); } public OperationResult Create(CreateInstitutionContract command) diff --git a/CompanyManagment.Application/PaymentCallbackHandler.cs b/CompanyManagment.Application/PaymentCallbackHandler.cs index 5bd85425..7a5185b4 100644 --- a/CompanyManagment.Application/PaymentCallbackHandler.cs +++ b/CompanyManagment.Application/PaymentCallbackHandler.cs @@ -18,6 +18,7 @@ using Company.Domain.FinancialStatmentAgg; using Company.Domain.FinancialTransactionAgg; using Company.Domain.InstitutionContractAgg; using CompanyManagment.EFCore.Migrations; +using Microsoft.Extensions.Logging; namespace CompanyManagment.Application; @@ -37,7 +38,8 @@ public class PaymentCallbackHandler : IPaymentCallbackHandler IFinancialInvoiceApplication financialInvoiceApplication, IInstitutionContractApplication institutionContractApplication, IHttpClientFactory httpClientFactory, IInstitutionContractRepository institutionContractRepository, - IFinancialStatmentRepository financialStatmentRepository) + IFinancialStatmentRepository financialStatmentRepository, + ILogger sepehrGatewayLogger) { _paymentTransactionApplication = paymentTransactionApplication; _financialStatmentApplication = financialStatmentApplication; @@ -45,7 +47,7 @@ public class PaymentCallbackHandler : IPaymentCallbackHandler _institutionContractApplication = institutionContractApplication; _institutionContractRepository = institutionContractRepository; _financialStatmentRepository = financialStatmentRepository; - _paymentGateway = new SepehrPaymentGateway(httpClientFactory); + _paymentGateway = new SepehrPaymentGateway(httpClientFactory, sepehrGatewayLogger); } /// diff --git a/CompanyManagment.Application/SepehrPaymentGatewayService.cs b/CompanyManagment.Application/SepehrPaymentGatewayService.cs index dc9749cf..9790f66b 100644 --- a/CompanyManagment.Application/SepehrPaymentGatewayService.cs +++ b/CompanyManagment.Application/SepehrPaymentGatewayService.cs @@ -7,6 +7,7 @@ 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; @@ -20,9 +21,10 @@ public class SepehrPaymentGatewayService : ISepehrPaymentGatewayService public SepehrPaymentGatewayService( IPaymentTransactionApplication paymentTransactionApplication, - IHttpClientFactory httpClientFactory) + IHttpClientFactory httpClientFactory, + ILogger sepehrGatewayLogger) { - _paymentGateway = new SepehrPaymentGateway(httpClientFactory); + _paymentGateway = new SepehrPaymentGateway(httpClientFactory, sepehrGatewayLogger); _paymentTransactionApplication = paymentTransactionApplication; } diff --git a/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs b/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs index 24197909..cb0e2408 100644 --- a/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs +++ b/ServiceHost/Areas/Admin/Controllers/institutionContractController.cs @@ -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 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); } /// diff --git a/ServiceHost/Areas/AdminNew/Pages/Company/AndroidApk/Index.cshtml.cs b/ServiceHost/Areas/AdminNew/Pages/Company/AndroidApk/Index.cshtml.cs index 660a659c..14c47181 100644 --- a/ServiceHost/Areas/AdminNew/Pages/Company/AndroidApk/Index.cshtml.cs +++ b/ServiceHost/Areas/AdminNew/Pages/Company/AndroidApk/Index.cshtml.cs @@ -79,7 +79,8 @@ namespace ServiceHost.Areas.AdminNew.Pages.Company.AndroidApk CompanyContext context, AccountContext accountContext, IHttpClientFactory httpClientFactory, IOptions appSetting, ITemporaryClientRegistrationApplication clientRegistrationApplication, IOnlinePayment onlinePayment, - IFaceEmbeddingService faceEmbeddingService, IAuthHelper authHelper, IInstitutionContractApplication institutionContractApplication) + IFaceEmbeddingService faceEmbeddingService, IAuthHelper authHelper, IInstitutionContractApplication institutionContractApplication + ,ILogger sepehrGatewayLogger) { _application = application; _rollCallDomainService = rollCallDomainService; @@ -91,7 +92,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() From fe66ff5aa3cdb53cf568f4190c92769246e1c39f Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 19:26:12 +0330 Subject: [PATCH 17/21] add: log response content in SepehrPaymentGateway --- .../PaymentGateway/SepehrPaymentGateway.cs | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs b/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs index 874df523..9a6cf10e 100644 --- a/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs +++ b/0_Framework/Application/PaymentGateway/SepehrPaymentGateway.cs @@ -24,9 +24,13 @@ public class SepehrPaymentGateway:IPaymentGateway public async Task Create(CreatePaymentGatewayRequest command, CancellationToken cancellationToken = default) { + _logger.LogInformation("Create payment started. TransactionId: {TransactionId}, Amount: {Amount}", command.TransactionId, command.Amount); command.ExtraData ??= new Dictionary(); + _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, @@ -35,17 +39,20 @@ 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, @@ -59,23 +66,24 @@ public class SepehrPaymentGateway:IPaymentGateway public async Task 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(content); + _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, From 6909fcf7159b9c9056830c53a660155011e3d8c5 Mon Sep 17 00:00:00 2001 From: mahan Date: Wed, 31 Dec 2025 20:06:56 +0330 Subject: [PATCH 18/21] remove financial transaction on institutioncontract veerification --- .../InstitutionContractApplication.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index 35a0159a..5790aaee 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -1285,9 +1285,6 @@ public class InstitutionContractApplication : IInstitutionContractApplication 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; @@ -1306,9 +1303,6 @@ public class InstitutionContractApplication : IInstitutionContractApplication 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; From 3c1bf7dff029fc4b6f303ef1ab4b1774f61386e7 Mon Sep 17 00:00:00 2001 From: SamSys Date: Wed, 31 Dec 2025 20:07:18 +0330 Subject: [PATCH 19/21] Log download --- .../Pages/Company/FileBackup/Index.cshtml | 2 +- .../Pages/Company/FileBackup/Index.cshtml.cs | 26 ++++++++++++++++--- ServiceHost/appsettings.json | 2 +- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml b/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml index 9220ef4a..73968c84 100644 --- a/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml +++ b/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml @@ -164,7 +164,7 @@
- + diff --git a/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml.cs b/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml.cs index 894764b7..de2e2326 100644 --- a/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml.cs +++ b/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml.cs @@ -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); + } + + } } diff --git a/ServiceHost/appsettings.json b/ServiceHost/appsettings.json index eb43b160..e5286144 100644 --- a/ServiceHost/appsettings.json +++ b/ServiceHost/appsettings.json @@ -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//" From 3300f60845b909b579ac7252c3d80074893ace2e Mon Sep 17 00:00:00 2001 From: SamSys Date: Wed, 31 Dec 2025 20:08:11 +0330 Subject: [PATCH 20/21] change --- .../Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml b/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml index 73968c84..5a27d5cd 100644 --- a/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml +++ b/ServiceHost/Areas/AdminNew/Pages/Company/FileBackup/Index.cshtml @@ -164,7 +164,7 @@