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.Application.Interface; using DS.WMS.Core.Fee.Dtos; using DS.WMS.Core.Fee.Entity; using DS.WMS.Core.Info.Entity; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Sys.Entity; using SqlSugar; namespace DS.WMS.Core.Application.Method { /// /// 付费申请实现 /// public class PaymentApplicationService : ApplicationService, IPaymentApplicationService { /// /// 初始化 /// /// public PaymentApplicationService(IServiceProvider serviceProvider) : base(serviceProvider) { } /// /// 获取分页列表 /// /// /// public async Task>> GetListAsync(PageRequest request) { var query = CreateListQuery(); if (!request.QueryCondition.IsNullOrEmpty()) { var whereList = Db.ConfigQuery.Context.Utilities.JsonToConditionalModels(request.QueryCondition); query = query.Where(whereList); } var result = await query.GroupBy(x => x.Id).ToQueryPageAsync(request.PageCondition); if (result.Data.Count > 0) { 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.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName; } } return result; } internal ISugarQueryable CreateListQuery() { var query1 = TenantDb.Queryable() .InnerJoin((a, d) => a.Id == d.ApplicationId) .LeftJoin((a, d, s) => d.BusinessId == s.Id) .LeftJoin((a, d, s, b) => a.CustomerBankId == b.Id) .Select((a, d, s, b) => new PaymentApplicationDto { Id = a.Id, ApplicationNO = a.ApplicationNO, CustomerId = a.CustomerId, CustomerName = a.CustomerName, AmountOther = a.AmountOther, AmountRMB = a.AmountRMB, AmountUSD = a.AmountUSD, SaleDeptId = a.SaleDeptId, CreateBy = a.CreateBy, CreateTime = a.CreateTime, Currency = a.Currency, ExchangeRate = a.ExchangeRate, Reason = a.Reason, Status = a.Status, AuditerId = a.AuditerId, AuditerName = a.AuditerName, AuditTime = a.AuditTime, IsInvoiceReceived = a.IsInvoiceReceived, ClientName = s.CustomerName, IsPrinted = a.IsPrinted, PrintTimes = a.PrintTimes, InvoiceAmount = a.InvoiceAmount, InvoiceDate = a.InvoiceDate, InvoiceNO = a.InvoiceNO, PaymentDate = a.PaymentDate, Note = a.Note, BillNO = s.CustomerNo, //业务编号=委托编号 CustomerBankId = a.CustomerBankId, CustomerBank = b.BankName, CustomerAccount = b.Account, //汇总项 RestAmountRMB = SqlFunc.Subqueryable().Where(f => f.Id == d.RecordId && f.FeeStatus == FeeStatus.AuditPassed && f.Currency == RMB_CODE).Select(f => SqlFunc.AggregateSum(f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount)), RestAmountUSD = SqlFunc.Subqueryable().Where(f => f.Id == d.RecordId && f.FeeStatus == FeeStatus.AuditPassed && f.Currency == USD_CODE).Select(f => SqlFunc.AggregateSum(f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount)), RestAmountOther = SqlFunc.Subqueryable().Where(f => f.Id == d.RecordId && f.FeeStatus == FeeStatus.AuditPassed && f.Currency != RMB_CODE && f.Currency != USD_CODE).Select(f => SqlFunc.AggregateSum(f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount)) }); return TenantDb.UnionAll(new List> { query1 }); } /// /// 获取待付费的业务列表(编辑用) /// /// /// public async Task>> GetBizListAsync(PageRequest request) { var queryList = CreateBizQuery(); if (!request.QueryCondition.IsNullOrEmpty()) { var whereList = Db.ConfigQuery.Context.Utilities.JsonToConditionalModels(request.QueryCondition); queryList = queryList.Where(whereList); } var result = await queryList.ToQueryPageAsync(request.PageCondition); if (result.Data.Count > 0) { //关联用户名称 var userIds = result.Data.Where(x => x.OperatorId.HasValue).Select(x => x.OperatorId.Value) .Union(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).Distinct(); var orgs = await Db.Queryable().Where(x => userIds.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; if (item.OperatorId.HasValue) item.Operator = users.Find(x => x.Id == item.OperatorId.Value)?.UserName; item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName; } } return result; } //创建各项业务数据的查询并集 internal ISugarQueryable CreateBizQuery() { //海运出口 var query1 = TenantDb.Queryable() .InnerJoin((s, f) => s.Id == f.BusinessId && f.BusinessType == BusinessType.OceanShippingExport) .Where((s, f) => f.FeeStatus == FeeStatus.AuditPassed) .GroupBy((s, f) => s.Id) .Select((s, f) => new BizPaymentApplication { Id = s.Id, AccountDate = s.AccountDate, BusinessType = BusinessType.OceanShippingExport, CntrTotal = s.CntrTotal, CreateBy = s.CreateBy, CustomerId = s.CustomerId,//费用对象 CustomerName = s.CustomerName, CustomerNo = s.CustomerNo, DischargePort = s.DischargePort, ETD = s.ETD, HBLNO = s.HBLNO, LoadPort = s.LoadPort, MBLNO = s.MBLNO, OperatorId = s.OperatorId, SaleDeptId = s.SaleDeptId, SaleId = s.SaleId, SaleName = s.Sale,//揽货人 Vessel = s.Vessel,//船名 Voyage = s.Voyno,//航次 BookingNO = s.BookingNo, StlName = s.StlName, FeeType = f.FeeType, FeeId = f.FeeId, Currency = f.Currency, IsAdvancedPay = f.IsAdvancedPay, IsInvoice = f.IsInvoice, //统计项 UnpaidRMB = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Payable && f.Currency == RMB_CODE).Select(f => SqlFunc.AggregateSumNoNull(f.Amount)), UnpaidUSD = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Payable && f.Currency == USD_CODE).Select(f => SqlFunc.AggregateSumNoNull(f.Amount)), UnpaidOther = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Payable && f.Currency != USD_CODE && f.Currency != RMB_CODE).Select(f => SqlFunc.AggregateSumNoNull(f.Amount)), UnreceivedRMB = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Receivable && f.Currency == RMB_CODE).Select(f => SqlFunc.AggregateSumNoNull(f.Amount)), UnreceivedUSD = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Receivable && f.Currency == USD_CODE).Select(f => SqlFunc.AggregateSumNoNull(f.Amount)), UnreceivedOther = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Receivable && f.Currency != USD_CODE && f.Currency != RMB_CODE).Select(f => SqlFunc.AggregateSumNoNull(f.Amount)), //UnpaidRMBInv = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && // f.FeeType == FeeType.Payable && f.Currency == "CNY").Select(f => SqlFunc.AggregateSumNoNull(f.InvoiceAmount.Value)), //UnpaidUSDInv = SqlFunc.Subqueryable().Where(f => f.BusinessId == s.Id && f.FeeStatus == FeeStatus.AuditPassed && // f.FeeType == FeeType.Payable && f.Currency == "USD").Select(f => SqlFunc.AggregateSumNoNull(f.InvoiceAmount.Value)) }); //海运进口 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) .Select(f => new FeePaymentDto { RecordId = f.Id, BusinessId = f.BusinessId, BusinessType = f.BusinessType, CustomerName = f.CustomerName, FeeId = f.FeeId, FeeName = f.FeeName, FeeType = f.FeeType, Amount = f.Amount, Currency = f.Currency, OriginalCurrency = f.Currency, OriginalRate = f.ExchangeRate, RestAmount = f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount, InvoiceAmount = f.InvoiceAmount, Remark = f.Remark, CreateBy = f.CreateBy, TaxRate = f.TaxRate }).ToListAsync(); //移除未接金额为0的项 list.RemoveAll(f => f.RestAmount == 0); if (list.Count > 0) { //关联用户名称 var userIds = list.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 list) { item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName; } } return DataResult.Success(new PaymentApplicaitonBiz(list)); } /// /// 获取申请单详情 /// /// 申请单ID /// public async Task> GetAsync(long id) { var dto = await TenantDb.Queryable().LeftJoin((a, b) => a.CustomerBankId == b.Id) .Where((a, b) => a.Id == id).Select((a, b) => new PaymentApplicationDto { Id = a.Id, ApplicationNO = a.ApplicationNO, Currency = a.Currency, CustomerId = a.CustomerId, CustomerName = a.CustomerName, CustomerBankId = a.CustomerBankId, CustomerBank = b.BankAccountNo, Status = a.Status, CreateTime = a.CreateTime, CreateBy = a.CreateBy, AmountRMB = a.AmountRMB, AmountUSD = a.AmountUSD, AmountOther = a.AmountOther, SettlementType = a.SettlementType, PaymentDate = a.PaymentDate, ChequeRemarks = a.ChequeRemarks, InvoiceDate = a.InvoiceDate, InvoiceAmount = a.InvoiceAmount, SaleDeptId = a.SaleDeptId, Note = a.Note }).FirstAsync(); if (dto != null) { dto.Details = await TenantDb.Queryable() .LeftJoin((d, f) => d.RecordId == f.Id) .LeftJoin((d, f, b) => f.BusinessId == b.BusinessId && f.BusinessType == b.BusinessType) .Where(d => d.ApplicationId == id) .Select((d, f, b) => new ApplicationDetailDto { Id = d.Id, RecordId = f.Id, AccTaxRate = f.AccTaxRate, Amount = d.Amount, FeeId = d.FeeId, FeeName = d.FeeName, FeeType = d.FeeType, CustomerId = f.CustomerId, CustomerName = d.CustomerName, OriginalCurrency = d.OriginalCurrency, OriginalRate = f.ExchangeRate, ExchangeRate = d.ExchangeRate, OriginalAmount = d.OriginalAmount, //未申请金额=(金额-结算金额-申请金额+申请金额已结算) RestAmount = f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount, BusinessId = d.BusinessId, BusinessType = d.BusinessType, IsBusinessLocking = b.IsBusinessLocking, IsFeeLocking = b.IsFeeLocking }).ToListAsync(); var gList = dto.Details.GroupBy(x => x.BusinessType).ToList(); foreach (var g in gList) { var ids = g.Select(x => x.BusinessId).ToList(); switch (g.Key) { case BusinessType.OceanShippingExport: var list1 = await TenantDb.Queryable().Where(x => ids.Contains(x.Id)).Select(x => new { x.Id, x.MBLNO, x.CustomerNo, x.CustomerName, x.ETD, x.CntrTotal, x.AccountDate, x.OperatorCode, x.Vessel, x.Voyno, x.Carrier, x.Forwarder }).ToListAsync(); foreach (var item in g) { var biz = list1.Find(x => x.Id == item.BusinessId); if (biz != null) { item.MBLNO = biz.MBLNO; item.CustomerName = biz.CustomerName; item.CustomerNo = biz.CustomerNo; item.ETD = biz.ETD; item.CntrTotal = biz.CntrTotal; item.AccountDate = biz.AccountDate; item.Operator = biz.OperatorCode; item.Vessel = biz.Vessel; item.Voyage = biz.Voyno; item.Carrier = biz.Carrier; item.Forwarder = biz.Forwarder; } } break; case BusinessType.OceanShippingImport: break; } } dto.RestAmountRMB = dto.Details.FindAll(x => x.OriginalCurrency == RMB_CODE).Sum(x => x.RestAmount); dto.RestAmountUSD = dto.Details.FindAll(x => x.OriginalCurrency == USD_CODE).Sum(x => x.RestAmount); dto.AmountOther = dto.Details.FindAll(x => x.OriginalCurrency != RMB_CODE && x.OriginalCurrency != USD_CODE).Sum(x => x.RestAmount); } return DataResult.Success(dto); } protected override async Task> GetDetailsAsync(IEnumerable items) { var ids1 = items.Select(x => x.Id); var ids2 = items.Select(x => x.BusinessType); var list = await TenantDb.Queryable().Where(x => ids1.Contains(x.BusinessId) && ids2.Contains(x.BusinessType) && x.FeeStatus == FeeStatus.AuditPassed) .Select(x => new ApplicationDetail { RecordId = x.Id, Amount = x.Amount - x.SettlementAmount - x.OrderAmount + x.OrderSettlementAmount, Currency = x.Currency, ExchangeRate = x.ExchangeRate, OriginalCurrency = x.Currency }).ToListAsync(); list.RemoveAll(x => x.Amount == 0); foreach (var item in list) item.OriginalAmount = item.Amount; return list; } protected override DataResult PreSave(PaymentApplication application, PaymentApplication dbValue) { if (dbValue != null) { if (dbValue.Status == PaymentApplicationStatus.AuditSubmittd || dbValue.Status == PaymentApplicationStatus.AuditPassed) return DataResult.Failed("只能修改状态为:未提交/审核驳回的申请单"); if (application.Id > 0 && !string.Equals(dbValue.Currency, application.Currency, StringComparison.OrdinalIgnoreCase)) return DataResult.Failed("提交申请单币别需与原申请单币别一致"); } return DataResult.Success; } protected override DataResult CalculateAmount(PaymentApplication application, List fees) { if (fees == null) return DataResult.Success; if (fees.Any(x => x.CustomerId != application.CustomerId)) return DataResult.Failed("申请明细的结算对象需与申请单一致"); StringBuilder sb = new(); foreach (var detail in application.Details) { var fee = fees.Find(x => x.Id == detail.RecordId); if (fee == null) { sb.Append($"未能关联明细【{detail.FeeName}】的费用信息;"); continue; } detail.Record = fee; //未申请金额=总金额-结算金额-申请金额+申请金额已结算 var restAmount = fee.Amount - fee.SettlementAmount - fee.OrderAmount + fee.OrderSettlementAmount; if (restAmount == 0) { sb.Append($"费用【{detail.FeeName}】的金额已全部申请完毕;"); continue; } if (detail.OriginalAmount > 0 && detail.OriginalAmount > restAmount) { sb.Append($"申请单明细【{detail.FeeName}】的申请金额不能超出原费用的金额;"); continue; } if (detail.OriginalAmount < 0 && detail.OriginalAmount < restAmount) { sb.Append($"申请单明细【{detail.FeeName}】的申请金额不能超出原费用的金额;"); continue; } //更新费用记录的已申请金额 fee.OrderAmount += detail.OriginalAmount; //类别固定为付费申请 detail.Category = FeeCategory.PaidApplication; } if (sb.Length > 0) return DataResult.Failed(sb.ToString()); application.AmountRMB = application.Details.Where(x => x.Currency == RMB_CODE).Sum(x => x.Amount); application.AmountUSD = application.Details.Where(x => x.Currency == USD_CODE).Sum(x => x.Amount); application.AmountOther = application.Details.Where(x => x.Currency != RMB_CODE && x.Currency != USD_CODE).Sum(x => x.Amount); return DataResult.Success; } protected override async Task OnSaveAsync(PaymentApplication application, List? fees) { if (fees != null && fees.Count > 0) await TenantDb.Updateable(fees).UpdateColumns(x => new { x.OrderAmount }).ExecuteCommandAsync(); } protected override DataResult PreDelete(List applications) { if (applications.Any(x => x.Status != PaymentApplicationStatus.Pending && x.Status != PaymentApplicationStatus.AuditRejected)) return DataResult.Failed("只能删除状态为‘未提交’或‘驳回’的申请单"); return DataResult.Success; } protected override async Task OnDeleteDetailAsync(List details) { //还原费用表的已申请金额 var fees = details.Select(x => new FeeRecord { Id = x.RecordId, OrderAmount = x.OriginalAmount }).ToList(); await TenantDb.Updateable(fees) .PublicSetColumns(it => it.OrderAmount, "-") .UpdateColumns(x => new { x.OrderAmount }) .ExecuteCommandAsync(); } protected override DataResult PreSubmitApproval(List applications) { if (applications.Exists(x => x.Status == PaymentApplicationStatus.AuditSubmittd || x.Status == PaymentApplicationStatus.AuditPassed)) return DataResult.Failed("提交内容包含正在审批中/已审批的申请单"); return DataResult.Success; } protected override void OnSubmitApproval(PaymentApplication application) { application.Status = PaymentApplicationStatus.AuditSubmittd; } /// /// 设置是否收到发票 /// /// /// /// public async Task SetInvoiceReceivedAsync(bool isInvoiceReceived, params long[] ids) { var list = ids.Select(x => new PaymentApplication { Id = x, IsInvoiceReceived = isInvoiceReceived }).ToList(); int rows = await TenantDb.Updateable(list) .UpdateColumns(x => new { x.IsInvoiceReceived }) .ExecuteCommandAsync(); return rows > 0 ? DataResult.Success : DataResult.Failed("设置失败"); } } }