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.Application.Method; using DS.WMS.Core.Fee.Entity; 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 { /// /// 发票服务基类 /// /// public class InvoiceService : ApplicationServiceBase, IInvoiceService where TEntity : Entity.Invoice, new() { readonly Lazy CommonService; /// /// 初始化 /// /// public InvoiceService(IServiceProvider provider) : base(provider) { CommonService = new Lazy(provider.GetRequiredService()); } /// /// 获取分页列表 /// /// /// public async Task>> GetListAsync(PageRequest request) { var query = TenantDb.Queryable() .Select(i => new InvoiceDto { Id = i.Id, InvoiceNO = i.InvoiceNO, BillNO = i.BillNO, InvoiceDate = i.InvoiceDate, CustomerId = i.CustomerId, CustomerName = i.CustomerName, Type = i.Mode, Category = i.Category, InvoiceHeader = i.InvoiceHeader, TaxID = i.TaxID, CustomerAddress = i.CustomerAddress, CustomerBankName = i.CustomerBankName, CustomerPhone = i.CustomerPhone, CustomerAccount = i.CustomerAccount, 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().InnerJoin((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().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().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; } /// /// 获取发票详情 /// /// 发票ID /// public async Task> GetAsync(long id) { var invoice = await TenantDb.Queryable().Select().FirstAsync(x => x.Id == id); if (invoice != null) { invoice.Details = await CreateApplicationDetailQuery((d, f, s) => d.ApplicationId == id && d.Category == DetailCategory.InvoiceIssuance) .Select(x => new ApplicationDetailDto { Id = x.Id, ApplicationId = x.ApplicationId, RecordId = x.RecordId, FeeName = x.FeeName, FeeType = x.FeeType, ApplyAmount = x.ApplyAmount, ExchangeRate = x.ExchangeRate, Currency = x.Currency, OriginalAmount = x.OriginalAmount, OriginalCurrency = x.OriginalCurrency, OriginalRate = x.OriginalRate, CustomerNo = x.CustomerNo, MBLNO = x.MBLNO, ClientName = x.ClientName, ETD = x.ETD, SaleName = x.SaleName, SourceName = x.SourceName, LoadPort = x.LoadPort, Vessel = x.Vessel, Voyage = x.Voyage, }).ToListAsync(); invoice.Summary = invoice.Details.GroupBy(x => new { x.FeeType, x.Currency }).Select(x => new SummaryItem { FeeType = x.Key.FeeType, Currency = x.Key.Currency, Amount = x.Sum(y => y.ApplyAmount) }).ToList(); invoice.InvoiceDetails = await TenantDb.Queryable().Where( x => x.ApplicationId == id && x.Category == DetailCategory.InvoiceIssuance).ToListAsync(); } return DataResult.Success(invoice); } #pragma warning disable CS4014 /// /// 提交发票开票 /// /// 请求参数 /// public async Task> SaveAsync(InvoiceRequest request) { var invoice = request.Invoice; if (invoice.InvoiceDate == default) invoice.InvoiceDate = DateTime.Now; if (invoice.Currency.IsNullOrEmpty()) invoice.Currency = FeeCurrency.RMB_CODE; TEntity? dbValue = default; if (request.Invoice.Id > 0) { dbValue = await TenantDb.Queryable().Select(x => new TEntity { Id = x.Id, IsLocked = x.IsLocked, Mode = x.Mode, }).FirstAsync(x => x.Id == request.Invoice.Id); } var result = EnsureSettlement(request.Invoice, dbValue); if (!result.Succeeded) return DataResult.Failed(result.Message, result.MultiCode); //按发票申请 if (request.Applications != null && request.Applications.Count > 0) { var ids = request.Applications.Select(x => x.ApplicationId); var details = await TenantDb.Queryable() .InnerJoin((x, y) => x.ApplicationId == y.Id) .Where((x, y) => ids.Contains(x.ApplicationId) && x.Category == DetailCategory.InvoiceApplication) .Select((x, y) => new { x.Id, x.ApplicationId, x.RecordId, x.CustomerName, x.FeeId, x.FeeType, x.FeeName, x.ApplyAmount, x.OriginalAmount, x.Currency, x.OriginalCurrency, x.ProcessedAmount, x.OriginalProcessedAmount, y.CustomerId }).ToListAsync(); invoice.Details ??= new List(details.Count); foreach (var item in details) { if (request.Invoice.CustomerId == 0) { request.Invoice.CustomerId = item.CustomerId; request.Invoice.CustomerName = item.CustomerName; } else if (request.Invoice.CustomerId != item.CustomerId) //校验开票单位是否一致 { return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceCustomerOnlyOne)); } //需转换为费用明细 var detail = new ApplicationDetail { ApplicationId = request.Invoice.Id, RefId = item.ApplicationId, DetailId = item.Id, RecordId = item.RecordId, Category = DetailCategory.InvoiceIssuance, CustomerName = item.CustomerName, FeeId = item.FeeId, FeeName = item.FeeName, FeeType = item.FeeType, Currency = FeeCurrency.RMB_CODE, OriginalCurrency = item.Currency, ApplyAmount = item.ApplyAmount - item.ProcessedAmount, OriginalAmount = item.OriginalAmount - item.OriginalProcessedAmount }; var app = request.Applications.Find(x => x.ApplicationId == item.ApplicationId); if (app != null && app.Currency != invoice.Currency) detail.ExchangeRate = app.ExchangeRate; else detail.ExchangeRate = 1m; if (detail.ExchangeRate.HasValue) detail.ApplyAmount = detail.ApplyAmount * detail.ExchangeRate.Value; invoice.Details.Add(detail); } } //自由申请 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 { Id = x.Id, ApplicationId = x.ApplicationId == 0 ? x.ApplicationId : invoice.Id, RefId = x.RefId, DetailId = x.Id == 0 ? null : x.Id, RecordId = x.RecordId, Category = DetailCategory.InvoiceIssuance, CustomerName = x.CustomerName ?? invoice.CustomerName, FeeId = x.FeeId, FeeName = x.FeeName, FeeType = x.FeeType, Currency = x.Currency, ApplyAmount = x.ApplyAmount, ExchangeRate = x.ExchangeRate, OriginalAmount = x.OriginalAmount, OriginalCurrency = x.OriginalCurrency ?? (invoice.Currency.IsNullOrEmpty() ? x.Currency : invoice.Currency), }).ToList(); } if (invoice.Details?.Count > 0) { //筛选出新增的费用明细 invoice.Details = invoice.Details.FindAll(x => x.Id == 0); //金额禁止为0 if (invoice.Details.Any(x => x.ApplyAmount == 0 || x.OriginalAmount == 0)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.AmountCannotBeZero)); if (invoice.Details.Any(x => x.OriginalCurrency.IsNullOrEmpty())) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.OriginalCurrencyCanNotNull)); if (invoice.Details.Any(x => x.Currency != invoice.Currency && x.ExchangeRate == null)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NeedExchangeRate)); result = await PreSaveAsync(invoice); if (!result.Succeeded) return DataResult.Failed(result.Message, result.MultiCode); } await TenantDb.Ado.BeginTranAsync(); try { BuildOption buildOption; if (invoice.Id == 0)//新增 { buildOption = BuildOption.Create; //创建时需要生成申请单编号 var sequence = CommonService.Value.GetSequenceNext(); if (!sequence.Succeeded) { return DataResult.Failed(sequence.Message, MultiLanguageConst.SequenceSetNotExist); } invoice.BillNO = sequence.Data; //关联导航属性插入 await TenantDb.InsertNav(invoice).Include(x => x.Details).ExecuteCommandAsync(); } else//编辑 { buildOption = BuildOption.Update; await TenantDb.Updateable(invoice).UpdateColumns(x => new { x.InvoiceNO, x.InvoiceDate, x.Account, x.BankName, //x.Currency, x.ReceiptCurrency, x.CustomerId, x.CustomerName, x.AutualCustomerName, x.InvoiceHeader, x.CustomerAddress, x.CustomerPhone, x.CustomerBankName, x.CustomerAccount, x.OperatorId, x.TaxID, x.TaxRate, x.OrgId, x.SaleDeptId }).ExecuteCommandAsync(); if (invoice.Details?.Count > 0) await TenantDb.Insertable(invoice.Details).ExecuteCommandAsync(); if (invoice.InvoiceDetails?.Count > 0) //发票明细只有更新 await TenantDb.Updateable(invoice.InvoiceDetails).IgnoreColumns(x => new { x.Category }).ExecuteCommandAsync(); } if (invoice.Details?.Count > 0) { //更新费用记录的已开票金额 var fees = invoice.Details.Select(x => new FeeRecord { Id = x.RecordId, InvoiceAmount = x.OriginalAmount, OrderInvSettlementAmount = x.OriginalAmount, }).ToList(); var updateable = TenantDb.Updateable(fees).PublicSetColumns(x => x.InvoiceAmount, "+"); if (invoice.Mode == InvoiceMode.Applcation) updateable = updateable.PublicSetColumns(x => x.OrderInvSettlementAmount, "+") .UpdateColumns(x => new { x.OrderInvSettlementAmount }); await updateable.UpdateColumns(x => new { x.InvoiceAmount }).ExecuteCommandAsync(); //生成发票明细 await BuildInvoiceDetailAsync(invoice, buildOption); //重新计算发票总金额 await RefreshInvoiceAsync([invoice]); } await OnSaveAsync(invoice); await TenantDb.Ado.CommitTranAsync(); PostSaveAsync(invoice); return DataResult.Success(invoice); } catch (Exception ex) { await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } /// /// 生成发票明细 /// /// 发票 /// 生成类型 /// protected async Task BuildInvoiceDetailAsync(TEntity invoice, BuildOption option) { if (invoice.Details == null || invoice.Details.Count == 0) return; var ids = invoice.Details.Select(x => x.Id); if (option == BuildOption.Create) { var feesCodes = await TenantDb.Queryable().InnerJoin((d, fc) => d.FeeId == fc.Id && ids.Contains(d.Id)) .Select((d, fc) => new { DetailId = d.Id, FeeId = fc.Id, fc.GoodName }).ToListAsync(); var feeCodeGroups = feesCodes.GroupBy(x => x.GoodName).ToList(); invoice.InvoiceDetails = new List(feeCodeGroups.Count); List relations = []; foreach (var g in feeCodeGroups) { var invDetail = new InvoiceDetail { Id = SnowFlakeSingle.Instance.NextId(), ApplicationId = invoice.Id, Name = g.Key, TaxRate = invoice.TaxRate, Quantity = 1, TaxUnitPrice = invoice.Details.FindAll(x => g.Select(x => x.DetailId).Contains(x.Id)).Sum(x => x.ApplyAmount), Category = DetailCategory.InvoiceIssuance }; invDetail.TaxAmount = invDetail.TaxUnitPrice * invoice.TaxRate; invDetail.UnitPrice = invDetail.TaxUnitPrice - invDetail.TaxAmount; invDetail.Amount = invDetail.TaxUnitPrice * invDetail.Quantity; invoice.InvoiceDetails.Add(invDetail); foreach (var item in g) { relations.Add(new ApplicationDetailRelation { DetailId = item.DetailId, InvoiceDetailId = invDetail.Id, OriginalName = g.Key, InvoiceId = invoice.Id }); } } await TenantDb.Insertable(invoice.InvoiceDetails).ExecuteCommandAsync(); await TenantDb.Insertable(relations).ExecuteCommandAsync(); } //更新时只处理增加的明细 else if (option == BuildOption.Update) { //获取现有发票明细对应关系 var relations = await TenantDb.Queryable().Where(x => x.InvoiceId == invoice.Id) .Select(x => new { x.DetailId, x.InvoiceDetailId, x.OriginalName, }).ToListAsync(); var feeIds = invoice.Details.Select(x => x.FeeId); var feesCodes = await TenantDb.Queryable().Where(x => feeIds.Contains(x.Id)) .Select(x => new { FeeId = x.Id, x.GoodName }).ToListAsync(); invoice.InvoiceDetails = []; //新增的发票明细 List invoiceDetailList = []; //更新的发票明细 List relationList = []; //新增的明细关系 foreach (var detail in invoice.Details) { var goodsName = feesCodes.Find(x => x.FeeId == detail.FeeId)?.GoodName; //转换为发票明细名称 var relation = relations.Find(x => string.Equals(x.OriginalName, goodsName, StringComparison.Ordinal)); if (relation == null) //需要新增发票明细 { var invDetail = new InvoiceDetail { Id = SnowFlakeSingle.Instance.NextId(), ApplicationId = invoice.Id, Name = goodsName, Quantity = 1, TaxRate = invoice.TaxRate, TaxUnitPrice = detail.ApplyAmount, Category = DetailCategory.InvoiceIssuance }; invDetail.TaxAmount = invDetail.TaxUnitPrice * invoice.TaxRate; invDetail.UnitPrice = invDetail.TaxUnitPrice - invDetail.TaxAmount; invDetail.Amount = invDetail.TaxUnitPrice * invDetail.Quantity; invoice.InvoiceDetails.Add(invDetail); relationList.Add(new ApplicationDetailRelation { DetailId = detail.Id, InvoiceDetailId = invDetail.Id, InvoiceId = invoice.Id, OriginalName = goodsName }); } else //发票明细已存在,追加金额 { //添加到更新列表 invoiceDetailList.Add(new InvoiceDetail { Id = relation.InvoiceDetailId, TaxUnitPrice = detail.ApplyAmount }); } } if (invoice.InvoiceDetails.Count > 0) await TenantDb.Insertable(invoice.InvoiceDetails).ExecuteCommandAsync(); //执行发票明细金额更新 if (invoiceDetailList.Count > 0) { var ids2 = invoiceDetailList.Select(x => x.Id); var updateList = await TenantDb.Queryable().Where(x => ids2.Contains(x.Id)).Select(x => new InvoiceDetail { Id = x.Id, TaxUnitPrice = x.TaxUnitPrice, TaxRate = x.TaxRate, TaxAmount = x.TaxAmount, UnitPrice = x.UnitPrice }).ToListAsync(); foreach (var item in updateList) { var invDetail = invoiceDetailList.Find(x => x.Id == item.Id); item.TaxUnitPrice += (invDetail?.TaxUnitPrice).GetValueOrDefault(); item.TaxAmount = item.TaxUnitPrice * invoice.TaxRate; item.UnitPrice = item.TaxUnitPrice - item.TaxAmount; } await TenantDb.Updateable(updateList).UpdateColumns(x => new { x.TaxUnitPrice, x.TaxAmount, x.UnitPrice }).ExecuteCommandAsync(); } if (relationList.Count > 0) await TenantDb.Insertable(relationList).ExecuteCommandAsync(); } else if (option == BuildOption.Delete) { } } /// /// 重新计算发票的各项金额数据 /// /// 发票 /// protected async Task RefreshInvoiceAsync(List invoices) { var ids = invoices.Select(x => x.Id); var details = await TenantDb.Queryable().Where(x => ids.Contains(x.ApplicationId)) .Select(x => new { x.ApplicationId, x.Currency, x.ApplyAmount, x.OriginalAmount }).ToListAsync(); var invDetails = await TenantDb.Queryable().Where(x => ids.Contains(x.ApplicationId)) .Select(x => new { x.ApplicationId, x.Amount }).ToListAsync(); foreach (var invoice in invoices) { var currDetails = details.FindAll(x => x.ApplicationId == invoice.Id); invoice.ApplyAmount = currDetails.Sum(x => x.ApplyAmount); invoice.AmountUppercase = new Money(invoice.ApplyAmount).ToString(); invoice.OriginalAmount = currDetails.Sum(x => x.OriginalAmount); invoice.OtherInvoiceAmount = currDetails.FindAll(x => x.Currency != FeeCurrency.RMB_CODE).Sum(x => x.OriginalAmount); invoice.InvoiceAmount = invDetails.FindAll(x => x.ApplicationId == invoice.Id).Sum(x => x.Amount); } return await TenantDb.Updateable(invoices).UpdateColumns(x => new { x.ApplyAmount, x.AmountUppercase, x.OriginalAmount, x.OtherInvoiceAmount, x.InvoiceAmount }).ExecuteCommandAsync(); } /// /// 用于发票的状态检查 /// /// 提交的发票 /// 数据库值,新增时为null /// protected virtual DataResult EnsureSettlement(TEntity invoice, TEntity? dbValue) { if (dbValue != null && dbValue.IsLocked) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked)); return DataResult.Success; } /// /// 在保存前调用 /// /// 发票 /// protected virtual Task PreSaveAsync(TEntity invoice) => Task.FromResult(DataResult.Success); /// /// 在保存时调用 /// /// 要保存的发票 /// protected virtual Task OnSaveAsync(TEntity invoice) => Task.CompletedTask; /// /// 在保存完成后调用 /// /// 发票 protected virtual Task PostSaveAsync(TEntity invoice) => Task.CompletedTask; /// /// 删除发票 /// /// 发票ID /// public async Task DeleteAsync(params long[] ids) { await TenantDb.Ado.BeginTranAsync(); try { var apps = await TenantDb.Queryable().Where(x => ids.Contains(x.Id)).Select(x => new TEntity { Id = x.Id, Mode = x.Mode, IsLocked = x.IsLocked }).ToListAsync(); if (apps.Count == 0) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); var details = await TenantDb.Queryable().Where(x => ids.Contains(x.ApplicationId)).Select( x => new ApplicationDetail { Id = x.Id, ApplicationId = x.ApplicationId, DetailId = x.DetailId, RefId = x.RefId, RecordId = x.RecordId, ApplyAmount = x.ApplyAmount, OriginalAmount = x.OriginalAmount }).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 OnDeleteDetailAsync(apps, DeleteOption.Entire); await TenantDb.DeleteNav(x => ids.Contains(x.Id)).Include(x => x.Details).ExecuteCommandAsync(); await TenantDb.Ado.CommitTranAsync(); PostDeleteAsync(apps, DeleteOption.Entire); return DataResult.Success; } catch (Exception ex) { await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } /// /// 删除发票费用明细 /// /// 明细ID /// public async Task DeleteDetailAsync(params long[] ids) { await TenantDb.Ado.BeginTranAsync(); try { var details = await TenantDb.Queryable().Where(x => ids.Contains(x.Id)).Select( x => new ApplicationDetail { Id = x.Id, ApplicationId = x.ApplicationId, DetailId = x.DetailId, RefId = x.RefId, RecordId = x.RecordId, ApplyAmount = x.ApplyAmount, OriginalAmount = x.OriginalAmount }).ToListAsync(); if (details.Count == 0) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); var invIds = details.Select(x => x.ApplicationId).Distinct().ToList(); var invoices = await TenantDb.Queryable().Where(x => invIds.Contains(x.Id)).Select(x => new TEntity { Id = x.Id, Mode = x.Mode, IsLocked = x.IsLocked }).ToListAsync(); foreach (var app in invoices) app.Details = details.FindAll(x => x.ApplicationId == app.Id); var result = PreDelete(invoices); if (!result.Succeeded) return result; await OnDeleteDetailAsync(invoices, DeleteOption.DetailOnly); await TenantDb.Deleteable(details).ExecuteCommandAsync(); //重新计算发票总金额 await RefreshInvoiceAsync(invoices); await TenantDb.Ado.CommitTranAsync(); PostDeleteAsync(invoices, DeleteOption.Entire); return DataResult.Success; } catch (Exception ex) { await TenantDb.Ado.RollbackTranAsync(); await ex.LogAsync(Db); return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } /// /// 删除发票明细 /// /// 发票明细ID /// public async Task DeleteInvoiceDetailAsync(params long[] ids) { await TenantDb.Ado.BeginTranAsync(); try { var invDetails = await TenantDb.Queryable().Where(x => ids.Contains(x.Id)) .Select(x => new { x.ApplicationId, x.Amount }).ToListAsync(); var groups = invDetails.GroupBy(x => x.ApplicationId); foreach (var g in groups) { var list = g.Select(x => new TEntity { Id = g.Key, InvoiceAmount = g.Sum(x => x.Amount) }).ToList(); //更新发票主表的开票金额 await TenantDb.Updateable(list).PublicSetColumns(x => x.InvoiceAmount, "-") .UpdateColumns(x => new { x.InvoiceAmount }).ExecuteCommandAsync(); } await TenantDb.Deleteable().Where(x => ids.Contains(x.Id)).ExecuteCommandAsync(); //删除对应关系 await TenantDb.Deleteable().Where(x => ids.Contains(x.InvoiceDetailId)).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)); } } /// /// 在删除发票或其明细之前调用,用于检查状态 /// /// 发票 /// protected virtual DataResult PreDelete(List invoices) { if (invoices.Any(x => x.IsLocked)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked)); return DataResult.Success; } /// /// 在执行删除发票或其明细时调用 /// /// 发票及其明细 /// 发票删除选项 /// protected virtual async Task OnDeleteDetailAsync(List invoices, DeleteOption deleteOption) { var appIds = invoices.Select(x => x.Id); if (deleteOption == DeleteOption.DetailOnly) { //删除明细需要同时变更发票明细 foreach (var item in invoices) BuildInvoiceDetailAsync(item, BuildOption.Delete); var excludeIds = invoices.SelectMany(x => x.Details).Select(x => x.Id); var details = await TenantDb.Queryable().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); item.ApplyAmount = item.Details.Sum(x => x.ApplyAmount); item.AmountUppercase = new Money(item.ApplyAmount).ToString(); } await TenantDb.Updateable(invoices).UpdateColumns(x => new { x.ApplyAmount, x.AmountUppercase }).ExecuteCommandAsync(); //删除明细之间的关系 await TenantDb.Deleteable().Where(x => excludeIds.Contains(x.DetailId)).ExecuteCommandAsync(); } else if (deleteOption == DeleteOption.Entire) { //删除发票主表则同时删除对应发票明细 await TenantDb.Deleteable().Where(x => appIds.Contains(x.ApplicationId)).ExecuteCommandAsync(); //删除明细之间的关系 await TenantDb.Deleteable().Where(x => appIds.Contains(x.InvoiceId)).ExecuteCommandAsync(); } foreach (var item in invoices) { //还原费用表的已开票金额 var fees = item.Details?.Select(x => new FeeRecord { Id = x.RecordId, InvoiceAmount = x.OriginalAmount }).ToList(); var updateable = TenantDb.Updateable(fees).PublicSetColumns(x => x.InvoiceAmount, "-"); if (item.Mode == InvoiceMode.Applcation) updateable = updateable.PublicSetColumns(x => x.OrderInvSettlementAmount, "-") .UpdateColumns(x => new { x.OrderInvSettlementAmount }); await updateable.UpdateColumns(x => new { x.InvoiceAmount }).ExecuteCommandAsync(); } } /// /// 在删除完成后调用 /// /// 发票及其明细 /// 发票删除选项 protected virtual Task PostDeleteAsync(List invoices, DeleteOption deleteOption) => Task.CompletedTask; /// /// 设置发票的锁定状态 /// /// 是否锁定 /// 发票ID /// public async Task 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)); } /// /// 设置发票的作废状态 /// /// 是否锁定 /// 发票ID /// public async Task SetCancelAsync(bool isCancelled, params long[] ids) { var dt = DateTime.Now; var userId = long.Parse(User.UserId); var list = ids.Select(x => new TEntity { Id = x, IsCancelled = isCancelled, CancelTime = isCancelled ? dt : null, CancelUserId = isCancelled ? userId : null }).ToList(); int rows = await TenantDb.Updateable(list) .UpdateColumns(x => new { x.IsCancelled, x.CancelTime, x.CancelUserId }).ExecuteCommandAsync(); return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed)); } } }