|
|
@@ -1,6 +1,7 @@ |
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
using Microsoft.AspNetCore.Mvc; |
|
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
|
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
|
|
using Microsoft.Extensions.Options; |
|
|
using Microsoft.Extensions.Options; |
|
|
|
|
|
using Microsoft.Extensions.Caching.Memory; |
|
|
using Altob.NtuInvoiceGateway.Models; |
|
|
using Altob.NtuInvoiceGateway.Models; |
|
|
using System.Text; |
|
|
using System.Text; |
|
|
using System.Text.Json; |
|
|
using System.Text.Json; |
|
|
@@ -13,20 +14,27 @@ public class InvoiceModel : PageModel |
|
|
{ |
|
|
{ |
|
|
private readonly ILogger<InvoiceModel> _logger; |
|
|
private readonly ILogger<InvoiceModel> _logger; |
|
|
private readonly IHttpClientFactory _httpClientFactory; |
|
|
private readonly IHttpClientFactory _httpClientFactory; |
|
|
|
|
|
private readonly IMemoryCache _memoryCache; |
|
|
private readonly CompanyInfo _companyInfo; |
|
|
private readonly CompanyInfo _companyInfo; |
|
|
private readonly InvoiceApiOptions _invoiceApiOptions; |
|
|
private readonly InvoiceApiOptions _invoiceApiOptions; |
|
|
|
|
|
private readonly DonateCodeApiOptions _donateCodeApiOptions; |
|
|
private const string ServiceName = "NtuInvoiceGateway"; |
|
|
private const string ServiceName = "NtuInvoiceGateway"; |
|
|
|
|
|
private const string DonateCodeCacheKey = "DonateCodeList"; |
|
|
|
|
|
|
|
|
public InvoiceModel( |
|
|
public InvoiceModel( |
|
|
ILogger<InvoiceModel> logger, |
|
|
ILogger<InvoiceModel> logger, |
|
|
IHttpClientFactory httpClientFactory, |
|
|
IHttpClientFactory httpClientFactory, |
|
|
|
|
|
IMemoryCache memoryCache, |
|
|
IOptions<CompanyInfo> companyInfo, |
|
|
IOptions<CompanyInfo> companyInfo, |
|
|
IOptions<InvoiceApiOptions> invoiceApiOptions) |
|
|
|
|
|
|
|
|
IOptions<InvoiceApiOptions> invoiceApiOptions, |
|
|
|
|
|
IOptions<DonateCodeApiOptions> donateCodeApiOptions) |
|
|
{ |
|
|
{ |
|
|
_logger = logger; |
|
|
_logger = logger; |
|
|
_httpClientFactory = httpClientFactory; |
|
|
_httpClientFactory = httpClientFactory; |
|
|
|
|
|
_memoryCache = memoryCache; |
|
|
_companyInfo = companyInfo.Value; |
|
|
_companyInfo = companyInfo.Value; |
|
|
_invoiceApiOptions = invoiceApiOptions.Value; |
|
|
_invoiceApiOptions = invoiceApiOptions.Value; |
|
|
|
|
|
_donateCodeApiOptions = donateCodeApiOptions.Value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
[BindProperty] |
|
|
[BindProperty] |
|
|
@@ -48,6 +56,74 @@ public class InvoiceModel : PageModel |
|
|
// GET 方法保留為空,主要接收方式改為 POST JSON |
|
|
// GET 方法保留為空,主要接收方式改為 POST JSON |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public async Task<IActionResult> OnGetDonateCodesAsync() |
|
|
|
|
|
{ |
|
|
|
|
|
var actionName = nameof(OnGetDonateCodesAsync); |
|
|
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
|
{ |
|
|
|
|
|
// 檢查 Cache 是否有資料 |
|
|
|
|
|
if (_memoryCache.TryGetValue(DonateCodeCacheKey, out List<DonateGroup>? cachedData) && cachedData != null) |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogInformation("{ServiceName} - {ActionName} returning cached donate codes, count: {Count}", |
|
|
|
|
|
ServiceName, actionName, cachedData.Count); |
|
|
|
|
|
return new JsonResult(cachedData); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Cache 中沒有資料,從 API 取得 |
|
|
|
|
|
if (string.IsNullOrWhiteSpace(_donateCodeApiOptions.Endpoint)) |
|
|
|
|
|
{ |
|
|
|
|
|
_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); |
|
|
|
|
|
|
|
|
|
|
|
var httpClient = _httpClientFactory.CreateClient(); |
|
|
|
|
|
var response = await httpClient.GetAsync(_donateCodeApiOptions.Endpoint); |
|
|
|
|
|
|
|
|
|
|
|
if (!response.IsSuccessStatusCode) |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogError("{ServiceName} - {ActionName} failed to fetch donate codes, status: {StatusCode}", |
|
|
|
|
|
ServiceName, actionName, response.StatusCode); |
|
|
|
|
|
return new JsonResult(new List<DonateGroup>()) { StatusCode = (int)response.StatusCode }; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var responseContent = await response.Content.ReadAsStringAsync(); |
|
|
|
|
|
var donateCodes = JsonSerializer.Deserialize<List<DonateGroup>>(responseContent, new JsonSerializerOptions |
|
|
|
|
|
{ |
|
|
|
|
|
PropertyNameCaseInsensitive = true |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (donateCodes != null && donateCodes.Count > 0) |
|
|
|
|
|
{ |
|
|
|
|
|
// 按照 Seq 欄位排序 |
|
|
|
|
|
var sortedDonateCodes = donateCodes.OrderBy(d => d.Seq).ToList(); |
|
|
|
|
|
|
|
|
|
|
|
// 將資料存入 Cache,有效期限 7 天 |
|
|
|
|
|
var cacheOptions = new MemoryCacheEntryOptions |
|
|
|
|
|
{ |
|
|
|
|
|
AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(7) |
|
|
|
|
|
}; |
|
|
|
|
|
_memoryCache.Set(DonateCodeCacheKey, sortedDonateCodes, cacheOptions); |
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation("{ServiceName} - {ActionName} cached {Count} donate codes for 7 days", |
|
|
|
|
|
ServiceName, actionName, sortedDonateCodes.Count); |
|
|
|
|
|
|
|
|
|
|
|
return new JsonResult(sortedDonateCodes); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_logger.LogWarning("{ServiceName} - {ActionName} received empty donate code list from API", ServiceName, actionName); |
|
|
|
|
|
return new JsonResult(new List<DonateGroup>()); |
|
|
|
|
|
} |
|
|
|
|
|
catch (Exception ex) |
|
|
|
|
|
{ |
|
|
|
|
|
_logger.LogError(ex, "{ServiceName} - {ActionName} error fetching donate codes", ServiceName, actionName); |
|
|
|
|
|
return new JsonResult(new List<DonateGroup>()) { StatusCode = 500 }; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
public async Task<IActionResult> OnPostAsync() |
|
|
public async Task<IActionResult> OnPostAsync() |
|
|
{ |
|
|
{ |
|
|
NormalizeInvoiceData(); |
|
|
NormalizeInvoiceData(); |
|
|
@@ -237,6 +313,11 @@ public class InvoiceModel : PageModel |
|
|
InvoiceData.CarPlateNum = InvoiceData.CarPlateNum ?? string.Empty; |
|
|
InvoiceData.CarPlateNum = InvoiceData.CarPlateNum ?? string.Empty; |
|
|
InvoiceData.OrderID = InvoiceData.OrderID ?? string.Empty; |
|
|
InvoiceData.OrderID = InvoiceData.OrderID ?? string.Empty; |
|
|
InvoiceData.TaxType = InvoiceData.TaxType ?? 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() |
|
|
private void RestoreDisplayValuesFromTempData() |
|
|
|