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.

284 lines
13 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.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 SqlSugar;
namespace DS.WMS.Core.Settlement.Method
{
/// <summary>
/// 发票结算
/// </summary>
public class InvoiceSettlementService : SettlementService<ApplicationSettlement>, IInvoiceSettlementService
{
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
public InvoiceSettlementService(IServiceProvider provider) : base(provider)
{
}
/// <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
}, 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();
model.SettlementDetails = await GetSettlementDetails(id);
if (model.SettlementDetails.Count > 0)
{
//关联用户名称
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;
}
}
}
return DataResult<ApplicationSettlementDto>.Success(model);
}
/// <summary>
/// 获取待结算的发票列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<InvoiceDto>>> GetInvoiceListAsync(PageRequest request)
{
var whereList = request.GetConditionalModels(Db);
var result = await TenantDb.Queryable<Invoice.Entity.Invoice>()
.InnerJoin<ApplicationDetail>((a, d) => d.Category == DetailCategory.InvoiceIssuance && a.Id == d.ApplicationId)
.InnerJoin<FeeRecord>((a, d, f) => d.RecordId == f.Id && (f.FeeStatus == FeeStatus.AuditPassed || f.FeeStatus == FeeStatus.PartialSettlement) &&
((f.Amount > 0 && d.OriginalAmount - d.OriginalProcessedAmount > 0 && d.OriginalAmount - d.OriginalProcessedAmount <= f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount) ||
(f.Amount < 0 && d.OriginalAmount - d.OriginalProcessedAmount < 0 && d.OriginalAmount - d.OriginalProcessedAmount >= f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount))
)
.GroupBy((a, d, f) => a.Id)
.Select((a, d, f) => new InvoiceDto
{
//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)),
}, true).MergeTable().Where(whereList).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).Distinct().ToList();
var orgs = await Db.Queryable<SysOrg>().Where(x => orgIds.Contains(x.Id)).Select(x => new { x.Id, x.OrgName }).ToListAsync();
var ids = result.Data.Select(x => x.Id);
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId) &&
x.Category == DetailCategory.InvoiceIssuance).Select<ApplicationDetailDto>().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;
item.Details = details.FindAll(x => x.ApplicationId == item.Id);
}
}
return result;
}
/// <summary>
/// 获取发票申请费用明细
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public async Task<DataResult<List<ApplicationDetailDto>>> GetInvoiceDetailsAsync(params long[] ids)
{
var query1 = TenantDb.Queryable<ApplicationDetail>()
.InnerJoin<FeeRecord>((d, f) => d.Category == DetailCategory.InvoiceIssuance && d.RecordId == f.Id &&
(f.FeeStatus == FeeStatus.AuditPassed || f.FeeStatus == FeeStatus.PartialSettlement) && f.BusinessType == BusinessType.OceanShippingExport &&
((f.Amount > 0 && d.OriginalAmount - d.OriginalProcessedAmount <= f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount) ||
(f.Amount < 0 && d.OriginalAmount - d.OriginalProcessedAmount >= f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount))
)
.LeftJoin<SeaExport>((d, f, s) => f.BusinessId == s.Id)
.Where((d, f, s) => ids.Contains(d.ApplicationId))
.Select((d, f, s) => new ApplicationDetailDto
{
ClientName = s.CustomerName,
Voyage = s.Voyno,
SourceName = s.SourceName,
}, true);
var list = await TenantDb.UnionAll(query1).ToListAsync();
var result = DataResult<List<ApplicationDetailDto>>.Success(list);
result.Count = list.Count;
return result;
}
/// <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) && d.Category == DetailCategory.InvoiceIssuance)
//.GroupBy(d => d.ApplicationId)
.Select(d => new
{
d.ApplicationId,
d.OriginalCurrency
}).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.OriginalCurrency))
document.ExchangeRates.Add(new CurrencyExchangeRate { Currency = item.OriginalCurrency });
}
}
return DataResult<List<SettlementDocument>>.Success(documents);
}
/// <summary>
/// 获取发票结算明细
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
protected override async Task<List<SettlementDetailDto>> GetSettlementDetails(long id)
{
var list = await TenantDb.Queryable<Invoice.Entity.Invoice>()
.InnerJoin<ApplicationDetail>((i, d1) => i.Id == d1.ApplicationId)
.InnerJoin<ApplicationDetail>((i, d1, d2) => d1.ApplicationId == d2.RefId)
.Where((i, d1, d2) => d2.ApplicationId == id &&
d2.Category == DetailCategory.InvoiceSettlement && d1.Category == DetailCategory.InvoiceIssuance)
.GroupBy((i, d1, d2) => i.Id)
.Select((i, d1, d2) => new SettlementDetailDto
{
Id = i.Id,
InvoiceApplyAmount = i.ApplyAmount,
InvoiceAmount = i.InvoiceAmount,
SettlementAmount = SqlFunc.Subqueryable<ApplicationDetail>().Where(d3 => d3.ApplicationId == i.Id).Sum(d3 => d3.ApplyAmount),
ApplicationNOList = SqlFunc.Subqueryable<InvoiceApplication>().Where(a => a.Id == d1.RefId).ToList(a => a.ApplicationNO)
}, true).ToListAsync();
return list;
}
protected override async Task<DataResult> PreSaveAsync(ApplicationSettlement settlement)
{
var appIds = settlement.Details.Select(x => x.RefId).Distinct();
var appList = await TenantDb.Queryable<Invoice.Entity.Invoice>().Where(x => appIds.Contains(x.Id))
.Select(x => new
{
x.Id,
x.CustomerId,
x.CustomerName,
}).ToListAsync();
if (appList.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
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.InvoiceIssuance)
.Select(x => new
{
x.Id,
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 = DetailCategory.InvoiceSettlement;
}
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,
Category = DetailCategory.InvoiceIssuance,
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();
}
}
}