发票备注模板渲染问题修复

dev
嵇文龙 1 week ago
parent 0e0530b2b6
commit 4de6bf3a15

@ -674,8 +674,6 @@ public static class MultiLanguageConst
public const string InvoiceRateFee = "Invoice_Rate_Fee";
[Description("模板字段定义文件不存在")]
public const string TemplateFileNotFound = "Template_File_NotFound";
[Description("模板")]
public const string DefaultTemplateName = "Default_Template_Name";
[Description("所选申请项已被其他业务(发票开出/发票结算/申请结算)所使用,无法删除")]
public const string ApplicationIsUsed = "Application_Is_Used";
#endregion

@ -43,12 +43,12 @@ namespace DS.WMS.Core.Application.Dtos
/// <summary>
/// 发票抬头
/// </summary>
public string InvoiceHeader { get; set; }
public string? InvoiceHeader { get; set; }
/// <summary>
/// 纳税人识别号
/// </summary>
public string TaxID { get; set; }
public string? TaxID { get; set; }
/// <summary>
/// 税率

@ -28,7 +28,7 @@
public string? ClientAccount { get; set; }
/// <summary>
/// 方银行
/// 方银行
/// </summary>
public string? BankName { get; set; }

@ -18,7 +18,13 @@ namespace DS.WMS.Core.Application.Entity
/// <summary>
/// 模板内容
/// </summary>
[SugarColumn(ColumnDescription = "模板内容", IsNullable = false, Length = 200)]
[SugarColumn(ColumnDescription = "模板内容", IsNullable = true, Length = 200)]
public string? Content { get; set; }
/// <summary>
/// 币别
/// </summary>
[SugarColumn(ColumnDescription = "币别", IsNullable = true, Length = 3)]
public string? Currency { get; set; }
}
}

@ -36,9 +36,9 @@ namespace DS.WMS.Core.Application.Interface
/// 渲染模板
/// </summary>
/// <param name="id">发票申请ID</param>
/// <param name="templateText">模板文本</param>
/// <param name="templateId">模板ID</param>
/// <param name="environment"></param>
/// <returns></returns>
Task<DataResult<string>> RenderTemplateAsync(long id, string templateText, IHostEnvironment environment);
Task<DataResult<string>> RenderTemplateAsync(long id, long templateId, IHostEnvironment environment);
}
}

