using DS.Module.Core; using DS.Module.Core.Condition; using DS.Module.Core.Data; using DS.Module.Core.Extensions; using DS.WMS.Core.Code.Entity; using DS.WMS.Core.Fee.Dtos; using DS.WMS.Core.Fee.Entity; using DS.WMS.Core.Fee.Interface; using DS.WMS.Core.Info.Entity; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Op.Interface.TaskInteraction; using Masuit.Tools; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using SqlSugar; namespace DS.WMS.Core.Fee.Method { /// /// 往来单位费用模板 /// public class FeeCustTemplateService : FeeServiceBase, IFeeCustTemplateService { Lazy actionService; Lazy feeService; /// /// 初始化 /// /// public FeeCustTemplateService(IServiceProvider serviceProvider) : base(serviceProvider) { actionService = new Lazy(serviceProvider.GetRequiredService()); feeService = new Lazy(serviceProvider.GetRequiredService()); } /// /// 根据开船日生成费用 /// /// 开船日 /// public async Task GenerateFeesAsync(DateTime etd) { DateTime dt = DateTime.Now; var list = await TenantDb.Queryable() .Where(x => !x.IsDisabled && SqlFunc.Between(dt, x.StartTime, x.EndTime) && (x.IsShared || x.CustomerId != null)) .Select(x => new FeeCustTemplate { Id = x.Id, CustomerId = x.CustomerId, FeeType = x.FeeType, FeeCategoryId = x.FeeCategoryId, FeeCategoryName = x.FeeCategoryName, Priority = x.Priority, IsShared = x.IsShared, POLCode = x.POLCode, PODCode = x.PODCode, LaneId = x.LaneId, SourceId = x.SourceId, CarrierId = x.CarrierId, ForwarderId = x.ForwarderId, MBLFrtCode = x.MBLFrtCode, Condition = x.Condition }).ToListAsync(); if (list.Count == 0) return; if (etd == default) etd = DateTime.Now.Date; var tids = list.Select(x => x.Id); var orders = await TenantDb.Queryable().Where(x => SqlFunc.DateIsSame(x.ETD, etd) && SqlFunc.Subqueryable().Where(y => y.BusinessId == x.Id && y.BusinessType == BusinessType.OceanShippingExport && tids.Contains(y.TemplateId)).NotAny()) .Select().ToListAsync(); if (orders.Count == 0) return; List feeList = []; await TenantDb.Ado.BeginTranAsync(); try { foreach (var order in orders) { var custList = list.Where(x => x.CustomerId == order.CustomerId).OrderBy(x => x.Priority); foreach (var template in custList) //遍历客户费用模板,查找匹配项 { var fees = await CreateFeesIfMatchAsync(order, template); if (fees != null) { feeList.AddRange(fees); var record = new FeeCustTemplateRecord { BusinessId = order.CustomerId, BusinessType = BusinessType.OceanShippingExport, CreateBy = long.Parse(User.UserId), CreateTime = dt, FeeCategoryId = template.FeeCategoryId, FeeType = template.FeeType, TemplateId = template.Id }; await TenantDb.Insertable(record).ExecuteCommandAsync(); } } //未找到客户模板,开始匹配共享模板 if (feeList.Count == 0) { var sharedList = list.Where(x => x.IsShared).OrderBy(x => x.Priority).ToList(); foreach (var template in sharedList) { var fees = await CreateFeesIfMatchAsync(order, template); if (fees != null) { feeList.AddRange(fees); var record = new FeeCustTemplateRecord { BusinessId = order.CustomerId, BusinessType = BusinessType.OceanShippingExport, CreateBy = long.Parse(User.UserId), CreateTime = dt, FeeCategoryId = template.FeeCategoryId, FeeType = template.FeeType, TemplateId = template.Id }; await TenantDb.Insertable(record).ExecuteCommandAsync(); } } } //写入当前业务的费用 if (feeList.Count > 0) { var result = await feeService.Value.SaveAsync(feeList, true, false); if (!result.Succeeded) { //记录失败日志 await new ApplicationException(result.Message).LogAsync(Db); } feeList.Clear(); } } await TenantDb.Ado.CommitTranAsync(); } catch (Exception ex) { await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); } } private async Task?> CreateFeesIfMatchAsync(SeaExportRes order, FeeCustTemplate template) { if (!string.IsNullOrEmpty(template.POLCode) && template.POLCode != order.LoadPortCode) return null; if (!string.IsNullOrEmpty(template.PODCode) && template.PODCode != order.DischargePortCode) return null; if (!string.IsNullOrEmpty(template.MBLFrtCode) && template.MBLFrtCode != order.MBLFrtCode) return null; if (template.LaneId.HasValue && template.LaneId != order.LaneId) return null; if (template.CarrierId.HasValue && template.CarrierId != order.CarrierId) return null; if (template.SourceId.HasValue && template.SourceId != order.SourceId) return null; if (template.ForwarderId.HasValue && template.ForwarderId != order.ForwarderId) return null; if (!string.IsNullOrEmpty(template.Condition)) //设置了自定义匹配条件 { var conditionModel = JsonConvert.DeserializeObject(template.Condition); if (!actionService.Value.IsMatch(order, conditionModel)) return null; } if (await TenantDb.Queryable().AnyAsync(x => x.BusinessId == order.Id && x.BusinessType == BusinessType.OceanShippingExport && x.FeeType == template.FeeType && x.FeeCategoryId == template.FeeCategoryId)) return null; var details = await TenantDb.Queryable().Where(y => y.TemplateId == template.Id) .Select(x => new FeeRecord { BusinessId = order.Id, BusinessType = BusinessType.OceanShippingExport, FeeType = template.FeeType, FeeId = x.FeeId, FeeCode = x.FeeCode, FeeName = x.FeeName, CustomerId = x.CustomerId, CustomerName = x.CustomerName, CustomerType = x.CustomerType, Unit = x.Unit, UnitPrice = SqlFunc.IsNull(x.UnitPrice.Value, 0), //Quantity = x.IsCtn ? 1 : 0, Currency = x.Currency, ExchangeRate = x.ExchangeRate, TaxRate = SqlFunc.IsNull(x.TaxRate.Value, 0), AccTaxRate = SqlFunc.IsNull(x.AccTaxRate.Value, 0), Tax = SqlFunc.IsNull(x.Tax.Value, 0), TaxUnitPrice = SqlFunc.IsNull(x.TaxUnitPrice.Value, 0), IsInvoice = x.IsInvoice, IsAdvancedPay = x.IsAdvancedPay, Remark = template.FeeCategoryName, TemplateId = x.TemplateId, InputMethod = InputMethod.Automatic }).ToListAsync(); foreach (var detail in details) { if (detail.CustomerId == 0) { switch (detail.CustomerType) { case "controller": detail.CustomerId = order.CustomerId; detail.CustomerName = order.CustomerName; break; case "yard": detail.CustomerId = order.YardId; detail.CustomerName = order.Yard; break; case "custom": detail.CustomerId = order.CustomserId; detail.CustomerName = order.Customser; break; case "contract": detail.CustomerId = order.ContractClientId; detail.CustomerName = order.ContractClientName; break; case "shipagency": detail.CustomerId = order.ShipAgencyId; detail.CustomerName = order.ShipAgency; break; case "shipper": detail.CustomerId = order.ShipperId.GetValueOrDefault(); detail.CustomerName = order.Shipper; break; case "truck": detail.CustomerId = order.TruckerId; detail.CustomerName = order.Trucker; break; case "booking": detail.CustomerId = order.ForwarderId; detail.CustomerName = order.Forwarder; break; case "carrier": detail.CustomerId = order.CarrierId; detail.CustomerName = order.Carrier; break; case "wareHouse": detail.CustomerId = order.WareHouseId; detail.CustomerName = order.WareHouse; break; case "shippercn": detail.CustomerId = order.ShipperCnId.GetValueOrDefault(); detail.CustomerName = order.ShipperCn; break; case "agent": detail.CustomerId = order.AgentId.GetValueOrDefault(); detail.CustomerName = order.Agent; break; } } } return details; } /// /// 导入费用模板 /// /// /// public async Task ImportAsync(IEnumerable models) { ArgumentNullException.ThrowIfNull(models, nameof(models)); long userId = long.Parse(User.UserId); DateTime dtNow = DateTime.Now; var custNames = models.Select(x => x.CustomerName).Distinct(); var custList = await TenantDb.Queryable().Where(x => custNames.Contains(x.Name) && x.Status == 0).Select(x => new { x.Id, x.Name }).ToListAsync(); var feeNames = models.Select(x => x.FeeName).Distinct(); var fees = await TenantDb.Queryable().Where(x => feeNames.Contains(x.Name)).Select(x => new { x.Id, x.Code, x.Name }).ToListAsync(); var carrierCodes = models.Select(x => x.CarrierName).Distinct(); var carriers = await TenantDb.Queryable().Where(x => carrierCodes.Contains(x.Code)).Select(x => new { x.Id, x.Code }).ToListAsync(); //var portCodes = models.Select(x => x.POL).Union(models.Select(x => x.POD)).Distinct(); //var ports = await TenantDb.Queryable().Where(x => portCodes.Contains(x.EdiCode)).Select(x => new //{ // x.Id, // x.EdiCode //}).ToListAsync(); var laneCodes = models.Select(x => x.LaneName).Distinct(); var lanes = await TenantDb.Queryable().Where(x => laneCodes.Contains(x.EdiCode)).Select(x => new { x.Id, x.EdiCode }).ToListAsync(); //var ptCodes = models.Select(x => x.PaymentType).Distinct(); //var frtList = await TenantDb.Queryable().Where(x => ptCodes.Contains(x.EdiCode)).Select(x => new //{ // x.Id, // x.EdiCode //}).ToListAsync(); List list = []; var groups = models.GroupBy(x => new { x.CarrierName, x.POL, x.POD, x.LaneName, x.PaymentType, x.CustomerName }).ToList(); foreach (var g in groups) { var first = g.First(); FeeCustTemplate template = new FeeCustTemplate { Name = "导入费用模板" + groups.IndexOf(g), BusinessType = BusinessType.OceanShippingExport, CustomerId = custList.Find(x => x.Name == g.Key.CustomerName)?.Id, CustomerName = g.Key.CustomerName, FeeType = FeeType.Receivable, IsDisabled = first.StatusText != "有效", StartTime = first.StartTime, EndTime = first.EndTime, IsShared = string.IsNullOrEmpty(g.Key.CustomerName), Priority = 1, CarrierId = carriers.Find(x => x.Code == g.Key.CarrierName)?.Id, LaneId = lanes.Find(x => x.EdiCode == g.Key.LaneName)?.Id, MBLFrtCode = g.Key.PaymentType, POLCode = g.Key.POL, PODCode = g.Key.POD, CreateBy = userId, CreateTime = dtNow, Note = "系统导入", Details = [] }; list.Add(template); foreach (var item in g) { var detail = new FeeCustTemplateDetail { CustomerId = template.CustomerId.GetValueOrDefault(), CustomerName = template.CustomerName, CustomerType = "controller", Currency = item.Currency, FeeId = (fees.Find(x => x.Name == item.FeeName)?.Id).GetValueOrDefault(), FeeCode = fees.Find(x => x.Name == item.FeeName)?.Code, FeeName = item.FeeName, IsCtn = item.UnitPrice == null, IsInvoice = true, CreateBy = userId, CreateTime = dtNow, }; if (item.UnitPrice.HasValue) { detail.UnitPrice = detail.TaxUnitPrice = item.UnitPrice.Value; template.Details.Add(detail); } if (item.GP20.HasValue) { var copiedDetail = detail.DeepClone(); copiedDetail.Unit = "20GP"; copiedDetail.UnitPrice = copiedDetail.TaxUnitPrice = item.GP20.Value; template.Details.Add(copiedDetail); } if (item.GP40.HasValue) { var copiedDetail = detail.DeepClone(); copiedDetail.Unit = "40GP"; copiedDetail.UnitPrice = copiedDetail.TaxUnitPrice = item.GP40.Value; template.Details.Add(copiedDetail); } if (item.HQ40.HasValue) { var copiedDetail = detail.DeepClone(); copiedDetail.Unit = "40HQ"; copiedDetail.UnitPrice = copiedDetail.TaxUnitPrice = item.HQ40.Value; template.Details.Add(copiedDetail); } } } try { await TenantDb.InsertNav(list).Include(x => x.Details).ExecuteCommandAsync(); return DataResult.Success; } catch (Exception ex) { await ex.LogAsync(Db); return DataResult.Failed(ex.Message); } } /// /// 列表 /// /// /// public async Task>> GetListAsync(PageRequest request) { var whereList = request.GetConditionalModels(Db); return await TenantDb.Queryable().Where(whereList).ToQueryPageAsync(request.PageCondition); } /// /// 详情 /// /// /// public async Task> GetAsync(long id) { var data = await TenantDb.Queryable().Where(x => x.Id == id).FirstAsync(); if (data != null) data.Details = await TenantDb.Queryable().Where(x => x.TemplateId == data.Id).ToListAsync(); return DataResult.Success(data, MultiLanguageConst.DataQuerySuccess); } /// /// 编辑 /// /// /// public async Task EditAsync(FeeCustTemplate model) { if (model.Details.Count > 0) { long userId = long.Parse(User.UserId); DateTime dt = DateTime.Now; foreach (var item in model.Details) { item.TemplateId = model.Id; if (item.CustomerId == 0 && model.CustomerId.HasValue) item.CustomerId = model.CustomerId.Value; if (string.IsNullOrEmpty(item.CustomerName)) item.CustomerName = model.CustomerName; item.CustomerType = model.CustomerType; item.CreateBy = userId; item.CreateTime = dt; } } await TenantDb.Ado.BeginTranAsync(); try { if (model.Id == 0) { await TenantDb.InsertNav(model).Include(x => x.Details).ExecuteCommandAsync(); } else { await TenantDb.Updateable(model).ExecuteCommandAsync(); if (model.Details.Count > 0) await TenantDb.Storageable(model.Details).DefaultAddElseUpdate().ExecuteCommandAsync(); } await TenantDb.Ado.CommitTranAsync(); return DataResult.Successed("提交成功", model.Id, MultiLanguageConst.DataCreateSuccess); } catch (Exception ex) { await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } /// /// 根据ID批量删除 /// /// /// public async Task DeleteAsync(IdModel model) { bool flag = await TenantDb.DeleteNav(x => model.Ids.Contains(x.Id)) .Include(x => x.Details).ExecuteCommandAsync(); return flag ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } }