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.Dtos; 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 PaymentFreeSettlementService : SettlementService, IPaymentFreeSettlementService { /// /// 初始化 /// /// public PaymentFreeSettlementService(IServiceProvider provider) : base(provider) { } /// /// 获取待结算业务分页列表 /// /// /// /// 查询条件请参考中定义的字段 public async Task>> GetBizListAsync(PageRequest request) { var whereList = request.GetConditionalModels(Db); var result = await CreateBizQuery().Where(whereList).GroupBy(x => new { x.BusinessId, x.BusinessType }) .Select().ToQueryPageAsync(request.PageCondition); if (result.Data.Count > 0) { //获取统计信息 var ids = result.Data.Select(x => x.BusinessId); var types = result.Data.Select(x => x.BusinessType).Distinct(); var fees = await TenantDb.Queryable().Where(x => ids.Contains(x.BusinessId) && types.Contains(x.BusinessType)) .Select(x => new { x.BusinessId, x.BusinessType, x.Currency, x.FeeType, //x.Amount, //x.OrderAmount, //x.SettlementAmount, //x.OrderSettlementAmount, x.InvoiceAmount, UnSettledAmount = x.Amount - x.SettlementAmount - x.OrderAmount + x.OrderSettlementAmount //剩余待结算 }).ToListAsync(); //关联用户名称 var userIds = result.Data.Select(x => x.CreateBy) .Union(result.Data.Select(x => x.OperatorId)) .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(); 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.UnpaidRMB = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency == RMB_CODE && x.FeeType == FeeType.Payable).Sum(x => x.UnSettledAmount); item.UnpaidUSD = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency == USD_CODE && x.FeeType == FeeType.Payable).Sum(x => x.UnSettledAmount); item.UnpaidOther = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency != RMB_CODE && x.Currency != USD_CODE && x.FeeType == FeeType.Payable).Sum(x => x.UnSettledAmount); item.UnchargedRMB = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency == RMB_CODE && x.FeeType == FeeType.Receivable).Sum(x => x.UnSettledAmount); item.UnchargedUSD = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency == USD_CODE && x.FeeType == FeeType.Receivable).Sum(x => x.UnSettledAmount); item.UnchargedOther = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency != RMB_CODE && x.Currency != USD_CODE && x.FeeType == FeeType.Receivable).Sum(x => x.UnSettledAmount); item.UnpaidInvoiceRMB = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency == RMB_CODE && x.FeeType == FeeType.Payable && x.UnSettledAmount == 0).Sum(x => x.InvoiceAmount); item.UnpaidInvoiceUSD = fees.FindAll(x => x.BusinessId == item.BusinessId && x.BusinessType == item.BusinessType && x.Currency == USD_CODE && x.FeeType == FeeType.Payable && x.UnSettledAmount == 0).Sum(x => x.InvoiceAmount); item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName; item.Operator = users.Find(x => x.Id == item.OperatorId)?.UserName; item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName; } } return result; } //创建各项费用数据的查询并集 internal ISugarQueryable CreateBizQuery() { var query1 = TenantDb.Queryable((f, s) => new JoinQueryInfos( JoinType.Inner, s.Id == f.BusinessId && f.BusinessType == BusinessType.OceanShippingExport && f.FeeStatus == FeeStatus.AuditPassed && (f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount) != 0)) .Select((f, s) => new FeeDto { Id = f.Id, FeeId = f.FeeId, FeeCode = f.FeeCode, FeeName = f.FeeName, FeeType = f.FeeType, CustomerId = f.CustomerId, CustomerName = f.CustomerName, BusinessId = f.BusinessId, BusinessType = BusinessType.OceanShippingExport, Currency = f.Currency, DebitNo = f.DebitNo, SaleOrgId = f.SaleOrgId, SaleOrg = f.SaleOrg, CreateBy = f.CreateBy, AccountDate = s.AccountDate, BusinessDate = s.BusinessDate,//业务日期 ClientName = s.CustomerName,//委托单位 CustomerNo = s.CustomerNo, CustomNo = s.CustomNo, DischargePort = s.DischargePort, ETD = s.ETD, HBLNO = s.HBLNO, LoadPort = s.LoadPort, MBLNO = s.MBLNO, OperatorId = s.OperatorId, SaleDeptId = s.SaleDeptId, Sale = s.Sale,//揽货人 Vessel = s.Vessel,//船名 Voyage = s.Voyno,//航次 BookingNo = s.BookingNo, Enterprise = s.Enterprise, }); //海运进口 return TenantDb.UnionAll(new List> { query1 }); } /// /// 根据业务编号及类型获取关联费用记录 /// /// 业务ID与业务类型 /// public async Task> GetFeesAsync(params BizItem[] items) { var bizIds = items.Select(x => x.Id).ToList(); var types = items.Select(x => x.BusinessType).ToList(); var list = await TenantDb.Queryable() .Where(f => bizIds.Contains(f.BusinessId) && types.Contains(f.BusinessType) && f.FeeStatus == FeeStatus.AuditPassed && (f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount) != 0) .Select(f => new FeeItem { Id = f.Id, BusinessId = f.BusinessId, BusinessType = f.BusinessType, CustomerName = f.CustomerName, FeeName = f.FeeName, FeeType = f.FeeType, Amount = f.Amount, Currency = f.Currency, OriginalRate = f.ExchangeRate, RestAmount = f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount, SettlementAmount = f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount, InvoiceAmount = f.InvoiceAmount, AccTaxRate = f.AccTaxRate, Remark = f.Remark }).ToListAsync(); return DataResult.Success(new FeeForm(list)); } /// /// 获取付费自由结算及其明细 /// /// 结算单ID /// public async Task> GetAsync(long id) { var model = await TenantDb.Queryable().Select(x => new FreePaymentSettlementDto { 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) { model.Details = await TenantDb.Queryable().Where(x => x.ApplicationId == id && x.Category == FeeCategory.PaidFreeSettlement) .InnerJoin((d, f) => d.RecordId == f.Id) .Select((d, f) => new FreeSettlementDetailDto { Id = d.Id, RecordId = f.Id, BusinessId = f.BusinessId, BusinessType = f.BusinessType, CustomerName = d.CustomerName, FeeName = d.FeeName, FeeType = d.FeeType, ExchangeRate = d.ExchangeRate, OriginalAmount = d.OriginalAmount, OriginalCurrency = d.OriginalCurrency, OriginalRate = f.ExchangeRate, ApplyAmount = d.ApplyAmount, Currency = d.Currency, Note = d.Note }).ToListAsync(); var gList = model.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(x => ids.Contains(x.Id)) .LeftJoin((s, cs) => s.SourceId == cs.Id) .Select((s, cs) => new { s.Id, s.MBLNO, s.HBLNO, s.CustomerNo, ClientName = s.CustomerName, s.ETD, cs.SourceName, s.Sale, s.AccountDate, s.Vessel, Voyage = s.Voyno, s.Carrier, s.Enterprise, s.CustomNo }).ToListAsync(); foreach (var item in g) { var biz = list1.Find(x => x.Id == item.BusinessId); if (biz != null) { item.MBLNO = biz.MBLNO; item.HBLNO = biz.HBLNO; item.CustomerNo = biz.CustomerNo; item.ClientName = biz.ClientName; item.ETD = biz.ETD; item.SourceName = biz.SourceName; item.Sale = biz.Sale; item.AccountDate = biz.AccountDate; item.Vessel = biz.Vessel; item.Voyage = biz.Voyage; item.Carrier = biz.Carrier; item.Enterprise = biz.Enterprise; item.CustomNo = biz.CustomNo; } } break; case BusinessType.OceanShippingImport: break; } } model.SummaryItems = model.Details.GroupBy(x => new { x.FeeType, x.Currency }).Select(x => new SummaryItem { FeeType = x.Key.FeeType, Currency = x.Key.Currency, Amount = x.Sum(y => y.ApplyAmount) }).ToList(); } return DataResult.Success(model); } /// /// 提交结算单 /// /// /// public override async Task> SaveAsync(SettlementRequest request) { var settlement = request.Settlement; if (settlement.SettlementDate == default) settlement.SettlementDate = DateTime.Now; settlement.Mode = SettlementMode.Payment; settlement.BillType = SettlementBillType.Payment; if (request.Details?.Count > 0) { 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.Amount == 0 || x.OriginalAmount == 0)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.AmountCannotBeZero)); if (settlement.Id == 0) { var app = appList[0]; settlement.CustomerId = app.CustomerId; settlement.CustomerName = app.CustomerName; } 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.PaidFreeSettlement, ApplyAmount = x.Amount, Currency = x.Currency, ExchangeRate = x.ExchangeRate, OriginalAmount = x.OriginalAmount, OriginalCurrency = x.OriginalCurrency ?? (settlement.Currency.IsNullOrEmpty() ? x.Currency : settlement.Currency), }).ToList(); if (settlement.Details.Any(x => x.OriginalCurrency.IsNullOrEmpty())) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.OriginalCurrencyCanNotNull)); //获取剩余待结算金额 var ids2 = settlement.Details.Select(x => x.DetailId); 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.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; } } 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.IsLocked, x.CreateBy, x.CreateTime, x.Deleted, x.DeleteBy, x.DeleteTime }).ExecuteCommandAsync(); } if (request.Details?.Count > 0) { //更新申请明细的已处理金额 var list = request.Details.Select(x => new ApplicationDetail { Id = x.Id, ProcessedAmount = x.Amount, OriginalProcessedAmount = x.OriginalAmount }).ToList(); await TenantDb.Updateable(list) .PublicSetColumns(x => x.ProcessedAmount, "+") .PublicSetColumns(x => x.OriginalProcessedAmount, "+") .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) .ExecuteCommandAsync(); //更新费用记录的已结算金额 var fees = request.Details.Select(x => new FeeRecord { Id = x.RecordId, SettlementAmount = x.OriginalAmount }).ToList(); 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)); } //finally //{ // if (request.Details?.Count > 0) // await WriteBackStatusAsync(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 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(); } } }