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.

448 lines
21 KiB
C#

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.Code.Entity;
using DS.WMS.Core.Fee.Entity;
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 PaymentSettlementService : SettlementService<PaymentSettlement>, IPaymentSettlementService
{
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
public PaymentSettlementService(IServiceProvider provider) : base(provider)
{
}
/// <summary>
/// 获取分页列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<PaymentSettlementDto>>> GetListAsync(PageRequest request)
{
var query = TenantDb.Queryable<PaymentSettlement>().Select(x => new PaymentSettlementDto
{
Id = x.Id,
ApplicationNO = x.ApplicationNO, //申请编号
SettlementNO = x.SettlementNO, //结算单号
CustomerId = x.CustomerId, //结算单位
CustomerName = x.CustomerName,
Mode = x.Mode, //结算类型
SettlementTypeName = x.SettlementType.StlName, //结算方式
RMBAmount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => y.ApplicationId == x.Id && y.Currency == RMB_CODE)
.Select(y => SqlFunc.AggregateSum(y.ApplyAmount)),
USDAmount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => y.ApplicationId == x.Id && y.Currency == USD_CODE)
.Select(y => SqlFunc.AggregateSum(y.ApplyAmount)),
OtherAmount = SqlFunc.Subqueryable<ApplicationDetail>().Where(y => y.ApplicationId == x.Id && y.Currency != RMB_CODE && y.Currency != USD_CODE)
.Select(y => SqlFunc.AggregateSum(y.ApplyAmount)),
Note = x.Note, //备注
CustomerAccount = x.CustomerBank.AccountName + "/" + x.CustomerBank.Currency,
CustomerBank = x.CustomerBank.BankName,
//未开票
UnInvoiceList = SqlFunc.Subqueryable<ApplicationDetail>().InnerJoin<FeeRecord>((d, f) => d.RecordId == f.Id && (f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount) != 0)
.GroupBy((d, f) => f.Currency).ToList((d, f) => new CurrencyAmount { Currency = f.Currency, Amount = f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount }),
CreateBy = x.CreateBy, //结算人
CreateTime = x.CreateTime, //创建日期
SettlementDate = x.SettlementDate, //结算日期
IsExportVoucher = default, //是否导出凭证
Currency = x.Currency, //币别
Amount = x.Amount, //原始金额
AccountAmount = x.AccountAmount, //记账资料
PrePayAmount = x.PrePayAmount, //预付支资料
AHSRAmount = x.AHSRAmount, //实收支资料
FinancialAmount = x.FinancialAmount,//财务费用
AdvanceAmount = x.AdvanceAmount, //预收支资料
IsLocked = x.IsLocked, //锁定状态
LockTime = x.LockTime,
LockUserId = x.LockUserId,
UnlockTime = x.UnlockTime,
UnlockUserId = x.UnlockUserId,
IsVoucherDisabled = x.IsVoucherDisabled, //禁用凭证
SaleDeptId = x.SaleDeptId, //所属分部
LedgerVoucherNO = x.LedgerVoucherNO //总账凭证号
//BillType = x.BillType, //单据类型
//Category = x.Category, //业务类别
});
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="request"></param>
/// <returns></returns>
public async Task<DataResult<List<PaymentApplicationDto>>> GetApplicationListAsync(PageRequest<bool> request)
{
var query = TenantDb.Queryable<PaymentApplication>().Where(a => a.Status == PaymentApplicationStatus.AuditPassed || a.Status == PaymentApplicationStatus.PartialSettlement)
.WhereIF(request.OtherQueryCondition, a => a.Status != PaymentApplicationStatus.SettlementCompleted && SqlFunc.Subqueryable<ApplicationDetail>().Where(d => d.ApplicationId == a.Id && (d.ApplyAmount - d.ProcessedAmount) != 0).Any())
.Select(a => new PaymentApplicationDto
{
Id = a.Id,
ApplicationNO = a.ApplicationNO,
Status = a.Status,
CustomerId = a.CustomerId,
CustomerName = a.CustomerName, //结算单位
CustomerBankId = a.CustomerBankId,
CustomerBank = a.CustomerBank.BankName, //结算对象银行
CustomerAccount = a.CustomerBank.Account, //结算对象账号
Currency = a.Currency,
AmountRMB = a.AmountRMB, //RMB申请金额
AmountUSD = a.AmountUSD, //USD申请金额
//RMB未结金额
UnSettlementRMB = SqlFunc.Subqueryable<ApplicationDetail>().Where(d => d.Currency == RMB_CODE)
.Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)),
//USD未结金额
UnSettlementUSD = SqlFunc.Subqueryable<ApplicationDetail>().Where(d => d.Currency == USD_CODE)
.Select(d => SqlFunc.AggregateSum(d.ApplyAmount - d.ProcessedAmount)),
SaleDeptId = a.SaleDeptId, //所属分部
SettlementTypeId = a.SettlementTypeId,
SettlementTypeName = a.SettlementType.StlName, //结算方式
CreateBy = a.CreateBy, //申请人
CreateTime = a.CreateTime, //申请日期
PayAmount = 0, //审核实付金额
PaymentDate = a.PaymentDate, //申请支付日期
AuditerId = a.AuditerId,
AuditerName = a.AuditerName,
AuditTime = a.AuditTime,
Note = a.Note
});
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).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;
}
}
return result;
}
/// <summary>
/// 获取费用明细
/// </summary>
/// <param name="id">申请单ID</param>
/// <returns></returns>
public async Task<DataResult<List<SettlementDetailDto>>> GetDetailsAsync(long id)
{
var details = await TenantDb.Queryable<ApplicationDetail>().Where(d => d.ApplicationId == id && (d.ApplyAmount - d.ProcessedAmount) != 0)
.InnerJoin<FeeRecord>((d, f) => d.RecordId == f.Id)
.InnerJoin<BusinessFeeStatus>((d, f, b) => f.BusinessId == b.BusinessId && f.BusinessType == b.BusinessType)
.Select((d, f, b) => new SettlementDetailDto
{
Id = d.Id,
ApplicationId = d.ApplicationId,
RecordId = d.RecordId,
FeeName = d.FeeName,
FeeType = d.FeeType, //收付
Amount = d.ApplyAmount, //申请金额
SettlementAmount = d.ApplyAmount, //结算金额默认=申请金额
CustomerId = f.CustomerId,
CustomerName = d.CustomerName,
OriginalCurrency = d.OriginalCurrency, //原始币别
OriginalRate = f.ExchangeRate, //原始汇率
ExchangeRate = d.ExchangeRate, //折算汇率
OriginalAmount = d.OriginalAmount, //原始金额
InvoiceNO = f.InvoiceNO, //发票号
BusinessId = f.BusinessId,
BusinessType = f.BusinessType
}).ToListAsync();
if (details.Count > 0)
{
var gList = details.GroupBy(x => x.BusinessType);
foreach (var g in gList)
{
var ids = g.Select(x => x.BusinessId);
switch (g.Key)
{
case BusinessType.OceanShippingExport:
var list1 = await TenantDb.Queryable<SeaExport>().Where(s => ids.Contains(s.Id))
.LeftJoin<CodeSource>((s, cs) => s.SourceId == cs.Id)
.Select((s, cs) => new
{
s.Id,
s.AccountDate,//会计期间
s.Vessel, //船名
s.Voyno, //航次
s.CustomerName,
s.MBLNO, //主提单号
s.CustomerNo, //委托编号
s.ETD, //开船日期
s.Sale, //揽货人
cs.SourceName, //业务来源
}).ToListAsync();
foreach (var item in g)
{
var biz = list1.Find(x => x.Id == item.BusinessId);
if (biz != null)
{
item.MBLNO = biz.MBLNO;
item.CustomerNo = biz.CustomerNo;
item.ClientName = biz.CustomerName;
item.ETD = biz.ETD;
item.SourceName = biz.SourceName;
item.SaleName = biz.Sale;
item.AccountDate = biz.AccountDate;
item.Vessel = biz.Vessel;
item.Voyage = biz.Voyno;
}
}
break;
case BusinessType.OceanShippingImport:
break;
}
}
}
return DataResult<List<SettlementDetailDto>>.Success(details);
}
/// <summary>
/// 创建结算单
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<PaymentSettlement>> CreateAsync(SettlementRequest<PaymentSettlement> request)
{
var ids = request.Details.Select(x => x.ApplicationId).Distinct();
var appList = await TenantDb.Queryable<PaymentApplication>().Where(x => ids.Contains(x.Id))
.Select(x => new
{
x.Id,
x.Status,
x.CustomerId,
x.CustomerName,
}).ToListAsync();
if (appList.Count == 0)
return DataResult<PaymentSettlement>.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (appList.Exists(x => x.Status != PaymentApplicationStatus.AuditSubmittd && x.Status != PaymentApplicationStatus.PartialSettlement))
return DataResult<PaymentSettlement>.FailedWithDesc(nameof(MultiLanguageConst.ApplicationSelectStatusError));
if (appList.GroupBy(x => x.CustomerId).Select(x => x.Key).Count() > 1)
return DataResult<PaymentSettlement>.FailedWithDesc(nameof(MultiLanguageConst.DetailCustomerOnlyOne));
//申请金额禁止为0
if (request.Details.Any(x => x.SettlementAmount == 0))
return DataResult<PaymentSettlement>.FailedWithDesc(nameof(MultiLanguageConst.AmountCannotBeZero));
StringBuilder sb = new();
var appDetails = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId))
.Select(x => new
{
x.Id,
x.ApplicationId,
x.ApplyAmount,
x.BusinessId,
x.BusinessType,
x.Currency,
x.CustomerName,
x.FeeId,
x.FeeName,
x.FeeType,
x.OriginalAmount,
x.OriginalCurrency,
x.ProcessedAmount,
x.OriginalProcessedAmount,
}).ToListAsync();
foreach (var item in request.Details)
{
var appDetail = appDetails.Find(x => x.Id == item.Id);
decimal restValue = appDetail.ApplyAmount - appDetail.ProcessedAmount;
if (item.SettlementAmount > 0 && item.SettlementAmount > restValue)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), item.FeeName);
sb.Append("");
continue;
}
else if (item.SettlementAmount < 0 && item.SettlementAmount < restValue)
{
sb.AppendFormat(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DetailExceedingLimit)), item.FeeName);
sb.Append("");
continue;
}
}
if (sb.Length > 0)
return DataResult<PaymentSettlement>.Failed(sb.ToString());
var ids2 = request.Details.Select(x => x.RecordId).Distinct().ToList();
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => ids2.Contains(x.Id)).Select(x => new FeeRecord
{
Id = x.Id,
//BusinessId = x.BusinessId,
//BusinessType = x.BusinessType,
//FeeId = x.FeeId,
//FeeName = x.FeeName,
//FeeType = x.FeeType,
//CustomerId = x.CustomerId,
//CustomerName = x.CustomerName,
Amount = x.Amount,
//Currency = x.Currency,
//ExchangeRate = x.ExchangeRate,
//OrderAmount = x.OrderAmount,
OrderSettlementAmount = x.OrderSettlementAmount,
//SettlementAmount = x.SettlementAmount
}).ToListAsync();
if (fees.Count != request.Details.Count)
return DataResult<PaymentSettlement>.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordNone));
var settlement = request.Settlement;
if (settlement.SettlementDate == default)
settlement.SettlementDate = DateTime.Now;
if (settlement.Id == 0)
{
var app = appList[0];
settlement.CustomerId = app.CustomerId;
settlement.CustomerName = app.CustomerName;
}
settlement.Mode = SettlementMode.ChargeAndPayment;
settlement.BillType = SettlementBillType.Payment;
settlement.Amount = request.Details.Sum(x => x.SettlementAmount);
settlement.Details = request.Details.Select(x => new ApplicationDetail
{
ApplicationId = x.ApplicationId,
DetailId = x.Id,
ApplyAmount = x.SettlementAmount,
BusinessId = x.BusinessId,
BusinessType = x.BusinessType,
Category = FeeCategory.PaidApplicationSettlement,
Currency = x.Currency,
CustomerName = x.CustomerName,
ExchangeRate = x.ExchangeRate,
FeeId = x.FeeId,
FeeName = x.FeeName,
FeeType = x.FeeType,
OriginalAmount = x.OriginalAmount,
OriginalCurrency = x.OriginalCurrency
}).ToList();
foreach (var detail in settlement.Details)
{
//var fee = fees.Find(x => x.Id == detail.RecordId);
//detail.BusinessId = fee.BusinessId;
//detail.BusinessType = fee.BusinessType;
//detail.ExchangeRate = detail.ExchangeRate ?? fee.ExchangeRate;
//detail.FeeId = fee.FeeId;
//detail.FeeName = fee.FeeName;
//detail.FeeType = fee.FeeType;
detail.CustomerName = detail.CustomerName ?? settlement.CustomerName;
//原币申请
if (settlement.Currency.IsNullOrEmpty())
{
detail.OriginalAmount = detail.ApplyAmount;
//if (detail.OriginalCurrency.IsNullOrEmpty())
// detail.OriginalCurrency = fee.Currency;
}
}
await TenantDb.Ado.BeginTranAsync();
try
{
//关联导航属性插入
if (settlement.Id == 0)
{
//创建时需要生成申请单编号
var sequence = CommonService.Value.GetSequenceNext<PaymentSettlement>();
if (!sequence.Succeeded)
{
return DataResult<PaymentSettlement>.Failed(sequence.Message, MultiLanguageConst.SequenceSetNotExist);
}
settlement.ApplicationNO = "CP" + SnowFlakeSingle.Instance.NextId(); //申请编号
settlement.SettlementNO = sequence.Data; //结算单号
await TenantDb.InsertNav(settlement).Include(x => x.Details).ExecuteCommandAsync();
}
else
{
if (settlement.Details.Count > 0)
await TenantDb.Insertable(settlement.Details).ExecuteCommandAsync();
await TenantDb.Updateable(settlement).IgnoreColumns(x => new
{
x.ApplicationNO,
x.SettlementNO,
x.CreateBy,
x.CreateTime,
x.Deleted,
x.DeleteBy,
x.DeleteTime
}).ExecuteCommandAsync();
}
if (fees != null && fees.Count > 0)
await TenantDb.Updateable(fees)
.PublicSetColumns(x => x.SettlementAmount, "+")
.UpdateColumns(x => new { x.SettlementAmount })
.ExecuteCommandAsync();
await TenantDb.Ado.CommitTranAsync();
return DataResult<PaymentSettlement>.Success(settlement);
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult<PaymentSettlement>.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
}
}