fix: if sats and fiat checkout conversion currency

This commit is contained in:
Arc 2026-05-07 14:34:22 +01:00
commit 32c230957e
7 changed files with 59 additions and 16 deletions

View file

@ -185,3 +185,13 @@ async def m007_add_allow_fiat(db):
ALTER TABLE events.events ALTER TABLE events.events
ADD COLUMN allow_fiat BOOLEAN NOT NULL DEFAULT FALSE; ADD COLUMN allow_fiat BOOLEAN NOT NULL DEFAULT FALSE;
""") """)
async def m008_add_fiat_currency(db):
"""
Add a fiat_currency column for sat-denominated events using fiat checkout.
"""
await db.execute("""
ALTER TABLE events.events
ADD COLUMN fiat_currency TEXT NOT NULL DEFAULT 'GBP';
""")

View file

@ -37,6 +37,7 @@ class CreateEvent(BaseModel):
event_end_date: str event_end_date: str
currency: str = "sat" currency: str = "sat"
allow_fiat: bool = False allow_fiat: bool = False
fiat_currency: str = "GBP"
amount_tickets: int = Query(..., ge=0) amount_tickets: int = Query(..., ge=0)
price_per_ticket: float = Query(..., ge=0) price_per_ticket: float = Query(..., ge=0)
banner: str | None = None banner: str | None = None
@ -54,6 +55,7 @@ class Event(BaseModel):
event_end_date: str event_end_date: str
currency: str currency: str
allow_fiat: bool = False allow_fiat: bool = False
fiat_currency: str = "GBP"
amount_tickets: int amount_tickets: int
price_per_ticket: float price_per_ticket: float
time: datetime time: datetime
@ -72,6 +74,7 @@ class PublicEvent(BaseModel):
event_end_date: str event_end_date: str
currency: str currency: str
allow_fiat: bool = False allow_fiat: bool = False
fiat_currency: str = "GBP"
price_per_ticket: float price_per_ticket: float
banner: str | None banner: str | None
extra: EventExtra = Field(default_factory=EventExtra) extra: EventExtra = Field(default_factory=EventExtra)

View file

