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.

238 lines
10 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.Fee.Dtos;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Invoice.Dtos;
using DS.WMS.Core.Invoice.Interface;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Entity;
using SqlSugar;
namespace DS.WMS.Core.Invoice.Method
{
/// <summary>
/// 自由开票实现
/// </summary>
public class FreeInvoiceService : InvoiceService<Entity.Invoice>, IFreeInvoiceService
{
/// <summary>
/// 允许的费用状态值
/// </summary>
internal readonly FeeStatus[] AllowedStatus = [FeeStatus.AuditPassed, FeeStatus.PartialSettlement, FeeStatus.SettlementCompleted];
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
public FreeInvoiceService(IServiceProvider provider) : base(provider)
{
}
/// <summary>
/// 获取待开票的业务列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<BizInvoiceApplication>>> GetBizListAsync(PageRequest<FeeRange?> request)
{
var expr = Expressionable.Create<SeaExport, FeeRecord>().And((s, f) => AllowedStatus.Contains(f.FeeStatus) &&
(f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount) != 0);
if (request.OtherQueryCondition.HasValue)
{
switch (request.OtherQueryCondition.Value)
{
case FeeRange.Unsettled:
expr = expr.And((s, f) => f.SettlementAmount == 0);
break;
case FeeRange.Settled:
expr = expr.And((s, f) => f.SettlementAmount > 0);
break;
}
}
var query = CreateFeeQuery(expr.ToExpression());
if (!request.QueryCondition.IsNullOrEmpty())
{
var whereList = request.GetConditionalModels(Db);
query = query.Where(whereList);
}
var result = await query.GroupBy(x => x.BusinessId).Select(x => new BizInvoiceApplication
{
Id = x.BusinessId,
BusinessType = x.BusinessType,
AccountDate = x.AccountDate,
CntrTotal = x.CntrTotal,
CreateBy = x.CreateBy,
CustomerNo = x.CustomerNo,
ClientName = x.ClientName,
CustomerId = x.CustomerId,
CustomerName = x.CustomerName,
DischargePort = x.DischargePort,
ETD = x.ETD,
HBLNO = x.HBLNO,
LoadPort = x.LoadPort,
MBLNO = x.MBLNO,
OperatorId = x.OperatorId,
SaleDeptId = x.SaleDeptId,
SaleId = x.SaleId,
SaleName = x.Sale,
Vessel = x.Vessel,
Voyage = x.Voyage,
BookingNO = x.BookingNo,
//未开票金额=金额-已开票金额-申请开票金额+申请开票金额已开票
UnBilledRMB = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == x.BusinessId && f.FeeStatus == FeeStatus.AuditPassed
&& f.Currency == FeeCurrency.RMB_CODE).Select(f => SqlFunc.AggregateSum(f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount)),
UnBilledUSD = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == x.BusinessId && f.FeeStatus == FeeStatus.AuditPassed
&& f.Currency == FeeCurrency.USD_CODE).Select(f => SqlFunc.AggregateSum(f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount)),
UnBilledOther = SqlFunc.Subqueryable<FeeRecord>().Where(f => f.BusinessId == x.BusinessId && f.FeeStatus == FeeStatus.AuditPassed
&& f.Currency != FeeCurrency.RMB_CODE && f.Currency != FeeCurrency.USD_CODE).Select(f => SqlFunc.AggregateSum(f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount)),
}).ToQueryPageAsync(request.PageCondition);
if (result.Data.Count > 0)
{
//关联用户名称
var userIds = result.Data.Where(x => x.OperatorId.HasValue).Select(x => x.OperatorId.Value)
.Union(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();
var orgs = await Db.Queryable<SysOrg>().Where(x => userIds.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;
if (item.OperatorId.HasValue)
item.Operator = users.Find(x => x.Id == item.OperatorId.Value)?.UserName;
item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName;
}
}
return result;
}
/// <summary>
/// 根据业务编号及类型获取费用记录
/// </summary>
/// <param name="items">业务ID与业务类型</param>
/// <returns></returns>
public override async Task<DataResult<InvoiceApplicaitonBiz>> GetFeesAsync(params FeeClient[] items)
{
var bizIds = items.Select(x => x.Id).Distinct();
var types = items.Select(x => x.BusinessType).Distinct();
var cIds = items.Select(x => x.CustomerId).Distinct();
var list = await TenantDb.Queryable<FeeRecord>()
.Where(f => bizIds.Contains(f.BusinessId) && types.Contains(f.BusinessType) && cIds.Contains(f.CustomerId) &&
AllowedStatus.Contains(f.FeeStatus) && f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount != 0)
.Select(f => new FeeInvoiceDto
{
RecordId = f.Id,
BusinessId = f.BusinessId,
BusinessType = f.BusinessType,
CustomerId = f.CustomerId,
CustomerName = f.CustomerName,
FeeId = f.FeeId,
FeeName = f.FeeName,
FeeType = f.FeeType,
Amount = f.Amount,
TaxRate = f.TaxRate,
Currency = f.Currency,
OriginalCurrency = f.Currency,
OriginalRate = f.ExchangeRate,
RestAmount = f.Amount - f.InvoiceAmount - f.OrderInvoiceAmount + f.OrderInvSettlementAmount,
ExchangeRate = f.ExchangeRate,
Remark = f.Remark,
}).ToListAsync();
foreach (var item in list)
item.ApplyAmount = item.OriginalAmount = item.RestAmount;
return DataResult<InvoiceApplicaitonBiz>.Success(new InvoiceApplicaitonBiz(list));
}
/// <summary>
/// 根据业务编号及类型获取该票业务的币别
/// </summary>
/// <param name="items">业务ID与业务类型</param>
/// <returns></returns>
public async Task<DataResult<List<FeeClient>>> GetCurrenciesAsync(params FeeClient[] items)
{
var bizIds = items.Select(x => x.Id).Distinct();
var types = items.Select(x => x.BusinessType).Distinct();
var cIds = items.Select(x => x.CustomerId).Distinct();
var list = await TenantDb.Queryable<FeeRecord>()
.Where(f => bizIds.Contains(f.BusinessId) && types.Contains(f.BusinessType) && cIds.Contains(f.CustomerId) &&
AllowedStatus.Contains(f.FeeStatus))
.Select(f => new
{
f.BusinessId,
f.BusinessType,
f.CustomerId,
f.Currency
}).ToListAsync();
var currencies = list.GroupBy(x => new { x.BusinessId, x.BusinessType, x.CustomerId }).Select(x => new FeeClient
{
Id = x.Key.BusinessId,
BusinessType = x.Key.BusinessType,
CustomerId = x.Key.CustomerId,
ExchangeRates = x.GroupBy(y => y.Currency).Select(y => new CurrencyExchangeRate
{
Currency = y.Key
}).ToList()
}).ToList();
return DataResult<List<FeeClient>>.Success(currencies);
}
protected override async Task<DataResult> PreSaveAsync(Entity.Invoice invoice)
{
invoice.Mode = InvoiceMode.Free;
//获取剩余待开票金额
var ids = invoice.Details.Select(x => x.RecordId);
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id) && AllowedStatus.Contains(x.FeeStatus))
.Select(x => new
{
x.Id,
OriginalRestAmount = x.Amount - x.InvoiceAmount - x.OrderInvoiceAmount + x.OrderInvSettlementAmount
}).ToListAsync();
StringBuilder sb = new();
foreach (var detail in invoice.Details)
{
var item = fees.Find(x => x.Id == detail.RecordId);
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;
}
}
return sb.Length > 0 ? DataResult.Failed(sb.ToString()) : DataResult.Success;
}
}
}