根据业务ID与类型生成费用

dev
嵇文龙 4 weeks ago
parent 75cc919a9c
commit 5ea451c0a6

@ -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 发票相关

@ -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<TEntity> : FeeServiceBase, IApplicationService<TEntity>
where TEntity : ApplicationForm, new()
{
internal static readonly DetailCategory[] detailCategories = [
DetailCategory.InvoiceSettlement, DetailCategory.InvoiceIssuance,
DetailCategory.ChargeApplicationSettlement,DetailCategory.PaidApplicationSettlement];
/// <summary>
/// 适用于当前申请单的审核类型
/// </summary>
@ -57,7 +62,7 @@ namespace DS.WMS.Core.Application.Method
var cIds = items.Select(x => x.CustomerId).Distinct();
var list = await TenantDb.Queryable<FeeRecord>()
.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<TEntity>.Failed($"非原币申请必须传入费用原币与申请币别 {request.Application.Currency} 之间的汇率信息");
detail.ExchangeRate = exchange.ExchangeRate;
@ -359,6 +364,7 @@ namespace DS.WMS.Core.Application.Method
}
}
/// <summary>
/// 在删除申请单或其明细之前调用,用于检查申请单状态
/// </summary>
@ -366,6 +372,14 @@ namespace DS.WMS.Core.Application.Method
/// <returns></returns>
protected virtual DataResult PreDelete(List<TEntity> applications)
{
var ids = applications.Select(x => x.Id);
bool exists = TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId))
.InnerJoin<ApplicationDetail>((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;
}

@ -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<InvoiceApplication> applications, DeleteOption deleteOption)

@ -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<PaymentApplication> applications, DeleteOption deleteOption)

@ -60,6 +60,47 @@ namespace DS.WMS.Core.Fee.Entity
[SugarColumn(ColumnDescription = "判定条件", IsNullable = true)]
public string? Condition { get; set; }
/// <summary>
/// 费用类型
/// </summary>
[SugarColumn(ColumnDescription = "费用类型", IsNullable = false)]
public FeeType FeeType { get; set; }
/// <summary>
/// 费用类型文本
/// </summary>
[SugarColumn(IsIgnore = true)]
public string FeeTypeText => FeeType.GetDescription();
/// <summary>
/// 开始时间
/// </summary>
[SugarColumn(ColumnDescription = "开始时间", IsNullable = true)]
public DateTime? StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
[SugarColumn(ColumnDescription = "结束时间", IsNullable = true)]
public DateTime? EndTime { get; set; }
/// <summary>
/// 是否禁用
/// </summary>
[SugarColumn(ColumnDescription = "是否禁用", IsNullable = false)]
public bool IsDisabled { get; set; }
/// <summary>
/// 费用类别
/// </summary>
[SugarColumn(ColumnDescription = "费用类别", IsNullable = true)]
public long? FeeCategory { get; set; }
/// <summary>
/// 优先级
/// </summary>
[SugarColumn(ColumnDescription = "优先级", IsNullable = false)]
public int Priority { get; set; }
/// <summary>
/// 模板明细
/// </summary>

@ -59,16 +59,6 @@ namespace DS.WMS.Core.Fee.Entity
[SugarColumn(ColumnDescription = "费用名称", Length = 100, IsNullable = false)]
public string FeeName { get; set; } = string.Empty;
/// <summary>
/// 费用类型
/// </summary>
[SugarColumn(ColumnDescription = "费用类型", IsNullable = false)]
public FeeType FeeType { get; set; }
/// <summary>
/// 费用类型文本
/// </summary>
[SugarColumn(IsIgnore = true)]
public string FeeTypeText => FeeType.GetDescription();
/// <summary>
/// 费用标准
/// </summary>
[SugarColumn(ColumnDescription = "费用标准", Length = 20, IsNullable = true)]

@ -50,7 +50,7 @@ namespace DS.WMS.Core.Fee.Entity
/// 费用代码 录入费用是作为检索
/// </summary>
[SugarColumn(ColumnDescription = "费用代码", Length = 50, IsNullable = true)]
public string FeeCode { get; set; }
public string? FeeCode { get; set; }
/// <summary>
/// 费用名称
/// </summary>
@ -60,7 +60,7 @@ namespace DS.WMS.Core.Fee.Entity
/// 费用英文名称
/// </summary>
[SugarColumn(ColumnDescription = "费用英文名称", Length = 100, IsNullable = true)]
public string FeeEnName { get; set; }
public string? FeeEnName { get; set; }
/// <summary>
/// 费用对象名称
/// </summary>
@ -84,7 +84,7 @@ namespace DS.WMS.Core.Fee.Entity
/// 客户类别
/// </summary>
[SugarColumn(ColumnDescription = "客户类别", Length = 50, IsNullable = true)]
public string CustomerType { get; set; }
public string? CustomerType { get; set; }
/// <summary>
/// 客户类别文本
/// </summary>

@ -38,50 +38,25 @@ namespace DS.WMS.Core.Fee.Method
/// <returns></returns>
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<SeaExport>().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<FeeCustTemplate>()
.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<FeeCustTemplateDetail>().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<FeeRecord> 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<FeeCustTemplateDetail>().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<FeeCustTemplateDetail>().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<DataResult<List<FeeCustTemplate>>> GetListAsync(PageRequest request)
{
var whereList = request.GetConditionalModels(Db);
return await TenantDb.Queryable<FeeCustTemplate>().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<FeeCustTemplate>().Where(whereList).ToQueryPageAsync(request.PageCondition);
}
/// <summary>

@ -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<Entity.Invoice> 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);
//}
}
}

@ -34,28 +34,13 @@ namespace DS.WMS.Core.Invoice.Method
SqlFunc.Subqueryable<ApplicationDetail>().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<ApplicationDetail>().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<ApplicationDetail>().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 })

@ -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<ApplicationDetail>().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();
}
}
/// <summary>

Loading…
Cancel
Save