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.

303 lines
12 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 DS.Module.Core;
using DS.Module.Core.Enums;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Application.Entity;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Fee.Method;
using DS.WMS.Core.Invoice.Dto;
using DS.WMS.Core.Invoice.Dtos;
using DS.WMS.Core.Invoice.Interface;
using DS.WMS.Core.Sys.Entity;
using DS.WMS.Core.Sys.Interface;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace DS.WMS.Core.Invoice.Method
{
/// <summary>
/// 发票服务基类
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public class InvoiceService<TEntity> : FeeServiceBase, IInvoiceService<TEntity>
where TEntity : Entity.Invoice, new()
{
protected readonly Lazy<ICommonService> CommonService;
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
public InvoiceService(IServiceProvider provider) : base(provider)
{
CommonService = new Lazy<ICommonService>(provider.GetRequiredService<ICommonService>());
}
/// <summary>
/// 获取分页列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<InvoiceDto>>> GetListAsync(PageRequest<string> request)
{
var query = TenantDb.Queryable<Entity.Invoice>()
.Select(i => new InvoiceDto
{
Id = i.Id,
InvoiceNO = i.InvoiceNO,
BillNO = i.BillNO,
InvoiceDate = i.InvoiceDate,
CustomerId = i.CustomerId,
CustomerName = i.CustomerName,
Type = i.Type,
Category = i.Category,
InvoiceHeader = i.InvoiceHeader,
TaxID = i.TaxID,
CustomerAddTel = i.CustomerAddTel,
CustomerBank = i.CustomerBank,
AutualCustomerName = i.AutualCustomerName,
Currency = i.Currency,
ReceiptCurrency = i.ReceiptCurrency,
ApplyAmount = i.ApplyAmount,
InvoiceAmount = i.InvoiceAmount,
OperatorId = i.OperatorId,
IsLocked = i.IsLocked,
LockUserId = i.LockUserId,
LockTime = i.LockTime,
TaxRate = i.TaxRate,
OrgId = i.OrgId,
SaleDeptId = i.SaleDeptId,
IsCancelled = i.IsCancelled,
CancelUserId = i.CancelUserId,
CancelTime = i.CancelTime,
CreateTime = i.CreateTime,
CreateBy = i.CreateBy,
InvoiceApplicationList = SqlFunc.Subqueryable<ApplicationDetail>().InnerJoin<InvoiceApplication>((d, a) =>
d.ApplicationId == i.Id && d.Category == DetailCategory.InvoiceIssuance && d.RefId == a.Id)
.GroupBy((d, a) => a.ApplicationNO).ToList((d, a) => a.ApplicationNO)
});
if (!request.OtherQueryCondition.IsNullOrEmpty())
{
query = query.Where(i => i.InvoiceApplicationList.Contains(request.OtherQueryCondition));
}
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.OperatorId.HasValue).Select(x => x.OperatorId.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.Where(x => x.SaleDeptId.HasValue).Select(x => x.SaleDeptId.Value)
.Union(result.Data.Where(x => x.OrgId.HasValue).Select(x => x.OrgId.Value))
.Distinct();
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.LockUserName = users.Find(x => x.Id == item.LockUserId)?.UserName;
item.OperatorName = users.Find(x => x.Id == item.OperatorId)?.UserName;
item.SaleDeptName = orgs.Find(x => x.Id == item.SaleDeptId)?.OrgName;
item.OrgName = orgs.Find(x => x.Id == item.OrgId)?.OrgName;
}
}
return result;
}
/// <summary>
/// 提交发票开票
/// </summary>
/// <param name="request">请求参数</param>
/// <returns></returns>
public async Task<DataResult<TEntity>> SaveAsync(InvoiceRequest<TEntity> request)
{
var invoice = request.Invoice;
if (invoice.InvoiceDate == default)
invoice.InvoiceDate = DateTime.Now;
TEntity? dbValue = default;
if (request.Invoice.Id > 0)
{
dbValue = await TenantDb.Queryable<TEntity>().Select(x => new TEntity
{
Id = x.Id,
IsLocked = x.IsLocked,
Type = x.Type,
}).FirstAsync(x => x.Id == request.Invoice.Id);
if (dbValue != null && dbValue.IsLocked)
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked));
}
var result = EnsureSettlement(request.Invoice, dbValue);
if (!result.Succeeded)
return DataResult<TEntity>.Failed(result.Message, result.MultiCode);
if (request.Details?.Count > 0)
{
if (invoice.Id == 0 && invoice.CustomerId == 0)
{
var first = request.Details[0];
invoice.CustomerId = first.CustomerId.GetValueOrDefault();
invoice.CustomerName = first.CustomerName;
}
invoice.Details = request.Details.Select(x => new ApplicationDetail
{
ApplicationId = x.ApplicationId,
DetailId = x.Id == 0 ? null : x.Id,
RecordId = x.RecordId,
CustomerName = x.CustomerName ?? invoice.CustomerName,
FeeId = x.FeeId,
FeeName = x.FeeName,
FeeType = x.FeeType,
ApplyAmount = x.Amount,
Currency = x.Currency,
ExchangeRate = x.ExchangeRate,
OriginalAmount = x.OriginalAmount,
OriginalCurrency = x.OriginalCurrency ?? (invoice.Currency.IsNullOrEmpty() ? x.Currency : invoice.Currency),
}).ToList();
//金额禁止为0
if (invoice.Details.Any(x => x.ApplyAmount == 0 || x.OriginalAmount == 0))
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.AmountCannotBeZero));
if (invoice.Details.Any(x => x.OriginalCurrency.IsNullOrEmpty()))
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.OriginalCurrencyCanNotNull));
if (invoice.Details.Any(x => x.Currency != invoice.Currency && x.ExchangeRate == null))
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.NeedExchangeRate));
result = await PreSaveAsync(invoice);
if (!result.Succeeded)
return DataResult<TEntity>.Failed(result.Message, result.MultiCode);
invoice.InvoiceAmount = invoice.Details.Sum(x => x.ApplyAmount);
}
await TenantDb.Ado.BeginTranAsync();
try
{
//关联导航属性插入
if (invoice.Id == 0)
{
//创建时需要生成申请单编号
var sequence = CommonService.Value.GetSequenceNext<TEntity>();
if (!sequence.Succeeded)
{
return DataResult<TEntity>.Failed(sequence.Message, MultiLanguageConst.SequenceSetNotExist);
}
invoice.BillNO = sequence.Data;
await TenantDb.InsertNav(invoice).Include(x => x.Details).ExecuteCommandAsync();
}
else
{
if (invoice.Details.Count > 0)
await TenantDb.Insertable(invoice.Details).ExecuteCommandAsync();
await TenantDb.Updateable(invoice).IgnoreColumns(x => new
{
x.BillNO,
x.IsLocked,
x.CreateBy,
x.CreateTime,
x.Deleted,
x.DeleteBy,
x.DeleteTime
}).ExecuteCommandAsync();
}
await OnSaveAsync(invoice);
if (invoice.Details?.Count > 0)
{
//更新费用记录的已结算金额
var fees = invoice.Details.Select(x => new FeeRecord
{
Id = x.RecordId,
InvoiceAmount = x.OriginalAmount
}).ToList();
await TenantDb.Updateable(fees)
.PublicSetColumns(x => x.InvoiceAmount, "+")
.UpdateColumns(x => new { x.InvoiceAmount })
.ExecuteCommandAsync();
}
await TenantDb.Ado.CommitTranAsync();
return DataResult<TEntity>.Success(await PostSaveAsync(invoice));
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
/// <summary>
/// 用于发票的状态检查
/// </summary>
/// <param name="invoice">提交的发票</param>
/// <param name="dbValue">数据库值新增时为null</param>
/// <returns></returns>
protected virtual DataResult EnsureSettlement(TEntity invoice, TEntity? dbValue)
{
return DataResult.Success;
}
/// <summary>
/// 在保存前调用
/// </summary>
/// <param name="invoice">发票</param>
/// <returns></returns>
protected virtual Task<DataResult> PreSaveAsync(TEntity invoice)
{
return Task.FromResult(DataResult.Success);
}
/// <summary>
/// 在保存时调用
/// </summary>
/// <param name="invoice">要保存的发票</param>
/// <returns></returns>
protected virtual Task OnSaveAsync(TEntity invoice)
{
return Task.CompletedTask;
}
/// <summary>
/// 在保存完成后调用
/// </summary>
/// <param name="invoice">发票</param>
protected virtual Task<TEntity> PostSaveAsync(TEntity invoice)
{
return Task.FromResult(invoice);
}
public Task<DataResult> DeleteAsync(params long[] ids)
{
throw new NotImplementedException();
}
public Task<DataResult> DeleteDetailAsync(params long[] ids)
{
throw new NotImplementedException();
}
public Task<DataResult> SetLockAsync(bool isLocked, params long[] ids)
{
throw new NotImplementedException();
}
}
}