|
|
|
|
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.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()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (invoice.Currency.IsNullOrEmpty())
|
|
|
|
|
invoice.Currency = RMB_CODE;
|
|
|
|
|
|
|
|
|
|
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.ApplyAmount = invoice.Details.Sum(x => x.ApplyAmount);
|
|
|
|
|
invoice.AmountUppercase = new Money(invoice.InvoiceAmount).ToString();
|
|
|
|
|
invoice.OriginalAmount = invoice.Details.Sum(x => x.OriginalAmount);
|
|
|
|
|
invoice.OtherInvoiceAmount = invoice.Details.Where(x => x.Currency != RMB_CODE).Sum(x => x.OriginalAmount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.Deleteable<InvoiceDetail>().Where(x => x.ApplicationId == invoice.Id).ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await TenantDb.Updateable(invoice).IgnoreColumns(x => new
|
|
|
|
|
{
|
|
|
|
|
x.BillNO,
|
|
|
|
|
x.IsLocked,
|
|
|
|
|
x.CreateBy,
|
|
|
|
|
x.CreateTime,
|
|
|
|
|
x.Deleted,
|
|
|
|
|
x.DeleteBy,
|
|
|
|
|
x.DeleteTime
|
|
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 CreateInvoiceDetailsAsync([invoice]);
|
|
|
|
|
if (invoice.InvoiceDetails?.Count > 0)
|
|
|
|
|
await TenantDb.Insertable(invoice.InvoiceDetails).ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await OnSaveAsync(invoice);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 删除发票
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ids">发票ID</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> DeleteAsync(params long[] ids)
|
|
|
|
|
{
|
|
|
|
|
var apps = await TenantDb.Queryable<TEntity>().Where(x => ids.Contains(x.Id)).Select(x => new TEntity
|
|
|
|
|
{
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
IsLocked = x.IsLocked
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId)).Select(
|
|
|
|
|
x => new ApplicationDetail
|
|
|
|
|
{
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
ApplicationId = x.ApplicationId,
|
|
|
|
|
RecordId = x.RecordId,
|
|
|
|
|
OriginalAmount = x.OriginalAmount
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
|
|
|
|
foreach (var app in apps)
|
|
|
|
|
app.Details = details.FindAll(x => x.ApplicationId == app.Id); await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
|
|
|
|
|
var result = PreDelete(apps);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await OnDeleteDetailAsync(apps, DeleteOption.Entire);
|
|
|
|
|
await TenantDb.DeleteNav<TEntity>(x => ids.Contains(x.Id)).Include(x => x.Details).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 删除发票费用明细
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ids">明细ID</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> DeleteDetailAsync(params long[] ids)
|
|
|
|
|
{
|
|
|
|
|
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id)).Select(
|
|
|
|
|
x => new ApplicationDetail
|
|
|
|
|
{
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
ApplicationId = x.ApplicationId,
|
|
|
|
|
RecordId = x.RecordId,
|
|
|
|
|
OriginalAmount = x.OriginalAmount
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
var appIds = details.Select(x => x.ApplicationId).Distinct().ToList();
|
|
|
|
|
var apps = await TenantDb.Queryable<TEntity>().Where(x => appIds.Contains(x.Id)).Select(x => new TEntity
|
|
|
|
|
{
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
IsLocked = x.IsLocked
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
|
|
|
|
foreach (var app in apps)
|
|
|
|
|
app.Details = details.FindAll(x => x.ApplicationId == app.Id);
|
|
|
|
|
|
|
|
|
|
var result = PreDelete(apps);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await OnDeleteDetailAsync(apps, DeleteOption.DetailOnly);
|
|
|
|
|
await TenantDb.Deleteable(details).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在删除发票或其明细之前调用,用于检查状态
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="invoices">发票</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual DataResult PreDelete(List<TEntity> invoices)
|
|
|
|
|
{
|
|
|
|
|
if (invoices.Any(x => x.IsLocked))
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked));
|
|
|
|
|
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在执行删除发票或其明细时调用
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="invoices">发票及其明细</param>
|
|
|
|
|
/// <param name="deleteOption">发票删除选项</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual async Task OnDeleteDetailAsync(List<TEntity> invoices, DeleteOption deleteOption)
|
|
|
|
|
{
|
|
|
|
|
if (deleteOption == DeleteOption.DetailOnly)
|
|
|
|
|
{
|
|
|
|
|
//删除明细需要同时变更发票明细
|
|
|
|
|
var appIds = invoices.Select(x => x.Id).ToList();
|
|
|
|
|
var excludeIds = invoices.SelectMany(x => x.Details).Select(x => x.Id).ToList();
|
|
|
|
|
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => appIds.Contains(x.ApplicationId) && !excludeIds.Contains(x.Id))
|
|
|
|
|
.Select(x => new ApplicationDetail
|
|
|
|
|
{
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
ApplicationId = x.ApplicationId,
|
|
|
|
|
RecordId = x.RecordId,
|
|
|
|
|
FeeId = x.FeeId,
|
|
|
|
|
ApplyAmount = x.ApplyAmount
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
foreach (var item in invoices)
|
|
|
|
|
{
|
|
|
|
|
//重新设置申请明细
|
|
|
|
|
item.Details = details.FindAll(x => x.ApplicationId == item.Id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await TenantDb.Deleteable<InvoiceDetail>().Where(x => appIds.Contains(x.ApplicationId)).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await CreateInvoiceDetailsAsync(invoices);
|
|
|
|
|
var invDetails = invoices.SelectMany(x => x.InvoiceDetails).ToList();
|
|
|
|
|
if (invDetails.Count > 0)
|
|
|
|
|
await TenantDb.Insertable(invDetails).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await TenantDb.Updateable(invoices).UpdateColumns(x => new
|
|
|
|
|
{
|
|
|
|
|
x.ApplyAmount,
|
|
|
|
|
x.AmountUppercase
|
|
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//还原费用表的已开票金额
|
|
|
|
|
var fees = invoices.SelectMany(x => x.Details).Select(x => new FeeRecord { Id = x.RecordId, InvoiceAmount = x.OriginalAmount }).ToList();
|
|
|
|
|
await TenantDb.Updateable(fees)
|
|
|
|
|
.PublicSetColumns(it => it.InvoiceAmount, "-").UpdateColumns(x => new { x.InvoiceAmount })
|
|
|
|
|
.ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 生成发票明细
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="invoices"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected async Task CreateInvoiceDetailsAsync(IEnumerable<TEntity> invoices)
|
|
|
|
|
{
|
|
|
|
|
foreach (var invoice in invoices)
|
|
|
|
|
{
|
|
|
|
|
if (invoice.Details?.Count > 0 && (invoice.InvoiceDetails == null || invoice.InvoiceDetails.Count == 0))
|
|
|
|
|
{
|
|
|
|
|
var ids = invoice.Details.Select(x => x.RecordId).ToList();
|
|
|
|
|
var feesCodes = await TenantDb.Queryable<FeeRecord>().InnerJoin<FeeCode>((f, c) => f.FeeId == c.Id && ids.Contains(f.Id))
|
|
|
|
|
.Select((f, c) => new
|
|
|
|
|
{
|
|
|
|
|
FeeId = c.Id,
|
|
|
|
|
c.GoodName
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
|
|
|
|
var list = feesCodes.GroupBy(x => x.GoodName).Select(x => new
|
|
|
|
|
{
|
|
|
|
|
Name = x.Key,
|
|
|
|
|
FeeIds = x.Select(y => y.FeeId)
|
|
|
|
|
}).ToList();
|
|
|
|
|
invoice.InvoiceDetails = new List<InvoiceDetail>(list.Count);
|
|
|
|
|
foreach (var item in list)
|
|
|
|
|
{
|
|
|
|
|
var invDetail = new InvoiceDetail
|
|
|
|
|
{
|
|
|
|
|
ApplicationId = invoice.Id,
|
|
|
|
|
Name = item.Name,
|
|
|
|
|
TaxRate = invoice.TaxRate,
|
|
|
|
|
TaxUnitPrice = invoice.Details.FindAll(x => item.FeeIds.Contains(x.FeeId)).Sum(x => x.ApplyAmount),
|
|
|
|
|
Category = DetailCategory.InvoiceIssuance
|
|
|
|
|
};
|
|
|
|
|
invDetail.TaxAmount = invDetail.TaxUnitPrice * invoice.TaxRate;
|
|
|
|
|
invDetail.UnitPrice = invDetail.TaxUnitPrice - invDetail.TaxAmount;
|
|
|
|
|
|
|
|
|
|
invoice.InvoiceDetails.Add(invDetail);
|
|
|
|
|
invoice.InvoiceAmount = invoice.InvoiceDetails.Sum(x => x.TaxUnitPrice);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 设置发票的锁定状态
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="isLocked">是否锁定</param>
|
|
|
|
|
/// <param name="ids">发票ID</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult> SetLockAsync(bool isLocked, params long[] ids)
|
|
|
|
|
{
|
|
|
|
|
var dt = DateTime.Now;
|
|
|
|
|
var userId = long.Parse(User.UserId);
|
|
|
|
|
var list = ids.Select(x => new TEntity
|
|
|
|
|
{
|
|
|
|
|
Id = x,
|
|
|
|
|
IsLocked = isLocked,
|
|
|
|
|
LockTime = isLocked ? dt : null,
|
|
|
|
|
LockUserId = isLocked ? userId : null
|
|
|
|
|
}).ToList();
|
|
|
|
|
int rows = await TenantDb.Updateable(list)
|
|
|
|
|
.UpdateColumns(x => new { x.IsLocked, x.LockTime, x.LockUserId }).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|