You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

692 lines
33 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System.Text;
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.Application.Interface;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Fee.Dtos;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Entity;
using LanguageExt;
using SqlSugar;
namespace DS.WMS.Core.Application.Method
{
/// <summary>
/// 发票申请
/// </summary>
public class InvoiceApplicationService : ApplicationService<InvoiceApplication>, IInvoiceApplicationService
{
public override TaskBaseTypeEnum AuditType => TaskBaseTypeEnum.APPLICATION_INVOICE_AUDIT;
/// <summary>
/// 初始化
/// </summary>
/// <param name="serviceProvider"></param>
public InvoiceApplicationService(IServiceProvider serviceProvider) : base(serviceProvider)
{
}
/// <summary>
/// 获取分页列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<InvoiceApplicationDto>>> GetListAsync(PageRequest request)
{
List<IConditionalModel> whereList = request.GetConditionalModels(Db);
var result = await TenantDb.Queryable<InvoiceApplication>().Where(whereList)
.Select((x) => new InvoiceApplicationDto
{
Id = x.Id,
ApplicationNO = x.ApplicationNO,
Status = x.Status,
CustomerName = x.CustomerName,
InvoiceHeader = x.InvoiceHeader,
Currency = x.Currency,
ApplyAmount = x.ApplyAmount,
InvoiceAmount = x.InvoiceAmount,
CreateTime = x.CreateTime, //申请时间
CreateBy = x.CreateBy, //申请人ID
InvoiceNO = x.InvoiceNO,
InvoiceBillNO = x.InvoiceBillNO, //实际开出票号
Note = x.Note,
Reason = x.Reason,
InvoiceDate = x.InvoiceDate,
Category = x.Category, //申请类型
TaxRate = x.TaxRate,
PushMode = x.PushMode,
Email = x.Email,
CellPhoneNO = x.CellPhoneNO,
InvoiceRemark = x.InvoiceRemark, //开票要求
//原币金额
OriginalAmountList = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => x.Id == y.ApplicationId)
.GroupBy(y => y.OriginalCurrency).ToList(y => new CurrencyAmount { Currency = y.OriginalCurrency, Amount = y.OriginalAmount }),
//未结算
UnsettledList = SqlFunc.Subqueryable<ApplicationDetail>().InnerJoin<FeeRecord>((d, f) => d.RecordId == f.Id && (f.Amount - f.SettlementAmount - f.OrderSettlementAmount) != 0)
.GroupBy((d, f) => f.Currency).ToList((d, f) => new CurrencyAmount { Currency = f.Currency, Amount = f.Amount - f.SettlementAmount - f.OrderSettlementAmount })
}).ToQueryPageAsync(request.PageCondition);
if (result.Data.Count > 0)
{
//关联用户名称
var userIds = result.Data.Select(x => x.CreateBy).Distinct();
var users = await Db.Queryable<SysUser>().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync();
foreach (var item in result.Data)
{
item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName;
}
result.AdditionalData = new Dictionary<string, object>
{
{ "ApplyAmountSum", result.Data.Sum(x => x.ApplyAmount) },
{ "InvoiceAmountSum", result.Data.Sum(x => x.InvoiceAmount.GetValueOrDefault()) }
};
}
return result;
}
/// <summary>
/// 获取待申请的业务列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<BizInvoiceApplication>>> GetBizListAsync(PageRequest<InvoiceApplicationQuery?> request)
{
var query = CreateBizQuery(request.GetConditionalModels(Db));
if (request.OtherQueryCondition != null)
{
if (request.OtherQueryCondition.FeeRange.HasValue)
{
switch (request.OtherQueryCondition.FeeRange)
{
case FeeRange.Unsettled:
query = query.Where(x => x.SettlementAmount == 0);
break;
case FeeRange.Settled:
query = query.Where(x => x.SettlementAmount > 0);
break;
case FeeRange.PaidNotReceived:
query = query.Where(x => x.UnSettlementPaid == 0 && x.UnSettlementCharged > 0);
break;
case FeeRange.ReceivedNotPaid:
query = query.Where(x => x.UnSettlementPaid > 0 && x.UnSettlementCharged == 0);
break;
case FeeRange.NotAppliedSettled:
query = query.Where(x => x.OrderAmount == 0 && x.SettlementAmount == 0);
break;
case FeeRange.UnreconciledSettled:
query = query.Where(x => x.DebitNo == null && x.SettlementAmount == 0);
break;
case FeeRange.NotIssuedSettled:
query = query.Where(x => x.InvoiceAmount == 0 && x.SettlementAmount == 0);
break;
case FeeRange.ReconciledNotSettled:
query = query.Where(x => x.DebitNo != null && x.SettlementAmount == 0);
break;
case FeeRange.NotReceivedPaid:
query = query.Where(x => x.UnSettlementPaid > 0 && x.UnSettlementCharged > 0);
break;
case FeeRange.SettledNotIssued:
query = query.Where(x => x.InvoiceAmount == 0 && x.SettlementAmount > 0);
break;
}
}
if (!string.IsNullOrEmpty(request.OtherQueryCondition.Number))
{
query = query.Where(x => x.MBLNO.Contains(request.OtherQueryCondition.Number) ||
x.CustomerNo.Contains(request.OtherQueryCondition.Number) ||
x.CustomerNum.Contains(request.OtherQueryCondition.Number) ||
x.BookingNo.Contains(request.OtherQueryCondition.Number));
}
}
var result = await query.ToQueryPageAsync(request.PageCondition);
if (result.Data.Count > 0)
{
//关联用户名称
var userIds = result.Data.Where(x => x.OperatorId.HasValue).Select(x => x.OperatorId.Value)
.Union(result.Data.Select(x => x.CreateBy))
.Distinct();
var users = await Db.Queryable<SysUser>().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync();
//关联机构名称
var orgIds = result.Data.Select(x => x.SaleDeptId).Distinct();
var orgs = await Db.Queryable<SysOrg>().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.OrgName }).ToListAsync();
foreach (var item in result.Data)
{
item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName;
if (item.OperatorId.HasValue)
item.Operator = users.Find(x => x.Id == item.OperatorId.Value)?.UserName;
item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName;
}
}
return result;
}
//创建各项业务数据的查询并集
internal ISugarQueryable<BizInvoiceApplication> CreateBizQuery(List<IConditionalModel> conditionals)
{
var query = CreateFeeQuery((s, f) => f.FeeStatus == FeeStatus.AuditPassed && (f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount != 0));
return query.MergeTable().Where(conditionals)
.GroupBy(x => new { x.BusinessId, x.BusinessType, x.CustomerId })
.Select(s => new BizInvoiceApplication
{
Id = s.BusinessId,
AccountDate = s.AccountDate,
BusinessType = BusinessType.OceanShippingExport,
CntrTotal = s.CntrTotal,
CreateBy = s.CreateBy,
CustomerId = s.CustomerId,//费用对象
CustomerName = s.CustomerName,
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,
SaleName = s.Sale,//揽货人
Vessel = s.Vessel,//船名
Voyage = s.Voyage,//航次
BookingNo = s.BookingNo,
StlName = s.StlName,
//OrderAmount = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId).Sum(f => f.OrderAmount),
//InvoiceAmount = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId).Sum(f => f.InvoiceAmount),
//SettlementAmount = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId).Sum(f => f.SettlementAmount),
//未申请开票金额=金额-开票金额-申请开票金额+申请开票金额已开票
UnBilledRMB = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId && f.FeeStatus == FeeStatus.AuditPassed
&& f.Currency == FeeCurrency.RMB_CODE).Sum(f => f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount),
UnBilledUSD = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId && f.FeeStatus == FeeStatus.AuditPassed
&& f.Currency == FeeCurrency.USD_CODE).Sum(f => f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount),
UnBilledOther = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId && f.FeeStatus == FeeStatus.AuditPassed
&& f.Currency != FeeCurrency.RMB_CODE && f.Currency != FeeCurrency.USD_CODE).Sum(f => f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount),
//未结算金额=金额-结算金额-申请金额+申请金额已结算
UnSettlementPaid = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Payable)
.Sum(f => f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount),
UnSettlementCharged = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == s.BusinessId && f.FeeStatus == FeeStatus.AuditPassed && f.FeeType == FeeType.Receivable)
.Sum(f => f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount),
});
}
/// <summary>
/// 根据业务编号及类型获取关联费用记录
/// </summary>
/// <param name="inquiry">业务ID与业务类型</param>
/// <returns></returns>
public async Task<DataResult<InvoiceApplicaitonBiz>> GetFeesAsync(DetailInquiry inquiry)
{
var bizIds = inquiry.Items.Select(x => x.Id).Distinct();
var types = inquiry.Items.Select(x => x.BusinessType).Distinct();
var cIds = inquiry.Items.Select(x => x.CustomerId).Distinct();
var list = await TenantDb.Queryable<FeeRecord>()
.Where(f => f.FeeStatus == FeeStatus.AuditPassed &&
bizIds.Contains(f.BusinessId) && types.Contains(f.BusinessType) && cIds.Contains(f.CustomerId))
.Where(inquiry.GetConditionalModels(Db))
.Select(f => new FeeInvoiceDto
{
RecordId = f.Id,
BusinessId = f.BusinessId,
BusinessType = f.BusinessType,
CustomerId = f.CustomerId,
CustomerName = f.CustomerName,
FeeId = f.FeeId,
FeeName = f.FeeName,
FeeType = f.FeeType,
Amount = f.Amount,
Currency = f.Currency,
OriginalAmount = f.Amount,
OriginalCurrency = f.Currency,
TaxRate = f.TaxRate,
RestAmount = f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount,
Remark = f.Remark,
CreateBy = f.CreateBy
}).ToListAsync();
//移除开票剩余金额为0的项
list.RemoveAll(f => f.RestAmount == 0);
if (list.Count > 0)
{
//关联用户名称
var userIds = list.Select(x => x.CreateBy).Distinct();
var users = await Db.Queryable<SysUser>().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync();
foreach (var item in list)
{
item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName;
}
}
return DataResult<InvoiceApplicaitonBiz>.Success(new InvoiceApplicaitonBiz(list));
}
/// <summary>
/// 获取发票申请详情
/// </summary>
/// <param name="id">申请单ID</param>
/// <returns></returns>
public async Task<DataResult<InvoiceApplicationDto>> GetAsync(long id)
{
var dto = await TenantDb.Queryable<InvoiceApplication>()
.LeftJoin<InfoClientBank>((a, b1) => a.CustomerBankId == b1.Id)
.LeftJoin<InfoClientBank>((a, b1, b2) => a.USDCustomerBankId == b2.Id)
.Where(a => a.Id == id)
.Select((a, b1, b2) => new InvoiceApplicationDto
{
Id = a.Id,
ApplicationNO = a.ApplicationNO,
AutualCustomerName = a.AutualCustomerName,
Currency = a.Currency,
CustomerId = a.CustomerId,
CustomerName = a.CustomerName,
Status = a.Status,
CreateTime = a.CreateTime,
CreateBy = a.CreateBy,
InvoiceDate = a.InvoiceDate,
InvoiceAmount = a.InvoiceAmount,
InvoiceHeader = a.InvoiceHeader,
InvoiceNO = a.InvoiceNO,
InvoiceBillNO = a.InvoiceBillNO,
InvoiceRemark = a.InvoiceRemark,
SaleDeptId = a.SaleDeptId,
TaxID = a.TaxID,
Note = a.Note,
ApplyAmount = a.ApplyAmount,
OtherCurrencyAmount = a.OtherCurrencyAmount,
Category = a.Category,
CustomerAddTel = a.CustomerAddTel,
CustomerBankId = a.CustomerBankId,
CustomerBankName = b1.BankName + " " + b1.Account,
USDCustomerBankId = a.USDCustomerBankId,
USDCustomerBankName = b2.BankName + " " + b2.Account
}).FirstAsync();
if (dto != null)
{
dto.CreateByName = await Db.Queryable<SysUser>().Where(x => x.Id == dto.CreateBy).Select(x => x.UserName).FirstAsync();
dto.SaleDeptName = await Db.Queryable<SysOrg>().Where(x => x.Id == dto.SaleDeptId).Select(x => x.OrgName).FirstAsync();
dto.InvoiceDetails = await TenantDb.Queryable<InvoiceDetail>().Where(x => x.ApplicationId == dto.Id && x.Category == DetailCategory.InvoiceApplication).ToListAsync();
dto.Details = await TenantDb.Queryable<ApplicationDetail>().LeftJoin<FeeRecord>((d, f) => d.RecordId == f.Id)
.Where(d => d.ApplicationId == id).Select((d, f) => new InvoiceApplicationDetailDto
{
Id = d.Id,
RecordId = f.Id,
FeeType = d.FeeType,
FeeId = d.FeeId,
FeeName = d.FeeName,
Amount = d.ApplyAmount,
ApplyAmount = d.ApplyAmount,
OriginalAmount = d.OriginalAmount,
//未申请金额=(金额-结算金额-申请金额+申请金额已结算)
RestAmount = f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount,
Currency = d.Currency,
OriginalCurrency = d.OriginalCurrency,
OriginalRate = f.ExchangeRate,
ExchangeRate = d.ExchangeRate,
AccTaxRate = f.AccTaxRate,
BusinessId = f.BusinessId,
BusinessType = f.BusinessType
}).ToListAsync();
var gList = dto.Details.GroupBy(x => x.BusinessType).ToList();
foreach (var g in gList)
{
var ids = g.Select(x => x.BusinessId).ToList();
switch (g.Key)
{
case BusinessType.OceanShippingExport:
var list1 = await TenantDb.Queryable<SeaExport>().Where(x => ids.Contains(x.Id)).Select(x => new
{
x.Id,
x.MBLNO,
x.CustomerNo,
x.CustomerName,
x.ETD,
x.CntrTotal,
x.AccountDate,
x.OperatorCode,
x.Vessel,
x.Voyno,
x.Carrier,
x.Forwarder
}).ToListAsync();
foreach (var item in g)
{
var biz = list1.Find(x => x.Id == item.BusinessId);
if (biz != null)
{
item.MBLNO = biz.MBLNO;
item.CustomerName = biz.CustomerName;
item.CustomerNo = biz.CustomerNo;
item.ETD = biz.ETD;
item.CntrTotal = biz.CntrTotal;
item.AccountDate = biz.AccountDate;
item.Operator = biz.OperatorCode;
item.Vessel = biz.Vessel;
item.Voyage = biz.Voyno;
item.Carrier = biz.Carrier;
item.Forwarder = biz.Forwarder;
}
}
break;
case BusinessType.OceanShippingImport:
break;
}
}
dto.SummaryItems = dto.Details.GroupBy(x => new { x.FeeType, x.Currency }).Select(x => new SummaryItem
{
FeeType = x.Key.FeeType,
Currency = x.Key.Currency,
Amount = x.Sum(y => y.Amount),
OriginalAmount = x.Sum(y => y.OriginalAmount)
}).ToList();
}
return DataResult<InvoiceApplicationDto>.Success(dto);
}
/// <summary>
/// 删除发票明细
/// </summary>
/// <param name="ids">发票明细ID</param>
/// <returns></returns>
public async Task<DataResult> DeleteInvoiceDetailAsync(params long[] ids)
{
int rows = await TenantDb.Deleteable<InvoiceDetail>().Where(x => ids.Contains(x.Id)).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
//获取发票申请关联明细
protected override async Task<List<ApplicationDetail>> GetDetailsAsync(ApplicationRequest<InvoiceApplication> request)
{
var ids1 = request.Items.Select(x => x.Id).Distinct();
var ids2 = request.Items.Select(x => x.BusinessType).Distinct();
var ids3 = request.Items.Select(x => x.CustomerId).Distinct();
var list = await TenantDb.Queryable<FeeRecord>().Where(x => x.FeeStatus == FeeStatus.AuditPassed &&
ids1.Contains(x.BusinessId) && ids2.Contains(x.BusinessType) && ids3.Contains(x.CustomerId) &&
x.Amount - x.InvoiceAmount - x.OrderInvoiceAmount + x.OrderInvSettlementAmount != 0)
.Where(request.GetQueryConditions(Db))
.Select(x => new ApplicationDetail
{
BusinessId = x.BusinessId,
BusinessType = x.BusinessType,
RecordId = x.Id,
CustomerName = x.CustomerName,
FeeType = x.FeeType,
FeeId = x.FeeId,
FeeName = x.FeeName,
Currency = x.Currency,
ApplyAmount = x.Amount - x.InvoiceAmount - x.OrderInvoiceAmount + x.OrderInvSettlementAmount,
ExchangeRate = x.ExchangeRate,
OriginalCurrency = x.Currency
}).ToListAsync();
foreach (var item in list)
item.OriginalAmount = item.ApplyAmount;
return list;
}
protected override DataResult EnsureApplication(InvoiceApplication application, InvoiceApplication? dbValue)
{
if (dbValue != null && dbValue.Status != InvoiceApplicationStatus.Pending && dbValue.Status != InvoiceApplicationStatus.AuditRejected)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationSaveStatusError));
return DataResult.Success;
}
protected override DataResult CalculateAmount(InvoiceApplication application, List<FeeRecord> fees)
{
if (fees == null)
return DataResult.Success;
//if (fees.Any(x => x.CustomerId != application.CustomerId))
// return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationCustomerDetail));
//原始金额为0则禁止提交
if (application.Details.Any(x => x.OriginalAmount == 0))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.OriginalAmountCannotBeZero));
StringBuilder sb = new();
foreach (var detail in application.Details)
{
var fee = fees.Find(x => x.Id == detail.RecordId);
if (fee == null)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.ApplicationCannotRelateFee)), detail.FeeName);
sb.Append("");
continue;
}
detail.Record = fee;
//检查税率是否一致
if (application.TaxRate != fee.TaxRate)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.InvoiceRateFee)), detail.FeeName);
sb.Append("");
continue;
}
//未申请开票金额=(金额-已开票金额-申请开票金额+申请开票金额已开票
var restAmount = fee.Amount - fee.InvoiceAmount - fee.OrderInvoiceAmount + fee.OrderInvSettlementAmount;
if (restAmount == 0)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.FeeNobalance)), fee.FeeName);
sb.Append("");
continue;
}
if (detail.OriginalAmount > 0 && detail.OriginalAmount > restAmount)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), fee.FeeName);
sb.Append("");
continue;
}
if (detail.OriginalAmount < 0 && detail.OriginalAmount < restAmount)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), fee.FeeName);
sb.Append("");
continue;
}
//更新费用记录的申请开票金额
fee.OrderInvoiceAmount += detail.OriginalAmount;
//类别固定为发票申请
detail.Category = DetailCategory.InvoiceApplication;
}
if (sb.Length > 0)
return DataResult.Failed(sb.ToString());
return DataResult.Success;
}
//保存前调用
protected override async Task PreSaveAsync(InvoiceApplication application)
{
//获取所有应收项
var recvDetails = application.Details.FindAll(x => x.FeeType == FeeType.Payable);
foreach (var item in recvDetails)
{
item.ApplyAmount *= -1;
}
if (application.Id > 0)
return;
if (application.CustomerBankId == null)
{
var bankId = await TenantDb.Queryable<InfoClientBank>().Where(x => x.ClientId == application.CustomerId &&
x.Currency == FeeCurrency.RMB_CODE).OrderByDescending(x => x.IsInvoiceDefault).Select(x => x.Id).FirstAsync();
if (bankId > 0)
application.CustomerBankId = bankId;
}
if (application.USDCustomerBankId == null)
{
var bankId = await TenantDb.Queryable<InfoClientBank>().Where(x => x.ClientId == application.CustomerId &&
x.Currency == FeeCurrency.USD_CODE).OrderByDescending(x => x.IsInvoiceDefault).Select(x => x.Id).FirstAsync();
if (bankId > 0)
application.CustomerBankId = bankId;
}
if (string.IsNullOrEmpty(application.InvoiceHeader))
{
application.TaxID = await TenantDb.Queryable<InfoClient>().Where(x => x.Id == application.CustomerId).Select(x => x.TaxNo).FirstAsync();
var header = await TenantDb.Queryable<InvoiceHeader>().Where(
x => x.RelativeId == application.CustomerId).OrderByDescending(x => x.Id).FirstAsync();
if (header != null)
{
application.InvoiceHeader = header.Header;
application.CustomerAddTel = header.AddressTel;
}
}
}
//提交事务前
protected override async Task OnSaveAsync(InvoiceApplication application, List<FeeRecord>? fees)
{
//根据申请单明细刷新发票明细
await RefreshInvoiceDetailsAsync(application);
if (application.InvoiceDetails?.Count > 0)
await TenantDb.Storageable(application.InvoiceDetails).DefaultAddElseUpdate().ExecuteCommandAsync();
//更新申请开票金额
if (fees != null && fees.Count > 0)
await TenantDb.Updateable(fees)
.PublicSetColumns(x => x.OrderInvoiceAmount, "+")
.UpdateColumns(x => new { x.OrderInvoiceAmount })
.ExecuteCommandAsync();
application.ApplyAmount = await TenantDb.Queryable<ApplicationDetail>().Where(x => x.ApplicationId == application.Id).SumAsync(x => x.ApplyAmount);
application.AmountUppercase = new Money(application.ApplyAmount).ToString();
await base.OnSaveAsync(application, fees);
}
//刷新发票明细
async Task RefreshInvoiceDetailsAsync(InvoiceApplication application)
{
if (application.Details.Count > 0)
{
application.InvoiceDetails ??= [];
var currencies = application.Details.Select(x => x.Currency).Distinct();
var codeList = await TenantDb.Queryable<CodeInvoice>()
.Where(ci => currencies.Contains(ci.DefaultCurrency))
.OrderBy(ci => ci.IsDefault)
.Select(ci => new
{
ci.Id,
ci.Name,
ci.DefaultCurrency,
ci.TaxRate,
ci.Specification,
ci.Unit
}).ToListAsync();
foreach (var detail in application.Details)
{
var code = codeList.Find(x => x.DefaultCurrency == detail.Currency);
if (code == null || string.IsNullOrEmpty(code.Name))
continue;
if (application.BuildOption == BuildOption.Create && codeList.IndexOf(code) == 0)//取第一条发票代码税率
application.TaxRate = code.TaxRate;
var invDetail = application.InvoiceDetails.Find(x => x.CodeId == code.Id);
if (invDetail == null)
{
invDetail = new InvoiceDetail
{
ApplicationId = application.Id,
CodeId = code.Id,
Name = code.Name,
Quantity = 1,
TaxUnitPrice = detail.ApplyAmount,
TaxRate = code.TaxRate,
Specification = code.Specification,
Unit = code.Unit,
Category = DetailCategory.InvoiceApplication
};
invDetail.Amount = invDetail.TaxUnitPrice;
application.InvoiceDetails.Add(invDetail);
}
else
{
invDetail.Amount += detail.ApplyAmount;
invDetail.UnitPrice = invDetail.TaxUnitPrice = invDetail.Amount;
}
}
foreach (var item in application.InvoiceDetails)
{
item.TaxAmount = item.Amount * (application.TaxRate / 100);
item.UnitPrice = item.TaxUnitPrice - item.TaxAmount;
item.Amount = item.TaxUnitPrice * item.Quantity;
}
}
}
protected override DataResult PreDelete(List<InvoiceApplication> applications)
{
if (applications.Any(x => x.Status != InvoiceApplicationStatus.Pending && x.Status != InvoiceApplicationStatus.AuditRejected))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationDeleteStatusError));
return base.PreDelete(applications);
}
protected override async Task OnDeleteDetailAsync(List<InvoiceApplication> applications, DeleteOption deleteOption)
{
//还原费用表的申请开票金额
var fees = applications.SelectMany(x => x.Details).Select(x => new FeeRecord
{
Id = x.RecordId,
OrderInvoiceAmount = x.OriginalAmount
}).ToList();
await TenantDb.Updateable(fees)
.PublicSetColumns(it => it.OrderInvoiceAmount, "-")
.UpdateColumns(x => new { x.OrderInvoiceAmount })
.ExecuteCommandAsync();
}
protected override DataResult PreSubmitApproval(List<InvoiceApplication> applications)
{
if (applications.Exists(x => x.Status == InvoiceApplicationStatus.AuditSubmittd || x.Status == InvoiceApplicationStatus.AuditPassed))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationIsAuditing));
return DataResult.Success;
}
protected override void OnSubmitApproval(InvoiceApplication application)
{
application.Status = InvoiceApplicationStatus.AuditSubmittd;
}
protected override void OnWithdraw(InvoiceApplication application)
{
application.Status = InvoiceApplicationStatus.Pending;
}
}
}