Pārlūkot izejas kodu

加上測試用的flag,如果有PaymentNotify要模擬英特拉打通知繳費成功

master
Joanne.Chuang pirms 2 nedēļām
vecāks
revīzija
3b1c0f8e7e
10 mainītis faili ar 121 papildinājumiem un 53 dzēšanām
  1. +0
    -6
      Altob.NtuInvoiceGateway/Models/DonateGroupApiOptions.cs
  2. +8
    -0
      Altob.NtuInvoiceGateway/Models/EndpointApiOptions.cs
  3. +0
    -6
      Altob.NtuInvoiceGateway/Models/InvoiceApiOptions.cs
  4. +86
    -26
      Altob.NtuInvoiceGateway/Pages/Invoice.cshtml.cs
  5. +2
    -4
      Altob.NtuInvoiceGateway/Program.cs
  6. +5
    -1
      Altob.NtuInvoiceGateway/Properties/PublishProfiles/Production.pubxml
  7. +5
    -1
      Altob.NtuInvoiceGateway/Properties/PublishProfiles/Staging.pubxml
  8. +5
    -2
      Altob.NtuInvoiceGateway/appsettings.Production.json
  9. +5
    -2
      Altob.NtuInvoiceGateway/appsettings.Staging.json
  10. +5
    -5
      Altob.NtuInvoiceGateway/appsettings.json

+ 0
- 6
Altob.NtuInvoiceGateway/Models/DonateGroupApiOptions.cs Parādīt failu

@@ -1,6 +0,0 @@
namespace Altob.NtuInvoiceGateway.Models;

public class DonateCodeApiOptions
{
public string Endpoint { get; set; } = string.Empty;
}

+ 8
- 0
Altob.NtuInvoiceGateway/Models/EndpointApiOptions.cs Parādīt failu

@@ -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;
}

+ 0
- 6
Altob.NtuInvoiceGateway/Models/InvoiceApiOptions.cs Parādīt failu

@@ -1,6 +0,0 @@
namespace Altob.NtuInvoiceGateway.Models;

public class InvoiceApiOptions
{
public string Endpoint { get; set; } = string.Empty;
}

+ 86
- 26
Altob.NtuInvoiceGateway/Pages/Invoice.cshtml.cs Parādīt failu

@@ -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> companyInfo,
IOptions<InvoiceApiOptions> invoiceApiOptions,
IOptions<DonateCodeApiOptions> donateCodeApiOptions)
IOptions<EndpointApiOptions> endpointApiOptions,
IConfiguration configuration)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
_memoryCache = memoryCache;
_companyInfo = companyInfo.Value;
_invoiceApiOptions = invoiceApiOptions.Value;
_donateCodeApiOptions = donateCodeApiOptions.Value;
_endpointApiOptions = endpointApiOptions.Value;
_debugMode = configuration.GetValue<bool>("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<DonateGroup>()) { 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<IActionResult> 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()


+ 2
- 4
Altob.NtuInvoiceGateway/Program.cs Parādīt failu

@@ -20,10 +20,8 @@ builder.Services.AddMemoryCache();
// Configure company info
builder.Services.Configure<Altob.NtuInvoiceGateway.Models.CompanyInfo>(
builder.Configuration.GetSection("CompanyInfo"));
builder.Services.Configure<Altob.NtuInvoiceGateway.Models.InvoiceApiOptions>(
builder.Configuration.GetSection("InvoiceApi"));
builder.Services.Configure<Altob.NtuInvoiceGateway.Models.DonateCodeApiOptions>(
builder.Configuration.GetSection("DonateCodeApi"));
builder.Services.Configure<Altob.NtuInvoiceGateway.Models.EndpointApiOptions>(
builder.Configuration.GetSection("Endpoint"));
builder.Services.Configure<IpWhitelistOptions>(
builder.Configuration.GetSection("IpWhitelist"));



+ 5
- 1
Altob.NtuInvoiceGateway/Properties/PublishProfiles/Production.pubxml Parādīt failu

@@ -8,9 +8,13 @@
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>D:\Output\Altob.NtuInvoiceGateway</PublishUrl>
<PublishUrl>D:\Output\NtuInvoiceGateway</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<EnvironmentName>Production</EnvironmentName>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net9.0</TargetFramework>
<ProjectGuid>056e4823-4b80-4779-8c69-fb1c0a19f585</ProjectGuid>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

+ 5
- 1
Altob.NtuInvoiceGateway/Properties/PublishProfiles/Staging.pubxml Parādīt failu

@@ -8,9 +8,13 @@
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>D:\Output\Altob.NtuInvoiceGateway</PublishUrl>
<PublishUrl>D:\Output\NtuInvoiceGateway</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<EnvironmentName>Staging</EnvironmentName>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net9.0</TargetFramework>
<ProjectGuid>056e4823-4b80-4779-8c69-fb1c0a19f585</ProjectGuid>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

+ 5
- 2
Altob.NtuInvoiceGateway/appsettings.Production.json Parādīt failu

@@ -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"
}
}

+ 5
- 2
Altob.NtuInvoiceGateway/appsettings.Staging.json Parādīt failu

@@ -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"
}
}

+ 5
- 5
Altob.NtuInvoiceGateway/appsettings.json Parādīt failu

@@ -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"
}
}

Notiek ielāde…
Atcelt
Saglabāt