donation item, shop soft open
All checks were successful
Deploy / build-deploy (push) Successful in 4m11s
All checks were successful
Deploy / build-deploy (push) Successful in 4m11s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b0666841f6
commit
abbd616b40
23 changed files with 2898 additions and 209 deletions
|
|
@ -120,6 +120,9 @@ std::vector<OrderRecord> FoldLocked() {
|
|||
r.shippingMinor = doc->Int("shipping_minor");
|
||||
r.totalMinor = doc->Int("total_minor");
|
||||
r.vatIncluded = doc->Bool("vat_included");
|
||||
// Additive key: absent (every pre-donations line) reads false,
|
||||
// so an old ledger's orders all stay sales.
|
||||
r.donation = doc->Bool("donation");
|
||||
r.status = std::string(doc->Str("status", "awaiting_payment"));
|
||||
// Read as written, with no default applied here: the ledger
|
||||
// should keep saying exactly what it recorded, and resolving an
|
||||
|
|
@ -175,11 +178,14 @@ void SetOrdersPath(const std::filesystem::path& p) {
|
|||
|
||||
bool CreateOrder(const OrderRecord& o) {
|
||||
std::lock_guard lock(gOrdersMutex);
|
||||
// "donation" is written only when true, matching the status writer's
|
||||
// omit-rather-than-empty rule: absent-means-false is what lets a ledger
|
||||
// from before donations existed keep reading correctly.
|
||||
return AppendLine(std::format(
|
||||
R"({{"type":"order","at":"{}","id":"{}","ref":"{}","product":"{}",)"
|
||||
R"("color":"{}","quantity":{},"unit_minor":{},)"
|
||||
R"("email":"{}","name":"{}","street":"{}","postal":"{}","city":"{}","country":"{}",)"
|
||||
R"("goods_minor":{},"shipping_minor":{},"total_minor":{},"vat_included":{},)"
|
||||
R"("goods_minor":{},"shipping_minor":{},"total_minor":{},"vat_included":{},{})"
|
||||
R"("status":"{}","pay_choice":"{}","pay_url":"{}","pay_id":"{}"}})",
|
||||
JsonEscape(o.createdAt), JsonEscape(o.token), JsonEscape(o.reference),
|
||||
JsonEscape(o.product),
|
||||
|
|
@ -187,6 +193,7 @@ bool CreateOrder(const OrderRecord& o) {
|
|||
JsonEscape(o.buyer.email), JsonEscape(o.buyer.name), JsonEscape(o.buyer.street),
|
||||
JsonEscape(o.buyer.postal), JsonEscape(o.buyer.city), JsonEscape(o.buyer.country),
|
||||
o.goodsMinor, o.shippingMinor, o.totalMinor, o.vatIncluded,
|
||||
o.donation ? R"("donation":true,)" : "",
|
||||
JsonEscape(o.status), JsonEscape(o.payChoice),
|
||||
JsonEscape(o.payUrl), JsonEscape(o.payId)));
|
||||
}
|
||||
|
|
@ -311,6 +318,13 @@ SalesSummary SummarizeSales(std::span<const OrderRecord> orders) {
|
|||
// being written — the same paid-or-shipped idiom the invoice
|
||||
// download uses.
|
||||
if (r.paidAt.empty() && r.status != "paid" && r.status != "shipped") continue;
|
||||
// A paid donation is income but not a sale: /financials shows it in
|
||||
// the donations row, and counting it here too would double-book it.
|
||||
if (r.donation) {
|
||||
++out.donationCount;
|
||||
out.donationsMinor += r.totalMinor;
|
||||
continue;
|
||||
}
|
||||
++out.count;
|
||||
out.totalMinor += r.totalMinor;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue