using System.Linq.Expressions; using DS.Module.Core; using DS.Module.Core.Extensions; using DS.WMS.Core.Fee.Dtos; using DS.WMS.Core.Fee.Entity; using DS.WMS.Core.Flow.Entity; using DS.WMS.Core.Op.Entity; using SqlSugar; namespace DS.WMS.Core.Fee.Method { /// /// 费用服务基类 /// public class FeeServiceBase : ServiceBase { /// /// 人民币代码 /// public const string RMB_CODE = "CNY"; /// /// 美元代码 /// public const string USD_CODE = "USD"; /// /// 初始化 /// /// 服务提供程序 public FeeServiceBase(IServiceProvider serviceProvider) :base(serviceProvider) { } /// /// 返回针对费用及其关联业务的查询对象 /// /// 关联条件1 /// 查询对象 public ISugarQueryable CreateFeeQuery( Expression>? expr1 = null) { //海运出口 var query1 = TenantDb.Queryable() .InnerJoin((s, f) => s.Id == f.BusinessId && f.BusinessType == BusinessType.OceanShippingExport) .WhereIF(expr1 != null, expr1) .Select((s, f) => new BusinessFeeDto { BusinessId = s.Id, BusinessType = BusinessType.OceanShippingExport, AccountDate = s.AccountDate, CntrTotal = s.CntrTotal, CreateBy = s.CreateBy, CustomerNo = s.CustomerNo, ClientName = s.CustomerName, //委托单位 DischargePort = s.DischargePort, ETD = s.ETD, HBLNO = s.HBLNO, LoadPort = s.LoadPort, MBLNO = s.MBLNO, OperatorId = s.OperatorId, SaleDeptId = s.SaleDeptId, SaleId = s.SaleId, Sale = s.Sale,//揽货人 Vessel = s.Vessel,//船名 Voyage = s.Voyno,//航次 BookingNo = s.BookingNo, StlName = s.StlName, InvoiceNo = s.InvoiceNo, RecordId = f.Id, FeeType = f.FeeType, FeeStatus = f.FeeStatus, CustomerId = f.CustomerId,//费用对象 CustomerName = f.CustomerName, FeeId = f.FeeId, FeeName = f.FeeName, Currency = f.Currency, Amount = f.Amount, ExchangeRate = f.ExchangeRate, OrderAmount = f.OrderAmount, InvoiceAmount = f.InvoiceAmount, SettlementAmount = f.SettlementAmount, OrderSettlementAmount = f.OrderSettlementAmount, OrderInvSettlementAmount = f.OrderInvSettlementAmount, TaxRate = f.TaxRate, AccTaxRate = f.AccTaxRate, IsDebit = f.IsDebit, DebitNo = f.DebitNo, IsInvoice = f.IsInvoice, SaleOrgId = f.SaleOrgId, }); //海运进口 return TenantDb.UnionAll(new List> { query1 }); } /// /// 更新费用及其业务的费用状态 /// /// 费用记录ID /// 此方法内部将始终异步执行,请确保在调用前已提交数据库事务等必要的操作。 protected internal void UpdateFeeStatus(IEnumerable ids) { var task1 = Task.Factory.StartNew(UpdateFeeStatusCore, ids, CancellationToken.None); task1.ContinueWith(t => UpdateBizStatusCore(t.Result), TaskContinuationOptions.OnlyOnRanToCompletion); } private List UpdateFeeStatusCore(object? state) { if (state == null) return []; var ids = (IEnumerable)state; var fees = TenantDb.Queryable().Where(x => ids.Contains(x.Id)) .Select(x => new FeeRecord { Id = x.Id, BusinessId = x.BusinessId, BusinessType = x.BusinessType, FeeStatus = x.FeeStatus, Amount = x.Amount, SettlementAmount = x.SettlementAmount, OrderAmount = x.OrderAmount, OrderSettlementAmount = x.OrderSettlementAmount }).ToList(); if (fees.Count == 0) return []; List list = new(fees.Count); foreach (var item in fees) { var restAmount = item.Amount - item.SettlementAmount - item.OrderAmount + item.OrderSettlementAmount; if (restAmount == 0) { item.FeeStatus = FeeStatus.SettlementCompleted; list.Add(item); } else if (restAmount != item.Amount) { item.FeeStatus = FeeStatus.PartialSettlement; list.Add(item); } else if (item.SettlementAmount == 0) { item.FeeStatus = FeeStatus.AuditPassed; list.Add(item); } } TenantDb.Updateable(list).UpdateColumns(x => new { x.FeeStatus }).ExecuteCommand(); return list; } private void UpdateBizStatusCore(List list) { var bizIds = list.Select(x => x.BusinessId); var types = list.Select(x => x.BusinessType).Distinct(); var fees2 = TenantDb.Queryable().Where(x => bizIds.Contains(x.BusinessId) && types.Contains(x.BusinessType)) .Select(x => new { x.BusinessId, x.BusinessType, x.FeeType, x.FeeStatus }).ToList(); if (fees2.Count == 0) return; var gpList = fees2.GroupBy(x => new { x.BusinessId, x.BusinessType }); foreach (var gp in gpList) { BusinessFeeStatus biz = new() { BusinessId = gp.Key.BusinessId, BusinessType = gp.Key.BusinessType }; var upt = TenantDb.Updateable(biz).WhereColumns(x => new { x.BusinessId, x.BusinessType }); //应收 var arList = gp.Where(x => x.FeeType == FeeType.Receivable).ToList(); if (arList.Count > 0) { if (arList.All(x => x.FeeStatus == FeeStatus.SettlementCompleted)) { biz.ARFeeStatus = BillFeeStatus.SettlementCompleted; upt = upt.UpdateColumns(x => x.ARFeeStatus); } else if (arList.Any(x => x.FeeStatus == FeeStatus.PartialSettlement)) { biz.ARFeeStatus = BillFeeStatus.PartialSettlement; upt = upt.UpdateColumns(x => x.ARFeeStatus); } } //应付 var apList = gp.Where(x => x.FeeType == FeeType.Payable).ToList(); if (apList.Count > 0) { if (apList.All(x => x.FeeStatus == FeeStatus.SettlementCompleted)) { biz.APFeeStatus = BillFeeStatus.SettlementCompleted; upt = upt.UpdateColumns(x => x.APFeeStatus); } else if (apList.Any(x => x.FeeStatus == FeeStatus.PartialSettlement)) { biz.APFeeStatus = BillFeeStatus.PartialSettlement; upt = upt.UpdateColumns(x => x.APFeeStatus); } } upt.ExecuteCommand(); } } /// /// 获取汇率 /// /// /// protected internal async Task FetchExchangeRateAsync(IEnumerable items) { var exRecords = items.Where(x => !x.ExchangeRate.HasValue && x.Currency != x.LocalCurrency).ToList(); if (exRecords.Count > 0) { var codes = exRecords.Select(x => x.Currency).Distinct().ToList(); var currencies = await TenantDb.Queryable().Where(x => codes.Contains(x.CodeName)).Includes(x => x.Exchanges).ToListAsync(); DateTime dtNow = DateTime.Now; foreach (var item in exRecords) { var currency = currencies.Find(x => x.CodeName == item.Currency); if (currency != null) { item.ExchangeRate = currency.DefaultRate; if (currency.Exchanges != null && currency.Exchanges.Count > 0) { //取当前时间范围内的最新一条 var exchange = currency.Exchanges.FindAll(x => x.Status == StatusEnum.Enable && x.StartDate >= dtNow && x.EndDate <= dtNow).OrderByDescending(x => x.UpdateTime).FirstOrDefault(); if (exchange != null) item.ExchangeRate = item.FeeType == FeeType.Receivable ? exchange.DRValue : exchange.CRValue; } } } } } /// /// 获取当前登录用户的待审批工作流的查询对象 /// /// 审核类型 /// protected internal ISugarQueryable GetCurrentFlowsQuery(AuditType[] auditTypes) { return Db.Queryable().Where(x => x.FlowStatus == FlowStatusEnum.Running && SqlFunc.SplitIn(x.MakerList, User.UserId) && auditTypes.Contains(x.Type.Value)) .Select(x => new FlowInstance { Id = x.Id, BusinessId = x.BusinessId, BusinessType = x.BusinessType }); } } }