using System.Text; using DS.Module.Core; using DS.Module.Core.Enums; using DS.Module.Core.Extensions; using DS.WMS.Core.Application.Dtos; using DS.WMS.Core.Application.Entity; using DS.WMS.Core.Code.Entity; using DS.WMS.Core.Fee.Entity; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Settlement.Dtos; using DS.WMS.Core.Settlement.Entity; using DS.WMS.Core.Settlement.Interface; using DS.WMS.Core.Sys.Entity; using SqlSugar; namespace DS.WMS.Core.Settlement.Method { /// /// 付费申请结算服务 /// public class PaymentSettlementService : SettlementService, IPaymentSettlementService { /// /// 初始化 /// /// public PaymentSettlementService(IServiceProvider provider) : base(provider) { } /// /// 获取分页列表 /// /// /// public async Task>> GetListAsync(PageRequest request) { var query = TenantDb.Queryable().Select(x => new PaymentSettlementDto { Id = x.Id, ApplicationNO = x.ApplicationNO, //申请编号 SettlementNO = x.SettlementNO, //结算单号 CustomerId = x.CustomerId, //结算单位 CustomerName = x.CustomerName, Mode = x.Mode, //结算类型 SettlementTypeName = x.SettlementType.StlName, //结算方式 RMBAmount = SqlFunc.Subqueryable().Where(y => y.ApplicationId == x.Id && y.Currency == FeeCurrency.RMB_CODE) .Select(y => SqlFunc.AggregateSum(y.ApplyAmount)), USDAmount = SqlFunc.Subqueryable().Where(y => y.ApplicationId == x.Id && y.Currency == FeeCurrency.USD_CODE) .Select(y => SqlFunc.AggregateSum(y.ApplyAmount)), OtherAmount = SqlFunc.Subqueryable().Where(y => y.ApplicationId == x.Id && y.Currency != FeeCurrency.RMB_CODE && y.Currency != FeeCurrency.USD_CODE) .Select(y => SqlFunc.AggregateSum(y.ApplyAmount)), Note = x.Note, //备注 CustomerAccount = x.CustomerBank.AccountName + "/" + x.CustomerBank.Currency, CustomerBank = x.CustomerBank.BankName, //未开票 UnInvoiceList = SqlFunc.Subqueryable().InnerJoin((d, f) => d.RecordId == f.Id && (f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount) != 0) .GroupBy((d, f) => f.Currency).ToList((d, f) => new CurrencyAmount { Currency = f.Currency, Amount = f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount }), CreateBy = x.CreateBy, //结算人 CreateTime = x.CreateTime, //创建日期 SettlementDate = x.SettlementDate, //结算日期 IsExportVoucher = default, //是否导出凭证 Currency = x.Currency, //币别 Amount = x.Amount, //原始金额 AccountAmount = x.AccountAmount, //记账资料 PrePayAmount = x.PrePayAmount, //预付支资料 AHSRAmount = x.AHSRAmount, //实收支资料 FinancialAmount = x.FinancialAmount,//财务费用 AdvanceAmount = x.AdvanceAmount, //预收支资料 IsLocked = x.IsLocked, //锁定状态 LockTime = x.LockTime, LockUserId = x.LockUserId, UnlockTime = x.UnlockTime, UnlockUserId = x.UnlockUserId, IsVoucherDisabled = x.IsVoucherDisabled, //禁用凭证 SaleDeptId = x.SaleDeptId, //所属分部 LedgerVoucherNO = x.LedgerVoucherNO //总账凭证号 }); var whereList = request.GetConditionalModels(Db); var result = await query.Where(whereList).ToQueryPageAsync(request.PageCondition); if (result.Data.Count > 0) { //关联用户名称 var userIds = result.Data.Select(x => x.CreateBy) .Union(result.Data.Where(x => x.LockUserId.HasValue).Select(x => x.LockUserId.Value)) .Union(result.Data.Where(x => x.UnlockUserId.HasValue).Select(x => x.UnlockUserId.Value)) .Distinct(); var users = await Db.Queryable().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync(); var orgIds = result.Data.Select(x => x.SaleDeptId).Distinct().ToList(); var orgs = await Db.Queryable().Where(x => orgIds.Contains(x.Id)).Select(x => new { x.Id, x.OrgName }).ToListAsync(); foreach (var item in result.Data) { item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName; item.LockUser = users.Find(x => x.Id == item.LockUserId)?.UserName; item.UnlockUser = users.Find(x => x.Id == item.UnlockUserId)?.UserName; item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName; } } return result; } /// /// 获取付费结算单 /// /// 结算单ID /// public async Task> GetAsync(long id) { var model = await TenantDb.Queryable().Select(x => new PaymentSettlementDto { Id = x.Id, ApplicationNO = x.ApplicationNO, //申请编号 SettlementNO = x.SettlementNO, //结算单号 CustomerId = x.CustomerId, //结算单位 CustomerName = x.CustomerName, Mode = x.Mode, //结算类型 SettlementDate = x.SettlementDate, //结算日期 SettlementTypeId = x.SettlementTypeId, //结算方式 CustomerBankId = x.CustomerBankId, //客户银行 Account = x.Account, //客户账户 Currency = x.Currency, //币别 Amount = x.Amount, //金额 ExchangeRate = x.ExchangeRate, //汇率 IsLocked = x.IsLocked, //锁定状态 SaleDeptId = x.SaleDeptId, //所属分部 BillType = x.BillType, //单据类型 Category = x.Category, //业务类别 LedgerVoucherNO = x.LedgerVoucherNO, //总账凭证号 RelativeNO = x.RelativeNO, //相关号码 InvoiceAmount = x.InvoiceAmount, InvoiceDate = x.InvoiceDate, InvoiceNO = x.InvoiceNO, Note = x.Note, //备注 AccountAmount = x.AccountAmount, //记账资料 AccountCurrency = x.AccountCurrency, AccountRate = x.AccountRate, PrePayAmount = x.PrePayAmount, //预付支资料 PrePayCurrency = x.PrePayCurrency, PrePayRate = x.PrePayRate, AHSRAmount = x.AHSRAmount, //实收支资料 AHSRCurrency = x.AHSRCurrency, AHSRRate = x.AHSRRate, FinancialAmount = x.FinancialAmount,//财务费用 FinancialCurrency = x.FinancialCurrency, FinancialRate = x.FinancialRate, AdvanceAmount = x.AdvanceAmount, //预收支资料 AdvanceCurrency = x.AdvanceCurrency, AdvanceRate = x.AdvanceRate, }).FirstAsync(x => x.Id == id && x.Mode == SettlementMode.Payment); if (model != null) { if (model.Details.Count > 0) { //关联用户名称 var userIds = model.Details.Select(x => x.CreateBy).Distinct(); var users = await Db.Queryable().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync(); foreach (var item in model.Details) { item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName; } } } return DataResult.Success(model); } /// /// 获取付费结算明细 /// /// /// public async Task>> GetDetailsAsync(PageRequest request) { var list = await TenantDb.Queryable() .InnerJoin((d, pd) => d.DetailId == pd.Id) .InnerJoin((d, pd, pa) => pd.ApplicationId == pa.Id) .Where(d => d.ApplicationId == request.OtherQueryCondition) .Select((d, pd, pa) => new { d.Id, d.ApplicationId, d.ApplyAmount, d.Currency, d.OriginalCurrency, d.OriginalAmount, pa.ApplicationNO, pa.Status, pa.CreateTime, pa.CreateBy, pa.PaymentDate, pa.Note }).ToListAsync(); var gp = list.GroupBy(x => x.ApplicationId); var details = new List(); foreach (var g in gp) { var firstItem = g.FirstOrDefault(); var dto = new SettlementDetailDto { ApplicationId = g.Key, Ids = g.Select(x => x.Id), RMBApplyAmount = g.Where(x => x.OriginalCurrency == FeeCurrency.RMB_CODE).Sum(x => x.ApplyAmount), USDApplyAmount = g.Where(x => x.OriginalCurrency == FeeCurrency.USD_CODE).Sum(x => x.ApplyAmount), ApplicationNO = firstItem.ApplicationNO, Status = firstItem.Status, CreateTime = firstItem?.CreateTime, CreateBy = firstItem?.CreateBy, PaymentDate = firstItem?.PaymentDate, Note = firstItem?.Note }; //包含多个币别 if (g.GroupBy(x => x.OriginalCurrency).Select(x => x.Key).Count() > 1) { //原始币别=不等于结算单币别的首个币别(参考DS7) dto.OriginalCurrency = g.Select(x => x.OriginalCurrency).FirstOrDefault(); //原始金额=当前结算单的币别合计 dto.OriginalAmount = g.Sum(x => x.ApplyAmount); } else { dto.OriginalCurrency = firstItem?.OriginalCurrency; dto.OriginalAmount = g.Where(x => x.OriginalCurrency == dto.OriginalCurrency).Sum(x => x.ApplyAmount); } //结算金额=原申请的原始币别合计 dto.SettlementAmount = g.Where(x => x.OriginalCurrency == dto.OriginalCurrency).Sum(x => x.ApplyAmount); details.Add(dto); } return DataResult>.Success(details); } /// /// 获取付费申请分页列表 /// /// /// public async Task>> GetApplicationListAsync(PageRequest request) { var query = TenantDb.Queryable() .InnerJoinIF(request.OtherQueryCondition != null && request.OtherQueryCondition.PortId.HasValue, (a, d) => a.Id == d.ApplicationId) .InnerJoinIF(request.OtherQueryCondition != null && request.OtherQueryCondition.PortId.HasValue, (a, d, f) => d.RecordId == f.Id) .InnerJoinIF(request.OtherQueryCondition != null && request.OtherQueryCondition.PortId.HasValue, (a, d, f, s) => f.BusinessId == s.Id && (s.LoadPortId == request.OtherQueryCondition.PortId.Value || s.DischargePortId == request.OtherQueryCondition.PortId.Value)) .GroupByIF(request.OtherQueryCondition != null && request.OtherQueryCondition.PortId.HasValue, (a, d, s) => a.Id) .Select(a => new PaymentApplicationDtoV2 { Id = a.Id, ApplicationNO = a.ApplicationNO, Status = a.Status, CustomerId = a.CustomerId, CustomerName = a.CustomerName, //结算单位 CustomerBankId = a.CustomerBankId, CustomerBankName = a.CustomerBank.BankName, //结算对象银行 CustomerAccount = a.CustomerBank.Account, //结算对象账号 Currency = a.Currency, AmountRMB = a.AmountRMB.GetValueOrDefault(), //RMB申请金额 AmountUSD = a.AmountUSD.GetValueOrDefault(), //USD申请金额 //RMB未结金额 UnSettledRMB = SqlFunc.Subqueryable().Where(d => d.Currency == FeeCurrency.RMB_CODE) .Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)), //USD未结金额 UnSettledUSD = SqlFunc.Subqueryable().Where(d => d.Currency == FeeCurrency.USD_CODE) .Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)), SaleDeptId = a.SaleDeptId, //所属分部 SettlementTypeId = a.SettlementTypeId, SettlementTypeName = a.SettlementType.StlName, //结算方式 CreateBy = a.CreateBy, //申请人 CreateTime = a.CreateTime, //申请日期 PayAmount = 0, //审核实付金额 PaymentDate = a.PaymentDate, //申请支付日期 AuditerId = a.AuditerId, AuditerName = a.AuditerName, AuditTime = a.AuditTime, Note = a.Note }); if (request.OtherQueryCondition != null && request.OtherQueryCondition.UnsettledOnly) query = query.Where(a => a.Status == PaymentApplicationStatus.AuditPassed || a.Status == PaymentApplicationStatus.PartialSettlement); else query = query.Where(a => a.Status == PaymentApplicationStatus.AuditPassed || a.Status == PaymentApplicationStatus.PartialSettlement || a.Status == PaymentApplicationStatus.SettlementCompleted); var whereList = request.GetConditionalModels(Db); var result = await query.Where(whereList).ToQueryPageAsync(request.PageCondition); if (result.Data.Count > 0) { var userIds = result.Data.Select(x => x.CreateBy).Distinct(); var users = await Db.Queryable().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync(); var orgIds = result.Data.Select(x => x.SaleDeptId).Where(x => x.HasValue).Distinct().ToList(); var orgs = await Db.Queryable().Where(x => orgIds.Contains(x.Id)).Select(x => new { x.Id, x.OrgName }).ToListAsync(); foreach (var item in result.Data) { item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName; item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName; item.SettlementRMB = item.UnSettledRMB; item.SettlementUSD = item.UnSettledUSD; } } return result; } /// /// 获取费用申请明细 /// /// 申请单ID /// public async Task>> GetApplicationDetailsAsync(long id) { var details = await TenantDb.Queryable().Where(d => d.ApplicationId == id && d.Category == DetailCategory.PaidApplication && (d.ApplyAmount - d.ProcessedAmount) != 0) .LeftJoin((d, f) => d.RecordId == f.Id) .Select((d, f) => new PaymentApplicationDetailDto { Id = d.Id, ApplicationId = d.ApplicationId, BusinessId = f.BusinessId, BusinessType = f.BusinessType, RecordId = d.RecordId, FeeName = d.FeeName, FeeType = d.FeeType, //收付 Amount = d.ApplyAmount, //申请金额 ApplyAmount = f.SettlementAmount, //已结算金额 RestAmount = d.ApplyAmount - d.ProcessedAmount, //剩余结算金额 CustomerId = f.CustomerId, CustomerName = d.CustomerName, OriginalCurrency = d.OriginalCurrency, //原始币别 OriginalRate = f.ExchangeRate, //原始汇率 ExchangeRate = d.ExchangeRate, //折算汇率 OriginalAmount = d.OriginalAmount //原始金额 }).ToListAsync(); await FulfillDetailsAsync(details); return DataResult>.Success(details); } /// /// 获取费用明细 /// /// 申请单明细ID /// public async Task>> GetApplicationDetailsAsync(long[] ids) { var details = await TenantDb.Queryable().Where(d => ids.Contains(d.Id) && d.Category == DetailCategory.PaidApplicationSettlement) .LeftJoin((d, f) => d.RecordId == f.Id) .LeftJoin((d, f, b) => f.BusinessId == b.BusinessId && f.BusinessType == b.BusinessType) .LeftJoin((d, f, b, p) => d.ApplicationId == p.Id) .Select((d, f, b, p) => new PaymentApplicationDetailDto { Id = d.Id, ApplicationId = d.ApplicationId, BusinessId = f.BusinessId, BusinessType = f.BusinessType, RecordId = d.RecordId, FeeName = d.FeeName, FeeType = d.FeeType, //收付 ApplyAmount = d.ApplyAmount, //结算金额 CustomerId = f.CustomerId, CustomerName = d.CustomerName, OriginalCurrency = d.OriginalCurrency, //原始币别 OriginalRate = f.ExchangeRate, //原始汇率 ExchangeRate = d.ExchangeRate, //折算汇率 OriginalAmount = d.OriginalAmount, //原始金额 InvoiceNO = p.InvoiceNO //发票号 }).ToListAsync(); await FulfillDetailsAsync(details); return DataResult>.Success(details); } async Task FulfillDetailsAsync(List details) { if (details.Count == 0) return; var gList = details.GroupBy(x => x.BusinessType); foreach (var g in gList) { var ids = g.Select(x => x.BusinessId); switch (g.Key) { case BusinessType.OceanShippingExport: var list1 = await TenantDb.Queryable().Where(s => ids.Contains(s.Id)) .LeftJoin((s, cs) => s.SourceId == cs.Id) .Select((s, cs) => new { s.Id, s.AccountDate,//会计期间 s.Vessel, //船名 s.Voyno, //航次 s.CustomerName, s.MBLNO, //主提单号 s.CustomerNo, //委托编号 s.ETD, //开船日期 s.Sale, //揽货人 cs.SourceName, //业务来源 s.Note }).ToListAsync(); foreach (var item in g) { var biz = list1.Find(x => x.Id == item.BusinessId); if (biz != null) { item.MBLNO = biz.MBLNO; item.CustomerNo = biz.CustomerNo; item.ClientName = biz.CustomerName; item.ETD = biz.ETD; item.SourceName = biz.SourceName; item.SaleName = biz.Sale; item.AccountDate = biz.AccountDate; item.Vessel = biz.Vessel; item.Voyage = biz.Voyno; item.Note = biz.Note; } } break; case BusinessType.OceanShippingImport: break; } } } protected override async Task PreSaveAsync(PaymentSettlement settlement) { var appIds = settlement.Details.Select(x => x.ApplicationId).Distinct(); var appList = await TenantDb.Queryable().Where(x => appIds.Contains(x.Id)) .Select(x => new { x.Id, x.Status, x.CustomerId, x.CustomerName, }).ToListAsync(); if (appList.Count == 0) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); if (appList.Exists(x => x.Status != PaymentApplicationStatus.AuditPassed && x.Status != PaymentApplicationStatus.PartialSettlement)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationSelectStatusError)); if (appList.GroupBy(x => x.CustomerId).Select(x => x.Key).Count() > 1) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.DetailCustomerOnlyOne)); //获取剩余待结算金额 var ids2 = settlement.Details.Select(x => x.DetailId); var appDetails = await TenantDb.Queryable().Where(x => ids2.Contains(x.Id) && x.Category == DetailCategory.PaidApplication) .Select(x => new { x.Id, //RestAmount = x.ApplyAmount - x.ProcessedAmount, OriginalRestAmount = x.OriginalAmount - x.OriginalProcessedAmount }).ToListAsync(); StringBuilder sb = new(); foreach (var detail in settlement.Details) { var item = appDetails.Find(x => x.Id == detail.DetailId); if (item == null) { sb.Append(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.EmptyData))); break; } if (detail.OriginalAmount > 0 && detail.OriginalAmount > item.OriginalRestAmount) { sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), detail.FeeName); sb.Append(";"); continue; } else if (detail.OriginalAmount < 0 && detail.OriginalAmount < item.OriginalRestAmount) { sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), detail.FeeName); sb.Append(";"); continue; } detail.Category = DetailCategory.PaidFreeSettlement; } return sb.Length > 0 ? DataResult.Failed(sb.ToString()) : DataResult.Success; } protected override async Task OnSaveAsync(PaymentSettlement settlement) { //更新申请明细的已处理金额 var list = settlement.Details.Select(x => new ApplicationDetail { Id = x.DetailId.Value, ProcessedAmount = x.ApplyAmount, OriginalProcessedAmount = x.OriginalAmount }).ToList(); await TenantDb.Updateable(list) .PublicSetColumns(x => x.ProcessedAmount, "+") .PublicSetColumns(x => x.OriginalProcessedAmount, "+") .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) .ExecuteCommandAsync(); } protected override async Task PostSaveAsync(PaymentSettlement settlement) { //回写付费申请的状态 var ids = settlement.Details.Select(x => x.DetailId); var appIds = await TenantDb.Queryable().Where(x => ids.Contains(x.Id) && x.Category == DetailCategory.PaidApplication) .Select(x => x.ApplicationId).ToListAsync(); var details = await TenantDb.Queryable().Where(x => appIds.Contains(x.ApplicationId) && x.Category == DetailCategory.PaidApplication).GroupBy(x => x.ApplicationId).Select(x => new { x.ApplicationId, Count = SqlFunc.AggregateCount(x.Id), ProcessedCount = SqlFunc.Subqueryable().Where(y => y.ApplicationId == x.ApplicationId && y.Category == DetailCategory.PaidApplication && y.OriginalAmount - y.OriginalProcessedAmount == 0).Count() }).ToListAsync(); List applications = []; foreach (var item in details) { if (item.Count == 0 || item.ProcessedCount == 0) continue; var entity = new PaymentApplication { Id = item.ApplicationId }; if (item.Count == item.ProcessedCount) { entity.Status = PaymentApplicationStatus.SettlementCompleted; } else if (item.ProcessedCount > 0) { entity.Status = PaymentApplicationStatus.PartialSettlement; } applications.Add(entity); } await TenantDb.Updateable(applications).UpdateColumns(x => new { x.Status }).ExecuteCommandAsync(); return await base.PostSaveAsync(settlement); } protected override DataResult PreDelete(List settlements) { if (settlements.Any(x => x.IsLocked)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.SettlementIsLocked)); return DataResult.Success; } protected override async Task OnDeleteDetailAsync(List settlements) { await base.OnDeleteDetailAsync(settlements); //还原付费申请明细 var list = settlements.FindAll(x => x.Mode == SettlementMode.Payment); if (list.Count > 0) { var items = list.SelectMany(x => x.Details); var ids = items.Select(x => x.DetailId); var details = TenantDb.Queryable().Where(x => ids.Contains(x.Id) && x.Category == DetailCategory.PaidApplication) .Select(x => new ApplicationDetail { Id = x.Id, ProcessedAmount = x.ProcessedAmount, OriginalProcessedAmount = x.OriginalProcessedAmount }).ToList(); foreach (var detail in details) { var item = items.FirstOrDefault(x => x.DetailId == detail.Id); detail.ProcessedAmount -= item.ApplyAmount; detail.OriginalProcessedAmount -= item.OriginalAmount; } await TenantDb.Updateable(details) .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) .ExecuteCommandAsync(); } } } }