@ -1,4 +1,5 @@
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.Core.Enums;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Application.Dtos;
@ -12,7 +13,7 @@ using SqlSugar;
namespace DS.WMS.Core.Application.Method
{
/// <summary>
/// 费用申请单审核服务
/// 发票申请审核服务
/// </summary>
public class InvoiceApplicationAuditService : ApplicationAuditService<InvoiceApplication>, IInvoiceApplicationAuditService
{
@ -24,6 +25,7 @@ namespace DS.WMS.Core.Application.Method
/// <param name="serviceProvider"></param>
public InvoiceApplicationAuditService(IServiceProvider serviceProvider) : base(serviceProvider)
{
TenantDb.QueryFilter.Clear<IOrgId>();
}
/// <summary>

@ -39,8 +39,8 @@ namespace DS.WMS.Core.Application.Method
{
List<IConditionalModel> whereList = request.GetConditionalModels(Db);
var result = await TenantDb.Queryable<InvoiceApplication>()
.WhereIF(!string.IsNullOrEmpty(request.OtherQueryCondition?.Number), x =>
SqlFunc.Subqueryable<ApplicationDetail>().InnerJoin<FeeRecord>((d, f) => d.RecordId == f.Id && f.BusinessType == BusinessType.OceanShippingExport)
.WhereIF(!string.IsNullOrEmpty(request.OtherQueryCondition?.Number), a => a.ApplicationNO.Contains(request.OtherQueryCondition.Number) ||
SqlFunc.Subqueryable<ApplicationDetail>().InnerJoin<FeeRecord>((d, f) => d.ApplicationId == a.Id && d.RecordId == f.Id && f.BusinessType == BusinessType.OceanShippingExport)
.InnerJoin<SeaExport>((d, f, s) => f.BusinessId == s.Id).Where((d, f, s) =>
s.CustomerNo.Contains(request.OtherQueryCondition.Number) || s.BookingNo.Contains(request.OtherQueryCondition.Number) ||
s.MBLNO.Contains(request.OtherQueryCondition.Number) || s.CustomerNum.Contains(request.OtherQueryCondition.Number)).Any())
@ -342,7 +342,6 @@ namespace DS.WMS.Core.Application.Method
OtherCurrencyAmount = a.OtherCurrencyAmount,
Category = a.Category,
CustomerAddTel = a.CustomerAddTel,
CustomerBankId = a.CustomerBankId,
CustomerBankName = b1.BankName + " " + b1.BankAccountNo,
USDCustomerBankId = a.USDCustomerBankId,

@ -1,6 +1,5 @@
using System.Text;
using DS.Module.Core;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Application.Dtos;
using DS.WMS.Core.Application.Entity;
using DS.WMS.Core.Application.Interface;
@ -8,9 +7,11 @@ using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Fee.Method;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Entity;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SqlSugar;
namespace DS.WMS.Core.Application.Method
{
@ -19,7 +20,7 @@ namespace DS.WMS.Core.Application.Method
/// </summary>
public class InvoiceTemplateService : FeeServiceBase, IInvoiceTemplateService
{
const int MAX_NUM = 3;//每个用户的最大模板数量
const int MAX_NUM = 2;//每个用户的最大模板数量
/// <summary>
/// 初始化
@ -58,10 +59,8 @@ namespace DS.WMS.Core.Application.Method
if (list.Count == 0 && createIfEmpty)
{
var arr = new InvoiceTemplate[MAX_NUM];
for (int i = 0; i < MAX_NUM; i++)
{
arr[i] = new InvoiceTemplate { Content = string.Empty, Name = $"{MultiLanguageConst.DefaultTemplateName}{i + 1}" };
}
arr[0] = new InvoiceTemplate { Currency = FeeCurrency.RMB_CODE, Name = $"发票备注模板-{FeeCurrency.RMB_CODE}" };
arr[1] = new InvoiceTemplate { Currency = FeeCurrency.USD_CODE, Name = $"发票备注模板-{FeeCurrency.USD_CODE}" };
return Save(arr);
}
@ -77,7 +76,7 @@ namespace DS.WMS.Core.Application.Method
{
int rows = TenantDb.Storageable(templates).DefaultAddElseUpdate().ExecuteCommand();
return rows > 0 ?
DataResult<List<InvoiceTemplate>>.Success(new List<InvoiceTemplate>(templates)) :
DataResult<List<InvoiceTemplate>>.Success([.. templates]) :
DataResult<List<InvoiceTemplate>>.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
@ -85,12 +84,21 @@ namespace DS.WMS.Core.Application.Method
/// 渲染模板
/// </summary>
/// <param name="id">发票申请ID</param>
/// <param name="templateText">模板文本</param>
/// <param name="templateId">模板ID</param>
/// <param name="environment"></param>
/// <returns></returns>
public async Task<DataResult<string>> RenderTemplateAsync(long id, string templateText, IHostEnvironment environment)
public async Task<DataResult<string>> RenderTemplateAsync(long id, long templateId, IHostEnvironment environment)
{
var dto = await GetTemplateFormAsync(id);
var template = await TenantDb.Queryable<InvoiceTemplate>().Where(x => x.Id == templateId).Select(x => new
{
x.Id,
x.Content,
x.Currency
}).FirstAsync();
if (template == null)
return DataResult<string>.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
var dto = await GetTemplateFormAsync(id, template.Currency);
if (dto == null)
return DataResult<string>.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
@ -98,13 +106,16 @@ namespace DS.WMS.Core.Application.Method
var jObj = JObject.Parse(json);
var jArray = jObj[nameof(InvoiceTemplateForm.Details)] as JArray;
StringBuilder sb = new(templateText);
StringBuilder sb2 = new();
var fields = GetFields(environment).Data;
if (fields == null)
return DataResult<string>.Success(string.Empty);
StringBuilder sb = new(template.Content);
StringBuilder sb2 = new();
foreach (var field in fields)
{
//循环输出
if (templateText.Contains($"<{field.DisplayName}>"))
if (template.Content.Contains($"<{field.DisplayName}>"))
{
foreach (var item in jArray)
{
@ -120,44 +131,53 @@ namespace DS.WMS.Core.Application.Method
}
}
//单次输出
else if (templateText.Contains($"[{field.DisplayName}]"))
else if (template.Content.Contains($"[{field.DisplayName}]"))
{
string val = string.Empty;
string? val = string.Empty;
if (field.IsSumValue)
{
val = jObj[field.FieldName]?.Value<string>();
}
else if (jArray.Count > 0)
else
{
var item1 = jArray[0];
val = item1[field.FieldName]?.Value<string>();
var token = jObj[field.FieldName];
if (token == null && jArray?.Count > 0)
token = jArray[0][field.FieldName];
if (token != null && token.Type != JTokenType.Null)
{
if (token.Type == JTokenType.Date)
val = token.Value<DateTime>().ToString("yyyy-MM-dd");
else if (token.Type == JTokenType.Array && token.HasValues)
val = string.Join(",", token.Values<string>());
else
val = token.Value<string>();
}
}
if (!val.IsNullOrEmpty())
sb = sb.Replace($"[{field.DisplayName}]", val);
sb = sb.Replace($"[{field.DisplayName}]", val);
}
}
return DataResult<string>.Success(sb.ToString());
}
/// <summary>
/// 获取发票模板所需数据
/// </summary>
/// <param name="id">发票申请ID</param>
/// <returns></returns>
internal async Task<InvoiceTemplateForm> GetTemplateFormAsync(long id)
//获取发票模板所需数据
internal async Task<InvoiceTemplateForm> GetTemplateFormAsync(long id, string currency)
{
var dto = await TenantDb.Queryable<InvoiceApplication>()
.LeftJoin<InfoClientBank>((a, b) => a.CustomerBankId == b.Id)
.Where((a, b) => a.Id == id).Select((a, b) => new InvoiceTemplateForm
{
CustomerId = a.CustomerId,
CustomerName = a.CustomerName,
CustomerBankId = a.CustomerBankId,
ClientAccount = b.Account,
ClientBankName = b.BankName
}).FirstAsync();
.LeftJoin<InfoClientBank>((a, b1) => a.CustomerBankId == b1.Id && b1.Currency == currency)
.LeftJoin<InfoClientBank>((a, b1, b2) => a.USDCustomerBankId == b2.Id && b2.Currency == currency)
.LeftJoin<SysBank>((a, b1, b2, sb) => sb.LinkId == SqlFunc.IsNull(a.SaleDeptId, a.OrgId), "shippingweb8_dev.sys_bank")
.Where((a, b1, b2, sb) => a.Id == id && sb.IsDefault).Select((a, b1, b2, sb) => new InvoiceTemplateForm
{
CustomerId = a.CustomerId,
CustomerName = a.CustomerName,
CustomerBankId = a.CustomerBankId,
ClientAccount = currency == FeeCurrency.USD_CODE ? b2.BankAccountNo : b1.BankAccountNo,
ClientBankName = currency == FeeCurrency.USD_CODE ? b2.BankName : b1.BankName,
BankName = sb.BankName
}).FirstAsync();
if (dto != null)
{
@ -191,7 +211,6 @@ namespace DS.WMS.Core.Application.Method
x.ETD,
x.CntrTotal,
x.AccountDate,
x.OperatorCode,
x.Vessel,
x.Voyno,
x.LoadPort,

@ -1,4 +1,5 @@
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.Core.Enums;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Application.Dtos;
@ -27,6 +28,7 @@ namespace DS.WMS.Core.Application.Method
/// <param name="serviceProvider"></param>
public PaymentApplicationAuditService(IServiceProvider serviceProvider) : base(serviceProvider)
{
TenantDb.QueryFilter.Clear<IOrgId>();
}
/// <summary>
@ -152,7 +154,9 @@ namespace DS.WMS.Core.Application.Method
x.Voyno,
x.Carrier,
x.Forwarder,
x.BookingNo
x.BookingNo,
x.Sale,
x.SaleDeptName,
}).ToListAsync();
foreach (var item in g)
{
@ -171,6 +175,8 @@ namespace DS.WMS.Core.Application.Method
item.Carrier = biz.Carrier;
item.Forwarder = biz.Forwarder;
item.BookingNo = biz.BookingNo;
item.SaleName = biz.Sale;
item.SaleDeptName = biz.SaleDeptName;
}
}
break;

@ -21,5 +21,13 @@ namespace DS.WMS.Core.Invoice.Interface
/// <param name="ids">申请单ID</param>
/// <returns></returns>
Task<DataResult<List<InvoiceApplicationDetailDto>>> GetApplicationDetailsAsync(params long[] ids);
/// <summary>
/// 更新发票申请的状态
/// </summary>
/// <param name="deleteOption">删除选项;仅在删除时指定</param>
/// <param name="invoiceNumbers">发票号</param>
/// <returns></returns>
Task RefreshApplicationStatus(IEnumerable<string> invoiceNumbers, DeleteOption? deleteOption = null);
}
}

@ -59,13 +59,5 @@ namespace DS.WMS.Core.Invoice.Interface
/// <param name="ids">发票ID</param>
/// <returns></returns>
Task<DataResult> SetLockAsync(bool isLocked, params long[] ids);
/// <summary>
/// 设置发票的作废状态
/// </summary>
/// <param name="isCancelled">是否锁定</param>
/// <param name="ids">发票ID</param>
/// <returns></returns>
Task<DataResult> SetCancelAsync(bool isCancelled, params long[] ids);
}
}

@ -146,11 +146,6 @@ namespace DS.WMS.Core.Invoice.Method
}
}
protected override Task PostSaveAsync(Entity.Invoice invoice)
{
return RefreshApplicationStatus([invoice], null);
}
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
@ -205,38 +200,21 @@ namespace DS.WMS.Core.Invoice.Method
await base.OnDeleteDetailAsync(invoices, deleteOption);
}
protected override Task PostDeleteAsync(List<Entity.Invoice> invoices, DeleteOption deleteOption)
{
////获取关联的发票申请的ID
//var ids = invoices.SelectMany(x => x.Details).Where(x => x.RefId.HasValue).Select(x => x.RefId.GetValueOrDefault()).Distinct();
//if (deleteOption == DeleteOption.Entire)
//{
// return TenantDb.Updateable<InvoiceApplication>()
// .SetColumns(x => x.Status == InvoiceApplicationStatus.AuditPassed)
// .Where(x => ids.Contains(x.Id))
// .ExecuteCommandAsync();
//}
//else if (deleteOption == DeleteOption.DetailOnly)
//{
// //获取关联的发票申请的明细ID
// var ids2 = invoices.SelectMany(x => x.Details).Where(x => x.DetailId.HasValue).Select(x => x.DetailId.GetValueOrDefault()).Distinct();
//}
//return Task.CompletedTask;
return RefreshApplicationStatus(invoices, deleteOption);
}
//更新发票申请的状态
private async Task RefreshApplicationStatus(List<Entity.Invoice> invoices, DeleteOption? deleteOption)
/// <summary>
/// 更新发票申请的状态
/// </summary>
/// <param name="deleteOption">删除选项;仅在删除时指定</param>
/// <param name="invoiceNumbers">发票号</param>
/// <returns></returns>
public async Task RefreshApplicationStatus(IEnumerable<string> invoiceNumbers, DeleteOption? deleteOption = null)
{
var invoices = await TenantDb.Queryable<Entity.Invoice>().Where(x => invoiceNumbers.Contains(x.InvoiceNO)).ToListAsync();
if (invoices == null || !invoices.Any())
return;
//获取关联的发票申请的ID
var ids = invoices.SelectMany(x => x.Details).Where(x => x.RefId.HasValue).Select(x => x.RefId.GetValueOrDefault()).Distinct().ToList();
var appDetails = await TenantDb.Queryable<ApplicationDetail>().Where(d => ids.Contains(d.ApplicationId))
var appIds = invoices.SelectMany(x => x.Details).Where(x => x.RefId.HasValue).Select(x => x.RefId.GetValueOrDefault()).Distinct().ToList();
var appDetails = await TenantDb.Queryable<ApplicationDetail>().Where(d => appIds.Contains(d.ApplicationId))
.Select(d => new ApplicationDetail
{
Id = d.Id,
@ -246,8 +224,8 @@ namespace DS.WMS.Core.Invoice.Method
OriginalProcessedAmount = d.OriginalProcessedAmount
}).ToListAsync();
List<InvoiceApplication> list2 = new(ids.Count);
foreach (var id in ids)
List<InvoiceApplication> list2 = new(appIds.Count);
foreach (var id in appIds)
{
var entity = new InvoiceApplication { Id = id };
var details = appDetails.FindAll(x => x.ApplicationId == id);

@ -19,7 +19,6 @@ namespace DS.WMS.Core.Invoice.Method
/// </summary>
public sealed class InvoiceIssuanceService : ApplicationServiceBase, IInvoiceIssuanceService
{
//readonly InvoiceApiFox api;
static readonly ApiFox api;
static InvoiceIssuanceService()
@ -264,6 +263,8 @@ namespace DS.WMS.Core.Invoice.Method
x.PDFUrl
}).ExecuteCommandAsync();
await InvoiceService.Value.RefreshApplicationStatus(invoices.Select(x => x.InvoiceNO)!);
await TenantDb.Ado.CommitTranAsync();
}
catch (Exception ex)

