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 == RMB_CODE) .Select(y => SqlFunc.AggregateSum(y.ApplyAmount)), USDAmount = SqlFunc.Subqueryable().Where(y => y.ApplicationId == x.Id && y.Currency == USD_CODE) .Select(y => SqlFunc.AggregateSum(y.ApplyAmount)), OtherAmount = SqlFunc.Subqueryable().Where(y => y.ApplicationId == x.Id && y.Currency != RMB_CODE && y.Currency != 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(); if (model != null) { var details = await TenantDb.Queryable().Where(d => d.ApplicationId == id) .LeftJoin((d, pd) => d.DetailId == pd.Id) .LeftJoin((d, pd, pa) => pd.ApplicationId == pa.Id) .Select((d, pd, pa) => new { d.Id, d.ApplicationId, d.ApplyAmount, //d.Currency, d.OriginalCurrency, d.OriginalAmount, pa.CreateTime, pa.CreateBy, pa.PaymentDate, pa.Note }).ToListAsync(); var gp = details.GroupBy(x => x.ApplicationId); model.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 == RMB_CODE).Sum(x => x.ApplyAmount), USDApplyAmount = g.Where(x => x.OriginalCurrency == USD_CODE).Sum(x => x.ApplyAmount), 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.Where(x => x.OriginalCurrency != model.Currency).Select(x => x.OriginalCurrency).FirstOrDefault(); //原始金额=当前结算单的币别合计 dto.OriginalAmount = g.Where(x => x.OriginalCurrency == model.Currency).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); model.Details.Add(dto); } 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>> GetApplicationListAsync(PageRequest request) { var query = TenantDb.Queryable().Where(a => a.Status == PaymentApplicationStatus.AuditPassed || a.Status == PaymentApplicationStatus.PartialSettlement) .WhereIF(request.OtherQueryCondition, a => a.Status != PaymentApplicationStatus.SettlementCompleted && SqlFunc.Subqueryable().Where(d => d.ApplicationId == a.Id && (d.ApplyAmount - d.ProcessedAmount) != 0).Any()) .Select(a => new PaymentApplicationDto { Id = a.Id, ApplicationNO = a.ApplicationNO, Status = a.Status, CustomerId = a.CustomerId, CustomerName = a.CustomerName, //结算单位 CustomerBankId = a.CustomerBankId, CustomerBank = a.CustomerBank.BankName, //结算对象银行 CustomerAccount = a.CustomerBank.Account, //结算对象账号 Currency = a.Currency, AmountRMB = a.AmountRMB, //RMB申请金额 AmountUSD = a.AmountUSD, //USD申请金额 //RMB未结金额 UnSettlementRMB = SqlFunc.Subqueryable().Where(d => d.Currency == RMB_CODE) .Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)), //USD未结金额 UnSettlementUSD = SqlFunc.Subqueryable().Where(d => d.Currency == 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 }); 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; } } return result; } /// /// 获取费用明细 /// /// 申请单ID /// public async Task>> GetDetailsAsync(long id) { var details = await TenantDb.Queryable().Where(d => d.ApplicationId == id && (d.ApplyAmount - d.ProcessedAmount) != 0) .InnerJoin((d, f) => d.RecordId == f.Id) .InnerJoin((d, f, b) => f.BusinessId == b.BusinessId && f.BusinessType == b.BusinessType) .Select((d, f, b) => new PaymentApplicationDetailDto { Id = d.Id, ApplicationId = d.ApplicationId, BusinessId = d.BusinessId, BusinessType = d.BusinessType, RecordId = d.RecordId, FeeName = d.FeeName, FeeType = d.FeeType, //收付 Amount = d.ApplyAmount, //申请金额 SettlementAmount = 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(); if (details.Count > 0) { 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; } } } return DataResult>.Success(details); } /// /// 提交结算单 /// /// /// public async Task> SaveAsync(SettlementRequest request) { var appIds = request.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)); //申请金额禁止为0 if (request.Details.Any(x => x.SettlementAmount == 0)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.AmountCannotBeZero)); var ids = request.Details.Select(x => x.RecordId).Distinct().ToList(); var fees = await TenantDb.Queryable().Where(x => ids.Contains(x.Id)).Select(x => new FeeRecord { Id = x.Id, Currency = x.Currency, OrderSettlementAmount = x.OrderSettlementAmount, SettlementAmount = x.SettlementAmount }).ToListAsync(); if (fees.Count != request.Details.Count) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordNone)); var settlement = request.Settlement; if (settlement.SettlementDate == default) settlement.SettlementDate = DateTime.Now; if (settlement.Id == 0) { var app = appList[0]; settlement.CustomerId = app.CustomerId; settlement.CustomerName = app.CustomerName; } settlement.Mode = SettlementMode.Payment; settlement.BillType = SettlementBillType.Payment; settlement.Details = request.Details.Select(x => new ApplicationDetail { ApplicationId = x.ApplicationId, DetailId = x.Id, RecordId = x.RecordId, BusinessId = x.BusinessId, BusinessType = x.BusinessType, CustomerName = x.CustomerName ?? settlement.CustomerName, FeeId = x.FeeId, FeeName = x.FeeName, FeeType = x.FeeType, Category = FeeCategory.PaidApplicationSettlement, ApplyAmount = x.RestAmount.GetValueOrDefault(), Currency = x.Currency, ExchangeRate = x.ExchangeRate, OriginalAmount = x.OriginalAmount, OriginalCurrency = x.OriginalCurrency }).ToList(); //获取剩余待结算金额 var ids2 = settlement.Details.Select(x => x.Id); var appDetails = await TenantDb.Queryable().Where(x => ids2.Contains(x.Id) && x.Category == FeeCategory.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.Id); 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; } } if (sb.Length > 0) return DataResult.Failed(sb.ToString()); settlement.Amount = settlement.Details.Sum(x => x.ApplyAmount); await TenantDb.Ado.BeginTranAsync(); try { //关联导航属性插入 if (settlement.Id == 0) { //创建时需要生成申请单编号 var sequence = CommonService.Value.GetSequenceNext(); if (!sequence.Succeeded) { return DataResult.Failed(sequence.Message, MultiLanguageConst.SequenceSetNotExist); } settlement.ApplicationNO = "CP" + SnowFlakeSingle.Instance.NextId(); //申请编号 settlement.SettlementNO = sequence.Data; //结算单号 await TenantDb.InsertNav(settlement).Include(x => x.Details).ExecuteCommandAsync(); } else { if (settlement.Details.Count > 0) await TenantDb.Insertable(settlement.Details).ExecuteCommandAsync(); await TenantDb.Updateable(settlement).IgnoreColumns(x => new { x.ApplicationNO, x.SettlementNO, x.CreateBy, x.CreateTime, x.Deleted, x.DeleteBy, x.DeleteTime }).ExecuteCommandAsync(); } //更新申请明细的已处理金额 var list = request.Details.Select(x => new ApplicationDetail { Id = x.Id, ProcessedAmount = x.SettlementAmount, OriginalProcessedAmount = x.OriginalAmount }).ToList(); await TenantDb.Updateable(list) .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) .ExecuteCommandAsync(); if (fees != null && fees.Count > 0) await TenantDb.Updateable(fees) .PublicSetColumns(x => x.SettlementAmount, "+") .UpdateColumns(x => new { x.SettlementAmount }) .ExecuteCommandAsync(); await TenantDb.Ado.CommitTranAsync(); return DataResult.Success(settlement); } catch (Exception ex) { await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } 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 detailList = settlements.SelectMany(x => x.Details); //还原费用表的已结算金额 var fees = detailList.Select(x => new FeeRecord { Id = x.RecordId, SettlementAmount = x.OriginalAmount }).ToList(); await TenantDb.Updateable(fees) .PublicSetColumns(it => it.SettlementAmount, "-") .UpdateColumns(x => new { x.SettlementAmount }) .ExecuteCommandAsync(); } } }