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.

330 lines
15 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<PaymentSettlementDto>> GetAsync(long id)
{
var model = await TenantDb.Queryable<ApplicationSettlement>().Select(x => new PaymentSettlementDto
{
}, true).FirstAsync(x => x.Id == id);
if (model != null)
{
model.Details = await GetSettlementDetails(id);
if (model.Details.Count > 0)
{
//关联用户名称
var userIds = model.Details.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.Details)
{
item.CreateByName = users.Find(x => x.Id == item.CreateBy)?.UserName;
}
}
}
return DataResult<PaymentSettlementDto>.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 <= f.Amount - f.SettlementAmount - f.OrderAmount + f.OrderSettlementAmount) ||
(f.Amount < 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);
}
protected override async Task<List<SettlementDetailDto>> GetSettlementDetails(long id)
{
var list = await TenantDb.Queryable<ApplicationDetail>()
.InnerJoin<ApplicationDetail>((d, pd) => d.DetailId == pd.Id)
.InnerJoin<Invoice.Entity.Invoice>((d, pd, i) => pd.ApplicationId == i.Id)
.Where(d => d.ApplicationId == id)
.Select((d, pd, i) => new
{
d.Id,
d.ApplicationId,
d.ApplyAmount,
d.Currency,
d.OriginalCurrency,
d.OriginalAmount,
i.CustomerName,
i.InvoiceAmount,
i.InvoiceHeader,
i.InvoiceDate,
i.InvoiceNO,
i.BillNO,
i.CreateTime,
i.CreateBy,
i.Note
}).ToListAsync();
var details = new List<SettlementDetailDto>();
if (list.Count == 0)
return details;
var gp = list.GroupBy(d => d.ApplicationId);
var uids = list.Select(x => x.CreateBy).Distinct();
var users = await Db.Queryable<SysUser>().Where(x => uids.Contains(x.Id)).Select(x => new
{
x.Id,
x.UserName
}).ToListAsync();
foreach (var g in gp)
{
var firstItem = g.FirstOrDefault();
var dto = new SettlementDetailDto
{
ApplicationId = g.Key,
RMBApplyAmount = g.Where(x => x.OriginalCurrency == FeeCurrency.RMB_CODE).Sum(x => x.ApplyAmount),
USDApplyAmount = g.Where(x => x.OriginalCurrency == FeeCurrency.USD_CODE).Sum(x => x.ApplyAmount),
BillNO = firstItem.BillNO,
InvoiceNO = firstItem.InvoiceNO,
CreateTime = firstItem?.CreateTime,
CreateBy = firstItem?.CreateBy,
CreateByName = users.Find(x => x.Id == firstItem?.CreateBy)?.UserName,
PaymentDate = firstItem?.CreateTime,
Note = firstItem?.Note
};
//包含多个币别
if (g.GroupBy(x => x.OriginalCurrency).Select(x => x.Key).Count() > 1)
{
//原始币别=不等于结算单币别的首个币别参考DS7
dto.OriginalCurrency = g.Select(x => x.OriginalCurrency).FirstOrDefault();
//原始金额=当前结算单的币别合计
dto.OriginalAmount = g.Sum(x => x.ApplyAmount);
}
else
{
dto.OriginalCurrency = firstItem?.OriginalCurrency;
dto.OriginalAmount = g.Where(x => x.OriginalCurrency == dto.OriginalCurrency).Sum(x => x.ApplyAmount);
}
//结算金额=原申请的原始币别合计
dto.SettlementAmount = g.Where(x => x.OriginalCurrency == dto.OriginalCurrency).Sum(x => x.ApplyAmount);
details.Add(dto);
}
return details;
}
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();
}
}
}