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