Apply taxes and set receipt properly for PoS Print View

This commit is contained in:
nicolas.dorier
2025-06-12 14:03:25 +09:00
parent 5959d22964
commit 9f04bd473a
9 changed files with 264 additions and 131 deletions

View File

@@ -34,6 +34,7 @@ using BTCPayServer.Services.Stores;
using LNURL;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Localization;
@@ -62,6 +63,8 @@ namespace BTCPayServer
private readonly InvoiceActivator _invoiceActivator;
private readonly PaymentMethodHandlerDictionary _handlers;
private readonly PayoutProcessorService _payoutProcessorService;
private readonly CurrencyNameTable _currencies;
private readonly DisplayFormatter _displayFormatter;
public IStringLocalizer StringLocalizer { get; }
public UILNURLController(InvoiceRepository invoiceRepository,
@@ -78,8 +81,11 @@ namespace BTCPayServer
BTCPayNetworkJsonSerializerSettings btcPayNetworkJsonSerializerSettings,
IPluginHookService pluginHookService,
IStringLocalizer stringLocalizer,
InvoiceActivator invoiceActivator)
InvoiceActivator invoiceActivator,
CurrencyNameTable currencies, DisplayFormatter displayFormatter)
{
_currencies = currencies;
_displayFormatter = displayFormatter;
_invoiceRepository = invoiceRepository;
_eventAggregator = eventAggregator;
_payoutHandlers = payoutHandlers;
@@ -112,7 +118,7 @@ namespace BTCPayServer
{
return NotFound();
}
var pmi = PayoutTypes.LN.GetPayoutMethodId(cryptoCode);
var paymentMethodId = PaymentTypes.LN.GetPaymentMethodId(cryptoCode);
var pp = await _pullPaymentHostedService.GetPullPayment(pullPaymentId, true);
@@ -264,31 +270,17 @@ namespace BTCPayServer
return network;
}
[HttpGet("pay/app/{appId}/{itemCode}")]
[HttpGet("pay/app/{appId}/{itemCode?}")]
public async Task<IActionResult> GetLNURLForApp(string cryptoCode, string appId, string itemCode = null)
{
var network = GetNetwork(cryptoCode);
if (network is null || !network.SupportLightning)
{
return NotFound();
}
var app = await _appService.GetApp(appId, null, true);
if (app is null)
{
return NotFound();
}
var store = app.StoreData;
var store = app?.StoreData;
if (store is null)
{
return NotFound();
}
if (string.IsNullOrEmpty(itemCode))
{
return NotFound();
}
if (network?.SupportLightning is not true ||
GetLNUrlPaymentMethodId(cryptoCode, store, out _) is null)
return NotFound(StringLocalizer["LNURL or LN is disabled"]);
AppItem[] items;
string currencyCode;
@@ -313,9 +305,6 @@ namespace BTCPayServer
AppItem item = null;
if (!string.IsNullOrEmpty(itemCode))
{
var pmi = GetLNUrlPaymentMethodId(cryptoCode, store, out _);
if (pmi is null)
return NotFound(StringLocalizer["LNURL or LN is disabled"]);
var escapedItemId = Extensions.UnescapeBackSlashUriString(itemCode);
item = items.FirstOrDefault(item1 =>
item1.Id.Equals(itemCode, StringComparison.InvariantCultureIgnoreCase) ||
@@ -329,9 +318,22 @@ namespace BTCPayServer
return NotFound();
}
var order = new PoSOrder(_currencies.GetNumberFormatInfo(currencyCode, true).CurrencyDecimalDigits);
var posAppData = new PosAppData();
posAppData.Cart = [];
if (item != null)
{
posAppData.Cart = new PosAppCartItem[] { new() { Id = item.Id, Count = 1, Price = item.Price ?? 0 } };
order.AddLine(new(item.Id ?? "", 1, item.Price ?? 0m, item.TaxRate ?? posS?.DefaultTaxRate ?? 0m));
}
var summary = order.Calculate();
var isTopup = item is null or { PriceType: AppItemPriceType.Topup } or { Price: null };
var receiptData = PosReceiptData.Create(isTopup, item is {} ? new[]{ item } : [], posAppData, order, summary, currencyCode, _displayFormatter);
var createInvoice = new CreateInvoiceRequest
{
Amount = item?.PriceType == AppItemPriceType.Topup ? null : item?.Price,
Amount = isTopup ? null : summary.PriceTaxIncludedWithTips,
Currency = currencyCode,
Checkout = new InvoiceDataBase.CheckoutOptions
{
@@ -342,17 +344,20 @@ namespace BTCPayServer
_ => null
}
},
Metadata = new InvoiceMetadata
{
ItemCode = item?.Id,
ItemDesc = item?.Title,
TaxIncluded = summary.Tax == 0m ? null : summary.Tax,
OrderId = AppService.GetRandomOrderId(),
OrderUrl = Request.GetDisplayUrl(),
PosData = JObject.FromObject(posAppData),
ReceiptData = receiptData
}.ToJObject(),
AdditionalSearchTerms = new[] { AppService.GetAppSearchTerm(app) }
};
var allowOverpay = item?.PriceType is not AppItemPriceType.Fixed;
var invoiceMetadata = new InvoiceMetadata { OrderId = AppService.GetRandomOrderId() };
if (item != null)
{
invoiceMetadata.ItemCode = item.Id;
invoiceMetadata.ItemDesc = item.Description;
}
createInvoice.Metadata = invoiceMetadata.ToJObject();
return await GetLNURLRequest(
cryptoCode,
@@ -406,7 +411,7 @@ namespace BTCPayServer
{
if (string.IsNullOrEmpty(username))
return NotFound("Unknown username");
LNURLPayRequest lnurlRequest;
// Check core and fall back to lookup Lightning Address via plugins
@@ -425,7 +430,7 @@ namespace BTCPayServer
var store = await _storeRepository.FindStore(lightningAddressSettings.StoreDataId);
if (store is null)
return NotFound("Unknown username");
var cryptoCode = "BTC";
if (GetLNUrlPaymentMethodId(cryptoCode, store, out var lnUrlMethod) is null)
return NotFound("LNURL not available for store");
@@ -503,8 +508,8 @@ namespace BTCPayServer
public async Task<IActionResult> GetLNUrlForStore(
string cryptoCode,
string storeId,
string currency = null,
string orderId = null,
string currency = null,
string orderId = null,
decimal? amount = null)
{
var store = await _storeRepository.FindStore(storeId);