@aglyn/plugins-commerce 1.0.0-beta.288 → 1.0.0-beta.290

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +2 -2
  2. package/package.json +13 -13
  3. package/src/lib/components/commerce-console-page.js +29 -2
  4. package/src/lib/components/commerce-console-page.js.map +1 -1
  5. package/src/lib/components/console/commerce-analytics-card.component.js +4 -2
  6. package/src/lib/components/console/commerce-analytics-card.component.js.map +1 -1
  7. package/src/lib/components/console/commerce-pdf-download.d.ts +30 -0
  8. package/src/lib/components/console/commerce-pdf-download.js +53 -0
  9. package/src/lib/components/console/commerce-pdf-download.js.map +1 -0
  10. package/src/lib/components/console/host-orders-card.component.js +5 -1
  11. package/src/lib/components/console/host-orders-card.component.js.map +1 -1
  12. package/src/lib/components/console/host-quotes-card.component.d.ts +34 -0
  13. package/src/lib/components/console/host-quotes-card.component.js +263 -0
  14. package/src/lib/components/console/host-quotes-card.component.js.map +1 -0
  15. package/src/lib/components/console/order-invoice.component.d.ts +6 -4
  16. package/src/lib/components/console/order-invoice.component.js +67 -11
  17. package/src/lib/components/console/order-invoice.component.js.map +1 -1
  18. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js +33 -28
  19. package/src/lib/components/console/pos-ops/pos-check-ins-card.component.js.map +1 -1
  20. package/src/lib/components/console/quote-editor-dialog.component.d.ts +45 -0
  21. package/src/lib/components/console/quote-editor-dialog.component.js +1317 -0
  22. package/src/lib/components/console/quote-editor-dialog.component.js.map +1 -0
  23. package/src/lib/components/console/quote-pay-link.component.d.ts +38 -0
  24. package/src/lib/components/console/quote-pay-link.component.js +213 -0
  25. package/src/lib/components/console/quote-pay-link.component.js.map +1 -0
  26. package/src/lib/components/console/quote-proofs.component.d.ts +37 -0
  27. package/src/lib/components/console/quote-proofs.component.js +626 -0
  28. package/src/lib/components/console/quote-proofs.component.js.map +1 -0
  29. package/src/lib/components/console/quote-settings-card.component.d.ts +29 -0
  30. package/src/lib/components/console/quote-settings-card.component.js +121 -0
  31. package/src/lib/components/console/quote-settings-card.component.js.map +1 -0
  32. package/src/lib/components/console/tax-settings-card.component.js +4 -1
  33. package/src/lib/components/console/tax-settings-card.component.js.map +1 -1
  34. package/src/lib/components/quote-page-body.d.ts +33 -0
  35. package/src/lib/components/quote-page-body.js +724 -0
  36. package/src/lib/components/quote-page-body.js.map +1 -0
  37. package/src/lib/components/quote-page.d.ts +29 -0
  38. package/src/lib/components/quote-page.js +96 -0
  39. package/src/lib/components/quote-page.js.map +1 -0
  40. package/src/lib/components/quote-proof-panel.d.ts +42 -0
  41. package/src/lib/components/quote-proof-panel.js +436 -0
  42. package/src/lib/components/quote-proof-panel.js.map +1 -0
  43. package/src/lib/components/storefront-payment-element.d.ts +7 -1
  44. package/src/lib/components/storefront-payment-element.js +8 -3
  45. package/src/lib/components/storefront-payment-element.js.map +1 -1
  46. package/src/lib/constants/orders-list-query.js +6 -1
  47. package/src/lib/constants/orders-list-query.js.map +1 -1
  48. package/src/lib/constants/quote-page.d.ts +30 -0
  49. package/src/lib/constants/quote-page.js +35 -0
  50. package/src/lib/constants/quote-page.js.map +1 -0
  51. package/src/lib/model/commerce-orders.d.ts +25 -2
  52. package/src/lib/model/commerce-orders.js +10 -1
  53. package/src/lib/model/commerce-orders.js.map +1 -1
  54. package/src/lib/model/commerce-quote-pay.d.ts +256 -0
  55. package/src/lib/model/commerce-quote-pay.js +426 -0
  56. package/src/lib/model/commerce-quote-pay.js.map +1 -0
  57. package/src/lib/model/commerce-quote-proofs.d.ts +159 -0
  58. package/src/lib/model/commerce-quote-proofs.js +348 -0
  59. package/src/lib/model/commerce-quote-proofs.js.map +1 -0
  60. package/src/lib/model/commerce-quotes.d.ts +335 -0
  61. package/src/lib/model/commerce-quotes.js +522 -0
  62. package/src/lib/model/commerce-quotes.js.map +1 -0
  63. package/src/lib/model/index.d.ts +3 -0
  64. package/src/lib/model/index.js +3 -0
  65. package/src/lib/model/index.js.map +1 -1
  66. package/src/lib/model/plugin-permissions.d.ts +1 -1
  67. package/src/lib/model/plugin-permissions.js +20 -0
  68. package/src/lib/model/plugin-permissions.js.map +1 -1
  69. package/src/lib/server/api-v1/orders-and-products.js +6 -2
  70. package/src/lib/server/api-v1/orders-and-products.js.map +1 -1
  71. package/src/lib/server/billing-webhook.js +127 -52
  72. package/src/lib/server/billing-webhook.js.map +1 -1
  73. package/src/lib/server/checkout-session-expiry.d.ts +36 -0
  74. package/src/lib/server/checkout-session-expiry.js +63 -0
  75. package/src/lib/server/checkout-session-expiry.js.map +1 -0
  76. package/src/lib/server/commerce-pdf.d.ts +100 -0
  77. package/src/lib/server/commerce-pdf.js +283 -0
  78. package/src/lib/server/commerce-pdf.js.map +1 -0
  79. package/src/lib/server/draft-order.js +16 -8
  80. package/src/lib/server/draft-order.js.map +1 -1
  81. package/src/lib/server/order-print.d.ts +6 -0
  82. package/src/lib/server/order-print.js +22 -5
  83. package/src/lib/server/order-print.js.map +1 -1
  84. package/src/lib/server/pdf-response.d.ts +31 -0
  85. package/src/lib/server/pdf-response.js +30 -0
  86. package/src/lib/server/pdf-response.js.map +1 -0
  87. package/src/lib/server/person-eraser.d.ts +7 -0
  88. package/src/lib/server/person-eraser.js +24 -2
  89. package/src/lib/server/person-eraser.js.map +1 -1
  90. package/src/lib/server/pos-reader-splash.d.ts +2 -18
  91. package/src/lib/server/pos-reader-splash.js +8 -93
  92. package/src/lib/server/pos-reader-splash.js.map +1 -1
  93. package/src/lib/server/pos-return.js +3 -1
  94. package/src/lib/server/pos-return.js.map +1 -1
  95. package/src/lib/server/quote-link-token.d.ts +39 -0
  96. package/src/lib/server/quote-link-token.js +97 -0
  97. package/src/lib/server/quote-link-token.js.map +1 -0
  98. package/src/lib/server/quote-pay.d.ts +110 -0
  99. package/src/lib/server/quote-pay.js +606 -0
  100. package/src/lib/server/quote-pay.js.map +1 -0
  101. package/src/lib/server/quote-proofs.d.ts +51 -0
  102. package/src/lib/server/quote-proofs.js +500 -0
  103. package/src/lib/server/quote-proofs.js.map +1 -0
  104. package/src/lib/server/quote-uploads.d.ts +33 -0
  105. package/src/lib/server/quote-uploads.js +29 -0
  106. package/src/lib/server/quote-uploads.js.map +1 -0
  107. package/src/lib/server/quote.d.ts +63 -0
  108. package/src/lib/server/quote.js +846 -0
  109. package/src/lib/server/quote.js.map +1 -0
  110. package/src/lib/server/related.js +2 -0
  111. package/src/lib/server/related.js.map +1 -1
  112. package/src/lib/server/site-image-source.d.ts +38 -0
  113. package/src/lib/server/site-image-source.js +130 -0
  114. package/src/lib/server/site-image-source.js.map +1 -0
  115. package/src/lib/server/site-page-resolver.d.ts +2 -0
  116. package/src/lib/server/site-page-resolver.js +75 -0
  117. package/src/lib/server/site-page-resolver.js.map +1 -1
  118. package/src/lib/server.js +33 -1
  119. package/src/lib/server.js.map +1 -1
  120. package/src/lib/site.js +6 -0
  121. package/src/lib/site.js.map +1 -1
  122. package/src/lib/transfer/tracking.server.js +6 -0
  123. package/src/lib/transfer/tracking.server.js.map +1 -1
  124. package/src/lib/utils/commerce-document-pdf.d.ts +77 -0
  125. package/src/lib/utils/commerce-document-pdf.js +608 -0
  126. package/src/lib/utils/commerce-document-pdf.js.map +1 -0
  127. package/src/lib/utils/order-invoice.d.ts +52 -3
  128. package/src/lib/utils/order-invoice.js +116 -64
  129. package/src/lib/utils/order-invoice.js.map +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/utils/commerce-document-pdf.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { buildEmailPalette, emailAccent, resolveEmailColor, type EmailPalette } from '@aglyn/shared-util-email'\nimport { relativeLuminanceOfRgb, rgbChannelsOfHex } from '@aglyn/shared-util-tools/contrast'\nimport type { PdfJpegImage } from '@aglyn/shared-util-tools/pdf/pdf-file'\nimport { PdfWriter, pdfRgbFromHex, type PdfRgb, type PdfTableCell } from '@aglyn/shared-util-tools/pdf/pdf-writer'\nimport type { QuotePageAddress, QuotePageView } from '../model/commerce-quote-pay'\nimport { buildOrderInvoiceData, invoiceAddressLines, invoiceMoney, type InvoiceOrder, type OrderInvoiceStore } from './order-invoice'\n\n/*==========================================\n * A QUOTE AND AN INVOICE AS BRANDED PDFs (AGL-4095).\n *\n * renderQuotePdf({ brand, view, revision, payUrl }) → Uint8Array\n * renderOrderInvoicePdf({ brand, order, orderId, store }) → Uint8Array\n *\n * Both are one layout: the business's logo, name and contact at the top left\n * under a band of the site's primary color, the document's name, number,\n * date and standing at the top right, who it is billed and shipped to, the\n * lines in a table whose header wears the primary color, the totals, then\n * notes, terms and (for a quote still to be paid) the pay link as a button\n * and as text, both clickable. Every page ends with the document's name and\n * its page number.\n *\n * Pure over its input: the server reads the site, its theme and its logo\n * (`server/commerce-pdf-brand.ts`) and the quote or order, and these turn\n * them into bytes, so the console's download, the customer's download and\n * the emails that attach a quote or an invoice all make the same file.\n *\n * A quote is drawn from `buildQuotePageView`, the customer-safe projection\n * the quote page shows, so the PDF never says more than the page does. An\n * invoice is drawn from `buildOrderInvoiceData`, the content the printed\n * invoice shows.\n *=========================================*/\n\n/** The colors a document is drawn in, as `#rrggbb`. */\nexport interface CommercePdfColors {\n /** The band, the table's header and the pay button: the site's primary color. */\n accent: string\n /** Text set on the accent. */\n onAccent: string\n /** The accent as text on white: the document's name, links. */\n accentText: string\n /** A wash of the accent, behind the total. */\n tint: string\n ink: string\n muted: string\n rule: string\n}\n\n/** Who the document is from. */\nexport interface CommercePdfBrand {\n businessName: string\n /** Address lines, email, phone and web address, in that order. */\n contactLines: readonly string[]\n /** The site's logo as a JPEG; the business name stands alone without one. */\n logo?: PdfJpegImage | null\n /** The site theme's colors; any left out are the neutral ones. */\n colors?: Partial<CommercePdfColors> | null\n /** The site's time zone, which dates are given in. */\n timeZone?: string | null\n}\n\nconst NEUTRAL_PALETTE = buildEmailPalette({ base: 'tenant' })\nconst neutral = (path: string) => resolveEmailColor(path, NEUTRAL_PALETTE) ?? ''\n\n/** The colors a document wears where its site's theme gives none: the default site theme's greys. */\nexport const COMMERCE_PDF_NEUTRAL_COLORS: Readonly<CommercePdfColors> = Object.freeze({\n accent: neutral('grey.800'),\n onAccent: neutral('background.paper'),\n accentText: neutral('grey.800'),\n tint: neutral('grey.100'),\n ink: neutral('text.primary'),\n muted: neutral('text.secondary'),\n rule: neutral('divider'),\n})\n\n/** WCAG contrast between two `#rrggbb` colors; 1 when either cannot be read. */\nfunction contrast(one: string, other: string): number {\n const a = rgbChannelsOfHex(one)\n const b = rgbChannelsOfHex(other)\n if (!a || !b) return 1\n const la = relativeLuminanceOfRgb(...a)\n const lb = relativeLuminanceOfRgb(...b)\n return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05)\n}\n\n/**\n * A document's colors from a site's resolved palette: the primary color for\n * the accent, the theme's own text and divider colors, and text on the\n * accent that reads at 4.5:1 (the theme's contrast text when it does, else\n * the theme's dark ink or white, whichever reads better).\n */\nexport function commercePdfColorsFromPalette(palette: EmailPalette): CommercePdfColors {\n const accent = emailAccent(palette)\n const read = (path: string, fallback: string) => resolveEmailColor(path, palette) ?? fallback\n const ink = read('text.primary', COMMERCE_PDF_NEUTRAL_COLORS.ink)\n const paper = read('background.paper', COMMERCE_PDF_NEUTRAL_COLORS.onAccent)\n const onAccent =\n contrast(accent.label, accent.fill) >= 4.5\n ? accent.label\n : contrast(ink, accent.fill) >= contrast(paper, accent.fill)\n ? ink\n : paper\n return {\n accent: accent.fill,\n onAccent,\n accentText: contrast(accent.link, paper) >= 4.5 ? accent.link : ink,\n tint: read('tint.primary', COMMERCE_PDF_NEUTRAL_COLORS.tint),\n ink,\n muted: read('text.secondary', COMMERCE_PDF_NEUTRAL_COLORS.muted),\n rule: read('divider', COMMERCE_PDF_NEUTRAL_COLORS.rule),\n }\n}\n\n/*==========================================\n * WHAT A DOCUMENT SAYS\n *=========================================*/\n\ninterface DocumentLine {\n name: string\n details: string[]\n quantity: number\n unit: string\n amount: string\n}\n\ninterface SummaryRow {\n label: string\n value: string\n emphasis?: boolean\n /** A note in place of a figure, such as \"Tax is added at payment\". */\n note?: boolean\n}\n\ninterface CommerceDocument {\n /** QUOTE or INVOICE, across the top. */\n kind: string\n /** `Quote #1042`. */\n title: string\n facts: Array<[string, string]>\n /** A short standing, set in a pill under the facts: `Paid October 30, 2026`. */\n stamp: string | null\n parties: Array<{ label: string; lines: string[] }>\n lines: DocumentLine[]\n summary: SummaryRow[]\n sections: Array<{ heading: string; text: string; link?: string }>\n pay: { url: string; label: string; intro: string } | null\n}\n\n/** A date the American way, in the site's time zone: `October 28, 2026`. */\nexport function formatPdfDate(ms: number | null | undefined, timeZone?: string | null): string {\n if (!ms || !Number.isFinite(ms)) return ''\n const options: Intl.DateTimeFormatOptions = { year: 'numeric', month: 'long', day: 'numeric' }\n try {\n return new Intl.DateTimeFormat('en-US', { ...options, ...(timeZone ? { timeZone } : {}) }).format(new Date(ms))\n } catch {\n return new Intl.DateTimeFormat('en-US', { ...options, timeZone: 'UTC' }).format(new Date(ms))\n }\n}\n\nconst minus = (text: string) => `-${text}`\n\n/*==========================================\n * THE QUOTE\n *=========================================*/\n\nexport interface QuotePdfInput {\n brand: CommercePdfBrand\n /** The quote as its customer may see it: `buildQuotePageView`. */\n view: QuotePageView\n /** The quote's revision, printed beside its date. */\n revision?: number | null\n /** The pay link, printed on a quote still to be paid; left off when the reader may not have it. */\n payUrl?: string | null\n}\n\nfunction quoteAddressLines(address: QuotePageAddress | null): string[] {\n return invoiceAddressLines(address as never, { phone: false })\n}\n\nfunction quoteDocument(input: QuotePdfInput): CommerceDocument {\n const { view, brand } = input\n const money = (cents: number) => invoiceMoney(cents, view.currency)\n const date = (ms: number | null) => formatPdfDate(ms, brand.timeZone)\n const customer = [view.customerName ?? '', view.company ?? ''].filter(Boolean)\n const billTo = quoteAddressLines(view.billTo)\n const parties: CommerceDocument['parties'] = []\n if (billTo.length) {\n // The bill-to's own name leads; the customer's name and company are added when it does not carry them.\n const named = customer.filter((part) => !billTo.includes(part))\n parties.push({ label: 'Bill to', lines: [...named, ...billTo] })\n } else if (customer.length) {\n parties.push({ label: 'Prepared for', lines: customer })\n }\n const shipTo = quoteAddressLines(view.shipTo)\n if (shipTo.length) parties.push({ label: 'Ship to', lines: shipTo })\n\n const summary: SummaryRow[] = [{ label: 'Subtotal', value: money(view.totals.itemsCents) }]\n if (view.totals.discountCents > 0) {\n summary.push({\n label: view.discountLabel ? `Discount (${view.discountLabel})` : 'Discount',\n value: minus(money(view.totals.discountCents)),\n })\n }\n if (view.totals.shippingCents > 0) summary.push({ label: 'Shipping', value: money(view.totals.shippingCents) })\n if (view.taxAtPayment) summary.push({ label: 'Tax is added at payment', value: '', note: true })\n else if (view.totals.taxCents > 0) summary.push({ label: view.taxLabel || 'Tax', value: money(view.totals.taxCents) })\n else if (view.taxLabel && view.taxLabel !== 'Tax') summary.push({ label: view.taxLabel, value: '', note: true })\n summary.push({ label: view.taxAtPayment ? 'Total before tax' : 'Total', value: money(view.totals.totalCents), emphasis: true })\n\n const stamp =\n view.status === 'paid'\n ? `Paid${view.paidAtMs ? ` ${date(view.paidAtMs)}` : ''}`\n : view.status === 'canceled'\n ? 'Canceled'\n : view.status === 'refunded'\n ? 'Refunded'\n : null\n const facts: Array<[string, string]> = []\n if (view.dateMs) facts.push(['Date', date(view.dateMs)])\n if (input.revision && input.revision > 0) facts.push(['Revision', String(input.revision)])\n\n const sections: CommerceDocument['sections'] = []\n if (view.notes) sections.push({ heading: 'Notes', text: view.notes })\n if (view.terms) sections.push({ heading: 'Terms', text: view.terms })\n\n const payUrl = view.status === 'unpaid' && input.payUrl ? input.payUrl : null\n return {\n kind: 'QUOTE',\n title: view.number,\n facts,\n stamp,\n parties,\n lines: view.lines.map((line) => ({\n name: line.name,\n details: [line.variantLabel ?? '', line.description ?? '', line.sku ? `SKU ${line.sku}` : ''].filter(Boolean),\n quantity: line.quantity,\n unit: line.included ? '' : money(line.unitAmountCents),\n amount: line.included ? 'Included' : money(line.amountCents),\n })),\n summary,\n sections,\n pay: payUrl\n ? {\n url: payUrl,\n label: 'Pay this quote',\n intro: view.approvalRequired\n ? `${view.storeName || 'We'} will ask you to approve the proof first, at this link:`\n : 'Open the quote on our site to pay it securely by card:',\n }\n : null,\n }\n}\n\n/** The quote as a PDF. */\nexport function renderQuotePdf(input: QuotePdfInput): Uint8Array {\n return renderCommerceDocument(input.brand, quoteDocument(input))\n}\n\n/*==========================================\n * THE INVOICE\n *=========================================*/\n\nexport interface OrderInvoicePdfInput {\n brand: CommercePdfBrand\n order: InvoiceOrder\n orderId: string\n /** The store's currency, receipt footer and terms address (`invoiceStoreFrom`). */\n store: OrderInvoiceStore\n}\n\nfunction invoiceDocument(input: OrderInvoicePdfInput): CommerceDocument {\n const data = buildOrderInvoiceData(input)\n const money = (cents: number) => invoiceMoney(cents, data.currency)\n const parties: CommerceDocument['parties'] = []\n if (data.billTo.length) parties.push({ label: 'Bill to', lines: data.billTo })\n if (data.shipTo.length) parties.push({ label: 'Ship to', lines: data.shipTo })\n const facts: Array<[string, string]> = []\n if (data.dateMs) facts.push(['Order date', formatPdfDate(data.dateMs, input.brand.timeZone)])\n const sections: CommerceDocument['sections'] = []\n if (data.footer) sections.push({ heading: '', text: data.footer })\n if (data.termsUrl) sections.push({ heading: 'Terms', text: data.termsUrl, link: data.termsUrl })\n return {\n kind: 'INVOICE',\n title: `Invoice ${data.number}`,\n facts,\n stamp: data.paymentStatus,\n parties,\n lines: data.lines.map((line) => ({\n name: line.name,\n details: [line.detail, line.description].filter(Boolean),\n quantity: line.quantity,\n unit: line.included ? '' : money(line.unitCents),\n amount: line.included ? 'Included' : money(line.amountCents),\n })),\n summary: data.summary.map((row) => ({\n label: row.label,\n value: row.minus ? minus(money(row.cents)) : money(row.cents),\n emphasis: row.emphasis,\n })),\n sections,\n pay: null,\n }\n}\n\n/** Any order's invoice as a PDF, a paid quote's included. */\nexport function renderOrderInvoicePdf(input: OrderInvoicePdfInput): Uint8Array {\n return renderCommerceDocument(input.brand, invoiceDocument(input))\n}\n\n/*==========================================\n * THE LAYOUT\n *=========================================*/\n\nconst PAGE_MARGIN = { top: 48, right: 48, bottom: 60, left: 48 }\nconst BAND_HEIGHT = 10\nconst LOGO_BOX = { width: 180, height: 50 }\n\nfunction renderCommerceDocument(brand: CommercePdfBrand, document: CommerceDocument): Uint8Array {\n const palette = { ...COMMERCE_PDF_NEUTRAL_COLORS, ...(brand.colors ?? {}) }\n const color = (hex: string, fallback: string): PdfRgb =>\n pdfRgbFromHex(hex) ?? pdfRgbFromHex(fallback) ?? [0, 0, 0]\n const colors = {\n accent: color(palette.accent, COMMERCE_PDF_NEUTRAL_COLORS.accent),\n onAccent: color(palette.onAccent, COMMERCE_PDF_NEUTRAL_COLORS.onAccent),\n accentText: color(palette.accentText, COMMERCE_PDF_NEUTRAL_COLORS.accentText),\n tint: color(palette.tint, COMMERCE_PDF_NEUTRAL_COLORS.tint),\n ink: color(palette.ink, COMMERCE_PDF_NEUTRAL_COLORS.ink),\n muted: color(palette.muted, COMMERCE_PDF_NEUTRAL_COLORS.muted),\n rule: color(palette.rule, COMMERCE_PDF_NEUTRAL_COLORS.rule),\n }\n const businessName = brand.businessName.trim()\n const documentTitle = businessName ? `${document.title} - ${businessName}` : document.title\n\n const writer: PdfWriter = new PdfWriter({\n title: documentTitle,\n margin: PAGE_MARGIN,\n onNewPage: (page) => {\n page.fillRect(0, page.pageHeight - BAND_HEIGHT / 2, page.pageWidth, BAND_HEIGHT / 2, colors.accent)\n const baseline = page.top + 14\n if (businessName) page.textIn(page.left, page.contentWidth, baseline, businessName, { size: 8.5, font: 'bold', color: colors.muted })\n page.textIn(page.left, page.contentWidth, baseline, `${document.title} (continued)`, { size: 8.5, color: colors.muted }, 'right')\n },\n })\n const { left, right } = writer\n\n // The band across the top of the first page.\n writer.fillRect(0, writer.pageHeight - BAND_HEIGHT, writer.pageWidth, BAND_HEIGHT, colors.accent)\n\n // Left: logo, business name, contact.\n const leftWidth = writer.contentWidth * 0.55\n let leftY = writer.top\n if (brand.logo) {\n const drawn = writer.image(brand.logo, { x: left, y: leftY - LOGO_BOX.height, width: LOGO_BOX.width, height: LOGO_BOX.height })\n leftY = drawn.y - 12\n }\n writer.y = leftY\n if (businessName) writer.paragraph(businessName, { width: leftWidth, style: { font: 'bold', size: 14, color: colors.ink }, leading: 1.25, after: 2 })\n for (const line of brand.contactLines) {\n writer.paragraph(line, { width: leftWidth, style: { size: 9, color: colors.muted }, leading: 1.3 })\n }\n leftY = writer.y\n\n // Right: the document's name, number, facts and standing.\n const factsWidth = 210\n const factsX = right - factsWidth\n let rightY = writer.top - 22\n writer.textIn(factsX, factsWidth, rightY, document.kind, { font: 'bold', size: 24, color: colors.accentText }, 'right')\n rightY -= 20\n writer.textIn(factsX, factsWidth, rightY, document.title, { font: 'bold', size: 11, color: colors.ink }, 'right')\n for (const [label, value] of document.facts) {\n rightY -= 14\n const valueWidth = writer.measure(value, { size: 9.5 })\n writer.textIn(factsX, factsWidth, rightY, value, { size: 9.5, color: colors.ink }, 'right')\n writer.textIn(factsX, factsWidth - valueWidth - 8, rightY, label, { size: 9.5, color: colors.muted }, 'right')\n }\n if (document.stamp) {\n rightY -= 24\n const style = { font: 'bold' as const, size: 8.5, color: colors.onAccent }\n const width = writer.measure(document.stamp, style) + 16\n writer.fillRect(right - width, rightY - 5, width, 17, colors.accent)\n writer.textIn(right - width, width, rightY, document.stamp, style, 'center')\n rightY -= 5\n }\n\n writer.y = Math.min(leftY, rightY) - 22\n\n // Who it is for.\n if (document.parties.length) {\n const columnWidth = Math.min(220, writer.contentWidth / document.parties.length)\n const top = writer.y\n let lowest = top\n document.parties.forEach((party, index) => {\n const x = left + index * (columnWidth + 16)\n writer.y = top\n writer.paragraph(party.label.toUpperCase(), { x, width: columnWidth, style: { font: 'bold', size: 8, color: colors.muted }, after: 2 })\n party.lines.forEach((line, lineIndex) => {\n writer.paragraph(line, {\n x,\n width: columnWidth,\n style: { size: 9.5, color: colors.ink, font: lineIndex === 0 ? 'bold' : 'regular' },\n })\n })\n lowest = Math.min(lowest, writer.y)\n })\n writer.y = lowest - 18\n }\n\n // The lines.\n const rows: PdfTableCell[][] = document.lines.map((line) => [\n [\n { text: line.name, style: { font: 'bold', size: 9.5, color: colors.ink } },\n ...line.details.map((detail) => ({ text: detail, style: { size: 8.5, color: colors.muted } })),\n ],\n String(line.quantity),\n line.unit,\n line.amount,\n ])\n writer.table({\n columns: [\n { header: 'Item', width: 0 },\n { header: 'Qty', width: 48, align: 'right' },\n { header: 'Unit price', width: 86, align: 'right' },\n { header: 'Amount', width: 90, align: 'right' },\n ],\n rows,\n headerFill: colors.accent,\n headerStyle: { font: 'bold', size: 8.5, color: colors.onAccent },\n bodyStyle: { size: 9.5, color: colors.ink },\n padding: { x: 8, y: 6 },\n ruleColor: colors.rule,\n })\n\n // The totals on the right; beside them on the left, paying it.\n const summaryWidth = 250\n const summaryX = right - summaryWidth\n const payWidth = writer.contentWidth - summaryWidth - 28\n const rowHeight = 17\n const summaryHeight = document.summary.reduce((sum, row) => sum + (row.emphasis ? rowHeight + 8 : rowHeight), 0)\n const pay = document.pay\n const buttonStyle = { font: 'bold' as const, size: 10.5, color: colors.onAccent }\n const buttonHeight = 26\n const payParts = pay\n ? {\n intro: writer.wrap(pay.intro, payWidth, { size: 9 }),\n url: writer.wrap(pay.url, payWidth, { size: 8 }),\n }\n : null\n const payHeight = payParts ? 18 + payParts.intro.length * 12 + 6 + buttonHeight + 8 + payParts.url.length * 11 : 0\n writer.down(12)\n writer.ensure(Math.max(summaryHeight, payHeight))\n const blockTop = writer.y\n for (const row of document.summary) {\n const height = row.emphasis ? rowHeight + 8 : rowHeight\n if (row.emphasis) writer.fillRect(summaryX, writer.y - height, summaryWidth, height, colors.tint)\n const size = row.emphasis ? 11.5 : 9.5\n const baseline = writer.y - height / 2 - size * 0.35\n const style = row.emphasis\n ? { font: 'bold' as const, size, color: colors.ink }\n : { size, color: row.note ? colors.muted : colors.ink, ...(row.note ? { font: 'italic' as const } : {}) }\n writer.textIn(summaryX + 8, summaryWidth - 16, baseline, row.label, style, 'left')\n if (row.value) writer.textIn(summaryX + 8, summaryWidth - 16, baseline, row.value, style, 'right')\n writer.down(height)\n }\n const summaryBottom = writer.y\n if (pay && payParts) {\n let y = blockTop - 12\n writer.text(left, y, 'Pay online', { font: 'bold', size: 11, color: colors.ink })\n y -= 6\n for (const line of payParts.intro) {\n y -= 12\n writer.text(left, y + 2, line, { size: 9, color: colors.muted })\n }\n y -= 6\n const buttonWidth = writer.measure(pay.label, buttonStyle) + 36\n writer.fillRect(left, y - buttonHeight, buttonWidth, buttonHeight, colors.accent)\n writer.textIn(left, buttonWidth, y - buttonHeight / 2 - 10.5 * 0.35, pay.label, buttonStyle, 'center')\n writer.link(left, y - buttonHeight, buttonWidth, buttonHeight, pay.url)\n y -= buttonHeight + 8\n for (const line of payParts.url) {\n y -= 11\n writer.text(left, y + 2, line, { size: 8, color: colors.accentText })\n writer.link(left, y, writer.measure(line, { size: 8 }), 11, pay.url)\n }\n writer.y = Math.min(summaryBottom, y)\n }\n writer.down(22)\n\n // Notes, terms, the store's footer.\n for (const section of document.sections) {\n if (section.heading) {\n writer.ensure(36)\n writer.paragraph(section.heading, { style: { font: 'bold', size: 10, color: colors.ink }, after: 1 })\n }\n writer.paragraph(section.text, {\n style: { size: 9, color: section.link ? colors.accentText : colors.muted },\n ...(section.link ? { link: section.link } : {}),\n after: 12,\n })\n }\n\n return writer.finish({\n footer: (page, pages) => ({\n left: businessName ? `${businessName} · ${document.title}` : document.title,\n right: `Page ${page} of ${pages}`,\n }),\n footerStyle: { size: 8, color: colors.muted },\n footerRule: colors.rule,\n })\n}\n"],"names":["buildEmailPalette","emailAccent","resolveEmailColor","relativeLuminanceOfRgb","rgbChannelsOfHex","PdfWriter","pdfRgbFromHex","buildOrderInvoiceData","invoiceAddressLines","invoiceMoney","NEUTRAL_PALETTE","base","neutral","path","COMMERCE_PDF_NEUTRAL_COLORS","Object","freeze","accent","onAccent","accentText","tint","ink","muted","rule","contrast","one","other","a","b","la","lb","Math","max","min","commercePdfColorsFromPalette","palette","read","fallback","paper","label","fill","link","formatPdfDate","ms","timeZone","Number","isFinite","options","year","month","day","Intl","DateTimeFormat","format","Date","minus","text","quoteAddressLines","address","phone","quoteDocument","input","view","brand","money","cents","currency","date","customer","customerName","company","filter","Boolean","billTo","parties","length","named","part","includes","push","lines","shipTo","summary","value","totals","itemsCents","discountCents","discountLabel","shippingCents","taxAtPayment","note","taxCents","taxLabel","totalCents","emphasis","stamp","status","paidAtMs","facts","dateMs","revision","String","sections","notes","heading","terms","payUrl","kind","title","number","map","line","name","details","variantLabel","description","sku","quantity","unit","included","unitAmountCents","amount","amountCents","pay","url","intro","approvalRequired","storeName","renderQuotePdf","renderCommerceDocument","invoiceDocument","data","footer","termsUrl","paymentStatus","detail","unitCents","row","renderOrderInvoicePdf","PAGE_MARGIN","top","right","bottom","left","BAND_HEIGHT","LOGO_BOX","width","height","document","colors","color","hex","businessName","trim","documentTitle","writer","margin","onNewPage","page","fillRect","pageHeight","pageWidth","baseline","textIn","contentWidth","size","font","leftWidth","leftY","logo","drawn","image","x","y","paragraph","style","leading","after","contactLines","factsWidth","factsX","rightY","valueWidth","measure","columnWidth","lowest","forEach","party","index","toUpperCase","lineIndex","rows","table","columns","header","align","headerFill","headerStyle","bodyStyle","padding","ruleColor","summaryWidth","summaryX","payWidth","rowHeight","summaryHeight","reduce","sum","buttonStyle","buttonHeight","payParts","wrap","payHeight","down","ensure","blockTop","summaryBottom","buttonWidth","section","finish","pages","footerStyle","footerRule"],"mappings":"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"}
@@ -14,7 +14,7 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
- import { type HostOrder } from '../model/commerce-orders';
17
+ import { type HostOrder, type OrderAddress } from '../model/commerce-orders';
18
18
  /**
19
19
  * The printable invoice (AGL-3611), beside the packing slip: the order as a
20
20
  * bill — who sold it, to whom, each line with its unit price, the totals,
@@ -42,19 +42,68 @@ export interface OrderInvoiceStore {
42
42
  * the order dialog's Invoice button and `commerce/order-print` read them.
43
43
  */
44
44
  export declare function invoiceStoreFrom(host: Record<string, unknown> | undefined | null, store: Record<string, unknown> | undefined | null): OrderInvoiceStore;
45
- type InvoiceOrder = Pick<HostOrder, 'number' | 'status' | 'lineItems' | 'totals' | 'refundedCents' | 'customerName' | 'customerEmail' | 'shippingAddress' | 'billingAddress'> & {
45
+ export type InvoiceOrder = Pick<HostOrder, 'number' | 'status' | 'lineItems' | 'totals' | 'refundedCents' | 'customerName' | 'customerEmail' | 'shippingAddress' | 'billingAddress'> & {
46
46
  createdAtMs?: number;
47
47
  currency?: string;
48
48
  amountCents?: number;
49
49
  };
50
50
  /** Money in the order's currency, integer cents in. */
51
51
  export declare function invoiceMoney(cents: number, currency: string): string;
52
+ /**
53
+ * An address as lines, the American way: name, street, `City, ST 12345`,
54
+ * the country unless it is the United States, then the phone when the
55
+ * address carries one and it is wanted.
56
+ */
57
+ export declare function invoiceAddressLines(address: Partial<OrderAddress> | undefined | null, options?: {
58
+ phone?: boolean;
59
+ }): string[];
52
60
  /** What the payment line says. */
53
61
  export declare function invoicePaymentStatus(order: Pick<InvoiceOrder, 'status' | 'refundedCents' | 'totals' | 'amountCents'>): string;
62
+ /** One line of an invoice, as both the printed page and the PDF set it. */
63
+ export interface InvoiceLine {
64
+ name: string;
65
+ /** The option chosen and the SKU, as one line under the name. */
66
+ detail: string;
67
+ /** A typed line's own description. */
68
+ description: string;
69
+ quantity: number;
70
+ unitCents: number;
71
+ amountCents: number;
72
+ /** Included at no charge. */
73
+ included: boolean;
74
+ }
75
+ /** One row of an invoice's summary: a figure, or a deduction printed with a minus. */
76
+ export interface InvoiceSummaryRow {
77
+ label: string;
78
+ cents: number;
79
+ minus?: boolean;
80
+ /** The row the summary leads to: the total, or what was paid after refunds. */
81
+ emphasis?: boolean;
82
+ }
83
+ /** An invoice's content, worked out once for the printed page and the PDF. */
84
+ export interface OrderInvoiceData {
85
+ /** `#1042`. */
86
+ number: string;
87
+ /** When the order was placed; 0 when it does not say. */
88
+ dateMs: number;
89
+ currency: string;
90
+ paymentStatus: string;
91
+ billTo: string[];
92
+ shipTo: string[];
93
+ lines: InvoiceLine[];
94
+ summary: InvoiceSummaryRow[];
95
+ footer: string;
96
+ termsUrl: string;
97
+ }
98
+ /** What an invoice says, from the order and its store. */
99
+ export declare function buildOrderInvoiceData(input: {
100
+ order: InvoiceOrder;
101
+ orderId: string;
102
+ store: OrderInvoiceStore;
103
+ }): OrderInvoiceData;
54
104
  /** The invoice's markup: a full document body, every value escaped. */
55
105
  export declare function buildOrderInvoiceHtml(input: {
56
106
  order: InvoiceOrder;
57
107
  orderId: string;
58
108
  store: OrderInvoiceStore;
59
109
  }): string;
60
- export {};
@@ -40,21 +40,31 @@ import { escapeHtml } from "./escape-html.js";
40
40
  return `${amount.toFixed(2)} ${String(currency || '').toUpperCase()}`.trim();
41
41
  }
42
42
  }
43
- function addressLines(address) {
43
+ /** The United States, however an address names it: left off, as a US envelope does. */ const US_COUNTRY = /^(us|usa|u\.s\.a?\.?|united states( of america)?)$/i;
44
+ /**
45
+ * An address as lines, the American way: name, street, `City, ST 12345`,
46
+ * the country unless it is the United States, then the phone when the
47
+ * address carries one and it is wanted.
48
+ */ export function invoiceAddressLines(address, options = {}) {
44
49
  if (!address) return [];
50
+ const clean = (part)=>String(part != null ? part : '').trim();
51
+ const region = [
52
+ clean(address.state),
53
+ clean(address.postalCode)
54
+ ].filter(Boolean).join(' ');
45
55
  return [
46
- address.name,
47
- address.line1,
48
- address.line2,
56
+ clean(address.name),
57
+ clean(address.line1),
58
+ clean(address.line2),
49
59
  [
50
- address.city,
51
- address.state,
52
- address.postalCode
53
- ].filter(Boolean).join(' '),
54
- address.country,
55
- address.phone
56
- ].map((part)=>String(part != null ? part : '').trim()).filter(Boolean);
60
+ clean(address.city),
61
+ region
62
+ ].filter(Boolean).join(', '),
63
+ US_COUNTRY.test(clean(address.country)) ? '' : clean(address.country),
64
+ options.phone === false ? '' : clean(address.phone)
65
+ ].filter(Boolean);
57
66
  }
