|
|
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();
|
|
|
|
|
|
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 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<SettlementDetailGroup>> 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 SettlementDetailGroup
|
|
|
{
|
|
|
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();
|
|
|
}
|
|
|
}
|
|
|
}
|