feat(offers): asking price on lots, published with sale offers (schema v11)

The data model always meant sale offers to carry an informational price
(data-model §2.8, sharing-model §4.4); with offer state collapsed onto
the Lot, the price lives there. Null amount on a sell lot = 'to be
agreed' — the NIP-99 event simply omits the price tag.

- schema v11: Lots.price_amount/price_currency, guarded migration,
  schema dump + generated schema_v11 for the round-trip test
- ShareableLot/VarietyLot carry the price (sell-only in shareableLots);
  addLot/updateLot persist it and clear it when the lot leaves sale
- OffersCubit.publishLots forwards it (outbox flush picks it up free)
- lot sheet: price + currency inputs revealed only on 'For sale', with
  the €/Ğ1/hours quick-picks extracted to a shared CurrencyQuickPicks
  widget (reused by the sale sheet)
- backup JSON round-trips the new columns
- i18n share.price/priceHint in en/es/pt/ast
This commit is contained in:
vjrj 2026-07-11 07:24:23 +02:00
parent 89addb1ed7
commit cfa1053842
25 changed files with 4690 additions and 31 deletions

View file

@ -109,6 +109,17 @@ class Lots extends Table with SyncColumns {
/// Distinct from [storageLocation]. Optional.
TextColumn get preservationFormat =>
textEnum<PreservationFormat>().nullable()();
/// Asking price when [offerStatus] is `sell` (data-model §2.8 puts price on
/// the Offer; with offer state collapsed onto the Lot, it lives here and is
/// published with the market offer). Informational only money changes
/// hands off-platform, never in-app. Null amount on a sell lot means
/// "price to be agreed" (the offer publishes without a price).
RealColumn get priceAmount => real().nullable()();
/// Free-text currency, like [Sales.currency]: "", "Ğ1", a local/time
/// currency. Never assumed (sharing-model §6).
TextColumn get priceCurrency => text().nullable()();
}
/// Optional germination history for a Lot; percent is derived in code.