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:
parent
89addb1ed7
commit
cfa1053842
25 changed files with 4690 additions and 31 deletions
|
|
@ -226,6 +226,8 @@ class ShareableLot extends Equatable {
|
|||
this.category,
|
||||
this.harvestYear,
|
||||
this.isOrganic = false,
|
||||
this.priceAmount,
|
||||
this.priceCurrency,
|
||||
});
|
||||
|
||||
final String lotId;
|
||||
|
|
@ -246,9 +248,23 @@ class ShareableLot extends Equatable {
|
|||
/// filter the market for it.
|
||||
final bool isOrganic;
|
||||
|
||||
/// Asking price, only populated for [OfferStatus.sell] lots. Null amount on
|
||||
/// a sale means "price to be agreed" — the offer publishes without a price.
|
||||
final double? priceAmount;
|
||||
final String? priceCurrency;
|
||||
|
||||
@override
|
||||
List<Object?> get props =>
|
||||
[lotId, varietyId, summary, offerStatus, category, harvestYear, isOrganic];
|
||||
List<Object?> get props => [
|
||||
lotId,
|
||||
varietyId,
|
||||
summary,
|
||||
offerStatus,
|
||||
category,
|
||||
harvestYear,
|
||||
isOrganic,
|
||||
priceAmount,
|
||||
priceCurrency,
|
||||
];
|
||||
}
|
||||
|
||||
/// One germination test on a lot; [rate] is derived (0..1), null when it can't
|
||||
|
|
@ -322,6 +338,8 @@ class VarietyLot extends Equatable {
|
|||
this.abundance,
|
||||
this.preservationFormat,
|
||||
this.offerStatus = OfferStatus.private,
|
||||
this.priceAmount,
|
||||
this.priceCurrency,
|
||||
this.germinationTests = const [],
|
||||
this.conditionChecks = const [],
|
||||
});
|
||||
|
|
@ -354,6 +372,11 @@ class VarietyLot extends Equatable {
|
|||
/// the network is Block 2.
|
||||
final OfferStatus offerStatus;
|
||||
|
||||
/// Asking price, meaningful when [offerStatus] is `sell`. Null amount means
|
||||
/// "price to be agreed".
|
||||
final double? priceAmount;
|
||||
final String? priceCurrency;
|
||||
|
||||
final List<GerminationEntry> germinationTests;
|
||||
|
||||
/// Storage-condition checks, most-recent first (`conditionChecks.first` = last).
|
||||
|
|
@ -377,6 +400,8 @@ class VarietyLot extends Equatable {
|
|||
abundance,
|
||||
preservationFormat,
|
||||
offerStatus,
|
||||
priceAmount,
|
||||
priceCurrency,
|
||||
germinationTests,
|
||||
conditionChecks,
|
||||
];
|
||||
|
|
@ -1281,9 +1306,12 @@ class VarietyRepository {
|
|||
Abundance? abundance,
|
||||
PreservationFormat? preservationFormat,
|
||||
OfferStatus offerStatus = OfferStatus.private,
|
||||
double? priceAmount,
|
||||
String? priceCurrency,
|
||||
}) async {
|
||||
final (created, updated) = await _stamp();
|
||||
final id = idGen.newId();
|
||||
final forSale = offerStatus == OfferStatus.sell;
|
||||
await _db
|
||||
.into(_db.lots)
|
||||
.insert(
|
||||
|
|
@ -1306,6 +1334,8 @@ class VarietyRepository {
|
|||
abundance: Value(abundance),
|
||||
preservationFormat: Value(preservationFormat),
|
||||
offerStatus: Value(offerStatus),
|
||||
priceAmount: Value(forSale ? priceAmount : null),
|
||||
priceCurrency: Value(forSale ? priceCurrency : null),
|
||||
),
|
||||
);
|
||||
return id;
|
||||
|
|
@ -1326,8 +1356,13 @@ class VarietyRepository {
|
|||
Abundance? abundance,
|
||||
PreservationFormat? preservationFormat,
|
||||
OfferStatus offerStatus = OfferStatus.private,
|
||||
double? priceAmount,
|
||||
String? priceCurrency,
|
||||
}) async {
|
||||
final (_, updated) = await _stamp();
|
||||
// Price only makes sense on a lot offered for sale; clearing the sale
|
||||
// status clears the price with it.
|
||||
final forSale = offerStatus == OfferStatus.sell;
|
||||
await (_db.update(_db.lots)..where((l) => l.id.equals(lotId))).write(
|
||||
LotsCompanion(
|
||||
type: Value(type),
|
||||
|
|
@ -1343,6 +1378,8 @@ class VarietyRepository {
|
|||
abundance: Value(abundance),
|
||||
preservationFormat: Value(preservationFormat),
|
||||
offerStatus: Value(offerStatus),
|
||||
priceAmount: Value(forSale ? priceAmount : null),
|
||||
priceCurrency: Value(forSale ? priceCurrency : null),
|
||||
updatedAt: Value(updated),
|
||||
lastAuthor: Value(nodeId),
|
||||
),
|
||||
|
|
@ -1580,6 +1617,12 @@ class VarietyRepository {
|
|||
category: v.category,
|
||||
harvestYear: l.harvestYear,
|
||||
isOrganic: v.isOrganic,
|
||||
priceAmount: l.offerStatus == OfferStatus.sell
|
||||
? l.priceAmount
|
||||
: null,
|
||||
priceCurrency: l.offerStatus == OfferStatus.sell
|
||||
? l.priceCurrency
|
||||
: null,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
|
@ -2363,6 +2406,8 @@ class VarietyRepository {
|
|||
abundance: l.abundance,
|
||||
preservationFormat: l.preservationFormat,
|
||||
offerStatus: l.offerStatus,
|
||||
priceAmount: l.priceAmount,
|
||||
priceCurrency: l.priceCurrency,
|
||||
germinationTests: germinationTests,
|
||||
conditionChecks: conditionChecks,
|
||||
quantity: hasQuantity
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue