diff --git a/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs b/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs index 860aa62b..a3a8fc4c 100644 --- a/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs +++ b/0_Framework/Exceptions/Handler/CustomExceptionHandler.cs @@ -68,7 +68,6 @@ public class CustomExceptionHandler : IExceptionHandler problemDetails.Extensions.Add("traceId", context.TraceIdentifier); - await context.Response.WriteAsJsonAsync(problemDetails, cancellationToken: cancellationToken); return true; diff --git a/Company.Domain/FinancialStatmentAgg/IFinancialStatmentRepository.cs b/Company.Domain/FinancialStatmentAgg/IFinancialStatmentRepository.cs index 8bed15be..56d26347 100644 --- a/Company.Domain/FinancialStatmentAgg/IFinancialStatmentRepository.cs +++ b/Company.Domain/FinancialStatmentAgg/IFinancialStatmentRepository.cs @@ -13,4 +13,6 @@ public interface IFinancialStatmentRepository : IRepository Search(FinancialStatmentSearchModel searchModel); + Task GetClientFinancialStatement(long accountId, + ClientFinancialStatementSearchModel searchModel); } \ No newline at end of file diff --git a/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs b/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs index d2ac6498..45e18826 100644 --- a/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs +++ b/CompanyManagment.App.Contracts/FinancialStatment/IFinancialStatmentApplication.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using _0_Framework.Application; +using CompanyManagment.App.Contracts.FinancilTransaction; namespace CompanyManagment.App.Contracts.FinancialStatment; @@ -13,4 +14,123 @@ public interface IFinancialStatmentApplication List Search(FinancialStatmentSearchModel searchModel); FinancialStatmentViewModel GetDetailsByContractingPartyId(long contractingPartyId); -} \ No newline at end of file + + /// + /// نمایش اطلاعات صورت حساب مالی کلاینت + /// + /// + /// + /// مدل صورت حساب مالی کلاینت + Task GetClientFinancialStatement(ClientFinancialStatementSearchModel searchModel, + long accountId); +} + +public class ClientFinancialStatementSearchModel +{ + /// + /// از تاریخ + /// + public string FromDate { get; set; } + /// + /// تا تاریخ + /// + public string ToDate { get; set; } + /// + /// از مبلغ + /// + public double FromAmount { get; set; } + /// + /// تا مبلغ + /// + public double ToAmount { get; set; } + /// + /// نوع عملیات تراکنش + /// + public FinancialTransactionType? Type { get; set; } + + /// + /// صفحه بندی + /// + public int PageIndex { get; set; } + +} + +public enum FinancialTransactionType +{ + /// + /// ایجاد درآمد + /// + Debt, + /// + /// دریافت درآمد + /// + Credit +} + +public class ClientFinancialStatementViewModel +{ + /// + /// آیدی FinancialStatement + /// + public long Id { get; set; } + + /// + /// جمع بدهکاری + /// + public double TotalDebt { get; set; } + /// + /// جمع بستانکاری + /// + public double TotalCredit { get; set; } + /// + /// مبلغ قابل پرداخت + /// + public double TotalAmountPayable { get; set; } + + /// + /// تراکنش ها + /// + public List Transactions { get; set; } +} + +public class ClientFinancialTransactionViewModel +{ + /// + /// زمان و تاریخ میلادی + /// + public DateTime DateTimeGr { get; set; } + /// + /// تاریخ + /// + public string DateFa { get; set; } + /// + /// زمان + /// + public string TimeFa { get; set; } + /// + /// شرح + /// + public string Description { get; set; } + /// + /// نوع عملیات پرداخت + /// + public FinancialTransactionType Type { get; set; } + + /// + /// نوع عملیات پرداخت به صورت استرینگ + /// + public string TypeStr { get; set; } + /// + /// بدهکار + /// + public double Debtor { get; set; } + /// + /// بستانکار + /// + public double Creditor { get; set; } + /// + /// باقی مانده + /// + public double Balance { get; set; } +} + diff --git a/CompanyManagment.Application/FinancialStatmentApplication.cs b/CompanyManagment.Application/FinancialStatmentApplication.cs index a4ee6c50..283c1091 100644 --- a/CompanyManagment.Application/FinancialStatmentApplication.cs +++ b/CompanyManagment.Application/FinancialStatmentApplication.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using _0_Framework.Application; using Company.Domain.FinancialStatmentAgg; using CompanyManagment.App.Contracts.FinancialStatment; @@ -110,4 +111,10 @@ public class FinancialStatmentApplication : IFinancialStatmentApplication { return _financialStatmentRepository.GetDetailsByContractingPartyId(contractingPartyId); } + + public async Task GetClientFinancialStatement( + ClientFinancialStatementSearchModel searchModel, long accountId) + { + return await _financialStatmentRepository.GetClientFinancialStatement(accountId, searchModel); + } } \ No newline at end of file diff --git a/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs b/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs index 2d61fe9f..15c5a475 100644 --- a/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs +++ b/CompanyManagment.EFCore/Repository/FinancialStatmentRepository.cs @@ -1,12 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using _0_Framework.Application; +using _0_Framework.Application; +using _0_Framework.Exceptions; using _0_Framework.InfraStructure; using Company.Domain.FinancialStatmentAgg; using CompanyManagment.App.Contracts.FinancialStatment; using CompanyManagment.App.Contracts.FinancilTransaction; using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AccountManagement.Application.Contracts.SubAccount; +using static Microsoft.EntityFrameworkCore.DbLoggerCategory; namespace CompanyManagment.EFCore.Repository; @@ -31,7 +35,7 @@ public class FinancialStatmentRepository : RepositoryBaset.TdateGr).ToList(), + }).OrderBy(t => t.TdateGr).ToList(), }; } @@ -63,4 +67,83 @@ public class FinancialStatmentRepository : RepositoryBase GetClientFinancialStatement(long accountId, + ClientFinancialStatementSearchModel searchModel) + { + var contractingPartyId = _context.ContractingPartyAccounts.Any(x => x.AccountId == accountId) ? + _context.ContractingPartyAccounts.FirstOrDefault(x => x.AccountId == accountId)!.PersonalContractingPartyId : 0; + + if (contractingPartyId == 0) + throw new BadRequestException("طرف حساب مورد نظر یافت نشد"); + + var resStatement = await _context.FinancialStatments.Include(x=>x.FinancialTransactionList) + .FirstOrDefaultAsync(x => x.ContractingPartyId == contractingPartyId); + + if (resStatement == null) + throw new BadRequestException("صورت حساب مالی شخص یافت نشد"); + + var resTransaction = resStatement.FinancialTransactionList.ToList(); + + #region Search + + //if (searchModel.FromAmount > 0 || searchModel.ToAmount > 0) + //{ + // if (searchModel.FromAmount > 0 && searchModel.ToAmount > 0) + // { + // resTransaction = resTransaction.Where(x => x.>= searchModel.FromAmount && x.Amount <= searchModel); + // } + // else if (searchModel.FromAmount > 0) + // { + // query = query.Where(x => x.Amount >= searchModel.FromAmount); + // } + // else if (searchModel.ToAmount > 0) + // { + // query = query.Where(x => x.Amount <= searchModel.ToAmount); + // } + //} + if (!string.IsNullOrWhiteSpace(searchModel.FromDate) && !string.IsNullOrWhiteSpace(searchModel.ToDate)) + { + if (searchModel.FromDate.TryToGeorgianDateTime(out var fromDate) == false) + throw new BadRequestException("تاریخ وارد شده نامعتبر است"); + + if (searchModel.FromDate.TryToGeorgianDateTime(out var toDate) == false) + throw new BadRequestException("تاریخ وارد شده نامعتبر است"); + + resTransaction = resTransaction.Where(x => x.TdateGr >= fromDate && x.TdateGr <= toDate).ToList(); + } + + if (searchModel.Type != null) + { + var type = searchModel.Type switch + { + FinancialTransactionType.Credit => "credit", + FinancialTransactionType.Debt => "debt" + }; + + resTransaction = resTransaction.Where(x => x.TypeOfTransaction == type).ToList(); + } + #endregion + + return new ClientFinancialStatementViewModel() + { + Id = resStatement.id, + TotalAmountPayable = resStatement.FinancialTransactionList.Sum(x=>x.Deptor) - resStatement.FinancialTransactionList.Sum(x=>x.Creditor), + TotalCredit = resTransaction.Sum(x=>x.Creditor), + TotalDebt = resTransaction.Sum(x=>x.Deptor), + Transactions = resTransaction.Select(t => new ClientFinancialTransactionViewModel() + { + DateTimeGr = t.TdateGr, + DateFa = t.TdateGr.ToFarsi(), + TimeFa = $"{t.TdateGr:HH:mm}", + Description = t.DescriptionOption + " " + t.Description, + Debtor = t.Deptor, + Creditor = t.Creditor, + Balance = t.Balance, + Type = t.TypeOfTransaction =="debt"? FinancialTransactionType.Debt :FinancialTransactionType.Credit, + TypeStr = t.TypeOfTransaction =="debt"? "ایجاد درآمد" : "دریافت درآمد" + }).OrderByDescending(t => t.DateTimeGr).ToList(), + }; + + } } \ No newline at end of file diff --git a/ServiceHost/Areas/Client/Controllers/FinancialController.cs b/ServiceHost/Areas/Client/Controllers/FinancialController.cs new file mode 100644 index 00000000..e9037069 --- /dev/null +++ b/ServiceHost/Areas/Client/Controllers/FinancialController.cs @@ -0,0 +1,26 @@ +using _0_Framework.Application; +using CompanyManagment.App.Contracts.FinancialStatment; +using Microsoft.AspNetCore.Mvc; +using ServiceHost.BaseControllers; + +namespace ServiceHost.Areas.Client.Controllers; + +public class FinancialController : ClientBaseController +{ + private readonly IFinancialStatmentApplication _financialStatementApplication; + private readonly IAuthHelper _authHelper; + + public FinancialController(IFinancialStatmentApplication financialStatementApplication, IAuthHelper authHelper) + { + _financialStatementApplication = financialStatementApplication; + _authHelper = authHelper; + } + + [HttpGet] + public async Task> GetList(ClientFinancialStatementSearchModel searchModel) + { + var accountId = _authHelper.CurrentAccountId(); + var result =await _financialStatementApplication.GetClientFinancialStatement(searchModel,accountId); + return result; + } +} \ No newline at end of file diff --git a/ServiceHost/BaseControllers/ClientBaseController.cs b/ServiceHost/BaseControllers/ClientBaseController.cs index 746cbfc7..9de7b335 100644 --- a/ServiceHost/BaseControllers/ClientBaseController.cs +++ b/ServiceHost/BaseControllers/ClientBaseController.cs @@ -1,8 +1,9 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; namespace ServiceHost.BaseControllers; -//[Authorize(Policy = "ClientArea")] +[Authorize(Policy = "ClientArea")] [Area("Client")] [ApiExplorerSettings(GroupName = "Client")] [Route("api/[area]/[controller]")] diff --git a/ServiceHost/MiddleWare/RazorJsonEnumOverrideMiddleware.cs b/ServiceHost/MiddleWare/RazorJsonEnumOverrideMiddleware.cs index f0d3cd23..45048085 100644 --- a/ServiceHost/MiddleWare/RazorJsonEnumOverrideMiddleware.cs +++ b/ServiceHost/MiddleWare/RazorJsonEnumOverrideMiddleware.cs @@ -14,48 +14,52 @@ public class RazorJsonEnumOverrideMiddleware public async Task InvokeAsync(HttpContext context) { - // نگه‌دار خروجی var originalBody = context.Response.Body; using var newBody = new MemoryStream(); context.Response.Body = newBody; - await _next(context); // اجرای مرحله بعدی - - // فقط برای مسیرهای غیر /api و وقتی Content-Type = application/json - if (!context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase) && - context.Response.ContentType?.Contains("application/json", StringComparison.OrdinalIgnoreCase) == true) + try { - newBody.Seek(0, SeekOrigin.Begin); - using var reader = new StreamReader(newBody); - var originalJson = await reader.ReadToEndAsync(); + await _next(context); - // JSON رو deserialize و دوباره serialize می‌کنیم بدون EnumConverter - try + if (!context.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase) && + context.Response.ContentType?.Contains("application/json", StringComparison.OrdinalIgnoreCase) == true) { - var obj = JsonSerializer.Deserialize(originalJson); - var newJson = JsonSerializer.Serialize(obj, new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }); - - context.Response.Body = originalBody; - context.Response.ContentLength = Encoding.UTF8.GetByteCount(newJson); - await context.Response.WriteAsync(newJson); - return; - } - catch - { - // fallback if deserialization fails - context.Response.Body = originalBody; newBody.Seek(0, SeekOrigin.Begin); - await newBody.CopyToAsync(originalBody); - return; - } - } + var originalJson = await new StreamReader(newBody).ReadToEndAsync(); - // اگر شرط نداشت، همون خروجی قبلی رو منتقل کن - context.Response.Body = originalBody; - newBody.Seek(0, SeekOrigin.Begin); - await newBody.CopyToAsync(originalBody); + try + { + var obj = JsonSerializer.Deserialize(originalJson); + var newJson = JsonSerializer.Serialize(obj, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + + context.Response.Body = originalBody; + context.Response.ContentLength = Encoding.UTF8.GetByteCount(newJson); + if (!context.Response.HasStarted) + await context.Response.WriteAsync(newJson); + return; + } + catch + { + context.Response.Body = originalBody; + newBody.Seek(0, SeekOrigin.Begin); + if (!context.Response.HasStarted) + await newBody.CopyToAsync(originalBody); + return; + } + } + + context.Response.Body = originalBody; + newBody.Seek(0, SeekOrigin.Begin); + if (!context.Response.HasStarted) + await newBody.CopyToAsync(originalBody); + } + finally + { + context.Response.Body = originalBody; + } } } \ No newline at end of file diff --git a/ServiceHost/Program.cs b/ServiceHost/Program.cs index 43a0cdfd..408db6e3 100644 --- a/ServiceHost/Program.cs +++ b/ServiceHost/Program.cs @@ -26,6 +26,8 @@ using System.Text.Json; using Microsoft.AspNetCore.CookiePolicy; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Diagnostics; + var builder = WebApplication.CreateBuilder(args); @@ -291,6 +293,7 @@ builder.Services.AddCors(options => builder.Services.AddExceptionHandler(); + var app = builder.Build(); app.UseCors("AllowSpecificOrigins"); @@ -323,6 +326,8 @@ if (app.Environment.IsDevelopment()) //Create Http Pipeline #region Create Http Pipeline + + if (builder.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); @@ -333,17 +338,23 @@ else app.UseHsts(); } +app.UseExceptionHandler(options => { }); // این خط CustomExceptionHandler رو فعال می‌کنه + +app.UseRouting(); + app.UseAuthentication(); +app.UseAuthorization(); + + app.UseHttpsRedirection(); + app.UseStaticFiles(); app.UseCookiePolicy(); -app.UseRouting(); -app.UseAuthorization(); #region Mahan diff --git a/ServiceHost/ServiceHost.csproj b/ServiceHost/ServiceHost.csproj index a6d7e7e7..76206104 100644 --- a/ServiceHost/ServiceHost.csproj +++ b/ServiceHost/ServiceHost.csproj @@ -95,6 +95,7 @@ + @@ -387,7 +388,6 @@ -