This commit is contained in:
parent
70668af8f5
commit
e68d2c245c
17 changed files with 1801 additions and 15 deletions
|
|
@ -154,6 +154,13 @@ std::vector<OrderRecord> FoldLocked() {
|
|||
if (const std::string_view via = doc->Str("via"); !via.empty()) {
|
||||
r->paidVia = std::string(via);
|
||||
}
|
||||
// The FIRST paid event is the sale, whatever happens later — a
|
||||
// refund folds the status onward but never unhappens the payment
|
||||
// (see SummarizeSales). First, not last, so a replayed line
|
||||
// cannot move the recorded moment.
|
||||
if (status == "paid" && r->paidAt.empty()) {
|
||||
r->paidAt = std::string(doc->Str("at"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
|
@ -296,6 +303,20 @@ std::vector<OrderRecord> ListOrders() {
|
|||
return FoldLocked();
|
||||
}
|
||||
|
||||
SalesSummary SummarizeSales(std::span<const OrderRecord> orders) {
|
||||
SalesSummary out;
|
||||
for (const OrderRecord& r : orders) {
|
||||
// paidAt is the signal. The status check keeps faith with a ledger
|
||||
// whose order was marked shipped by hand without a paid event ever
|
||||
// being written — the same paid-or-shipped idiom the invoice
|
||||
// download uses.
|
||||
if (r.paidAt.empty() && r.status != "paid" && r.status != "shipped") continue;
|
||||
++out.count;
|
||||
out.totalMinor += r.totalMinor;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string NewOrderToken() {
|
||||
// std::random_device on this platform reads the kernel CSPRNG. The token
|
||||
// gates access to a name and address, so 128 bits — the same order of
|
||||
|
|
|
|||
Loading…
Reference in a new issue