From 5805d892ef8170de8592a8e11be9c345e713ae3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B5=87=E6=96=87=E9=BE=99?= Date: Thu, 14 Nov 2024 10:34:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E9=80=81=E5=BC=80=E7=A5=A8=E9=82=AE?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Application/Entity/InvoiceDetail.cs | 6 + .../Method/InvoiceApplicationService.cs | 1 + .../Interface/IInvoiceIssuanceService.cs | 7 ++ .../Invoice/Method/GeneralInvoiceService.cs | 69 ++++------- .../Invoice/Method/InvoiceIssuanceService.cs | 113 ++++++++++++++---- .../Invoice/Method/InvoiceService`1.cs | 37 ++++-- .../Method/ApplicationSettlementService.cs | 5 +- .../Controllers/GeneralInvoiceController.cs | 17 ++- 8 files changed, 166 insertions(+), 89 deletions(-) diff --git a/ds-wms-service/DS.WMS.Core/Application/Entity/InvoiceDetail.cs b/ds-wms-service/DS.WMS.Core/Application/Entity/InvoiceDetail.cs index f465c4ad..4f8860b4 100644 --- a/ds-wms-service/DS.WMS.Core/Application/Entity/InvoiceDetail.cs +++ b/ds-wms-service/DS.WMS.Core/Application/Entity/InvoiceDetail.cs @@ -92,5 +92,11 @@ namespace DS.WMS.Core.Application.Entity /// [SugarColumn(ColumnDescription = "类别", IsNullable = true)] public DetailCategory Category { get; set; } + + /// + /// 币别 + /// + [SugarColumn(ColumnDescription = "币别", IsNullable = false, Length = 3)] + public string Currency { get; set; } } } diff --git a/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs b/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs index 0377ac7d..240ce73e 100644 --- a/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs +++ b/ds-wms-service/DS.WMS.Core/Application/Method/InvoiceApplicationService.cs @@ -653,6 +653,7 @@ namespace DS.WMS.Core.Application.Method ApplicationId = application.Id, CodeId = code.Id, Name = code.Name, + Currency = code.DefaultCurrency ?? string.Empty, Quantity = 1, TaxUnitPrice = detail.ApplyAmount, TaxRate = code.TaxRate, diff --git a/ds-wms-service/DS.WMS.Core/Invoice/Interface/IInvoiceIssuanceService.cs b/ds-wms-service/DS.WMS.Core/Invoice/Interface/IInvoiceIssuanceService.cs index 26fe8383..309e6371 100644 --- a/ds-wms-service/DS.WMS.Core/Invoice/Interface/IInvoiceIssuanceService.cs +++ b/ds-wms-service/DS.WMS.Core/Invoice/Interface/IInvoiceIssuanceService.cs @@ -36,5 +36,12 @@ namespace DS.WMS.Core.Invoice.Interface /// /// 为null时引发。 Task AddTenantAsync(Tenant tenant); + + /// + /// 发送邮件 + /// + /// 发票ID + /// + Task SendMailAsync(long id); } } diff --git a/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs b/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs index 103c7db1..496ff7a2 100644 --- a/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs +++ b/ds-wms-service/DS.WMS.Core/Invoice/Method/GeneralInvoiceService.cs @@ -132,7 +132,8 @@ namespace DS.WMS.Core.Invoice.Method var list = invoice.Details?.Where(x => x.DetailId.HasValue).Select(x => new ApplicationDetail { Id = x.DetailId.GetValueOrDefault(), - ProcessedAmount = x.ApplyAmount, + ProcessedAmount = x.Currency == x.OriginalCurrency ? + x.ApplyAmount : x.ApplyAmount / (x.ExchangeRate ?? 1), OriginalProcessedAmount = x.OriginalAmount }).ToList(); @@ -148,55 +149,33 @@ namespace DS.WMS.Core.Invoice.Method protected override async Task OnDeleteDetailAsync(List invoices, DeleteOption deleteOption) { - var list = invoices.SelectMany(x => x.Details).Where(x => x.DetailId.HasValue).Select(x => new ApplicationDetail - { - Id = x.DetailId.GetValueOrDefault(), - ProcessedAmount = x.ApplyAmount, - OriginalProcessedAmount = x.OriginalAmount - }).ToList(); - //恢复发票申请费用明细的已处理金额 - await TenantDb.Updateable(list) - .PublicSetColumns(x => x.ProcessedAmount, "-").PublicSetColumns(x => x.OriginalProcessedAmount, "-") - .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) - .ExecuteCommandAsync(); - - //还原发票申请状态 - var ids = list.Where(x => x.DetailId.HasValue).Select(x => x.DetailId).Distinct(); - var details = TenantDb.Queryable().Where(x => ids.Contains(x.Id)) - .Select(x => new ApplicationDetail - { - Id = x.Id, - ApplicationId = x.ApplicationId, - ProcessedAmount = x.ProcessedAmount, - OriginalAmount = x.OriginalAmount, - OriginalProcessedAmount = x.OriginalProcessedAmount - }).ToList(); - - var gpList = details.GroupBy(x => x.ApplicationId); - List applications = []; - foreach (var gp in gpList) - { - var processedCount = gp.Count(x => x.OriginalAmount - x.OriginalProcessedAmount == 0); - var itemCount = gp.Count(); - if (itemCount == processedCount) - continue; - - var entity = new InvoiceApplication { Id = gp.Key }; - if (processedCount == 0) + var items = invoices.SelectMany(x => x.Details); + var ids = items.Select(x => x.DetailId); + //获取发票申请明细 + var details = await TenantDb.Queryable().Where(x => ids.Contains(x.Id)) + .Select(x => new ApplicationDetail { - entity.Status = InvoiceApplicationStatus.AuditPassed; - } - else if (itemCount > processedCount) - { - entity.Status = InvoiceApplicationStatus.PartialInvoiced; - } + Id = x.Id, + Currency = x.Currency, + ApplicationId = x.ApplicationId, + ProcessedAmount = x.ProcessedAmount, + OriginalAmount = x.OriginalAmount, + OriginalProcessedAmount = x.OriginalProcessedAmount + }).ToListAsync(); - applications.Add(entity); + foreach (var detail in details) + { + var item = items.FirstOrDefault(x => x.DetailId == detail.Id); + detail.ProcessedAmount -= detail.Currency == item.Currency ? item.ApplyAmount : item.OriginalAmount; + detail.OriginalProcessedAmount -= item.OriginalAmount; } - if (applications.Count > 0) - await TenantDb.Updateable(applications).UpdateColumns(x => new { x.Status }).ExecuteCommandAsync(); + //恢复发票申请费用明细的已处理金额 + await TenantDb.Updateable(details) + .UpdateColumns(x => new { x.ProcessedAmount, x.OriginalProcessedAmount }) + .ExecuteCommandAsync(); + await base.OnDeleteDetailAsync(invoices, deleteOption); } diff --git a/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceIssuanceService.cs b/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceIssuanceService.cs index bc25da9f..be469346 100644 --- a/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceIssuanceService.cs +++ b/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceIssuanceService.cs @@ -15,7 +15,7 @@ using SqlSugar; namespace DS.WMS.Core.Invoice.Method { /// - /// 发票开具服务 + /// 发票开出接口服务 /// public sealed class InvoiceIssuanceService : ApplicationServiceBase, IInvoiceIssuanceService { @@ -167,21 +167,22 @@ namespace DS.WMS.Core.Invoice.Method /// public async Task UpdateInvoiceNumberAsync(string sn) { - var result2 = DataResult.Success; + var invResult = DataResult.Success; var invoices = await TenantDb.Queryable() - .Where(x => x.SN == sn && !SqlFunc.IsNullOrEmpty(x.PDFUrl)) + .Where(x => x.SN == sn && !SqlFunc.IsNullOrEmpty(x.InvoiceNO)) .Select(x => new Entity.Invoice { SN = x.SN, BillNO = x.BillNO, InvoiceNO = x.InvoiceNO, + Type = x.Type, ApiCode = x.ApiCode, ApiStatus = x.ApiStatus, PDFUrl = x.PDFUrl }).ToListAsync(); - result2.Data = invoices; + invResult.Data = invoices; if (invoices.Count > 0) - return result2; + return invResult; var order = await TenantDb.Queryable().Where(x => x.SN == sn).FirstAsync(); //如果开票中所属机构为空,则取用户的orgId @@ -212,6 +213,18 @@ namespace DS.WMS.Core.Invoice.Method if (queryResult.data.Order?.Count > 0) { + var billNumbers = queryResult.data.Order.Select(x => x.orderNo); + //获取发票ID及类型 + var list = await TenantDb.Queryable().Where(x => billNumbers.Contains(x.BillNO)) + .Select(x => new + { + x.Id, + x.BillNO, + x.Type, + x.Mode + }).ToListAsync(); + DateTime dtNow = DateTime.Now; + long userId = long.Parse(User.UserId); foreach (var item in queryResult.data.Order) { var inv = new Entity.Invoice @@ -221,8 +234,18 @@ namespace DS.WMS.Core.Invoice.Method InvoiceNO = item.fphm, ApiCode = item.State.ToString(), ApiStatus = item.UpMessage, - PDFUrl = item.FileUrl + PDFUrl = item.FileUrl, + IsLocked = true, + LockTime = dtNow, + LockUserId = userId }; + var storedItem = list.Find(x => x.BillNO == inv.BillNO); + if (storedItem == null) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); + + inv.Id = storedItem.Id; + inv.Type = storedItem.Type; + inv.Mode = storedItem.Mode; invoices.Add(inv); switch (item.State) @@ -242,28 +265,33 @@ namespace DS.WMS.Core.Invoice.Method await TenantDb.Ado.BeginTranAsync(); try { - var billNumbers = invoices.Select(x => x.BillNO); - //获取发票费用明细ID - var ids = await TenantDb.Queryable() - .InnerJoin((i, d) => i.Id == d.ApplicationId) - .Where((i, d) => billNumbers.Contains(i.BillNO) && i.Type == InvoiceType.Blue) - .Select((i, d) => d.Id).ToArrayAsync(); - if (ids.Length > 0) + var redIds = invoices.Where(x => x.Type == InvoiceType.Red).Select(x => x.Id).ToList(); + //开出红票时,需要删除蓝票的费用明细 + if (redIds.Count > 0) { + //获取蓝票费用明细ID + var ids = await TenantDb.Queryable() + .InnerJoin((d, i) => d.ApplicationId == i.Id) + .Where((d, i) => redIds.Contains(i.RedId.Value)) + .Select((d, i) => d.Id).ToArrayAsync(); //删除蓝票费用明细 await InvoiceService.Value.DeleteDetailAsync(ids); } - await TenantDb.Updateable(invoices).WhereColumns(x => x.BillNO) - .UpdateColumns(x => new - { - x.InvoiceNO, - x.ApiCode, - x.ApiStatus, - x.PDFUrl - }).ExecuteCommandAsync(); - - await InvoiceService.Value.RefreshApplicationStatus(invoices.Select(x => x.InvoiceNO)!); + await TenantDb.Updateable(invoices).UpdateColumns(x => new + { + x.InvoiceNO, + x.ApiCode, + x.ApiStatus, + x.PDFUrl, + x.IsLocked, + x.LockUserId, + x.LockTime + }).ExecuteCommandAsync(); + + //回写发票申请的状态 + if (invoices.Exists(x => x.Mode == InvoiceMode.Applcation && x.Type == InvoiceType.Blue)) + await InvoiceService.Value.RefreshApplicationStatus(invoices.Select(x => x.InvoiceNO)!); await TenantDb.Ado.CommitTranAsync(); } @@ -275,8 +303,8 @@ namespace DS.WMS.Core.Invoice.Method } } - result2.Data = invoices; - return result2; + invResult.Data = invoices; + return invResult; } /// @@ -350,6 +378,7 @@ namespace DS.WMS.Core.Invoice.Method try { await TenantDb.InsertNav(redInvoice).Include(x => x.Details).Include(x => x.InvoiceDetails).ExecuteCommandAsync(); + blueInvoice.RedId = redInvoice.Id; blueInvoice.IsSetRed = true; blueInvoice.RedCode = request.chyyDm; @@ -407,6 +436,40 @@ namespace DS.WMS.Core.Invoice.Method } } + /// + /// 发送邮件 + /// + /// 发票ID + /// + public async Task SendMailAsync(long id) + { + var inv = await TenantDb.Queryable().Where(x => x.Id == id) + .Select(x => new + { + orderNo = x.BillNO, + x.SaleDeptId, + x.InvoiceNO + }).FirstAsync(); + if (inv == null) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData)); + + if (!string.IsNullOrEmpty(inv.InvoiceNO)) + return DataResult.Failed("发票尚未开出"); + + //如果开票中所属机构为空,则取用户的orgId + var userOrgId = (inv.SaleDeptId != null && inv.SaleDeptId > 0) ? inv.SaleDeptId : User.OrgId; + //接口请求key密钥 + var orgauthinfo = Db.Queryable().Where(t => t.OrgId == userOrgId).First(); + api.DefaultHeaders.Clear(); + api.DefaultHeaders.Add("USER_KEY", orgauthinfo.Key); + api.DefaultHeaders.Add("USER_SECRET", orgauthinfo.Secret); + var result = await api.PostAsync>(AppSetting.app(["InvoiceApi", "BaseUrl"]) + "/api/Invoice/InvoiceToEmil", inv); + if (result.Data == null || !result.Data.success) + return DataResult.Failed(result.Data == null ? "请求失败" : result.Data.msg); + + return DataResult.Success; + } + /// /// 添加租户信息 /// diff --git a/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs b/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs index c217714d..a31654c6 100644 --- a/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs +++ b/ds-wms-service/DS.WMS.Core/Invoice/Method/InvoiceService`1.cs @@ -9,6 +9,7 @@ using DS.WMS.Core.Code.Entity; using DS.WMS.Core.Fee.Entity; using DS.WMS.Core.Info.Entity; using DS.WMS.Core.Invoice.Dtos; +using DS.WMS.Core.Invoice.Entity; using DS.WMS.Core.Invoice.Interface; using DS.WMS.Core.Op.Entity; using DS.WMS.Core.Sys.Entity; @@ -222,7 +223,9 @@ namespace DS.WMS.Core.Invoice.Method dbValue = await TenantDb.Queryable().Select(x => new TEntity { Id = x.Id, + InvoiceNO = x.InvoiceNO, IsLocked = x.IsLocked, + IsSettled = x.IsSettled, Mode = x.Mode, }).FirstAsync(x => x.Id == request.Invoice.Id); } @@ -362,7 +365,7 @@ namespace DS.WMS.Core.Invoice.Method if (app.AmountOther.HasValue) { - result2 = AssignAmount(details2.FindAll(x => x.Currency != FeeCurrency.RMB_CODE && x.OriginalCurrency != FeeCurrency.USD_CODE), app.AmountOther.Value); + result2 = AssignAmount(details2.FindAll(x => x.Currency != FeeCurrency.RMB_CODE && x.Currency != FeeCurrency.USD_CODE), app.AmountOther.Value); if (!result2.Succeeded) return DataResult.Failed(result2.Message, result2.MultiCode); } @@ -458,8 +461,7 @@ namespace DS.WMS.Core.Invoice.Method } //补充销方信息 - //var org = await Db.Queryable().Where(x => x.Id == User.OrgId).Select(x => new { x.OrgFullName, x.LicenseCode }).FirstAsync(); - var orgId = invoice.SaleDeptId ?? User.OrgId; + var orgId = invoice.SaleDeptId.GetValueOrDefault() == 0 ? User.OrgId : invoice.SaleDeptId; var org = await Db.Queryable().LeftJoin((t, a) => t.Id == a.OrgId).Where((t, a) => t.Id == orgId).Select((t, a) => new { t.OrgFullName, t.LicenseCode }).FirstAsync(); if (org != null) { @@ -477,9 +479,6 @@ namespace DS.WMS.Core.Invoice.Method invoice.Account = orgBank.BankAccountNo; } - //生成默认备注 - //invoice.InvoiceRemark = $"购买方地址电话:" + Environment.NewLine + invoice.CustomerAddressTel + Environment.NewLine - // + "购买方开户行/账号:" + invoice.CustomerBankName + " " + invoice.CustomerAccount; if (!string.IsNullOrEmpty(invRemark)) { invoice.Note += Environment.NewLine + invRemark; @@ -696,6 +695,7 @@ namespace DS.WMS.Core.Invoice.Method ApplicationId = invoice.Id, CodeId = code.Id, Name = code.Name, + Currency = FeeCurrency.RMB_CODE, Quantity = 1, TaxUnitPrice = detail.ApplyAmount, TaxRate = code.TaxRate, @@ -765,8 +765,17 @@ namespace DS.WMS.Core.Invoice.Method /// protected virtual DataResult EnsureSettlement(TEntity invoice, TEntity? dbValue) { - if (dbValue != null && dbValue.IsLocked) - return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked)); + if (dbValue != null) + { + if (dbValue.IsLocked) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked)); + + if (!string.IsNullOrEmpty(dbValue.InvoiceNO)) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsIssued)); + + if (dbValue.IsSettled) + return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsSettled)); + } return DataResult.Success; } @@ -947,11 +956,14 @@ namespace DS.WMS.Core.Invoice.Method if (invoices.Any(x => x.IsLocked)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsLocked)); - if (invoices.Any(x => !string.IsNullOrEmpty(x.ApiCode))) + if (invoices.Any(x => !string.IsNullOrEmpty(x.InvoiceNO))) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsIssued)); - var ids = invoices.Select(x => x.Id); - if (TenantDb.Queryable().Any(x => ids.Contains(x.RefId.Value) && x.Category == DetailCategory.InvoiceSettlement)) + //var ids = invoices.Select(x => x.Id); + //if (TenantDb.Queryable().Any(x => ids.Contains(x.RefId.Value) && x.Category == DetailCategory.InvoiceSettlement)) + // return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsSettled)); + + if (invoices.Any(x => x.IsSettled)) return DataResult.FailedWithDesc(nameof(MultiLanguageConst.InvoiceIsSettled)); return DataResult.Success; @@ -1038,8 +1050,7 @@ namespace DS.WMS.Core.Invoice.Method 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(); + 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)); } diff --git a/ds-wms-service/DS.WMS.Core/Settlement/Method/ApplicationSettlementService.cs b/ds-wms-service/DS.WMS.Core/Settlement/Method/ApplicationSettlementService.cs index d54cb1c2..ba873c5b 100644 --- a/ds-wms-service/DS.WMS.Core/Settlement/Method/ApplicationSettlementService.cs +++ b/ds-wms-service/DS.WMS.Core/Settlement/Method/ApplicationSettlementService.cs @@ -646,17 +646,16 @@ namespace DS.WMS.Core.Settlement.Method var items = list.SelectMany(x => x.Details); var ids = items.Select(x => x.DetailId); //获取申请明细 - var details = TenantDb.Queryable().Where(x => ids.Contains(x.Id)) + var details = await TenantDb.Queryable().Where(x => ids.Contains(x.Id)) .Select(x => new ApplicationDetail { Id = x.Id, Currency = x.Currency, - OriginalCurrency = x.OriginalCurrency, ApplicationId = x.ApplicationId, ProcessedAmount = x.ProcessedAmount, OriginalAmount = x.OriginalAmount, OriginalProcessedAmount = x.OriginalProcessedAmount - }).ToList(); + }).ToListAsync(); foreach (var detail in details) { diff --git a/ds-wms-service/DS.WMS.FeeApi/Controllers/GeneralInvoiceController.cs b/ds-wms-service/DS.WMS.FeeApi/Controllers/GeneralInvoiceController.cs index c1c74926..65de506e 100644 --- a/ds-wms-service/DS.WMS.FeeApi/Controllers/GeneralInvoiceController.cs +++ b/ds-wms-service/DS.WMS.FeeApi/Controllers/GeneralInvoiceController.cs @@ -137,13 +137,12 @@ namespace DS.WMS.FeeApi.Controllers /// 发票ID /// [HttpPost, Route("SetLock")] - public async Task SetLockAsync([FromBody] IdModel model) + public async Task SetLockAsync([FromBody] IdModel model) { if (!ModelState.IsValid) return DataResult.Failed(ModelState.GetErrorMessage(), MultiLanguageConst.IllegalRequest); - bool isLocked = Convert.ToBoolean(model.Value); - return await _service.SetLockAsync(isLocked, model.Ids); + return await _service.SetLockAsync(model.Value, model.Ids); } /// @@ -187,6 +186,18 @@ namespace DS.WMS.FeeApi.Controllers return await issuanceService.ReverseAsync(request); } + /// + /// 发送开票邮件 + /// + /// + /// 发票ID + /// + [HttpPost, Route("SendMail")] + public async Task SendMailAsync([FromServices] IInvoiceIssuanceService issuanceService, long id) + { + return await issuanceService.SendMailAsync(id); + } + /// /// 添加租户信息 ///