fix(services): convert fiat menu prices to sat via exchange rates
Before this fix `_to_msat(item.price)` blindly did `price * 1000`,
treating any menu price as sat-denominated regardless of the item's
`currency` field. Quote and bolt11 were internally consistent but
charged ~0.1% of the real price for fiat-priced menus.
Big Jay's seeded with GTQ:
2× Tacos (Maíz, +Brisket, +Chicken)
pre-fix: 170 GTQ → 170000 msat → 170 sat invoice (~$0.14)
post-fix: 170 GTQ → 26968000 msat → 26968 sat invoice (~$22)
services.py:
- Drop `_to_msat` in favor of a `_price_to_msat(amount, currency)`
helper. Sat-aliased currencies ("sat", "sats", "satoshi",
"msat", …) take the flat ×1000 path; everything else round-
trips through lnbits.utils.exchange_rates.fiat_amount_as_satoshis
(same pool the events extension uses).
- Update _price_line_item: item.price AND each modifier.price_delta
are converted using item.currency. Modifier deltas inherit the
parent item's currency since we don't carry a per-modifier
currency field.
- Update quote_balance_required: same conversion via the item's
currency.
Verified live against the seeded "Big Jay's Bustaurant":
GTQ → sat conversion matches LNbits's bitcoin-price aggregate
(Binance / Blockchain / Bitfinex / Bitstamp / Coinbase / yadio).
Quote returns 26968 sats for 170 GTQ — within ~2% of expected
rate from external sources.
This commit is contained in:
parent
6dae57f3f4
commit
638f36e945
2 changed files with 51 additions and 12 deletions
|
|
@ -37,14 +37,22 @@ States and their meaning:
|
|||
2. Re-prices every line item against the live menu (modifier ids
|
||||
are matched server-side; the customer's claimed `price_delta`
|
||||
values are ignored).
|
||||
3. Sums `subtotal_msat`, applies `tax_rate`, adds `tip_msat` →
|
||||
3. Converts each item's `price` from its declared `currency` to
|
||||
msat. For sat-denominated items (`currency` ∈ `{sat, sats,
|
||||
satoshi}`) this is a flat `× 1000`. For fiat (`USD`, `GTQ`, …)
|
||||
it calls `lnbits.utils.exchange_rates.fiat_amount_as_satoshis`
|
||||
to look up the live rate, then `× 1000`. The conversion lives
|
||||
in `services._price_to_msat` so the rate lookup is the same path
|
||||
the quote endpoint uses — a customer's preview and the recorded
|
||||
`order.total_msat` cannot drift apart between request and place.
|
||||
4. Sums `subtotal_msat`, applies `tax_rate`, adds `tip_msat` →
|
||||
`total_msat`.
|
||||
4. For Lightning / internal: calls
|
||||
5. For Lightning / internal: calls
|
||||
`lnbits.core.services.create_invoice` with
|
||||
`extra={"tag": "restaurant", "restaurant_id": ...}`.
|
||||
5. Persists the order with `id = payment_hash` so the listener can
|
||||
6. Persists the order with `id = payment_hash` so the listener can
|
||||
look it up cheaply, plus one `order_items` row per line.
|
||||
6. For cash: `payment_method = "cash"` skips invoice creation and
|
||||
7. For cash: `payment_method = "cash"` skips invoice creation and
|
||||
marks the order `accepted` directly.
|
||||
|
||||
Returns `(Order, OrderInvoice | None)`. The webapp pays the bolt11.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue