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.

700 lines
35 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.Data;
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.Entity;
using DS.WMS.Core.Invoice.Dtos;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Settlement.Dtos;
using DS.WMS.Core.Settlement.Entity;
using DS.WMS.Core.Settlement.Interface;
using DS.WMS.Core.Sys.Entity;
using Masuit.Tools.Systems;
using SqlSugar;
namespace DS.WMS.Core.Settlement.Method
{
/// <summary>
/// 收/付费申请结算服务
/// </summary>
public class ApplicationSettlementService : SettlementService<ApplicationSettlement>, IApplicationSettlementService
{
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
public ApplicationSettlementService(IServiceProvider provider) : base(provider)
{
TenantDb.QueryFilter.Clear<IOrgId>();
}
/// <summary>
/// 获取结算单分页列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<ApplicationSettlementDto>>> GetListAsync(PageRequest<NumberQuery> request)
{
var query = TenantDb.Queryable<ApplicationSettlement>().WhereIF(!string.IsNullOrEmpty(request.OtherQueryCondition?.Number), x =>
SqlFunc.Subqueryable<ApplicationDetail>().InnerJoin<FeeRecord>((d, f) => 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())
.Select(x => new ApplicationSettlementDto
{
ApplicationNO = x.ApplicationNO,
SettlementNO = x.SettlementNO,
SettlementTypeName = x.SettlementType.StlName, //结算方式
//-----结算金额统计-----
RMBAmount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => y.ApplicationId == x.Id && y.Currency == FeeCurrency.RMB_CODE)
.Select(y => SqlFunc.AggregateSum(y.ApplyAmount)),
USDAmount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => y.ApplicationId == x.Id && y.Currency == FeeCurrency.USD_CODE)
.Select(y => SqlFunc.AggregateSum(y.ApplyAmount)),
OtherAmount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => y.ApplicationId == x.Id && y.Currency != FeeCurrency.RMB_CODE && y.Currency != FeeCurrency.USD_CODE)
.Select(y => SqlFunc.AggregateSum(y.ApplyAmount)),
CustomerAccount = x.CustomerBank.AccountName + "/" + x.CustomerBank.Currency,
CustomerBankName = x.CustomerBank.BankName,
//未开票
UnInvoiceList = SqlFunc.Subqueryable<ApplicationDetail>().InnerJoin<FeeRecord>((d, f) => d.ApplicationId == x.Id && d.RecordId == f.Id)
.GroupBy((d, f) => new { f.BusinessId, f.BusinessType, f.Currency }).ToList((d, f) => new CurrencyAmount { Currency = f.Currency, Amount = SqlFunc.AggregateSum(f.Amount - f.InvoiceAmount) }),
}, true);
var whereList = request.GetConditionalModels(Db);
var result = await query.Where(whereList).ToQueryPageAsync(request.PageCondition);
if (result.Data.Count > 0)
{
//关联用户名称
var userIds = result.Data.Select(x => x.CreateBy)
.Union(result.Data.Where(x => x.LockUserId.HasValue).Select(x => x.LockUserId.Value))
.Union(result.Data.Where(x => x.UnlockUserId.HasValue).Select(x => x.UnlockUserId.Value))
.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().ToList();
var orgs = await Db.Queryable<SysOrg>().Where(x => orgIds.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;
item.LockUser = users.Find(x => x.Id == item.LockUserId)?.UserName;
item.UnlockUser = users.Find(x => x.Id == item.UnlockUserId)?.UserName;
item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName;
}
}
return result;
}
/// <summary>
/// 获取结算单详情
/// </summary>
/// <param name="id">结算单ID</param>
/// <returns></returns>
public async Task<DataResult<ApplicationSettlementDto>> GetAsync(long id)
{
var model = await TenantDb.Queryable<ApplicationSettlement>().Select(x => new ApplicationSettlementDto
{
SettlementTypeName = x.SettlementType.StlName, //结算方式
CustomerBankName = x.CustomerBank.BankName,
CustomerAccount = x.CustomerBank.Account,
CreateByName = x.CreateUserName
}, true).FirstAsync(x => x.Id == id);
if (model != null)
{
if (model.SaleDeptId.HasValue)
model.SaleDeptName = await Db.Queryable<SysOrg>().Where(x => x.Id == model.SaleDeptId.Value)
.Select(x => x.OrgName).FirstAsync();
if (model.OrgBankId.HasValue)
model.OrgBankName = await Db.Queryable<SysBank>().Where(x => x.Id == model.OrgBankId.Value)
.Select(x => x.BankName + " " + x.BankAccountNo).FirstAsync();
model.SettlementDetails = await GetSettlementDetails(id);
if (model.SettlementDetails.Count > 0)
{
var ids = model.SettlementDetails.Select(x => x.Id);
var appList = await TenantDb.Queryable<PaymentApplication>().Where(x => ids.Contains(x.Id))
.Select(x => new PaymentApplication { Id = x.Id, ApplicationNO = x.ApplicationNO }).ToListAsync();
//关联用户名称
var userIds = model.SettlementDetails.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 model.SettlementDetails)
{
item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName;
item.ApplicationNOList = appList.Where(x => x.Id == item.Id).Select(x => x.ApplicationNO).ToList();
}
}
}
return DataResult<ApplicationSettlementDto>.Success(model);
}
/// <summary>
/// 获取费用申请结算明细
/// </summary>
/// <param name="id">结算单ID</param>
/// <returns></returns>
protected override async Task<List<SettlementDetailGroup>> GetSettlementDetails(long id)
{
var appIds = await TenantDb.Queryable<ApplicationDetail>().Where(x => x.ApplicationId == id)
.Select(x => x.DetailId).ToListAsync();
var list = await TenantDb.Queryable<PaymentApplication>()
.InnerJoin<ApplicationDetail>((pa, d1) => pa.Id == d1.ApplicationId) //d1=申请明细
.Where((pa, d1) => SqlFunc.Subqueryable<ApplicationDetail>().Where(d2 => d2.DetailId == d1.Id && d2.ApplicationId == id).Any())
.GroupBy((pa, d1) => pa.Id)
.Select((pa, d1) => new SettlementDetailGroup
{
Id = pa.Id,
Status = (int)pa.Status,
BillNO = pa.ApplicationNO,
PaymentDate = pa.PaymentDate
}, true).ToListAsync();
var ids = list.Select(x => x.Id);
//获取原申请明细
var appDetails = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId))
.Select(x => new
{
x.Id,
x.ApplicationId,
x.Currency,
x.OriginalCurrency,
x.ApplyAmount,
x.OriginalAmount,
x.ProcessedAmount,
x.OriginalProcessedAmount
}).ToListAsync();
//获取结算单明细
var stlDetails = await TenantDb.Queryable<ApplicationDetail>().Where(x => x.ApplicationId == id)
.Select(x => new
{
x.ApplicationId,
x.DetailId,
x.RefId,
x.Currency,
x.OriginalCurrency,
x.ApplyAmount,
x.OriginalAmount,
x.ProcessedAmount,
x.OriginalProcessedAmount
}).ToListAsync();
foreach (var item in list)
{
PaymentApplicationStatus status = (PaymentApplicationStatus)item.Status;
item.StatusText = status.GetDescription();
//申请金额
var details = appDetails.Where(x => x.ApplicationId == item.Id);
item.RMBApplyAmount = details.Where(x => x.Currency == FeeCurrency.RMB_CODE).Sum(x => x.ApplyAmount);
item.USDApplyAmount = details.Where(x => x.Currency == FeeCurrency.USD_CODE).Sum(x => x.ApplyAmount);
//未结金额
item.RMBStlRestAmount = details.Where(x => appIds.Contains(x.Id) && x.OriginalCurrency == FeeCurrency.RMB_CODE).Sum(x => x.OriginalAmount - x.OriginalProcessedAmount);
item.USDStlRestAmount = details.Where(x => appIds.Contains(x.Id) && x.OriginalCurrency == FeeCurrency.USD_CODE).Sum(x => x.OriginalAmount - x.OriginalProcessedAmount);
//本次结算金额
item.RMBStlAmount = stlDetails.Where(x => x.RefId == item.Id && x.OriginalCurrency == FeeCurrency.RMB_CODE).Sum(x => x.OriginalAmount);
item.USDStlAmount = stlDetails.Where(x => x.RefId == item.Id && x.OriginalCurrency == FeeCurrency.USD_CODE).Sum(x => x.OriginalAmount);
}
return list;
}
/// <summary>
/// 获取结算单明细
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<SettlementDetailGroup>>> GetDetailsAsync(PageRequest<long> request)
{
var details = await GetSettlementDetails(request.OtherQueryCondition);
return DataResult<List<SettlementDetailGroup>>.Success(details);
}
/// <summary>
/// 获取待结算的申请分页列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<PaymentApplicationDtoV2>>> GetApplicationListAsync(PageRequest<ApplicationListQuery> request)
{
var query = TenantDb.Queryable<PaymentApplication>()
.InnerJoin<ApplicationDetail>((a, d) => a.Id == d.ApplicationId && d.ApplyAmount - d.ProcessedAmount != 0)
.InnerJoin<FeeRecord>((a, d, f) => d.RecordId == f.Id)
.InnerJoin<SeaExport>((a, d, f, s) => f.BusinessId == s.Id && f.BusinessType == BusinessType.OceanShippingExport)
.Where(request.GetConditionalModels(Db))
.GroupBy((a, d) => a.Id);
if (request.OtherQueryCondition != null)
{
if (request.OtherQueryCondition.PortId.HasValue)
query = query.Where((a, d, f, s) => s.LoadPortId == request.OtherQueryCondition.PortId || s.DischargePortId == request.OtherQueryCondition.PortId);
if (request.OtherQueryCondition.UnsettledOnly)
query = query.Where(a => a.Status == PaymentApplicationStatus.AuditPassed || a.Status == PaymentApplicationStatus.PartialSettlement);
}
else
{
query = query.Where(a => a.Status == PaymentApplicationStatus.AuditPassed || a.Status == PaymentApplicationStatus.PartialSettlement || a.Status == PaymentApplicationStatus.SettlementCompleted);
}
var result = await query.Select(a => new PaymentApplicationDtoV2
{
AmountRMB = a.AmountRMB == null ? 0 : a.AmountRMB.Value, //RMB申请金额
AmountUSD = a.AmountUSD == null ? 0 : a.AmountUSD.Value, //USD申请金额
AmountOther = a.AmountOther == null ? 0 : a.AmountOther.Value,
//RMB未结金额
UnSettledRMB = SqlFunc.Subqueryable<ApplicationDetail>().Where(d => d.ApplicationId == a.Id && d.Currency == FeeCurrency.RMB_CODE)
.Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)),
//USD未结金额
UnSettledUSD = SqlFunc.Subqueryable<ApplicationDetail>().Where(d => d.ApplicationId == a.Id && d.Currency == FeeCurrency.USD_CODE)
.Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)),
//USD未结其他
UnSettledOther = SqlFunc.Subqueryable<ApplicationDetail>().Where(d => d.ApplicationId == a.Id && d.Currency != FeeCurrency.RMB_CODE && d.Currency != FeeCurrency.USD_CODE)
.Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)),
SettlementTypeName = a.SettlementType.StlName, //结算方式
}, true).MergeTable().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();
var orgIds = result.Data.Select(x => x.SaleDeptId).Where(x => x.HasValue).Distinct().ToList();
var orgs = await Db.Queryable<SysOrg>().Where(x => orgIds.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;
item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName;
item.SettlementRMB = item.UnSettledRMB;
item.SettlementUSD = item.UnSettledUSD;
item.SettlementOther = item.UnSettledOther;
}
}
return result;
}
/// <summary>
/// 获取申请单费用明细
/// </summary>
/// <param name="id">申请单ID</param>
/// <param name="currency">结算币别</param>
/// <returns></returns>
public async Task<DataResult<List<PaymentApplicationDetailDto>>> GetApplicationDetailsAsync(long id, string? currency = null)
{
var details = await CreateApplicationDetailQuery((d, f, s) => d.ApplicationId == id)
.LeftJoin<PaymentApplication>((d, pa) => d.ApplicationId == pa.Id)
.WhereIF(!string.IsNullOrEmpty(currency), d => d.Currency == currency)
.Select((d, pa) => new PaymentApplicationDetailDto
{
Id = d.Id,
ApplicationId = d.ApplicationId,
BusinessId = d.BusinessId,
BusinessType = d.BusinessType,
RecordId = d.RecordId,
FeeName = d.FeeName,
FeeType = d.FeeType,
Amount = d.Amount, //总金额
Currency = d.Currency,
ApplyAmount = d.ApplyAmount, //申请金额
SettlementAmount = d.ProcessedAmount,
RestAmount = d.ApplyAmount - d.ProcessedAmount, //剩余结算金额
CustomerId = d.CustomerId,
CustomerName = d.CustomerName,
OriginalCurrency = d.OriginalCurrency, //原始币别
OriginalRate = d.ExchangeRate, //原始汇率
ExchangeRate = d.ExchangeRate, //折算汇率
OriginalAmount = d.OriginalAmount, //原始金额
CustomerNo = d.CustomerNo,
MBLNO = d.MBLNO,
HBLNO = d.HBLNO,
ETD = d.ETD,
SourceName = d.SourceName,
SaleName = d.SaleName,
AccountDate = d.AccountDate,
Vessel = d.Vessel,
Voyage = d.Voyage,
InvoiceNO = pa.InvoiceNO
}).ToListAsync();
return DataResult<List<PaymentApplicationDetailDto>>.Success(details);
}
/// <summary>
/// 获取申请单费用明细的币别
/// </summary>
/// <param name="documents"></param>
/// <returns></returns>
public async Task<DataResult<List<SettlementDocument>>> GetExchangesAsync(List<SettlementDocument> documents)
{
var ids = documents.Select(x => x.Id);
var list = await TenantDb.Queryable<ApplicationDetail>()
.Where(d => ids.Contains(d.ApplicationId))
.Select(d => new
{
d.ApplicationId,
d.Currency
}).ToListAsync();
foreach (var document in documents)
{
document.ExchangeRates ??= [];
//获取费用明细的全部币别
var items = list.FindAll(x => x.ApplicationId == document.Id);
foreach (var item in items)
{
if (!document.ExchangeRates.Exists(x => x.Currency == item.Currency))
document.ExchangeRates.Add(new CurrencyExchangeRate { Currency = item.Currency });
}
}
return DataResult<List<SettlementDocument>>.Success(documents);
}
/// <summary>
/// 保存申请结算
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public override async Task<DataResult<ApplicationSettlement>> SaveAsync(SettlementRequest<ApplicationSettlement> request)
{
var settlement = request.Settlement;
if (settlement.SettlementDate == default)
settlement.SettlementDate = DateTime.Now;
if (settlement.BillType == 0)
return DataResult<ApplicationSettlement>.FailedWithDesc(nameof(MultiLanguageConst.UnknownSettlementType));
settlement.Mode = settlement.BillType == SettlementBillType.Payment ? SettlementMode.Payment : SettlementMode.Charge;
ApplicationSettlement? dbValue = default;
if (request.Settlement.Id > 0)
{
dbValue = await TenantDb.Queryable<ApplicationSettlement>().Select(x => new ApplicationSettlement
{
Id = x.Id,
IsLocked = x.IsLocked,
Mode = x.Mode
}).FirstAsync(x => x.Id == request.Settlement.Id);
if (dbValue != null && dbValue.IsLocked)
return DataResult<ApplicationSettlement>.FailedWithDesc(nameof(MultiLanguageConst.SettlementIsLocked));
}
var result = EnsureSettlement(request.Settlement, dbValue);
if (!result.Succeeded)
return DataResult<ApplicationSettlement>.Failed(result.Message, result.MultiCode);
List<ApplicationDetail>? details1 = null;
if (request.Documents != null && (settlement.Mode == SettlementMode.Payment || settlement.Mode == SettlementMode.Charge))
request.Documents = request.Documents.FindAll(x => x.SettlementUSD.HasValue || x.SettlementRMB.HasValue || x.SettlementOther.HasValue);
//按申请结算
if (request.Documents?.Count > 0)
{
if (settlement.Id == 0)
{
var first = request.Documents[0];
settlement.CustomerId = first.CustomerId;
settlement.CustomerName = first.CustomerName;
}
var ids = request.Documents.Select(x => x.Id);
Expressionable<ApplicationDetail>? expr = null;
if (request.Documents.Any(x => x.SettlementRMB.GetValueOrDefault() == 0) || request.Documents.Any(x => x.SettlementUSD.GetValueOrDefault() == 0) ||
request.Documents.Any(x => x.SettlementOther.GetValueOrDefault() == 0)) //按币别结算
{
expr = Expressionable.Create<ApplicationDetail>();
if (request.Documents.Any(x => x.SettlementRMB.GetValueOrDefault() != 0))
expr = expr.Or(x => x.Currency == FeeCurrency.RMB_CODE);
if (request.Documents.Any(x => x.SettlementUSD.GetValueOrDefault() != 0))
expr = expr.Or(x => x.Currency == FeeCurrency.USD_CODE);
}
var detailCategory = settlement.Mode == SettlementMode.Payment ? DetailCategory.PaidApplication : DetailCategory.ChargeApplication;
details1 = await TenantDb.Queryable<ApplicationDetail>()
.Where(x => ids.Contains(x.ApplicationId) && x.Category == detailCategory)
.WhereIF(expr != null, expr.ToExpression())
.Select(x => new ApplicationDetail
{
ApplicationId = settlement.Id,
RefId = x.ApplicationId,
DetailId = x.Id,
RecordId = x.RecordId,
Category = settlement.Mode == SettlementMode.Payment ? DetailCategory.PaidApplicationSettlement : DetailCategory.ChargeApplicationSettlement,
CustomerName = x.CustomerName ?? settlement.CustomerName,
FeeId = x.FeeId,
FeeName = x.FeeName,
FeeType = x.FeeType,
ApplyAmount = x.ApplyAmount - x.ProcessedAmount,
Currency = x.Currency,
OriginalAmount = x.OriginalAmount - x.OriginalProcessedAmount,
OriginalCurrency = x.OriginalCurrency,
ExchangeRate = x.ExchangeRate
}).ToListAsync();
if (!string.IsNullOrEmpty(settlement.Currency)) //指定结算币别
{
var details2 = details1.FindAll(x => x.Currency != settlement.Currency);
foreach (var detail in details2)
{
var doc = request.Documents.Find(x => x.Id == detail.RefId);
if (doc == null)
return DataResult<ApplicationSettlement>.Failed("结算单据与费用明细不一致");
var exchange = doc.ExchangeRates?.Find(x => x.Currency == detail.Currency);
if (exchange == null)
return DataResult<ApplicationSettlement>.Failed($"未传入结算币别 {settlement.Currency} 与费用原币别 {detail.OriginalCurrency} 之间的汇率信息");
detail.ExchangeRate = exchange.ExchangeRate;
}
}
//执行结算费用分配
foreach (var doc in request.Documents)
{
var details2 = settlement.Mode != SettlementMode.FreeSettlement ?
details1.Where(x => x.RefId == doc.Id).OrderBy(x => x.ApplyAmount) :
details1.Where(x => x.BusinessId == doc.Id && x.BusinessType == doc.BusinessType && x.CustomerName == doc.CustomerName).OrderBy(x => x.ApplyAmount);
if (doc.SettlementRMB.HasValue)
{
var rmbDetails = details2.Where(x => x.Currency == FeeCurrency.RMB_CODE).ToList();
result = AssignAmount(rmbDetails, doc.SettlementRMB.Value, settlement.Currency);
if (!result.Succeeded)
return DataResult<ApplicationSettlement>.Failed(result.Message, result.MultiCode);
}
if (doc.SettlementUSD.HasValue)
{
var usdDetails = details2.Where(x => x.Currency == FeeCurrency.USD_CODE).ToList();
result = AssignAmount(usdDetails, doc.SettlementUSD.Value, settlement.Currency);
if (!result.Succeeded)
return DataResult<ApplicationSettlement>.Failed(result.Message, result.MultiCode);
}
if (doc.SettlementOther.HasValue)
{
var otherDetails = details2.Where(x => x.Currency != FeeCurrency.RMB_CODE && x.Currency != FeeCurrency.USD_CODE).ToList();
result = AssignAmount(otherDetails, doc.SettlementOther.Value, settlement.Currency);
if (!result.Succeeded)
return DataResult<ApplicationSettlement>.Failed(result.Message, result.MultiCode);
}
}
}
if (details1?.Count > 0)
settlement.Details.AddRange(details1.FindAll(x => x.Assigned));
return await base.SaveAsync(request);
}
protected override async Task<DataResult> PreSaveAsync(ApplicationSettlement settlement)
{
if (settlement.Details.Count == 0)
return DataResult.Success;
var appIds = settlement.Details.Select(x => x.RefId).Distinct();
var appList = await TenantDb.Queryable<PaymentApplication>().Where(x => appIds.Contains(x.Id))
.Select(x => new
{
x.Id,
x.Status,
x.CustomerId,
x.CustomerName,
}).ToListAsync();
if (appList.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (appList.Exists(x => x.Status != PaymentApplicationStatus.AuditPassed && x.Status != PaymentApplicationStatus.PartialSettlement))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationSelectStatusError));
if (appList.GroupBy(x => x.CustomerId).Select(x => x.Key).Count() > 1)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.DetailCustomerOnlyOne));
//获取剩余待结算金额
var ids2 = settlement.Details.Select(x => x.DetailId);
var appDetails = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids2.Contains(x.Id) && x.Category == DetailCategory.PaidApplication)
.Select(x => new
{
x.Id,
//RestAmount = x.ApplyAmount - x.ProcessedAmount,
OriginalRestAmount = x.OriginalAmount - x.OriginalProcessedAmount
}).ToListAsync();
StringBuilder sb = new();
foreach (var detail in settlement.Details)
{
var item = appDetails.Find(x => x.Id == detail.DetailId);
if (item == null)
{
sb.Append(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.EmptyData)));
break;
}
if (detail.OriginalAmount > 0 && detail.OriginalAmount > item.OriginalRestAmount)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), detail.FeeName);
sb.Append("");
continue;
}
else if (detail.OriginalAmount < 0 && detail.OriginalAmount < item.OriginalRestAmount)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), detail.FeeName);
sb.Append("");
continue;
}
detail.Category = settlement.BillType == SettlementBillType.Payment ? DetailCategory.PaidApplicationSettlement : DetailCategory.ChargeApplicationSettlement;
}
return sb.Length > 0 ? DataResult.Failed(sb.ToString()) : DataResult.Success;
}
protected override async Task OnSaveAsync(ApplicationSettlement settlement)
{
//更新付费申请明细的已处理金额
var list = settlement.Details.Select(x => new ApplicationDetail
{
Id = x.DetailId.Value,
ProcessedAmount = x.Currency == x.OriginalCurrency ?
x.ApplyAmount : x.ApplyAmount / (x.ExchangeRate ?? 1),
OriginalProcessedAmount = x.OriginalAmount
}).ToList();
await TenantDb.Updateable(list)
.PublicSetColumns(x => x.ProcessedAmount, "+")
.PublicSetColumns(x => x.OriginalProcessedAmount, "+")
.UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount })
.ExecuteCommandAsync();
}
protected override async Task<ApplicationSettlement> PostSaveAsync(ApplicationSettlement settlement)
{
//回写付费申请的状态
if (settlement.BillType == SettlementBillType.Payment)
{
var ids = settlement.Details.Select(x => x.DetailId);
var appIds = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id) && x.Category == DetailCategory.PaidApplication)
.Select(x => x.ApplicationId).ToListAsync();
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => appIds.Contains(x.ApplicationId) && x.Category == DetailCategory.PaidApplication)
.GroupBy(x => x.ApplicationId).Select(x => new
{
x.ApplicationId,
Count = SqlFunc.AggregateCount(x.Id),
ProcessingCount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => appIds.Contains(y.ApplicationId) &&
y.Category == DetailCategory.PaidApplication && y.OriginalProcessedAmount != 0 && y.OriginalAmount != y.OriginalProcessedAmount).Count(),
ProcessedCount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => appIds.Contains(y.ApplicationId) &&
y.Category == DetailCategory.PaidApplication && y.OriginalAmount == y.OriginalProcessedAmount).Count()
}).ToListAsync();
List<PaymentApplication> applications = [];
foreach (var item in details)
{
if (item.Count == 0 && item.ProcessedCount == 0)
continue;
var entity = new PaymentApplication { Id = item.ApplicationId };
if (item.Count == item.ProcessedCount)
{
entity.Status = PaymentApplicationStatus.SettlementCompleted;
}
else if (item.ProcessingCount != 0 || item.ProcessedCount != 0)
{
entity.Status = PaymentApplicationStatus.PartialSettlement;
}
else if (item.ProcessingCount == 0 && item.ProcessedCount == 0)
{
entity.Status = PaymentApplicationStatus.AuditPassed;
}
applications.Add(entity);
}
await TenantDb.Updateable(applications).UpdateColumns(x => new { x.Status }).ExecuteCommandAsync();
}
return await base.PostSaveAsync(settlement);
}
protected override DataResult PreDelete(List<ApplicationSettlement> settlements)
{
if (settlements.Any(x => x.IsLocked))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.SettlementIsLocked));
return DataResult.Success;
}
//还原收/付费申请明细
protected override async Task OnDeleteDetailAsync(List<ApplicationSettlement> settlements)
{
await base.OnDeleteDetailAsync(settlements);
var list = settlements.FindAll(x => x.Mode == SettlementMode.Payment || x.Mode == SettlementMode.Charge);
if (list.Count > 0)
{
var items = list.SelectMany(x => x.Details);
var ids = items.Select(x => x.DetailId);
//获取申请明细
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id))
.Select(x => new ApplicationDetail
{
Id = x.Id,
Currency = x.Currency,
ApplicationId = x.ApplicationId,
ProcessedAmount = x.ProcessedAmount,
OriginalAmount = x.OriginalAmount,
OriginalProcessedAmount = x.OriginalProcessedAmount
}).ToListAsync();
foreach (var detail in details)
{
var item = items.FirstOrDefault(x => x.DetailId == detail.Id);
detail.ProcessedAmount -= detail.Currency == item.Currency ? item.ApplyAmount : item.OriginalAmount;
detail.OriginalProcessedAmount -= item.OriginalAmount;
}
await TenantDb.Updateable(details)
.UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount })
.ExecuteCommandAsync();
var gpList = details.GroupBy(x => x.ApplicationId);
List<PaymentApplication> applications = [];
foreach (var gp in gpList)
{
var processedCount = gp.Count(x => x.OriginalAmount - x.OriginalProcessedAmount == 0);
var itemCount = gp.Count();
if (itemCount == processedCount)
continue;
var entity = new PaymentApplication { Id = gp.Key };
if (processedCount == 0)
{
entity.Status = PaymentApplicationStatus.AuditPassed;
}
else if (itemCount > processedCount)
{
entity.Status = PaymentApplicationStatus.PartialSettlement;
}
applications.Add(entity);
}
if (applications.Count > 0)
await TenantDb.Updateable(applications).UpdateColumns(x => new { x.Status }).ExecuteCommandAsync();
}
}
}
}