From 3b1c0f8e7edeeeb0161b0baa7b6e6b4ce9ac9068 Mon Sep 17 00:00:00 2001 From: "Joanne.Chuang" Date: Thu, 15 Jan 2026 15:00:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E6=B8=AC=E8=A9=A6=E7=94=A8?= =?UTF-8?q?=E7=9A=84flag=EF=BC=8C=E5=A6=82=E6=9E=9C=E6=9C=89PaymentNotify?= =?UTF-8?q?=E8=A6=81=E6=A8=A1=E6=93=AC=E8=8B=B1=E7=89=B9=E6=8B=89=E6=89=93?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E7=B9=B3=E8=B2=BB=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/DonateGroupApiOptions.cs | 6 -- .../Models/EndpointApiOptions.cs | 8 ++ .../Models/InvoiceApiOptions.cs | 6 -- Altob.NtuInvoiceGateway/Pages/Invoice.cshtml.cs | 112 ++++++++++++++++----- Altob.NtuInvoiceGateway/Program.cs | 6 +- .../Properties/PublishProfiles/Production.pubxml | 6 +- .../Properties/PublishProfiles/Staging.pubxml | 6 +- .../appsettings.Production.json | 7 +- Altob.NtuInvoiceGateway/appsettings.Staging.json | 7 +- Altob.NtuInvoiceGateway/appsettings.json | 10 +- 10 files changed, 121 insertions(+), 53 deletions(-) delete mode 100644 Altob.NtuInvoiceGateway/Models/DonateGroupApiOptions.cs create mode 100644 Altob.NtuInvoiceGateway/Models/EndpointApiOptions.cs delete mode 100644 Altob.NtuInvoiceGateway/Models/InvoiceApiOptions.cs diff --git a/Altob.NtuInvoiceGateway/Models/DonateGroupApiOptions.cs b/Altob.NtuInvoiceGateway/Models/DonateGroupApiOptions.cs deleted file mode 100644 index 0cd9f4e..0000000 --- a/Altob.NtuInvoiceGateway/Models/DonateGroupApiOptions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Altob.NtuInvoiceGateway.Models; - -public class DonateCodeApiOptions -{ - public string Endpoint { get; set; } = string.Empty; -} diff --git a/Altob.NtuInvoiceGateway/Models/EndpointApiOptions.cs b/Altob.NtuInvoiceGateway/Models/EndpointApiOptions.cs new file mode 100644 index 0000000..edd7563 --- /dev/null +++ b/Altob.NtuInvoiceGateway/Models/EndpointApiOptions.cs @@ -0,0 +1,8 @@ +namespace Altob.NtuInvoiceGateway.Models; + +public class EndpointApiOptions +{ + public string InvoiceApi { get; set; } = string.Empty; + public string PaymentNotifyApi { get; set; } = string.Empty; + public string DonateCodeApi { get; set; } = string.Empty; +} diff --git a/Altob.NtuInvoiceGateway/Models/InvoiceApiOptions.cs b/Altob.NtuInvoiceGateway/Models/InvoiceApiOptions.cs deleted file mode 100644 index 0196b84..0000000 --- a/Altob.NtuInvoiceGateway/Models/InvoiceApiOptions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Altob.NtuInvoiceGateway.Models; - -public class InvoiceApiOptions -{ - public string Endpoint { get; set; } = string.Empty; -} diff --git a/Altob.NtuInvoiceGateway/Pages/Invoice.cshtml.cs b/Altob.NtuInvoiceGateway/Pages/Invoice.cshtml.cs index 7975d0c..7aee343 100644 --- a/Altob.NtuInvoiceGateway/Pages/Invoice.cshtml.cs +++ b/Altob.NtuInvoiceGateway/Pages/Invoice.cshtml.cs @@ -1,11 +1,13 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; using Microsoft.Extensions.Caching.Memory; using Altob.NtuInvoiceGateway.Models; using System.Text; using System.Text.Json; using System.Linq; +using System.Globalization; namespace Altob.NtuInvoiceGateway.Pages; @@ -16,8 +18,8 @@ public class InvoiceModel : PageModel private readonly IHttpClientFactory _httpClientFactory; private readonly IMemoryCache _memoryCache; private readonly CompanyInfo _companyInfo; - private readonly InvoiceApiOptions _invoiceApiOptions; - private readonly DonateCodeApiOptions _donateCodeApiOptions; + private readonly EndpointApiOptions _endpointApiOptions; + private readonly bool _debugMode; private const string ServiceName = "NtuInvoiceGateway"; private const string DonateCodeCacheKey = "DonateCodeList"; private const string InvoiceDataTempKey = "InvoiceFormData"; @@ -27,15 +29,15 @@ public class InvoiceModel : PageModel IHttpClientFactory httpClientFactory, IMemoryCache memoryCache, IOptions companyInfo, - IOptions invoiceApiOptions, - IOptions donateCodeApiOptions) + IOptions endpointApiOptions, + IConfiguration configuration) { _logger = logger; _httpClientFactory = httpClientFactory; _memoryCache = memoryCache; _companyInfo = companyInfo.Value; - _invoiceApiOptions = invoiceApiOptions.Value; - _donateCodeApiOptions = donateCodeApiOptions.Value; + _endpointApiOptions = endpointApiOptions.Value; + _debugMode = configuration.GetValue("DebugMode"); } [BindProperty(SupportsGet = true)] @@ -81,17 +83,17 @@ public class InvoiceModel : PageModel } // Cache 中沒有資料,從 API 取得 - if (string.IsNullOrWhiteSpace(_donateCodeApiOptions.Endpoint)) + if (string.IsNullOrWhiteSpace(_endpointApiOptions.DonateCodeApi)) { _logger.LogError("{ServiceName} - {ActionName} DonateCode API endpoint is not configured", ServiceName, actionName); return new JsonResult(new List()) { StatusCode = 500 }; } _logger.LogInformation("{ServiceName} - {ActionName} fetching donate codes from API: {Endpoint}", - ServiceName, actionName, _donateCodeApiOptions.Endpoint); + ServiceName, actionName, _endpointApiOptions.DonateCodeApi); var httpClient = _httpClientFactory.CreateClient(); - var response = await httpClient.GetAsync(_donateCodeApiOptions.Endpoint); + var response = await httpClient.GetAsync(_endpointApiOptions.DonateCodeApi); if (!response.IsSuccessStatusCode) { @@ -176,7 +178,7 @@ public class InvoiceModel : PageModel // 顯示表單讓用戶填寫 return Page(); } - + public async Task OnPostToEndPointAsync() { NormalizeInvoiceData(); @@ -235,7 +237,7 @@ public class InvoiceModel : PageModel return Page(); } - if (string.IsNullOrWhiteSpace(_invoiceApiOptions.Endpoint)) + if (string.IsNullOrWhiteSpace(_endpointApiOptions.InvoiceApi)) { ErrorMessage = "未設定外部發票 API 的位址"; _logger.LogError("{ServiceName} - {ActionName} Invoice API endpoint is not configured", ServiceName, actionName); @@ -261,6 +263,11 @@ public class InvoiceModel : PageModel // "loveCode": "" // } var httpClient = _httpClientFactory.CreateClient(); + + if (_debugMode) + { + await PostPaymentNotifyForDebugAsync(httpClient, actionName); + } var requestBody = JsonSerializer.Serialize(InvoiceData, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase @@ -270,7 +277,7 @@ public class InvoiceModel : PageModel var content = new StringContent(requestBody, Encoding.UTF8, "application/json"); - var response = await httpClient.PostAsync(_invoiceApiOptions.Endpoint, content); + var response = await httpClient.PostAsync(_endpointApiOptions.InvoiceApi, content); var responseContent = await response.Content.ReadAsStringAsync(); _logger.LogInformation("{ServiceName} - {ActionName} received API response status {StatusCode} body: {ResponseBody}", @@ -318,23 +325,76 @@ public class InvoiceModel : PageModel return Page(); } + private async Task PostPaymentNotifyForDebugAsync(HttpClient httpClient, string actionName) + { + if (string.IsNullOrWhiteSpace(_endpointApiOptions.PaymentNotifyApi)) + { + _logger.LogWarning("{ServiceName} - {ActionName} DebugMode enabled but PaymentNotify API endpoint is not configured", + ServiceName, actionName); + return; + } + + try + { + var licensePlate = string.IsNullOrWhiteSpace(InvoiceData.CarPlateNum) ? "9M1234" : InvoiceData.CarPlateNum; + var parkingArea = string.IsNullOrWhiteSpace(InvoiceData.LocationID) ? "1" : InvoiceData.LocationID; + var orderId = string.IsNullOrWhiteSpace(InvoiceData.OrderID) + ? $"Order{DateTime.UtcNow:yyyyMMddHHmmss}" + : InvoiceData.OrderID; + + var amount = 0m; + var rawAmount = InvoiceData.TransAmount?.Trim(); + if (!string.IsNullOrWhiteSpace(rawAmount)) + { + if (!decimal.TryParse(rawAmount, NumberStyles.Any, CultureInfo.InvariantCulture, out amount) && + !decimal.TryParse(rawAmount, NumberStyles.Any, CultureInfo.CurrentCulture, out amount)) + { + _logger.LogWarning("{ServiceName} - {ActionName} unable to parse TransAmount {TransAmount}, using 0 for debug PaymentNotify", + ServiceName, actionName, InvoiceData.TransAmount); + amount = 0m; + } + } + + var paymentNotifyPayload = new + { + licensePlate, + parkingArea, + orderId, + amount + }; + var payloadJson = JsonSerializer.Serialize(paymentNotifyPayload); + _logger.LogInformation("{ServiceName} - {ActionName} sending debug PaymentNotify payload: {Payload}", + ServiceName, actionName, payloadJson); + + using var content = new StringContent(payloadJson, Encoding.UTF8, "application/json"); + var response = await httpClient.PostAsync(_endpointApiOptions.PaymentNotifyApi, content); + var responseContent = await response.Content.ReadAsStringAsync(); + _logger.LogInformation("{ServiceName} - {ActionName} debug PaymentNotify response status {StatusCode} body: {ResponseBody}", + ServiceName, actionName, response.StatusCode, responseContent); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "{ServiceName} - {ActionName} failed to POST debug PaymentNotify but continuing", + ServiceName, actionName); + } + } + private void NormalizeInvoiceData() { InvoiceData ??= new InvoiceRequest(); - - InvoiceData.Identifier = InvoiceData.Identifier ?? string.Empty; - InvoiceData.TransDateTime = InvoiceData.TransDateTime ?? string.Empty; - InvoiceData.TransAmount = InvoiceData.TransAmount ?? string.Empty; - InvoiceData.DeviceID = InvoiceData.DeviceID ?? string.Empty; - InvoiceData.LocationID = InvoiceData.LocationID ?? string.Empty; - InvoiceData.CarPlateNum = InvoiceData.CarPlateNum ?? string.Empty; - InvoiceData.OrderID = InvoiceData.OrderID ?? string.Empty; - InvoiceData.TaxType = InvoiceData.TaxType ?? string.Empty; - - InvoiceData.Email = InvoiceData.Email ?? string.Empty; - InvoiceData.CarrierID = InvoiceData.CarrierID ?? string.Empty; - InvoiceData.BuyerIdentifier = InvoiceData.BuyerIdentifier ?? string.Empty; - InvoiceData.LoveCode = InvoiceData.LoveCode ?? string.Empty; + // InvoiceData.Identifier = InvoiceData.Identifier ?? string.Empty; + // InvoiceData.TransDateTime = InvoiceData.TransDateTime ?? string.Empty; + // InvoiceData.TransAmount = InvoiceData.TransAmount ?? string.Empty; + // InvoiceData.DeviceID = InvoiceData.DeviceID ?? string.Empty; + // InvoiceData.LocationID = InvoiceData.LocationID ?? string.Empty; + // InvoiceData.CarPlateNum = InvoiceData.CarPlateNum ?? string.Empty; + // InvoiceData.OrderID = InvoiceData.OrderID ?? string.Empty; + // InvoiceData.TaxType = InvoiceData.TaxType ?? string.Empty; + // + // InvoiceData.Email = InvoiceData.Email ?? string.Empty; + // InvoiceData.CarrierID = InvoiceData.CarrierID ?? string.Empty; + // InvoiceData.BuyerIdentifier = InvoiceData.BuyerIdentifier ?? string.Empty; + // InvoiceData.LoveCode = InvoiceData.LoveCode ?? string.Empty; } private void RestoreDisplayValuesFromTempData() diff --git a/Altob.NtuInvoiceGateway/Program.cs b/Altob.NtuInvoiceGateway/Program.cs index e9f034f..6e6ee13 100644 --- a/Altob.NtuInvoiceGateway/Program.cs +++ b/Altob.NtuInvoiceGateway/Program.cs @@ -20,10 +20,8 @@ builder.Services.AddMemoryCache(); // Configure company info builder.Services.Configure( builder.Configuration.GetSection("CompanyInfo")); -builder.Services.Configure( - builder.Configuration.GetSection("InvoiceApi")); -builder.Services.Configure( - builder.Configuration.GetSection("DonateCodeApi")); +builder.Services.Configure( + builder.Configuration.GetSection("Endpoint")); builder.Services.Configure( builder.Configuration.GetSection("IpWhitelist")); diff --git a/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Production.pubxml b/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Production.pubxml index 1cc62ec..5e77a7d 100644 --- a/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Production.pubxml +++ b/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Production.pubxml @@ -8,9 +8,13 @@ Release Any CPU FileSystem - D:\Output\Altob.NtuInvoiceGateway + D:\Output\NtuInvoiceGateway FileSystem <_TargetId>Folder Production + + net9.0 + 056e4823-4b80-4779-8c69-fb1c0a19f585 + false \ No newline at end of file diff --git a/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Staging.pubxml b/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Staging.pubxml index abdbe04..06b552e 100644 --- a/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Staging.pubxml +++ b/Altob.NtuInvoiceGateway/Properties/PublishProfiles/Staging.pubxml @@ -8,9 +8,13 @@ Release Any CPU FileSystem - D:\Output\Altob.NtuInvoiceGateway + D:\Output\NtuInvoiceGateway FileSystem <_TargetId>Folder Staging + + net9.0 + 056e4823-4b80-4779-8c69-fb1c0a19f585 + false \ No newline at end of file diff --git a/Altob.NtuInvoiceGateway/appsettings.Production.json b/Altob.NtuInvoiceGateway/appsettings.Production.json index 5366604..8686246 100644 --- a/Altob.NtuInvoiceGateway/appsettings.Production.json +++ b/Altob.NtuInvoiceGateway/appsettings.Production.json @@ -1,4 +1,5 @@ { + "DebugMode": false, "DetailedErrors": false, "Logging": { "LogLevel": { @@ -30,7 +31,9 @@ "Enabled": true, "AllowedIps": [ "127.0.0.1", "::1","61.219.172.82","61.222.237.97","125.227.77.79" ] }, - "InvoiceApi": { - "Endpoint": "http://140.112.143.162:8077/api/Intella/invoiceInfo" + "Endpoint": { + "InvoiceApi":"http://140.112.143.162:8077/api/Intella/invoiceInfo", + "PaymentNotifyApi": "", //當上方DebugMode=true時,會多打這個Api + "DonateCodeApi": "https://dataset.einvoice.nat.gov.tw/ods/portal/api/v1/DonateCodeList" } } diff --git a/Altob.NtuInvoiceGateway/appsettings.Staging.json b/Altob.NtuInvoiceGateway/appsettings.Staging.json index f9b6597..c10909c 100644 --- a/Altob.NtuInvoiceGateway/appsettings.Staging.json +++ b/Altob.NtuInvoiceGateway/appsettings.Staging.json @@ -1,4 +1,5 @@ { + "DebugMode": true, "DetailedErrors": false, "Logging": { "LogLevel": { @@ -30,7 +31,9 @@ "Enabled": true, "AllowedIps": [ "127.0.0.1", "::1","61.219.172.82","61.222.237.97","125.227.77.79" ] }, - "InvoiceApi": { - "Endpoint": "http://localhost:22055/api/Intella/invoiceInfo" + "Endpoint": { + "InvoiceApi": "http://localhost:22055/api/Intella/invoiceInfo", + "PaymentNotifyApi": "http://localhost:22055/api/Intella/paymentNotify", //當上方DebugMode=true時,會多打這個Api + "DonateCodeApi": "https://dataset.einvoice.nat.gov.tw/ods/portal/api/v1/DonateCodeList" } } diff --git a/Altob.NtuInvoiceGateway/appsettings.json b/Altob.NtuInvoiceGateway/appsettings.json index 894062f..78efec8 100644 --- a/Altob.NtuInvoiceGateway/appsettings.json +++ b/Altob.NtuInvoiceGateway/appsettings.json @@ -1,4 +1,5 @@ { + "DebugMode": true, "Logging": { "LogLevel": { "Default": "Debug", @@ -34,10 +35,9 @@ "Name": "國立臺灣大學臨時停車場", "TaxId": "18384226" }, - "InvoiceApi": { - "Endpoint": "http://192.168.110.72:22055/api/Intella/invoiceInfo" - }, - "DonateCodeApi": { - "Endpoint": "https://dataset.einvoice.nat.gov.tw/ods/portal/api/v1/DonateCodeList" + "Endpoint": { + "InvoiceApi": "http://192.168.110.72:22055/api/Intella/invoiceInfo", + "PaymentNotifyApi": "http://192.168.110.72:22055/api/Intella/paymentNotify", //當上方DebugMode=true時,會多打這個Api + "DonateCodeApi": "https://dataset.einvoice.nat.gov.tw/ods/portal/api/v1/DonateCodeList" } }