67
+ const addressLines = (address)=>invoiceAddressLines(address);
58
68
  /** What the payment line says. */ export function invoicePaymentStatus(order) {
59
69
  var _ref, _ref1, _order_refundedCents, _order_status;
60
70
  var _order_totals;
@@ -67,75 +77,117 @@ function addressLines(address) {
67
77
  if (refunded > 0) return 'Paid, partially refunded';
68
78
  return 'Paid';
69
79
  }
70
- /** The invoice's markup: a full document body, every value escaped. */ export function buildOrderInvoiceHtml(input) {
71
- var _ref, _order_lineItems, _ref1, _ref2, _order_refundedCents, _order_customerName, _order_customerEmail, _order_lineItems1, _ref3, _ref4, _ref5, _ref6;
80
+ /** What an invoice says, from the order and its store. */ export function buildOrderInvoiceData(input) {
81
+ var _ref, _order_lineItems, _ref1, _ref2, _order_refundedCents, _order_lineItems1, _ref3, _ref4, _ref5, _ref6, _order_customerName, _order_customerEmail, _store_footer, _store_termsUrl;
72
82
  const { order, orderId, store } = input;
73
83
  const currency = String(order.currency || store.currency || 'USD').toUpperCase();
74
- const money = (cents)=>escapeHtml(invoiceMoney(cents, currency));
75
- const number = formatOrderNumber(order, orderId);
76
- const createdAt = orderCreatedAtMs(order);
77
84
  const totals = order.totals;
78
85
  const itemsCents = (_ref = totals == null ? void 0 : totals.itemsCents) != null ? _ref : ((_order_lineItems = order.lineItems) != null ? _order_lineItems : []).reduce((sum, line)=>sum + Number(line.unitAmountCents || 0) * Number(line.quantity || 0), 0);
79
86
  const totalCents = Number((_ref1 = (_ref2 = totals == null ? void 0 : totals.totalCents) != null ? _ref2 : order.amountCents) != null ? _ref1 : itemsCents);
80
87
  const refundedCents = Math.max(0, Number((_order_refundedCents = order.refundedCents) != null ? _order_refundedCents : 0));
81
- const billTo = [
82
- ...order.billingAddress ? addressLines(order.billingAddress) : [
83
- (_order_customerName = order.customerName) != null ? _order_customerName : ''
84
- ].filter(Boolean),
85
- (_order_customerEmail = order.customerEmail) != null ? _order_customerEmail : ''
86
- ].filter(Boolean);
87
- const shipTo = addressLines(order.shippingAddress);
88
- const rows = ((_order_lineItems1 = order.lineItems) != null ? _order_lineItems1 : []).map((line)=>{
88
+ const lines = ((_order_lineItems1 = order.lineItems) != null ? _order_lineItems1 : []).map((line)=>{
89
+ var _line_name, _line_description;
89
90
  const quantity = Number(line.quantity) || 0;
90
91
  const unit = Number(line.unitAmountCents) || 0;
91
- const detail = [
92
- line.variantLabel ? escapeHtml(line.variantLabel) : '',
93
- line.sku ? `SKU ${escapeHtml(line.sku)}` : ''
94
- ].filter(Boolean).join(' · ');
95
- return `<tr><td>${escapeHtml(line.name)}${detail ? `<br/><small>${detail}</small>` : ''}</td>` + `<td align="right">${escapeHtml(quantity)}</td>` + `<td align="right">${money(unit)}</td>` + `<td align="right">${money(unit * quantity)}</td></tr>`;
96
- }).join('');
92
+ return {
93
+ name: String((_line_name = line.name) != null ? _line_name : ''),
94
+ detail: [
95
+ line.variantLabel ? String(line.variantLabel) : '',
96
+ line.sku ? `SKU ${line.sku}` : ''
97
+ ].filter(Boolean).join(' · '),
98
+ description: String((_line_description = line.description) != null ? _line_description : '').trim(),
99
+ quantity,
100
+ unitCents: unit,
101
+ amountCents: unit * quantity,
102
+ included: line.included === true
103
+ };
104
+ });
97
105
  const summary = [
98
- [
99
- 'Subtotal',
100
- money(itemsCents)
101
- ]
106
+ {
107
+ label: 'Subtotal',
108
+ cents: itemsCents
109
+ }
102
110
  ];
103
- if (Number((_ref3 = totals == null ? void 0 : totals.discountCents) != null ? _ref3 : 0) > 0) summary.push([
104
- 'Discount',
105
- `−${money(Number(totals == null ? void 0 : totals.discountCents))}`
106
- ]);
107
- if (Number((_ref4 = totals == null ? void 0 : totals.shippingCents) != null ? _ref4 : 0) > 0) summary.push([
108
- 'Shipping',
109
- money(Number(totals == null ? void 0 : totals.shippingCents))
110
- ]);
111
- if (Number((_ref5 = totals == null ? void 0 : totals.taxCents) != null ? _ref5 : 0) > 0) summary.push([
112
- 'Tax',
113
- money(Number(totals == null ? void 0 : totals.taxCents))
114
- ]);
115
- summary.push([
116
- '<b>Total</b>',
117
- `<b>${money(totalCents)}</b>`
118
- ]);
119
- if (Number((_ref6 = totals == null ? void 0 : totals.tipCents) != null ? _ref6 : 0) > 0) summary.push([
120
- 'Tip',
121
- money(Number(totals == null ? void 0 : totals.tipCents))
122
- ]);
111
+ if (Number((_ref3 = totals == null ? void 0 : totals.discountCents) != null ? _ref3 : 0) > 0) summary.push({
112
+ label: 'Discount',
113
+ cents: Number(totals == null ? void 0 : totals.discountCents),
114
+ minus: true
115
+ });
116
+ if (Number((_ref4 = totals == null ? void 0 : totals.shippingCents) != null ? _ref4 : 0) > 0) summary.push({
117
+ label: 'Shipping',
118
+ cents: Number(totals == null ? void 0 : totals.shippingCents)
119
+ });
120
+ if (Number((_ref5 = totals == null ? void 0 : totals.taxCents) != null ? _ref5 : 0) > 0) summary.push({
121
+ label: 'Tax',
122
+ cents: Number(totals == null ? void 0 : totals.taxCents)
123
+ });
124
+ summary.push({
125
+ label: 'Total',
126
+ cents: totalCents,
127
+ emphasis: true
128
+ });
129
+ if (Number((_ref6 = totals == null ? void 0 : totals.tipCents) != null ? _ref6 : 0) > 0) summary.push({
130
+ label: 'Tip',
131
+ cents: Number(totals == null ? void 0 : totals.tipCents)
132
+ });
123
133
  if (refundedCents > 0) {
124
- summary.push([
125
- 'Refunded',
126
- `−${money(refundedCents)}`
127
- ]);
128
- summary.push([
129
- '<b>Net paid</b>',
130
- `<b>${money(Math.max(0, totalCents - refundedCents))}</b>`
131
- ]);
134
+ summary.push({
135
+ label: 'Refunded',
136
+ cents: refundedCents,
137
+ minus: true
138
+ });
139
+ summary.push({
140
+ label: 'Net paid',
141
+ cents: Math.max(0, totalCents - refundedCents),
142
+ emphasis: true
143
+ });
132
144
  }
145
+ return {
146
+ number: formatOrderNumber(order, orderId),
147
+ dateMs: orderCreatedAtMs(order),
148
+ currency,
149
+ paymentStatus: invoicePaymentStatus(order),
150
+ billTo: [
151
+ ...order.billingAddress ? addressLines(order.billingAddress) : [
152
+ (_order_customerName = order.customerName) != null ? _order_customerName : ''
153
+ ].filter(Boolean),
154
+ (_order_customerEmail = order.customerEmail) != null ? _order_customerEmail : ''
155
+ ].filter(Boolean),
156
+ shipTo: addressLines(order.shippingAddress),
157
+ lines,
158
+ summary,
159
+ footer: String((_store_footer = store.footer) != null ? _store_footer : '').trim(),
160
+ termsUrl: String((_store_termsUrl = store.termsUrl) != null ? _store_termsUrl : '').trim()
161
+ };
162
+ }
163
+ /** The invoice's markup: a full document body, every value escaped. */ export function buildOrderInvoiceHtml(input) {
164
+ const data = buildOrderInvoiceData(input);
165
+ const { store } = input;
166
+ const money = (cents)=>escapeHtml(invoiceMoney(cents, data.currency));
167
+ const number = data.number;
168
+ const rows = data.lines.map((line)=>{
169
+ const detail = [
170
+ line.detail,
171
+ line.description
172
+ ].filter(Boolean).map((part)=>escapeHtml(part)).join('<br/>');
173
+ return `<tr><td>${escapeHtml(line.name)}${detail ? `<br/><small>${detail}</small>` : ''}</td>` + `<td align="right">${escapeHtml(line.quantity)}</td>` + `<td align="right">${line.included ? '' : money(line.unitCents)}</td>` + `<td align="right">${line.included ? 'Included' : money(line.amountCents)}</td></tr>`;
174
+ }).join('');
175
+ const summary = data.summary.map(({ label, cents, minus, emphasis })=>{
176
+ const figure = `${minus ? '−' : ''}${money(cents)}`;
177
+ return emphasis ? [
178
+ `<b>${label}</b>`,
179
+ `<b>${figure}</b>`
180
+ ] : [
181
+ label,
182
+ figure
183
+ ];
184
+ });
133
185
  const block = (title, lines)=>lines.length ? `<td valign="top"><b>${title}</b><br/>${lines.map((line)=>escapeHtml(line)).join('<br/>')}</td>` : '';
134
- return `<title>${escapeHtml(`Invoice ${number}`)}</title>` + `<h2>${escapeHtml(store.name || 'Invoice')}</h2>` + `<h3>${escapeHtml(`Invoice ${number}`)}</h3>` + `<p>${createdAt ? `Date: ${escapeHtml(new Date(createdAt).toLocaleDateString('en-US', {
186
+ return `<title>${escapeHtml(`Invoice ${number}`)}</title>` + `<h2>${escapeHtml(store.name || 'Invoice')}</h2>` + `<h3>${escapeHtml(`Invoice ${number}`)}</h3>` + `<p>${data.dateMs ? `Date: ${escapeHtml(new Date(data.dateMs).toLocaleDateString('en-US', {
135
187
  year: 'numeric',
136
188
  month: 'long',
137
189
  day: 'numeric'
138
- }))}<br/>` : ''}` + `Payment: ${escapeHtml(invoicePaymentStatus(order))}<br/>Currency: ${escapeHtml(currency)}</p>` + `<table width="100%" cellpadding="6"><tr>${block('Bill to', billTo)}${block('Ship to', shipTo)}</tr></table>` + `<table width="100%" cellpadding="6" border="1" cellspacing="0">` + `<tr><th align="left">Item</th><th align="right">Qty</th><th align="right">Unit price</th><th align="right">Amount</th></tr>` + rows + `</table>` + `<table width="100%" cellpadding="4">${summary.map(([label, value])=>`<tr><td align="right" width="80%">${label}</td><td align="right">${value}</td></tr>`).join('')}</table>` + (store.footer ? `<p>${escapeHtml(store.footer)}</p>` : '') + (store.termsUrl ? `<p><small>Terms: ${escapeHtml(store.termsUrl)}</small></p>` : '');
190
+ }))}<br/>` : ''}` + `Payment: ${escapeHtml(data.paymentStatus)}<br/>Currency: ${escapeHtml(data.currency)}</p>` + `<table width="100%" cellpadding="6"><tr>${block('Bill to', data.billTo)}${block('Ship to', data.shipTo)}</tr></table>` + `<table width="100%" cellpadding="6" border="1" cellspacing="0">` + `<tr><th align="left">Item</th><th align="right">Qty</th><th align="right">Unit price</th><th align="right">Amount</th></tr>` + rows + `</table>` + `<table width="100%" cellpadding="4">${summary.map(([label, value])=>`<tr><td align="right" width="80%">${label}</td><td align="right">${value}</td></tr>`).join('')}</table>` + (store.footer ? `<p>${escapeHtml(store.footer)}</p>` : '') + (store.termsUrl ? `<p><small>Terms: ${escapeHtml(store.termsUrl)}</small></p>` : '');
139
191
  }
140
192
 
141
193
  //# sourceMappingURL=order-invoice.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/utils/order-invoice.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n formatOrderNumber,\n orderCreatedAtMs,\n type HostOrder,\n type OrderAddress,\n} from '../model/commerce-orders'\nimport { escapeHtml } from './escape-html'\n\n/**\n * The printable invoice (AGL-3611), beside the packing slip: the order as a\n * bill — who sold it, to whom, each line with its unit price, the totals,\n * what was refunded and what was paid in the end.\n *\n * A string of markup, because it is written into a print popup the way the\n * packing slip is, and the browser's print dialog saves it as a PDF. Every\n * value is escaped: the addresses are typed by the shopper, and the popup\n * inherits the console's origin (AGL-2283). No `<style>` and no `style`\n * attributes, because the popup inherits the console's content security\n * policy; the layout is the table attributes HTML still honors.\n */\n\nexport interface OrderInvoiceStore {\n /** The business's name, as its emails sign. */\n name: string\n /** The store's currency, for an order that does not carry its own. */\n currency: string\n /** The receipt footer the store set, printed at the foot. */\n footer?: string | null\n /** The store's terms address, printed at the foot. */\n termsUrl?: string | null\n}\n\n/**\n * The invoice's store from the site's document and its store settings, as\n * the order dialog's Invoice button and `commerce/order-print` read them.\n */\nexport function invoiceStoreFrom(\n host: Record<string, unknown> | undefined | null,\n store: Record<string, unknown> | undefined | null,\n): OrderInvoiceStore {\n const hostData = host ?? {}\n const storeData = store ?? {}\n return {\n name: String(hostData['businessName'] ?? hostData['displayName'] ?? hostData['name'] ?? ''),\n currency: String(storeData['currency'] ?? 'USD'),\n footer: (storeData['receiptFooter'] as string | undefined) ?? null,\n termsUrl: (storeData['termsUrl'] as string | undefined) ?? null,\n }\n}\n\ntype InvoiceOrder = Pick<\n HostOrder,\n | 'number'\n | 'status'\n | 'lineItems'\n | 'totals'\n | 'refundedCents'\n | 'customerName'\n | 'customerEmail'\n | 'shippingAddress'\n | 'billingAddress'\n> & { createdAtMs?: number; currency?: string; amountCents?: number }\n\n/** Money in the order's currency, integer cents in. */\nexport function invoiceMoney(cents: number, currency: string): string {\n const amount = (Number(cents) || 0) / 100\n try {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency || 'USD' }).format(amount)\n } catch {\n return `${amount.toFixed(2)} ${String(currency || '').toUpperCase()}`.trim()\n }\n}\n\nfunction addressLines(address: OrderAddress | undefined | null): string[] {\n if (!address) return []\n return [\n address.name,\n address.line1,\n address.line2,\n [address.city, address.state, address.postalCode].filter(Boolean).join(' '),\n address.country,\n address.phone,\n ]\n .map((part) => String(part ?? '').trim())\n .filter(Boolean)\n}\n\n/** What the payment line says. */\nexport function invoicePaymentStatus(order: Pick<InvoiceOrder, 'status' | 'refundedCents' | 'totals' | 'amountCents'>): string {\n const total = Number(order.totals?.totalCents ?? order.amountCents ?? 0)\n const refunded = Math.max(0, Number(order.refundedCents ?? 0))\n const status = String(order.status ?? '')\n if (status === 'pending' || status === 'draft') return 'Awaiting payment'\n if (status === 'cancelled') return 'Canceled'\n if (refunded > 0 && refunded >= total) return 'Refunded'\n if (refunded > 0) return 'Paid, partially refunded'\n return 'Paid'\n}\n\n/** The invoice's markup: a full document body, every value escaped. */\nexport function buildOrderInvoiceHtml(input: {\n order: InvoiceOrder\n orderId: string\n store: OrderInvoiceStore\n}): string {\n const { order, orderId, store } = input\n const currency = String(order.currency || store.currency || 'USD').toUpperCase()\n const money = (cents: number) => escapeHtml(invoiceMoney(cents, currency))\n const number = formatOrderNumber(order, orderId)\n const createdAt = orderCreatedAtMs(order as never)\n const totals = order.totals\n const itemsCents =\n totals?.itemsCents ??\n (order.lineItems ?? []).reduce((sum, line) => sum + Number(line.unitAmountCents || 0) * Number(line.quantity || 0), 0)\n const totalCents = Number(totals?.totalCents ?? order.amountCents ?? itemsCents)\n const refundedCents = Math.max(0, Number(order.refundedCents ?? 0))\n\n const billTo = [\n ...(order.billingAddress ? addressLines(order.billingAddress) : [order.customerName ?? ''].filter(Boolean)),\n order.customerEmail ?? '',\n ].filter(Boolean)\n const shipTo = addressLines(order.shippingAddress)\n\n const rows = (order.lineItems ?? [])\n .map((line) => {\n const quantity = Number(line.quantity) || 0\n const unit = Number(line.unitAmountCents) || 0\n const detail = [line.variantLabel ? escapeHtml(line.variantLabel) : '', line.sku ? `SKU ${escapeHtml(line.sku)}` : '']\n .filter(Boolean)\n .join(' · ')\n return (\n `<tr><td>${escapeHtml(line.name)}${detail ? `<br/><small>${detail}</small>` : ''}</td>` +\n `<td align=\"right\">${escapeHtml(quantity)}</td>` +\n `<td align=\"right\">${money(unit)}</td>` +\n `<td align=\"right\">${money(unit * quantity)}</td></tr>`\n )\n })\n .join('')\n\n const summary: Array<[string, string]> = [['Subtotal', money(itemsCents)]]\n if (Number(totals?.discountCents ?? 0) > 0) summary.push(['Discount', `−${money(Number(totals?.discountCents))}`])\n if (Number(totals?.shippingCents ?? 0) > 0) summary.push(['Shipping', money(Number(totals?.shippingCents))])\n if (Number(totals?.taxCents ?? 0) > 0) summary.push(['Tax', money(Number(totals?.taxCents))])\n summary.push(['<b>Total</b>', `<b>${money(totalCents)}</b>`])\n if (Number(totals?.tipCents ?? 0) > 0) summary.push(['Tip', money(Number(totals?.tipCents))])\n if (refundedCents > 0) {\n summary.push(['Refunded', `−${money(refundedCents)}`])\n summary.push(['<b>Net paid</b>', `<b>${money(Math.max(0, totalCents - refundedCents))}</b>`])\n }\n\n const block = (title: string, lines: string[]) =>\n lines.length ? `<td valign=\"top\"><b>${title}</b><br/>${lines.map((line) => escapeHtml(line)).join('<br/>')}</td>` : ''\n\n return (\n `<title>${escapeHtml(`Invoice ${number}`)}</title>` +\n `<h2>${escapeHtml(store.name || 'Invoice')}</h2>` +\n `<h3>${escapeHtml(`Invoice ${number}`)}</h3>` +\n `<p>${createdAt ? `Date: ${escapeHtml(new Date(createdAt).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }))}<br/>` : ''}` +\n `Payment: ${escapeHtml(invoicePaymentStatus(order))}<br/>Currency: ${escapeHtml(currency)}</p>` +\n `<table width=\"100%\" cellpadding=\"6\"><tr>${block('Bill to', billTo)}${block('Ship to', shipTo)}</tr></table>` +\n `<table width=\"100%\" cellpadding=\"6\" border=\"1\" cellspacing=\"0\">` +\n `<tr><th align=\"left\">Item</th><th align=\"right\">Qty</th><th align=\"right\">Unit price</th><th align=\"right\">Amount</th></tr>` +\n rows +\n `</table>` +\n `<table width=\"100%\" cellpadding=\"4\">${summary\n .map(([label, value]) => `<tr><td align=\"right\" width=\"80%\">${label}</td><td align=\"right\">${value}</td></tr>`)\n .join('')}</table>` +\n (store.footer ? `<p>${escapeHtml(store.footer)}</p>` : '') +\n (store.termsUrl ? `<p><small>Terms: ${escapeHtml(store.termsUrl)}</small></p>` : '')\n )\n}\n"],"names":["formatOrderNumber","orderCreatedAtMs","escapeHtml","invoiceStoreFrom","host","store","hostData","storeData","name","String","currency","footer","termsUrl","invoiceMoney","cents","amount","Number","Intl","NumberFormat","style","format","toFixed","toUpperCase","trim","addressLines","address","line1","line2","city","state","postalCode","filter","Boolean","join","country","phone","map","part","invoicePaymentStatus","order","total","totals","totalCents","amountCents","refunded","Math","max","refundedCents","status","buildOrderInvoiceHtml","input","orderId","money","number","createdAt","itemsCents","lineItems","reduce","sum","line","unitAmountCents","quantity","billTo","billingAddress","customerName","customerEmail","shipTo","shippingAddress","rows","unit","detail","variantLabel","sku","summary","discountCents","push","shippingCents","taxCents","tipCents","block","title","lines","length","Date","toLocaleDateString","year","month","day","label","value"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/commerce/src/lib/utils/order-invoice.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n formatOrderNumber,\n orderCreatedAtMs,\n type HostOrder,\n type OrderAddress,\n} from '../model/commerce-orders'\nimport { escapeHtml } from './escape-html'\n\n/**\n * The printable invoice (AGL-3611), beside the packing slip: the order as a\n * bill — who sold it, to whom, each line with its unit price, the totals,\n * what was refunded and what was paid in the end.\n *\n * A string of markup, because it is written into a print popup the way the\n * packing slip is, and the browser's print dialog saves it as a PDF. Every\n * value is escaped: the addresses are typed by the shopper, and the popup\n * inherits the console's origin (AGL-2283). No `<style>` and no `style`\n * attributes, because the popup inherits the console's content security\n * policy; the layout is the table attributes HTML still honors.\n */\n\nexport interface OrderInvoiceStore {\n /** The business's name, as its emails sign. */\n name: string\n /** The store's currency, for an order that does not carry its own. */\n currency: string\n /** The receipt footer the store set, printed at the foot. */\n footer?: string | null\n /** The store's terms address, printed at the foot. */\n termsUrl?: string | null\n}\n\n/**\n * The invoice's store from the site's document and its store settings, as\n * the order dialog's Invoice button and `commerce/order-print` read them.\n */\nexport function invoiceStoreFrom(\n host: Record<string, unknown> | undefined | null,\n store: Record<string, unknown> | undefined | null,\n): OrderInvoiceStore {\n const hostData = host ?? {}\n const storeData = store ?? {}\n return {\n name: String(hostData['businessName'] ?? hostData['displayName'] ?? hostData['name'] ?? ''),\n currency: String(storeData['currency'] ?? 'USD'),\n footer: (storeData['receiptFooter'] as string | undefined) ?? null,\n termsUrl: (storeData['termsUrl'] as string | undefined) ?? null,\n }\n}\n\nexport type InvoiceOrder = Pick<\n HostOrder,\n | 'number'\n | 'status'\n | 'lineItems'\n | 'totals'\n | 'refundedCents'\n | 'customerName'\n | 'customerEmail'\n | 'shippingAddress'\n | 'billingAddress'\n> & { createdAtMs?: number; currency?: string; amountCents?: number }\n\n/** Money in the order's currency, integer cents in. */\nexport function invoiceMoney(cents: number, currency: string): string {\n const amount = (Number(cents) || 0) / 100\n try {\n return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency || 'USD' }).format(amount)\n } catch {\n return `${amount.toFixed(2)} ${String(currency || '').toUpperCase()}`.trim()\n }\n}\n\n/** The United States, however an address names it: left off, as a US envelope does. */\nconst US_COUNTRY = /^(us|usa|u\\.s\\.a?\\.?|united states( of america)?)$/i\n\n/**\n * An address as lines, the American way: name, street, `City, ST 12345`,\n * the country unless it is the United States, then the phone when the\n * address carries one and it is wanted.\n */\nexport function invoiceAddressLines(\n address: Partial<OrderAddress> | undefined | null,\n options: { phone?: boolean } = {},\n): string[] {\n if (!address) return []\n const clean = (part: unknown) => String(part ?? '').trim()\n const region = [clean(address.state), clean(address.postalCode)].filter(Boolean).join(' ')\n return [\n clean(address.name),\n clean(address.line1),\n clean(address.line2),\n [clean(address.city), region].filter(Boolean).join(', '),\n US_COUNTRY.test(clean(address.country)) ? '' : clean(address.country),\n options.phone === false ? '' : clean(address.phone),\n ].filter(Boolean)\n}\n\nconst addressLines = (address: OrderAddress | undefined | null) => invoiceAddressLines(address)\n\n/** What the payment line says. */\nexport function invoicePaymentStatus(order: Pick<InvoiceOrder, 'status' | 'refundedCents' | 'totals' | 'amountCents'>): string {\n const total = Number(order.totals?.totalCents ?? order.amountCents ?? 0)\n const refunded = Math.max(0, Number(order.refundedCents ?? 0))\n const status = String(order.status ?? '')\n if (status === 'pending' || status === 'draft') return 'Awaiting payment'\n if (status === 'cancelled') return 'Canceled'\n if (refunded > 0 && refunded >= total) return 'Refunded'\n if (refunded > 0) return 'Paid, partially refunded'\n return 'Paid'\n}\n\n/** One line of an invoice, as both the printed page and the PDF set it. */\nexport interface InvoiceLine {\n name: string\n /** The option chosen and the SKU, as one line under the name. */\n detail: string\n /** A typed line's own description. */\n description: string\n quantity: number\n unitCents: number\n amountCents: number\n /** Included at no charge. */\n included: boolean\n}\n\n/** One row of an invoice's summary: a figure, or a deduction printed with a minus. */\nexport interface InvoiceSummaryRow {\n label: string\n cents: number\n minus?: boolean\n /** The row the summary leads to: the total, or what was paid after refunds. */\n emphasis?: boolean\n}\n\n/** An invoice's content, worked out once for the printed page and the PDF. */\nexport interface OrderInvoiceData {\n /** `#1042`. */\n number: string\n /** When the order was placed; 0 when it does not say. */\n dateMs: number\n currency: string\n paymentStatus: string\n billTo: string[]\n shipTo: string[]\n lines: InvoiceLine[]\n summary: InvoiceSummaryRow[]\n footer: string\n termsUrl: string\n}\n\n/** What an invoice says, from the order and its store. */\nexport function buildOrderInvoiceData(input: {\n order: InvoiceOrder\n orderId: string\n store: OrderInvoiceStore\n}): OrderInvoiceData {\n const { order, orderId, store } = input\n const currency = String(order.currency || store.currency || 'USD').toUpperCase()\n const totals = order.totals\n const itemsCents =\n totals?.itemsCents ??\n (order.lineItems ?? []).reduce((sum, line) => sum + Number(line.unitAmountCents || 0) * Number(line.quantity || 0), 0)\n const totalCents = Number(totals?.totalCents ?? order.amountCents ?? itemsCents)\n const refundedCents = Math.max(0, Number(order.refundedCents ?? 0))\n\n const lines = (order.lineItems ?? []).map((line): InvoiceLine => {\n const quantity = Number(line.quantity) || 0\n const unit = Number(line.unitAmountCents) || 0\n return {\n name: String(line.name ?? ''),\n detail: [line.variantLabel ? String(line.variantLabel) : '', line.sku ? `SKU ${line.sku}` : ''].filter(Boolean).join(' · '),\n description: String(line.description ?? '').trim(),\n quantity,\n unitCents: unit,\n amountCents: unit * quantity,\n included: line.included === true,\n }\n })\n\n const summary: InvoiceSummaryRow[] = [{ label: 'Subtotal', cents: itemsCents }]\n if (Number(totals?.discountCents ?? 0) > 0) summary.push({ label: 'Discount', cents: Number(totals?.discountCents), minus: true })\n if (Number(totals?.shippingCents ?? 0) > 0) summary.push({ label: 'Shipping', cents: Number(totals?.shippingCents) })\n if (Number(totals?.taxCents ?? 0) > 0) summary.push({ label: 'Tax', cents: Number(totals?.taxCents) })\n summary.push({ label: 'Total', cents: totalCents, emphasis: true })\n if (Number(totals?.tipCents ?? 0) > 0) summary.push({ label: 'Tip', cents: Number(totals?.tipCents) })\n if (refundedCents > 0) {\n summary.push({ label: 'Refunded', cents: refundedCents, minus: true })\n summary.push({ label: 'Net paid', cents: Math.max(0, totalCents - refundedCents), emphasis: true })\n }\n\n return {\n number: formatOrderNumber(order, orderId),\n dateMs: orderCreatedAtMs(order as never),\n currency,\n paymentStatus: invoicePaymentStatus(order),\n billTo: [\n ...(order.billingAddress ? addressLines(order.billingAddress) : [order.customerName ?? ''].filter(Boolean)),\n order.customerEmail ?? '',\n ].filter(Boolean),\n shipTo: addressLines(order.shippingAddress),\n lines,\n summary,\n footer: String(store.footer ?? '').trim(),\n termsUrl: String(store.termsUrl ?? '').trim(),\n }\n}\n\n/** The invoice's markup: a full document body, every value escaped. */\nexport function buildOrderInvoiceHtml(input: {\n order: InvoiceOrder\n orderId: string\n store: OrderInvoiceStore\n}): string {\n const data = buildOrderInvoiceData(input)\n const { store } = input\n const money = (cents: number) => escapeHtml(invoiceMoney(cents, data.currency))\n const number = data.number\n\n const rows = data.lines\n .map((line) => {\n const detail = [line.detail, line.description].filter(Boolean).map((part) => escapeHtml(part)).join('<br/>')\n return (\n `<tr><td>${escapeHtml(line.name)}${detail ? `<br/><small>${detail}</small>` : ''}</td>` +\n `<td align=\"right\">${escapeHtml(line.quantity)}</td>` +\n `<td align=\"right\">${line.included ? '' : money(line.unitCents)}</td>` +\n `<td align=\"right\">${line.included ? 'Included' : money(line.amountCents)}</td></tr>`\n )\n })\n .join('')\n\n const summary = data.summary.map(({ label, cents, minus, emphasis }): [string, string] => {\n const figure = `${minus ? '−' : ''}${money(cents)}`\n return emphasis ? [`<b>${label}</b>`, `<b>${figure}</b>`] : [label, figure]\n })\n\n const block = (title: string, lines: string[]) =>\n lines.length ? `<td valign=\"top\"><b>${title}</b><br/>${lines.map((line) => escapeHtml(line)).join('<br/>')}</td>` : ''\n\n return (\n `<title>${escapeHtml(`Invoice ${number}`)}</title>` +\n `<h2>${escapeHtml(store.name || 'Invoice')}</h2>` +\n `<h3>${escapeHtml(`Invoice ${number}`)}</h3>` +\n `<p>${data.dateMs ? `Date: ${escapeHtml(new Date(data.dateMs).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }))}<br/>` : ''}` +\n `Payment: ${escapeHtml(data.paymentStatus)}<br/>Currency: ${escapeHtml(data.currency)}</p>` +\n `<table width=\"100%\" cellpadding=\"6\"><tr>${block('Bill to', data.billTo)}${block('Ship to', data.shipTo)}</tr></table>` +\n `<table width=\"100%\" cellpadding=\"6\" border=\"1\" cellspacing=\"0\">` +\n `<tr><th align=\"left\">Item</th><th align=\"right\">Qty</th><th align=\"right\">Unit price</th><th align=\"right\">Amount</th></tr>` +\n rows +\n `</table>` +\n `<table width=\"100%\" cellpadding=\"4\">${summary\n .map(([label, value]) => `<tr><td align=\"right\" width=\"80%\">${label}</td><td align=\"right\">${value}</td></tr>`)\n .join('')}</table>` +\n (store.footer ? `<p>${escapeHtml(store.footer)}</p>` : '') +\n (store.termsUrl ? `<p><small>Terms: ${escapeHtml(store.termsUrl)}</small></p>` : '')\n )\n}\n"],"names":["formatOrderNumber","orderCreatedAtMs","escapeHtml","invoiceStoreFrom","host","store","hostData","storeData","name","String","currency","footer","termsUrl","invoiceMoney","cents","amount","Number","Intl","NumberFormat","style","format","toFixed","toUpperCase","trim","US_COUNTRY","invoiceAddressLines","address","options","clean","part","region","state","postalCode","filter","Boolean","join","line1","line2","city","test","country","phone","addressLines","invoicePaymentStatus","order","total","totals","totalCents","amountCents","refunded","Math","max","refundedCents","status","buildOrderInvoiceData","input","orderId","itemsCents","lineItems","reduce","sum","line","unitAmountCents","quantity","lines","map","unit","detail","variantLabel","sku","description","unitCents","included","summary","label","discountCents","push","minus","shippingCents","taxCents","emphasis","tipCents","number","dateMs","paymentStatus","billTo","billingAddress","customerName","customerEmail","shipTo","shippingAddress","buildOrderInvoiceHtml","data","money","rows","figure","block","title","length","Date","toLocaleDateString","year","month","day","value"],"mappings":"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"}