diff --git a/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs b/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs index 66337712..bc4083b6 100644 --- a/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs +++ b/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs @@ -665,6 +665,8 @@ public static class MultiLanguageConst public const string TemplateFileNotFound = "Template_File_NotFound"; [Description("模板")] public const string DefaultTemplateName = "Default_Template_Name"; + [Description("所选申请项已被其他业务(发票开出/发票结算/申请结算)所使用,无法删除")] + public const string ApplicationIsUsed = "Application_Is_Used"; #endregion #region 结算相关 @@ -678,6 +680,8 @@ public static class MultiLanguageConst public const string ApplicationSelectStatusError = "Application_Select_StatusError"; [Description("非原币申请必须指定原始币别")] public const string OriginalCurrencyCanNotNull = "OriginalCurrency_CanNot_Null"; + [Description("无法删除已提交开票的发票")] + public const string InvoiceIsIssued = "Invoice_Is_Issued"; #endregion #region 发票相关 diff --git a/ds-wms-service/DS.WMS.Core/Application/Method/ApplicationService`1.cs b/ds-wms-service/DS.WMS.Core/Application/Method/ApplicationService`1.cs index eb04fd88..a9f39468 100644 --- a/ds-wms-service/DS.WMS.Core/Application/Method/ApplicationService`1.cs +++ b/ds-wms-service/DS.WMS.Core/Application/Method/ApplicationService`1.cs @@ -1,4 +1,5 @@ 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; @@ -25,6 +26,10 @@ namespace DS.WMS.Core.Application.Method public abstract class ApplicationService : FeeServiceBase, IApplicationService where TEntity : ApplicationForm, new() { + internal static readonly DetailCategory[] detailCategories = [ + DetailCategory.InvoiceSettlement, DetailCategory.InvoiceIssuance, + DetailCategory.ChargeApplicationSettlement,DetailCategory.PaidApplicationSettlement]; + /// /// 适用于当前申请单的审核类型 /// @@ -57,7 +62,7 @@ namespace DS.WMS.Core.Application.Method var cIds = items.Select(x => x.CustomerId).Distinct(); var list = await TenantDb.Queryable() - .Where(f => bizIds.Contains(f.BusinessId) && types.Contains(f.BusinessType) && cIds.Contains(f.CustomerId) + .Where(f => bizIds.Contains(f.BusinessId) && types.Contains(f.BusinessType) && cIds.Contains(f.CustomerId) && f.FeeStatus == FeeStatus.AuditPassed) .Select(f => new { @@ -230,7 +235,7 @@ namespace DS.WMS.Core.Application.Method { var fc = request.Items.Find(x => x.Id == detail.BusinessId && x.BusinessType == x.BusinessType); var exchange = fc?.ExchangeRates?.Find(x => x.Currency == request.Application.Currency); - if (exchange == null) + if (exchange == null) return DataResult.Failed($"非原币申请必须传入费用原币与申请币别 {request.Application.Currency} 之间的汇率信息"); detail.ExchangeRate = exchange.ExchangeRate; @@ -359,6 +364,7 @@ namespace DS.WMS.Core.Application.Method } } + /// /// 在删除申请单或其明细之前调用,用于检查申请单状态 /// @@ -366,6 +372,14 @@ namespace DS.WMS.Core.Application.Method /// protected virtual DataResult PreDelete(List applications) { + var ids = applications.Select(x => x.Id); + bool exists = TenantDb.Queryable().Where(x => ids.Contains(x.ApplicationId)) + .InnerJoin((d1, d2) => d1.Id == d2.DetailId) + .Where((d1, d2) => d1.DetailId.HasValue && detailCategories.Contains(d2.Category.Value)) + .Any(); + if (exists) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationIsUsed)); + return DataResult.Success; } diff --git a/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs b/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs index ace42816..ae90b0d1 100644 --- a/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs +++ b/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs @@ -641,7 +641,7 @@ namespace DS.WMS.Core.Application.Method if (applications.Any(x => x.Status != InvoiceApplicationStatus.Pending && x.Status != InvoiceApplicationStatus.AuditRejected)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationDeleteStatusError)); - return DataResult.Success; + return base.PreDelete(applications); } protected override async Task OnDeleteDetailAsync(List applications, DeleteOption deleteOption) diff --git a/ds-wms-service/DS.WMS.Core/Application/Method/PaymentApplicationService.cs b/ds-wms-service/DS.WMS.Core/Application/Method/PaymentApplicationService.cs index 7f06cb29..18c2d9c1 100644 --- a/ds-wms-service/DS.WMS.Core/Application/Method/PaymentApplicationService.cs +++ b/ds-wms-service/DS.WMS.Core/Application/Method/PaymentApplicationService.cs @@ -558,7 +558,7 @@ namespace DS.WMS.Core.Application.Method if (applications.Any(x => x.Status != PaymentApplicationStatus.Pending && x.Status != PaymentApplicationStatus.AuditRejected)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationDeleteStatusError)); - return DataResult.Success; + return base.PreDelete(applications); } protected override async Task OnDeleteDetailAsync(List applications, DeleteOption deleteOption) diff --git a/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplate.cs b/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplate.cs index 2e028c5a..4b57339d 100644 --- a/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplate.cs +++ b/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplate.cs @@ -60,6 +60,47 @@ namespace DS.WMS.Core.Fee.Entity [SugarColumn(ColumnDescription = "判定条件", IsNullable = true)] public string? Condition { get; set; } + /// + /// 费用类型 + /// + [SugarColumn(ColumnDescription = "费用类型", IsNullable = false)] + public FeeType FeeType { get; set; } + /// + /// 费用类型文本 + /// + [SugarColumn(IsIgnore = true)] + public string FeeTypeText => FeeType.GetDescription(); + + /// + /// 开始时间 + /// + [SugarColumn(ColumnDescription = "开始时间", IsNullable = true)] + public DateTime? StartTime { get; set; } + + /// + /// 结束时间 + /// + [SugarColumn(ColumnDescription = "结束时间", IsNullable = true)] + public DateTime? EndTime { get; set; } + + /// + /// 是否禁用 + /// + [SugarColumn(ColumnDescription = "是否禁用", IsNullable = false)] + public bool IsDisabled { get; set; } + + /// + /// 费用类别 + /// + [SugarColumn(ColumnDescription = "费用类别", IsNullable = true)] + public long? FeeCategory { get; set; } + + /// + /// 优先级 + /// + [SugarColumn(ColumnDescription = "优先级", IsNullable = false)] + public int Priority { get; set; } + /// /// 模板明细 /// diff --git a/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplateDetail.cs b/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplateDetail.cs index 4925fd66..9519841b 100644 --- a/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplateDetail.cs +++ b/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeCustTemplateDetail.cs @@ -59,16 +59,6 @@ namespace DS.WMS.Core.Fee.Entity [SugarColumn(ColumnDescription = "费用名称", Length = 100, IsNullable = false)] public string FeeName { get; set; } = string.Empty; /// - /// 费用类型 - /// - [SugarColumn(ColumnDescription = "费用类型", IsNullable = false)] - public FeeType FeeType { get; set; } - /// - /// 费用类型文本 - /// - [SugarColumn(IsIgnore = true)] - public string FeeTypeText => FeeType.GetDescription(); - /// /// 费用标准 /// [SugarColumn(ColumnDescription = "费用标准", Length = 20, IsNullable = true)] diff --git a/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeRecord.cs b/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeRecord.cs index bd312139..e55bb438 100644 --- a/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeRecord.cs +++ b/ds-wms-service/DS.WMS.Core/Fee/Entity/FeeRecord.cs @@ -50,7 +50,7 @@ namespace DS.WMS.Core.Fee.Entity /// 费用代码 录入费用是作为检索 /// [SugarColumn(ColumnDescription = "费用代码", Length = 50, IsNullable = true)] - public string FeeCode { get; set; } + public string? FeeCode { get; set; } /// /// 费用名称 /// @@ -60,7 +60,7 @@ namespace DS.WMS.Core.Fee.Entity /// 费用英文名称 /// [SugarColumn(ColumnDescription = "费用英文名称", Length = 100, IsNullable = true)] - public string FeeEnName { get; set; } + public string? FeeEnName { get; set; } /// /// 费用对象名称 /// @@ -84,7 +84,7 @@ namespace DS.WMS.Core.Fee.Entity /// 客户类别 /// [SugarColumn(ColumnDescription = "客户类别", Length = 50, IsNullable = true)] - public string CustomerType { get; set; } + public string? CustomerType { get; set; } /// /// 客户类别文本 /// diff --git a/ds-wms-service/DS.WMS.Core/Fee/Method/FeeCustTemplateService.cs b/ds-wms-service/DS.WMS.Core/Fee/Method/FeeCustTemplateService.cs index 88a7b45b..4d739fd6 100644 --- a/ds-wms-service/DS.WMS.Core/Fee/Method/FeeCustTemplateService.cs +++ b/ds-wms-service/DS.WMS.Core/Fee/Method/FeeCustTemplateService.cs @@ -38,50 +38,25 @@ namespace DS.WMS.Core.Fee.Method /// public async Task GenerateFeesAsync(long bsId, BusinessType businessType = BusinessType.OceanShippingExport) { - //switch (businessType) - //{ - // case BusinessType.OceanShippingExport: - // break; - // case BusinessType.OceanShippingImport: - // break; - //} - var order = await TenantDb.Queryable().Where(x => x.Id == bsId).Select( - x => new { x.CustomerId }).FirstAsync(); + x => new { x.CustomerId, x.CustomerName }).FirstAsync(); if (order == null) return; + DateTime dt = DateTime.Now; try { var list = await TenantDb.Queryable() - .Where(x => x.BusinessType == businessType && !SqlFunc.IsNullOrEmpty(x.Condition) && - (x.IsShared || x.CustomerId == order.CustomerId)) + .Where(x => !x.IsDisabled && x.BusinessType == businessType && SqlFunc.Between(dt, x.StartTime, x.EndTime) && + !SqlFunc.IsNullOrEmpty(x.Condition) && (x.IsShared || x.CustomerId == order.CustomerId)) .Select(x => new { x.Id, - x.Condition, - Details = SqlFunc.Subqueryable().Where(y => - y.TemplateId == x.Id && y.CustomerId == order.CustomerId).ToList(y => new - { - y.CustomerId, - y.CustomerName, - y.CustomerType, - y.FeeId, - y.FeeCode, - y.FeeName, - y.FeeType, - y.Unit, - y.IsCtn, - y.Currency, - y.UnitPrice, - y.ExchangeRate, - y.TaxRate, - y.AccTaxRate, - y.Tax, - y.TaxUnitPrice, - y.IsInvoice, - y.IsAdvancedPay - }) + x.CustomerId, + x.FeeType, + x.Priority, + x.IsShared, + x.Condition }).ToListAsync(); if (list.Count == 0) @@ -97,16 +72,38 @@ namespace DS.WMS.Core.Fee.Method return; List feeList = []; - foreach (var item in list) + var custList = list.Where(x => x.CustomerId == order.CustomerId).OrderBy(x => x.Priority).ToList(); + foreach (var item in custList) //遍历客户费用模板,查找匹配项 { var conditionModel = conditionModels.Find(x => x.Id == item.Id)?.ConditionModel; if (actionService.Value.IsMatch(data, conditionModel)) { - var fees = item.Details.Select(x => new FeeRecord + var details = await TenantDb.Queryable().Where(y => y.TemplateId == item.Id) + .Select(y => new + { + y.CustomerId, + y.CustomerName, + y.CustomerType, + y.FeeId, + y.FeeCode, + y.FeeName, + y.Unit, + y.IsCtn, + y.Currency, + y.UnitPrice, + y.ExchangeRate, + y.TaxRate, + y.AccTaxRate, + y.Tax, + y.TaxUnitPrice, + y.IsInvoice, + y.IsAdvancedPay + }).ToListAsync(); + var fees = details.Select(x => new FeeRecord { BusinessId = bsId, BusinessType = businessType, - FeeType = x.FeeType, + FeeType = item.FeeType, FeeId = x.FeeId, FeeCode = x.FeeCode, FeeName = x.FeeName, @@ -126,8 +123,67 @@ namespace DS.WMS.Core.Fee.Method IsInvoice = x.IsInvoice, IsAdvancedPay = x.IsAdvancedPay, }); - feeList.AddRange(fees); + break; + } + } + + if (feeList.Count == 0) //未找到客户模板,开始匹配共享模板 + { + var sharedList = list.Where(x => x.IsShared).OrderBy(x => x.Priority).ToList(); + foreach (var item in sharedList) + { + var conditionModel = conditionModels.Find(x => x.Id == item.Id)?.ConditionModel; + if (actionService.Value.IsMatch(data, conditionModel)) + { + var details = await TenantDb.Queryable().Where(y => y.TemplateId == item.Id) + .Select(y => new + { + y.CustomerId, + y.CustomerName, + y.CustomerType, + y.FeeId, + y.FeeCode, + y.FeeName, + y.Unit, + y.IsCtn, + y.Currency, + y.UnitPrice, + y.ExchangeRate, + y.TaxRate, + y.AccTaxRate, + y.Tax, + y.TaxUnitPrice, + y.IsInvoice, + y.IsAdvancedPay + }).ToListAsync(); + var fees = details.Select(x => new FeeRecord + { + BusinessId = bsId, + BusinessType = businessType, + FeeType = item.FeeType, + FeeId = x.FeeId, + FeeCode = x.FeeCode, + FeeName = x.FeeName, + CustomerId = x.CustomerId, + CustomerName = x.CustomerName, + CustomerType = x.CustomerType?.ToString(), + Unit = x.Unit, + UnitPrice = x.UnitPrice.GetValueOrDefault(), + Quantity = x.IsCtn ? 1 : 0, + Note = x.IsCtn.ToString().ToLowerInvariant(), //临时存储 + Currency = x.Currency, + ExchangeRate = x.ExchangeRate, + TaxRate = x.TaxRate.GetValueOrDefault(), + AccTaxRate = x.AccTaxRate.GetValueOrDefault(), + Tax = x.Tax.GetValueOrDefault(), + TaxUnitPrice = x.TaxUnitPrice.GetValueOrDefault(), + IsInvoice = x.IsInvoice, + IsAdvancedPay = x.IsAdvancedPay, + }); + feeList.AddRange(fees); + break; + } } } @@ -155,19 +211,7 @@ namespace DS.WMS.Core.Fee.Method public async Task>> GetListAsync(PageRequest request) { var whereList = request.GetConditionalModels(Db); - return await TenantDb.Queryable().Select(x => new FeeCustTemplate - { - Id = x.Id, - BusinessType = x.BusinessType, - CustomerId = x.CustomerId, - CustomerName = x.CustomerName, - CustomerType = x.CustomerType, - Name = x.Name, - IsShared = x.IsShared, - Note = x.Note, - CreateBy = x.CreateBy, - CreateTime = x.CreateTime - }).Where(whereList).ToQueryPageAsync(request.PageCondition); + return await TenantDb.Queryable().Where(whereList).ToQueryPageAsync(request.PageCondition); } /// diff --git a/ds-wms-service/DS.WMS.Core/Invoice/Method/FreeInvoiceService.cs b/ds-wms-service/DS.WMS.Core/Invoice/Method/FreeInvoiceService.cs index 912946d4..8ffa2a93 100644 --- a/ds-wms-service/DS.WMS.Core/Invoice/Method/FreeInvoiceService.cs +++ b/ds-wms-service/DS.WMS.Core/Invoice/Method/FreeInvoiceService.cs @@ -3,6 +3,7 @@ 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.Fee.Dtos; using DS.WMS.Core.Fee.Entity; using DS.WMS.Core.Invoice.Dtos; @@ -233,5 +234,22 @@ namespace DS.WMS.Core.Invoice.Method return sb.Length > 0 ? DataResult.Failed(sb.ToString()) : DataResult.Success; } + + //protected override async Task OnDeleteDetailAsync(List invoices, DeleteOption deleteOption) + //{ + // var list = invoices.SelectMany(x => x.Details).Where(x => x.DetailId.HasValue).Select(x => new ApplicationDetail + // { + // Id = x.DetailId.GetValueOrDefault(), + // ProcessedAmount = x.ApplyAmount, + // OriginalProcessedAmount = x.OriginalAmount + // }).ToList(); + // //恢复发票申请明细的已处理金额 + // await TenantDb.Updateable(list) + // .PublicSetColumns(x => x.ProcessedAmount, "-").PublicSetColumns(x => x.OriginalProcessedAmount, "-") + // .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) + // .ExecuteCommandAsync(); + + // await base.OnDeleteDetailAsync(invoices, deleteOption); + //} } } diff --git a/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs b/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs index 5df2fd01..bcedd015 100644 --- a/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs +++ b/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs @@ -34,28 +34,13 @@ namespace DS.WMS.Core.Invoice.Method SqlFunc.Subqueryable().Where(d => d.ApplicationId == a.Id && d.Category == DetailCategory.InvoiceApplication && (d.OriginalAmount - d.OriginalProcessedAmount) != 0).Any()) .Select(a => new InvoiceApplicationDto { - Id = a.Id, - ApplicationNO = a.ApplicationNO, - Status = a.Status, - CustomerId = a.CustomerId, - CustomerName = a.CustomerName, //结算单位 - InvoiceHeader = a.InvoiceHeader, - ApplyAmount = a.ApplyAmount, - InvoiceAmount = a.InvoiceAmount, //Currency = SqlFunc.IsNullOrEmpty(a.Currency) ? SqlFunc.Subqueryable().Where( // d => d.ApplicationId == a.Id && d.Category == DetailCategory.InvoiceApplication).SelectStringJoin(d => d.Currency, ",") // : a.Currency, - Category = a.Category, - OrgId = a.OrgId, //所属部门 - SaleDeptId = a.SaleDeptId, //所属分部 - CreateBy = a.CreateBy, //申请人 - CreateTime = a.CreateTime, //申请日期 - InvoiceRemark = a.InvoiceRemark, //开票要求 - Note = a.Note, //原币金额 OriginalAmountList = SqlFunc.Subqueryable().Where(y => a.Id == y.ApplicationId) .GroupBy(y => y.OriginalCurrency).ToList(y => new CurrencyAmount { Currency = y.OriginalCurrency, Amount = y.OriginalAmount }) - }); + }, true); var whereList = request.GetConditionalModels(Db); var result = await query.Where(whereList).ToQueryPageAsync(request.PageCondition); @@ -169,7 +154,7 @@ namespace DS.WMS.Core.Invoice.Method ProcessedAmount = x.ApplyAmount, OriginalProcessedAmount = x.OriginalAmount }).ToList(); - //恢复发票申请明细的已处理金额 + //恢复发票申请费用明细的已处理金额 await TenantDb.Updateable(list) .PublicSetColumns(x => x.ProcessedAmount, "-").PublicSetColumns(x => x.OriginalProcessedAmount, "-") .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) diff --git a/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs b/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs index b714d256..b9165ac6 100644 --- a/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs +++ b/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs @@ -829,6 +829,9 @@ namespace DS.WMS.Core.Invoice.Method if (invoices.Any(x => x.IsLocked)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked)); + if (invoices.Any(x => !string.IsNullOrEmpty(x.ApiCode))) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsIssued)); + return DataResult.Success; } @@ -844,10 +847,6 @@ namespace DS.WMS.Core.Invoice.Method if (deleteOption == DeleteOption.DetailOnly) { - ////删除明细需要同时变更发票明细 - //foreach (var item in invoices) - // BuildInvoiceDetailAsync(item, BuildOption.Delete); - var excludeIds = invoices.SelectMany(x => x.Details).Select(x => x.Id); var details = await TenantDb.Queryable().Where(x => appIds.Contains(x.ApplicationId) && !excludeIds.Contains(x.Id)) .Select(x => new ApplicationDetail @@ -890,9 +889,7 @@ namespace DS.WMS.Core.Invoice.Method .UpdateColumns(x => new { x.OrderInvSettlementAmount }); await updateable.UpdateColumns(x => new { x.InvoiceAmount }).ExecuteCommandAsync(); - } - } ///