@ -593,7 +593,7 @@ namespace DS.WMS.Core.Invoice.Method
}
}
static DataResult AssignAmount(List<ApplicationDetail> details, decimal invoiceAmount)
internal static DataResult AssignAmount(List<ApplicationDetail> details, decimal invoiceAmount, string currency = FeeCurrency.RMB_CODE)
{
if (details.Count == 0)
return DataResult.Success;
@ -601,48 +601,54 @@ namespace DS.WMS.Core.Invoice.Method
if (invoiceAmount == 0)
return DataResult.Failed("开票金额不能为零");
var totalAmount = details.Exists(x => x.Currency != FeeCurrency.RMB_CODE) ?
details.Sum(x => x.OriginalAmount) : details.Sum(x => x.ApplyAmount);
var totalAmount = details.Sum(x => x.ApplyAmount);
if (Math.Abs(invoiceAmount) > totalAmount)
return DataResult.Failed("申请开票金额不能大于剩余票金额");
return DataResult.Failed("申请开票金额不能大于剩余票金额");
if (totalAmount != invoiceAmount) //非全额开票
decimal rest = invoiceAmount;
decimal currentAmount = default;
foreach (var detail in details)
{
decimal rest = invoiceAmount;
foreach (var detail in details)
{
if (rest <= 0)
break;
if (rest <= 0)
break;
if (rest >= detail.OriginalAmount)
if (totalAmount != invoiceAmount) //非全额开
{
if (rest >= detail.ApplyAmount)
{
rest = rest - detail.OriginalAmount;
rest -= detail.ApplyAmount;
}
else
{
detail.OriginalAmount = rest;
detail.ApplyAmount = rest;
rest = 0;
}
}
currentAmount = detail.ApplyAmount;
if (detail.Currency == FeeCurrency.RMB_CODE)
detail.ApplyAmount = detail.OriginalAmount;
else
detail.ApplyAmount = detail.OriginalAmount * detail.ExchangeRate.GetValueOrDefault();
detail.Assigned = true;
if (detail.Currency == currency)
{
detail.ExchangeRate = 1;
detail.OriginalAmount = detail.ApplyAmount;
}
}
else
{
foreach (var detail in details)
else //开票币别与费用币别不一致
{
if (detail.Currency == FeeCurrency.RMB_CODE)
detail.ApplyAmount = detail.OriginalAmount;
detail.ExchangeRate ??= 1;
detail.ApplyAmount *= detail.ExchangeRate.Value;
if (detail.OriginalCurrency == detail.Currency)
{
detail.OriginalAmount = currentAmount;
}
else
detail.ApplyAmount = detail.OriginalAmount * detail.ExchangeRate.GetValueOrDefault();
{
detail.OriginalAmount = currentAmount * detail.ExchangeRate.Value;
}
detail.Assigned = true;
detail.Currency = currency;
}
detail.Assigned = true;
}
return DataResult.Success;
@ -1015,7 +1021,6 @@ namespace DS.WMS.Core.Invoice.Method
/// <param name="deleteOption">发票删除选项</param>
protected virtual Task PostDeleteAsync(List<TEntity> invoices, DeleteOption deleteOption) => Task.CompletedTask;
/// <summary>
/// 设置发票的锁定状态
/// </summary>

@ -93,7 +93,6 @@ namespace DS.WMS.Core.Settlement.Method
detail.Assigned = true;
}
return DataResult.Success;
}

@ -221,15 +221,15 @@ namespace DS.WMS.FeeApi.Controllers
/// 以申请单的数据渲染发票模板
/// </summary>
/// <param name="id">发票申请ID</param>
/// <param name="template">模板文本</param>
/// <param name="templateId">模板ID</param>
/// <param name="templateService"></param>
/// <param name="host"></param>
/// <returns></returns>
[HttpGet, Route("RenderTemplate")]
public async Task<DataResult<string>> RenderTemplate([FromQuery] long id, [FromQuery] string template,
public async Task<DataResult<string>> RenderTemplate([FromQuery] long id, [FromQuery] long templateId,
[FromServices] IInvoiceTemplateService templateService, [FromServices] IHostEnvironment host)
{
return await templateService.RenderTemplateAsync(id, template, host);
return await templateService.RenderTemplateAsync(id, templateId, host);
}
}
}

Loading…
Cancel
Save