diff --git a/Company.Domain/FinancialStatmentAgg/FinancialStatment.cs b/Company.Domain/FinancialStatmentAgg/FinancialStatment.cs index bd6f6858..d9e5d0ff 100644 --- a/Company.Domain/FinancialStatmentAgg/FinancialStatment.cs +++ b/Company.Domain/FinancialStatmentAgg/FinancialStatment.cs @@ -37,4 +37,12 @@ public class FinancialStatment : EntityBase { PublicId = Guid.NewGuid(); } + + public void AddFinancialTransaction(FinancialTransaction financialTransaction) + { + if (financialTransaction == null) + throw new ArgumentNullException(nameof(financialTransaction)); + FinancialTransactionList.Add(financialTransaction); + } + } \ No newline at end of file diff --git a/Company.Domain/InstitutionContractAgg/InstitutionContract.cs b/Company.Domain/InstitutionContractAgg/InstitutionContract.cs index f0bdf849..b2680895 100644 --- a/Company.Domain/InstitutionContractAgg/InstitutionContract.cs +++ b/Company.Domain/InstitutionContractAgg/InstitutionContract.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Security.Cryptography; +using _0_Framework.Application; using _0_Framework.Domain; using Company.Domain.InstitutionContractContactInfoAgg; using CompanyManagment.App.Contracts.InstitutionContract; @@ -50,6 +51,7 @@ public class InstitutionContract : EntityBase Status = InstitutionContractStatus.Incomplete; ContactInfoList = []; WorkshopDetails = []; + Installments = []; } public string ContractNo { get; private set; } @@ -98,10 +100,13 @@ public class InstitutionContract : EntityBase public List ContactInfoList { get; set; } + public List Installments { get; set; } + public InstitutionContract() { - ContactInfoList = new List(); - WorkshopDetails = new List(); + ContactInfoList = []; + WorkshopDetails = []; + Installments = []; } public void Edit(DateTime contractDateGr, string contractDateFa, string state, string city, string address, @@ -168,6 +173,11 @@ public class InstitutionContract : EntityBase { WorkshopDetails = commandWorkshops; } + + public void SetInstallments(List installments) + { + Installments = installments; + } } public class InstitutionContractWorkshopDetail:EntityBase @@ -242,4 +252,26 @@ public enum InstitutionContractStatus /// تکمیل شده - قرارداد به طور کامل انجام شده و نهایی شده است /// Completed = 1 +} + +public class InstitutionContractInstallment +{ + public InstitutionContractInstallment(DateTime installmentDateGr, double amount, + string description) + { + InstallmentDateGr = installmentDateGr; + InstallmentDateFa = installmentDateGr.ToFarsi(); + Amount = amount; + Description = description; + } + + public long Id { get; private set; } + public DateTime InstallmentDateGr { get; private set; } + public string InstallmentDateFa { get; private set; } + public double Amount { get; private set; } + public string Description { get; private set; } + + public long InstitutionContractId { get; private set; } + + public InstitutionContract InstitutionContract { get; private set; } } \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs b/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs index 8b9e2688..015ed2d5 100644 --- a/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs +++ b/CompanyManagment.App.Contracts/InstitutionContract/IInstitutionContractApplication.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Linq; @@ -10,53 +11,149 @@ using Microsoft.AspNetCore.Mvc; namespace CompanyManagment.App.Contracts.InstitutionContract; +/// +/// رابط اپلیکیشن قراردادهای مؤسسه +/// مدیریت عملیات مربوط به قراردادهای مالی مؤسسات +/// public interface IInstitutionContractApplication { + /// + /// ایجاد قرارداد جدید + /// + /// اطلاعات قرارداد جدید + /// نتیجه عملیات OperationResult Create(CreateInstitutionContract command); + + /// + /// تمدید قرارداد موجود + /// + /// اطلاعات قرارداد برای تمدید + /// نتیجه عملیات OperationResult Extension(CreateInstitutionContract command); + + /// + /// ویرایش قرارداد موجود + /// + /// اطلاعات جدید قرارداد + /// نتیجه عملیات OperationResult Edit(EditInstitutionContract command); + + /// + /// دریافت جزئیات قرارداد برای ویرایش + /// + /// شناسه قرارداد + /// اطلاعات قرارداد EditInstitutionContract GetDetails(long id); + /// + /// جستجو در قراردادها + /// + /// مدل جستجو + /// لیست قراردادها List Search(InstitutionContractSearchModel searchModel); + + /// + /// جستجوی جدید در قراردادها + /// + /// مدل جستجو + /// لیست قراردادها List NewSearch(InstitutionContractSearchModel searchModel); /// - /// دریافت اطلاعات قزداد های مالی فعال + /// دریافت اطلاعات قرارداد های مالی فعال ///دارای کارگاه /// جهت ست کردن سرویس ها از طریق اکسل /// /// List GetInstitutionContractToSetServicesExcelImport(); + /// + /// چاپ مجموعه قراردادها + /// + /// لیست شناسه قراردادها + /// لیست قراردادها برای چاپ List PrintAll(List id); + + /// + /// چاپ یک قرارداد + /// + /// شناسه قرارداد + /// اطلاعات قرارداد برای چاپ InstitutionContractViewModel PrintOne(long id); + /// + /// فعال کردن قرارداد + /// + /// شناسه قرارداد + /// نتیجه عملیات OperationResult Active(long id); - + /// + /// غیرفعال کردن قرارداد + /// + /// شناسه قرارداد + /// نتیجه عملیات OperationResult DeActive(long id); - + /// + /// غیرفعال کردن قرارداد (حالت آبی) + /// + /// شناسه قرارداد + /// نتیجه عملیات OperationResult DeActiveBlue(long id); - + /// + /// غیرفعال کردن تمام اتصالات قرارداد + /// + /// شناسه قرارداد + /// نتیجه عملیات OperationResult DeActiveAllConnections(long id); - + /// + /// فعال کردن مجدد تمام اتصالات قرارداد + /// + /// شناسه قرارداد + /// نتیجه عملیات OperationResult ReActiveAllConnections(long id); + /// + /// فعال کردن مجدد تمام قراردادها بعد از ایجاد قرارداد جدید + /// + /// شناسه طرف قرارداد void ReActiveAllAfterCreateNew(long contractingPartyId); - + /// + /// حذف قرارداد + /// + /// شناسه قرارداد void RemoveContract(long id); - + /// + /// امضای قرارداد + /// + /// شناسه قرارداد + /// نتیجه عملیات OperationResult Sign(long id); - + /// + /// لغو امضای قرارداد + /// + /// شناسه قرارداد + /// نتیجه عملیات OperationResult UnSign(long id); + + /// + /// ایجاد حساب کاربری برای طرف قرارداد + /// + /// شناسه طرف قرارداد + /// شناسه حساب کاربری void CreateContractingPartyAccount(long contractingPartyid, long accountId); + /// + /// محاسبه مبلغ قرارداد بر اساس تعداد افراد + /// + /// تعداد افراد + /// مبلغ قرارداد double GetcontractAmount(int countPerson); #region Api @@ -82,53 +179,110 @@ public interface IInstitutionContractApplication /// /// Task CreateAsync(CreateInstitutionContractRequest command); + /// /// ویرایش /// /// /// Task EditAsync(EditInstitutionContractRequest command); + /// /// تمدید قرارداد /// /// /// Task ExtensionَAsync(CreateInstitutionContractRequest command); - - + #endregion } public class GetInstitutionContractListStatsViewModel { /// - /// Represents the total outstanding debt of institution contracts. - /// This property aggregates the liabilities of the respective contracts and provides - /// a single metric to measure financial obligations. + /// مجموع بدهی قراردادهای مؤسسه + /// این ویژگی بدهی‌های قراردادهای مربوطه را تجمیع می‌کند و + /// یک معیار واحد برای اندازه‌گیری تعهدات مالی ارائه می‌دهد /// public double TotalDebt { get; set; } /// - /// Represents the total monetary value associated with institution contracts. - /// This property consolidates the aggregate amount from relevant contracts - /// for financial reporting and analysis. + /// مجموع ارزش پولی مرتبط با قراردادهای مؤسسه + /// این ویژگی مبلغ کل قراردادهای مربوطه را برای + /// گزارش‌گیری و تجزیه و تحلیل مالی تجمیع می‌کند /// public double TotalAmount { get; set; } /// - /// Represents a collection of counts for institution contracts categorized by their status. - /// This property provides the count of contracts for each status defined in the - /// InstitutionContractStatus enumeration, enabling analysis and monitoring of contract distribution. + /// مجموعه‌ای از تعداد قراردادهای مؤسسه دسته‌بندی شده بر اساس وضعیت + /// این ویژگی تعداد قراردادها را برای هر وضعیت تعریف شده در + /// شمارش InstitutionContractStatus ارائه می‌دهد که امکان تجزیه و تحلیل و نظارت بر توزیع قراردادها را فراهم می‌کند /// - public List Counts { get; set; } + public List Counts { get; set; } } +/// +/// شمارش وضعیت قراردادهای مؤسسه +/// نمایش تعداد قراردادها برای هر وضعیت خاص +/// public class InstitutionContractStatusCount { + /// + /// وضعیت لیست قرارداد + /// public InstitutionContractListStatus ListStatus { get; set; } + + /// + /// تعداد قراردادها در این وضعیت + /// public int Count { get; set; } } -public class ExtenstionInstitutionContractRequest:EditInstitutionContractRequest + +/// +/// درخواست تمدید قرارداد مؤسسه +/// شامل اطلاعات قرارداد قبلی برای فرآیند تمدید +/// +public class ExtenstionInstitutionContractRequest : EditInstitutionContractRequest { + /// + /// شناسه قرارداد قبلی که قرار است تمدید شود + /// public long PreviousContractId { get; set; } +} + +/// +/// مدل نمایش اقساط قرارداد مؤسسه +/// شامل اطلاعات مربوط به هر قسط از قرارداد +/// +public class InstitutionContractInstallmentViewModel +{ + /// + /// شناسه یکتای قسط + /// + public long Id { get; set; } + + /// + /// تاریخ میلادی قسط + /// + public DateTime InstallmentDateGr { get; set; } + + /// + /// تاریخ فارسی قسط + /// + public string InstallmentDateFa { get; set; } + + /// + /// مبلغ قسط + /// + public double Amount { get; set; } + + /// + /// توضیحات قسط + /// + public string Description { get; set; } + + /// + /// شناسه قرارداد مؤسسه مربوط به این قسط + /// + public long InstitutionContractId { get; set; } } \ No newline at end of file diff --git a/CompanyManagment.Application/InstitutionContractApplication.cs b/CompanyManagment.Application/InstitutionContractApplication.cs index c4b943c5..6383e39f 100644 --- a/CompanyManagment.Application/InstitutionContractApplication.cs +++ b/CompanyManagment.Application/InstitutionContractApplication.cs @@ -9,6 +9,8 @@ using _0_Framework.Exceptions; using Company.Domain.ContarctingPartyAgg; using Company.Domain.EmployeeAgg; using Company.Domain.empolyerAgg; +using Company.Domain.FinancialStatmentAgg; +using Company.Domain.FinancialTransactionAgg; using Company.Domain.InstitutionContractAgg; using Company.Domain.LeftWorkAgg; using Company.Domain.RepresentativeAgg; @@ -21,6 +23,7 @@ using CompanyManagment.App.Contracts.Workshop; using CompanyManagment.EFCore.Migrations; using PersianTools.Core; using ConnectedPersonnelViewModel = CompanyManagment.App.Contracts.Workshop.ConnectedPersonnelViewModel; +using FinancialStatment = Company.Domain.FinancialStatmentAgg.FinancialStatment; namespace CompanyManagment.Application; @@ -35,6 +38,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication private readonly ILeftWorkRepository _leftWorkRepository; private readonly IWorkshopApplication _workshopApplication; private readonly IContractingPartyTempRepository _contractingPartyTempRepository; + private readonly IFinancialStatmentRepository _financialStatmentRepository; public InstitutionContractApplication(IInstitutionContractRepository institutionContractRepository, @@ -42,7 +46,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication IRepresentativeRepository representativeRepository, IEmployerRepository employerRepository, IWorkshopRepository workshopRepository, ILeftWorkRepository leftWorkRepository, IFinancialStatmentApplication financialStatmentApplication, IWorkshopApplication workshopApplication, - IContractingPartyTempRepository contractingPartyTempRepository) + IContractingPartyTempRepository contractingPartyTempRepository, IFinancialStatmentRepository financialStatmentRepository) { _institutionContractRepository = institutionContractRepository; _contractingPartyRepository = contractingPartyRepository; @@ -53,6 +57,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication _financialStatmentApplication = financialStatmentApplication; _workshopApplication = workshopApplication; _contractingPartyTempRepository = contractingPartyTempRepository; + _financialStatmentRepository = financialStatmentRepository; } public OperationResult Create(CreateInstitutionContract command) @@ -937,42 +942,72 @@ public class InstitutionContractApplication : IInstitutionContractApplication contractStartGr.AddMonthsFa((int)command.Duration, out var contractEndGr); contractEndGr = contractEndGr.ToFarsi().FindeEndOfMonth().ToGeorgianDateTime(); - var contractDateGr = DateTime.Today; + + var today = DateTime.Today; + + var contractDateGr = today; var contractDateFa = contractDateGr.ToFarsi(); //Todo: Calculate Amount. - double contractAmount = 0; - - if (command.IsInstallment) - { - - } - else - { - - } - - var hasValueAddedTax = command.TaxAmount> 0 ? "true" : "false"; - + + + var hasValueAddedTax = command.TaxAmount > 0 ? "true" : "false"; + var contractingPartyFullName = contractingParty.FName + " " + contractingParty.LName; - + var entity = new InstitutionContract(contractNo, command.RepresentativeId, representative.FullName, contractingParty.id, contractingPartyFullName, contractDateGr, contractDateFa, command.Province, command.City, command.Address, contractStartGr, - contractStartGr.ToFarsi(), contractEndGr, contractEndGr.ToFarsi(),contractAmount, command.DailyCompensation, - command.Obligation,command.TotalAmount, 0, + contractStartGr.ToFarsi(), contractEndGr, contractEndGr.ToFarsi(), 0, command.DailyCompensation, + command.Obligation, command.TotalAmount, 0, command.Workshops.Count.ToString(), command.Workshops.Sum(x => x.PersonnelCount).ToString(), command.Description, - "Official", "JobRelation",hasValueAddedTax + "NotOfficial", "JobRelation", hasValueAddedTax , command.TaxAmount); + var workshopDetails = command.Workshops.Select(x => new InstitutionContractWorkshopDetail(x.WorkshopName, x.HasRollCallPlan, x.HasCustomizeCheckoutPlan, x.HasContractPlan, x.PersonnelCount)).ToList(); - + + var financialStatement = new FinancialStatment(contractingParty.id,contractingPartyFullName); + + if (command.IsInstallment) + { + var installments = + CalculateInstallment(command.TotalAmount, (int)command.Duration, command.ContractStartFa, true); + + // دریافت مبلغ اولین قسط + //این کار برای این هست که اولین قسط باید با تاریخ امروز باشد و باید به وضعیت مالی بدهی ایجاد شود که یوزر اولین بدهی را وارد کند + var firstInstallmentAmount = installments.First().Amount; + + // حذف اولین قسط + installments.RemoveAt(0); + + // ایجاد قسط جدید با تاریخ امروز + var todayInstallment = new InstitutionContractInstallment(DateTime.Today, firstInstallmentAmount, ""); + + var financialTransaction = new FinancialTransaction(0,today,today.ToFarsi(), + "قسط اول سرویس", "debt","بابت خدمات",firstInstallmentAmount,0,0); + + financialStatement.AddFinancialTransaction(financialTransaction); + + // اضافه کردن قسط جدید به ابتدای لیست + installments.Insert(0, todayInstallment); + + entity.SetInstallments(installments); + } + else + { + var financialTransaction = new FinancialTransaction(0, today, today.ToFarsi(), + "پرداخت کل سرویس", "debt", "بابت خدمات", command.TotalAmount, 0, 0); + financialStatement.AddFinancialTransaction(financialTransaction); + } + entity.SetWorkshopDetails(workshopDetails); + await _financialStatmentRepository.CreateAsync(financialStatement); await _institutionContractRepository.CreateAsync(entity); await _institutionContractRepository.SaveChangesAsync(); await transaction.CommitAsync(); @@ -1025,7 +1060,7 @@ public class InstitutionContractApplication : IInstitutionContractApplication "*", "*", request.RegisterId, request.NationalId, "حقوقی", request.PhoneNumber, request.PhoneNumber, null, representativeId, representative.FullName, - archiveCode, null, null, null, null,request.Position); + archiveCode, null, null, null, null, request.Position); await _contractingPartyRepository.CreateAsync(legalContractingParty); @@ -1075,6 +1110,97 @@ public class InstitutionContractApplication : IInstitutionContractApplication return operation.Succcedded(personalContractingParty); } + + private List CalculateInstallment(double amount, int installmentCount, + string loanStartDate, bool getRounded) + { + int day = Convert.ToInt32(loanStartDate.Substring(8, 2)); + int month = Convert.ToInt32(loanStartDate.Substring(5, 2)); + int year = Convert.ToInt32(loanStartDate.Substring(0, 4)); + + var installments = new List(); + + + bool endOfMonth = day == 31; + + + var dividedAmount = amount / installmentCount; + + double moneyPerMonth = 0; + + if (getRounded) + moneyPerMonth = Math.Floor(dividedAmount / 1000) * 1000; + else + moneyPerMonth = Math.Floor(dividedAmount); + + double lastLoan = amount - (moneyPerMonth * (installmentCount - 1)); + + if (endOfMonth) + { + for (int i = 1; i < installmentCount; i++) + { + var installment = + new InstitutionContractInstallment(loanStartDate.ToGeorgianDateTime(), moneyPerMonth, ""); + + installments.Add(installment); + + if (month == 12) + { + year++; + month = 1; + } + else + { + month++; + } + + loanStartDate = $"{year:0000}/{month:00}/01".FindeEndOfMonth(); + } + + var lastInstallment = new InstitutionContractInstallment(loanStartDate.ToGeorgianDateTime(), lastLoan, ""); + + installments.Add(lastInstallment); + return installments; + } + else + { + for (int i = 1; i < installmentCount; i++) + { + var installment = + new InstitutionContractInstallment(loanStartDate.ToGeorgianDateTime(), moneyPerMonth, ""); + + installments.Add(installment); + var endDay = 0; + + if (month == 12) + { + year++; + month = 1; + } + else + { + month++; + } + + if (day == 30) + { + if (month == 12) + { + var lastYearDay = + Convert.ToInt32($"{year:0000}/{month:00}/1".FindeEndOfMonth().Substring(8, 2)); + endDay = lastYearDay == 30 ? lastYearDay : 29; + } + } + + loanStartDate = + endDay == 0 ? $"{year:0000}/{month:00}/{day:00}" : $"{year:0000}/{month:00}/{endDay:00}"; + } + + var lastInstallment = new InstitutionContractInstallment(loanStartDate.ToGeorgianDateTime(), lastLoan, ""); + installments.Add(lastInstallment); + return installments; + } + } } #region CustomViewModels diff --git a/CompanyManagment.Application/LoanApplication.cs b/CompanyManagment.Application/LoanApplication.cs index 667a1681..3c9eb999 100644 --- a/CompanyManagment.Application/LoanApplication.cs +++ b/CompanyManagment.Application/LoanApplication.cs @@ -200,7 +200,8 @@ public class LoanApplication : ILoanApplication DateGr = loanStartDate.ToGeorgianDateTime(), Month = loanStartDate.Substring(5, 2), Year = loanStartDate.Substring(0, 4), - Day = loanStartDate.Substring(8, 2) + Day = loanStartDate.Substring(8, 2), + AmountDouble = moneyPerMonth }; installments.Add(installment); @@ -225,7 +226,8 @@ public class LoanApplication : ILoanApplication DateGr = loanStartDate.ToGeorgianDateTime(), Month = loanStartDate.Substring(5, 2), Year = loanStartDate.Substring(0, 4), - Day = loanStartDate.Substring(8, 2) + Day = loanStartDate.Substring(8, 2), + AmountDouble = lastLoan }; installments.Add(lastInstallment); @@ -243,7 +245,8 @@ public class LoanApplication : ILoanApplication DateGr = loanStartDate.ToGeorgianDateTime(), Month = loanStartDate.Substring(5, 2), Year = loanStartDate.Substring(0, 4), - Day = loanStartDate.Substring(8, 2) + Day = loanStartDate.Substring(8, 2), + AmountDouble = moneyPerMonth }; installments.Add(installment); @@ -278,7 +281,8 @@ public class LoanApplication : ILoanApplication DateGr = loanStartDate.ToGeorgianDateTime(), Month = loanStartDate.Substring(5, 2), Year = loanStartDate.Substring(0, 4), - Day = loanStartDate.Substring(8, 2) + Day = loanStartDate.Substring(8, 2), + AmountDouble = lastLoan }; installments.Add(lastInstallment); diff --git a/CompanyManagment.EFCore/Mapping/InstitutionContractInstallmentMapping.cs b/CompanyManagment.EFCore/Mapping/InstitutionContractInstallmentMapping.cs new file mode 100644 index 00000000..6741ac7e --- /dev/null +++ b/CompanyManagment.EFCore/Mapping/InstitutionContractInstallmentMapping.cs @@ -0,0 +1,23 @@ +using Company.Domain.InstitutionContractAgg; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace CompanyManagment.EFCore.Mapping; + +public class InstitutionContractInstallmentMapping : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("InstitutionContractInstallments"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.InstallmentDateFa).HasMaxLength(10).IsRequired(); + builder.Property(x => x.Description).HasMaxLength(1000); + builder.Property(x => x.Amount).IsRequired(); + + builder.HasOne(x => x.InstitutionContract) + .WithMany(x => x.Installments) + .HasForeignKey(x => x.InstitutionContractId) + .OnDelete(DeleteBehavior.Cascade); + } +} \ No newline at end of file diff --git a/CompanyManagment.EFCore/Mapping/InstitutionContractMapping.cs b/CompanyManagment.EFCore/Mapping/InstitutionContractMapping.cs index 26a9032c..3a69903c 100644 --- a/CompanyManagment.EFCore/Mapping/InstitutionContractMapping.cs +++ b/CompanyManagment.EFCore/Mapping/InstitutionContractMapping.cs @@ -37,7 +37,9 @@ public class InstitutionContractMapping : IEntityTypeConfiguration x.WorkshopId).IsRequired(false); }); - + builder.HasMany(x => x.Installments) + .WithOne(x => x.InstitutionContract) + .HasForeignKey(x => x.InstitutionContractId); builder.HasMany(x => x.ContactInfoList) .WithOne(x => x.InstitutionContracts) diff --git a/DadmehrGostar.sln.DotSettings b/DadmehrGostar.sln.DotSettings index cd0dd14f..97a23101 100644 --- a/DadmehrGostar.sln.DotSettings +++ b/DadmehrGostar.sln.DotSettings @@ -2,5 +2,6 @@ False True True + True True True \ No newline at end of file