/* catcrafts.net Copyright (C) 2026 Catcrafts The source code of this website is made available for viewing purposes only. No permission is granted to copy, modify, distribute, or create derivative works. */ // The invoice builder and the order confirmation email — the two documents a // paying customer actually receives, including the VAT treatment on each and // the header-injection guard on the address that goes into the envelope. import std; import Catcrafts.Shared; import Catcrafts.Server; using namespace Catcrafts; namespace { int failures = 0; void Check(bool ok, std::string_view what, std::string_view got = {}) { if (ok) return; ++failures; std::println(std::cerr, "FAIL: {}{}{}", what, got.empty() ? "" : " got: ", got); } } // namespace int main() { Server::OrderRecord o; o.token = "0123456789abcdef0123456789abcdef"; o.reference = "CC-TEST01"; o.invoiceNumber = "f57c6512-f012-4b91-adb3-077876480178-7"; o.invoicedAt = "2026-08-05T10:00:00Z"; o.createdAt = "2026-08-05T09:55:00Z"; o.paidVia = "ideal"; o.buyer = { "b@example.org", "Ada Lovelace", "Main St 1", "1234AB", "Delft", "NL" }; o.quantity = 2; o.unitMinor = 56330; o.goodsMinor = 112660; o.shippingMinor = 863; o.totalMinor = 113523; o.vatIncluded = true; const std::string eu = Server::BuildInvoiceMarkdown(o, "Fairphone 6", "Forest Green"); Check(eu.find("# Invoice f57c6512-f012-4b91-adb3-077876480178-7") != std::string::npos, "invoice: number heading"); Check(eu.find("* Customer number: f57c6512-f012-4b91-adb3-077876480178") != std::string::npos, "invoice: customer series shown separately"); Check(eu.find("* Invoice number: 7") != std::string::npos, "invoice: sequence within the series"); Check(eu.find("Chico Mendesring 256") != std::string::npos, "invoice: seller address"); Check(eu.find("3315NN Dordrecht") != std::string::npos, "invoice: seller city"); Check(eu.find("KVK 78437059") != std::string::npos, "invoice: KVK"); Check(eu.find("NL003329281B38") != std::string::npos, "invoice: VAT id"); Check(eu.find("CC-TEST01") != std::string::npos, "invoice: order reference"); Check(eu.find("Ada Lovelace") != std::string::npos, "invoice: buyer name"); Check(eu.find("Fairphone 6 — Forest Green") != std::string::npos, "invoice: item names the colour"); Check(eu.find("VAT 21% (NL)") != std::string::npos, "invoice: EU VAT line"); Check(eu.find("€1135.23") != std::string::npos, "invoice: EU total"); Check(eu.find("zero-rated") == std::string::npos, "invoice: EU is not an export"); o.vatIncluded = false; o.buyer.country = "GB"; o.goodsMinor = 93107; o.shippingMinor = 2395; o.totalMinor = 95502; const std::string ex = Server::BuildInvoiceMarkdown(o, "Fairphone 6", "Forest Green"); Check(ex.find("VAT 0%") != std::string::npos, "invoice: export VAT 0%"); Check(ex.find("art. 146") != std::string::npos, "invoice: export legal basis"); Check(ex.find("€955.02") != std::string::npos, "invoice: export total"); // ── the order confirmation email ────────────────────────────────── // Same order, EU shape again; the attachment stands in for the // clearsigned invoice — the builder must carry it verbatim. o.vatIncluded = true; o.buyer.country = "NL"; o.goodsMinor = 112660; o.shippingMinor = 863; o.totalMinor = 113523; const std::string mail = Server::BuildOrderConfirmationEmail( o, "Fairphone 6", "Forest Green", "Catcrafts ", "https://catcrafts.net/order/0123456789abcdef0123456789abcdef", "SIGNED-INVOICE-STAND-IN\n", "Fri, 08 Aug 2026 10:00:00 +0000"); Check(mail.find("From: Catcrafts \n") != std::string::npos, "email: From header"); Check(mail.find("To: b@example.org\n") != std::string::npos, "email: To header"); Check(mail.find("Subject: Catcrafts order CC-TEST01 confirmed\n") != std::string::npos, "email: subject carries the reference"); Check(mail.find("Date: Fri, 08 Aug 2026 10:00:00 +0000\n") != std::string::npos, "email: date header"); Check(mail.find("Message-ID: <0123456789abcdef0123456789abcdef@catcrafts.net>\n") != std::string::npos, "email: message id from the token"); Check(mail.find("MIME-Version: 1.0\n") != std::string::npos, "email: mime version"); Check(mail.find("multipart/mixed") != std::string::npos, "email: multipart"); Check(mail.find("Fairphone 6 — Forest Green × 2") != std::string::npos, "email: item names colour and quantity"); Check(mail.find("€1135.23") != std::string::npos, "email: total"); Check(mail.find("incl. 21% NL VAT") != std::string::npos, "email: EU VAT wording"); Check(mail.find("* Paid via: ideal\n") != std::string::npos, "email: payment method"); Check(mail.find("https://catcrafts.net/order/0123456789abcdef0123456789abcdef") != std::string::npos, "email: order page link"); Check(mail.find("filename=\"catcrafts-invoice-" "f57c6512-f012-4b91-adb3-077876480178-7.md\"") != std::string::npos, "email: attachment filename is the invoice number"); Check(mail.find("SIGNED-INVOICE-STAND-IN\n") != std::string::npos, "email: attachment body verbatim"); Check(mail.find("--=_cc_0123456789abcdef0123456789abcdef--\n") != std::string::npos, "email: multipart closes"); Check(mail.find("KVK 78437059") != std::string::npos, "email: footer identity"); // The export wording mirrors the invoice's VAT treatment. o.vatIncluded = false; o.buyer.country = "GB"; o.totalMinor = 95502; const std::string exMail = Server::BuildOrderConfirmationEmail( o, "Fairphone 6", "Forest Green", "Catcrafts ", "https://catcrafts.net/order/x", "S\n", "Fri, 08 Aug 2026 10:00:00 +0000"); Check(exMail.find("zero-rated export") != std::string::npos, "email: export VAT wording"); Check(exMail.find("€955.02") != std::string::npos, "email: export total"); // A single unit does not advertise a quantity. o.quantity = 1; const std::string one = Server::BuildOrderConfirmationEmail( o, "Fairphone 6", "Forest Green", "Catcrafts ", "https://catcrafts.net/order/x", "S\n", "Fri, 08 Aug 2026 10:00:00 +0000"); Check(one.find("Forest Green ×") == std::string::npos, "email: qty 1 stays silent"); // The last line of defence: an address that could smuggle a header // yields NO message at all, however it got into the record. o.buyer.email = "a@b.example\nBcc: leak@evil.example"; Check(Server::BuildOrderConfirmationEmail( o, "F", "", "x", "u", "S", "D").empty(), "email: header-injecting address yields no message"); if (failures != 0) { std::println(std::cerr, "{} check(s) failed", failures); return 1; } return 0; }