@ -41,8 +41,16 @@ window.PageEventsDisplay = {
return LNbits.utils.convertMarkdown(this.event?.info || '') return LNbits.utils.convertMarkdown(this.event?.info || '')
}, },
allowFiatCheckout() { allowFiatCheckout() {
const currency = (this.event?.currency || '').toLowerCase() return Boolean(this.event?.allow_fiat)
return this.event?.allow_fiat && !['sat', 'sats'].includes(currency) },
fiatCheckoutLabel() {
if (!this.allowFiatCheckout) return 'Fiat'
const unit = ['sat', 'sats'].includes(
(this.event?.currency || '').toLowerCase()
)
? this.event?.fiat_currency
: this.event?.currency
return `Fiat (${(unit || 'GBP').toUpperCase()})`
}, },
allowEmailNotifications() { allowEmailNotifications() {
return Boolean(this.event?.extra?.email_notifications) return Boolean(this.event?.extra?.email_notifications)

View file

@ -72,7 +72,7 @@
:options="[ :options="[
{label: 'Lightning', value: 'lightning'}, {label: 'Lightning', value: 'lightning'},
{ {
label: `Fiat (${event.currency.toUpperCase()})`, label: fiatCheckoutLabel,
value: 'fiat' value: 'fiat'
} }
]" ]"

View file

@ -99,6 +99,7 @@ window.PageEvents = {
data: { data: {
currency: 'sats', currency: 'sats',
allow_fiat: false, allow_fiat: false,
fiat_currency: 'GBP',
extra: { extra: {
promo_codes: [] promo_codes: []
} }
@ -171,7 +172,9 @@ window.PageEvents = {
})) }))
} }
if (!this.isFiatCurrency(data.currency)) { if (!this.isFiatCurrency(data.currency)) {
data.allow_fiat = false if (!data.allow_fiat) {
data.fiat_currency = 'GBP'
}
} }
if (data.id) { if (data.id) {
@ -188,6 +191,7 @@ window.PageEvents = {
this.formDialog.data = { this.formDialog.data = {
currency: 'sats', currency: 'sats',
allow_fiat: false, allow_fiat: false,
fiat_currency: 'GBP',
extra: { extra: {
conditional: false, conditional: false,
min_tickets: 1, min_tickets: 1,
@ -204,6 +208,7 @@ window.PageEvents = {
this.formDialog.data = { this.formDialog.data = {
currency: 'sats', currency: 'sats',
allow_fiat: false, allow_fiat: false,
fiat_currency: 'GBP',
extra: { extra: {
email_notifications: false, email_notifications: false,
nostr_notifications: false, nostr_notifications: false,

View file

@ -373,16 +373,27 @@
</div> </div>
<q-toggle <q-toggle
v-model="formDialog.data.allow_fiat" v-model="formDialog.data.allow_fiat"
:disable="
formDialog.data.currency == null ||
['sat', 'sats'].includes(
(formDialog.data.currency || '').toLowerCase()
)
"
label="Allow fiat checkout" label="Allow fiat checkout"
left-label left-label
hint="Lets attendees pay through a configured fiat provider using the event currency." hint="Lets attendees pay through a configured fiat provider using the event currency."
></q-toggle> ></q-toggle>
<q-select
v-if="
formDialog.data.allow_fiat &&
['sat', 'sats'].includes(
(formDialog.data.currency || '').toLowerCase()
)
"
filled
dense
v-model="formDialog.data.fiat_currency"
label="Fiat checkout currency"
:options="
currencies.filter(
c => !['sat', 'sats'].includes((c || '').toLowerCase())
)
"
></q-select>
<q-expansion-item <q-expansion-item
group="advanced" group="advanced"
icon="settings" icon="settings"

View file

@ -25,6 +25,7 @@ from lnbits.settings import settings
from lnbits.utils.exchange_rates import ( from lnbits.utils.exchange_rates import (
fiat_amount_as_satoshis, fiat_amount_as_satoshis,
get_fiat_rate_satoshis, get_fiat_rate_satoshis,
satoshis_amount_as_fiat,
) )
from lnbits.utils.nostr import normalize_public_key from lnbits.utils.nostr import normalize_public_key
@ -266,13 +267,18 @@ async def api_ticket_create(
price = await fiat_amount_as_satoshis(price, event.currency) price = await fiat_amount_as_satoshis(price, event.currency)
invoice_unit = event.currency invoice_unit = event.currency
fiat_amount = price
fiat_provider = None fiat_provider = None
if payment_method == "fiat": if payment_method == "fiat":
if not _is_fiat_currency(event.currency): if _is_fiat_currency(event.currency):
raise HTTPException( invoice_unit = event.currency
status_code=HTTPStatus.BAD_REQUEST, else:
detail="Fiat checkout requires a fiat-denominated ticket price.", invoice_unit = event.fiat_currency
) fiat_amount = await satoshis_amount_as_fiat(price, invoice_unit)
extra["fiat"] = True
extra["currency"] = invoice_unit
extra["fiatAmount"] = fiat_amount
extra["rate"] = await get_fiat_rate_satoshis(invoice_unit)
wallet = await get_wallet(event.wallet) wallet = await get_wallet(event.wallet)
if not wallet: if not wallet:
raise HTTPException( raise HTTPException(
@ -293,7 +299,7 @@ async def api_ticket_create(
wallet_id=event.wallet, wallet_id=event.wallet,
invoice_data=CreateInvoice( invoice_data=CreateInvoice(
out=False, out=False,
amount=price, amount=fiat_amount if payment_method == "fiat" else price,
unit=invoice_unit, unit=invoice_unit,
fiat_provider=fiat_provider, fiat_provider=fiat_provider,
memo=f"{event_id}", memo=f"{event_id}",