order confirmation
All checks were successful
Deploy / build-deploy (push) Successful in 6m14s

This commit is contained in:
Jorijn van der Graaf 2026-08-09 00:14:09 +02:00
commit 2fa6e70af1
10 changed files with 619 additions and 20 deletions

View file

@ -8,10 +8,12 @@ No permission is granted to copy, modify, distribute, or create derivative works
// Order storage: an append-only JSON-lines event log.
//
// Two event types share the file:
// Four event types share the file:
//
// {"type":"order", ...full record...} written once, at checkout
// {"type":"status", "id":..,"status":..} one per transition
// {"type":"order", ...full record...} written once, at checkout
// {"type":"status", "id":..,"status":..} one per transition
// {"type":"invoice", "id":..,"number":..} the number assignment, at paid
// {"type":"notified","id":..,"what":..} the confirmation email left
//
// Current state is a left fold over the file; later events win. Nothing is
// ever rewritten, so the log doubles as the audit trail the tax records need,
@ -126,6 +128,14 @@ std::vector<OrderRecord> FoldLocked() {
if (!r) continue;
r->invoiceNumber = std::string(doc->Str("number"));
r->invoicedAt = std::string(doc->Str("at"));
} else if (type == "notified") {
OrderRecord* r = find(doc->Str("id"));
if (!r) continue;
// "what" names the message so a future shipped-notice can share
// the event type without re-marking the confirmation as sent.
if (doc->Str("what") == "confirmation") {
r->confirmationSentAt = std::string(doc->Str("at"));
}
} else if (type == "status") {
OrderRecord* r = find(doc->Str("id"));
if (!r) continue; // status for an unknown order: skip, keep folding
@ -257,6 +267,13 @@ std::optional<std::string> AssignInvoiceNumber(std::string_view token,
return number;
}
bool AppendOrderNotified(std::string_view token, std::string_view isoTimestamp) {
std::lock_guard lock(gOrdersMutex);
return AppendLine(std::format(
R"({{"type":"notified","at":"{}","id":"{}","what":"confirmation"}})",
JsonEscape(isoTimestamp), JsonEscape(token)));
}
std::optional<OrderRecord> FindOrder(std::string_view token) {
std::lock_guard lock(gOrdersMutex);
for (OrderRecord& r : FoldLocked()) {