@teleporthq/teleport-plugin-next-workflows 0.44.0 → 0.44.1
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.
- package/__tests__/_helpers/fake-store-database.ts +428 -0
- package/__tests__/_helpers/invoice-store.ts +382 -0
- package/__tests__/email-locale-senders.test.ts +3 -1
- package/__tests__/email-sender-name.test.ts +513 -0
- package/__tests__/graph-utils-topological-order.test.ts +155 -1
- package/__tests__/invoice-billing-details.test.ts +107 -1
- package/__tests__/invoice-data-access-replace.test.ts +236 -2
- package/__tests__/invoice-order-items-settle.test.ts +1 -1
- package/__tests__/invoice-payment-email.test.ts +191 -0
- package/__tests__/invoice-regenerate-email.test.ts +288 -0
- package/__tests__/invoice-regenerate-route.test.ts +9 -7
- package/__tests__/invoice-reservation.test.ts +1 -1
- package/__tests__/invoice-tender.test.ts +1 -1
- package/__tests__/segment-splitter-checkout-order.test.ts +306 -0
- package/__tests__/streaming-on-end-env-filter.test.ts +18 -18
- package/__tests__/streaming-on-end-order.test.ts +387 -0
- package/dist/cjs/account-delete-route-generator.d.ts +1 -0
- package/dist/cjs/account-delete-route-generator.d.ts.map +1 -1
- package/dist/cjs/account-delete-route-generator.js +2 -1
- package/dist/cjs/account-delete-route-generator.js.map +1 -1
- package/dist/cjs/auth-generator.d.ts +1 -0
- package/dist/cjs/auth-generator.d.ts.map +1 -1
- package/dist/cjs/auth-generator.js +2 -1
- package/dist/cjs/auth-generator.js.map +1 -1
- package/dist/cjs/executor-generator.d.ts.map +1 -1
- package/dist/cjs/executor-generator.js +9 -26
- package/dist/cjs/executor-generator.js.map +1 -1
- package/dist/cjs/graph-utils.d.ts +31 -1
- package/dist/cjs/graph-utils.d.ts.map +1 -1
- package/dist/cjs/graph-utils.js +112 -10
- package/dist/cjs/graph-utils.js.map +1 -1
- package/dist/cjs/invoice/api-routes-code.d.ts +12 -3
- package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/cjs/invoice/api-routes-code.js +152 -21
- package/dist/cjs/invoice/api-routes-code.js.map +1 -1
- package/dist/cjs/invoice/data-access-code.d.ts.map +1 -1
- package/dist/cjs/invoice/data-access-code.js +133 -21
- package/dist/cjs/invoice/data-access-code.js.map +1 -1
- package/dist/cjs/invoice/email-sender-code.d.ts.map +1 -1
- package/dist/cjs/invoice/email-sender-code.js +15 -25
- package/dist/cjs/invoice/email-sender-code.js.map +1 -1
- package/dist/cjs/invoice/index.js +1 -1
- package/dist/cjs/invoice/index.js.map +1 -1
- package/dist/cjs/invoice/invoice-assembly-code.d.ts.map +1 -1
- package/dist/cjs/invoice/invoice-assembly-code.js +10 -6
- package/dist/cjs/invoice/invoice-assembly-code.js.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/cjs/invoice/invoice-html-code.js +3 -0
- package/dist/cjs/invoice/invoice-html-code.js.map +1 -1
- package/dist/cjs/nodes/email/email-mailgun.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-mailgun.js +4 -2
- package/dist/cjs/nodes/email/email-mailgun.js.map +1 -1
- package/dist/cjs/nodes/email/email-postmark.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-postmark.js +5 -2
- package/dist/cjs/nodes/email/email-postmark.js.map +1 -1
- package/dist/cjs/nodes/email/email-resend.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-resend.js +5 -2
- package/dist/cjs/nodes/email/email-resend.js.map +1 -1
- package/dist/cjs/nodes/email/email-sendgrid.d.ts.map +1 -1
- package/dist/cjs/nodes/email/email-sendgrid.js +8 -2
- package/dist/cjs/nodes/email/email-sendgrid.js.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-remove.d.ts.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-remove.js +2 -0
- package/dist/cjs/nodes/storage/storage-local-remove.js.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-set.d.ts.map +1 -1
- package/dist/cjs/nodes/storage/storage-local-set.js +4 -0
- package/dist/cjs/nodes/storage/storage-local-set.js.map +1 -1
- package/dist/cjs/segment-splitter.d.ts.map +1 -1
- package/dist/cjs/segment-splitter.js +65 -27
- package/dist/cjs/segment-splitter.js.map +1 -1
- package/dist/cjs/transactional-email-code.d.ts.map +1 -1
- package/dist/cjs/transactional-email-code.js +32 -18
- package/dist/cjs/transactional-email-code.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
- package/dist/cjs/workflow-project-plugin.js +2 -0
- package/dist/cjs/workflow-project-plugin.js.map +1 -1
- package/dist/esm/account-delete-route-generator.d.ts +1 -0
- package/dist/esm/account-delete-route-generator.d.ts.map +1 -1
- package/dist/esm/account-delete-route-generator.js +2 -1
- package/dist/esm/account-delete-route-generator.js.map +1 -1
- package/dist/esm/auth-generator.d.ts +1 -0
- package/dist/esm/auth-generator.d.ts.map +1 -1
- package/dist/esm/auth-generator.js +2 -1
- package/dist/esm/auth-generator.js.map +1 -1
- package/dist/esm/executor-generator.d.ts.map +1 -1
- package/dist/esm/executor-generator.js +9 -26
- package/dist/esm/executor-generator.js.map +1 -1
- package/dist/esm/graph-utils.d.ts +31 -1
- package/dist/esm/graph-utils.d.ts.map +1 -1
- package/dist/esm/graph-utils.js +109 -9
- package/dist/esm/graph-utils.js.map +1 -1
- package/dist/esm/invoice/api-routes-code.d.ts +12 -3
- package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
- package/dist/esm/invoice/api-routes-code.js +152 -21
- package/dist/esm/invoice/api-routes-code.js.map +1 -1
- package/dist/esm/invoice/data-access-code.d.ts.map +1 -1
- package/dist/esm/invoice/data-access-code.js +133 -21
- package/dist/esm/invoice/data-access-code.js.map +1 -1
- package/dist/esm/invoice/email-sender-code.d.ts.map +1 -1
- package/dist/esm/invoice/email-sender-code.js +15 -25
- package/dist/esm/invoice/email-sender-code.js.map +1 -1
- package/dist/esm/invoice/index.js +1 -1
- package/dist/esm/invoice/index.js.map +1 -1
- package/dist/esm/invoice/invoice-assembly-code.d.ts.map +1 -1
- package/dist/esm/invoice/invoice-assembly-code.js +10 -6
- package/dist/esm/invoice/invoice-assembly-code.js.map +1 -1
- package/dist/esm/invoice/invoice-html-code.d.ts.map +1 -1
- package/dist/esm/invoice/invoice-html-code.js +3 -0
- package/dist/esm/invoice/invoice-html-code.js.map +1 -1
- package/dist/esm/nodes/email/email-mailgun.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-mailgun.js +4 -2
- package/dist/esm/nodes/email/email-mailgun.js.map +1 -1
- package/dist/esm/nodes/email/email-postmark.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-postmark.js +5 -2
- package/dist/esm/nodes/email/email-postmark.js.map +1 -1
- package/dist/esm/nodes/email/email-resend.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-resend.js +5 -2
- package/dist/esm/nodes/email/email-resend.js.map +1 -1
- package/dist/esm/nodes/email/email-sendgrid.d.ts.map +1 -1
- package/dist/esm/nodes/email/email-sendgrid.js +8 -2
- package/dist/esm/nodes/email/email-sendgrid.js.map +1 -1
- package/dist/esm/nodes/storage/storage-local-remove.d.ts.map +1 -1
- package/dist/esm/nodes/storage/storage-local-remove.js +2 -0
- package/dist/esm/nodes/storage/storage-local-remove.js.map +1 -1
- package/dist/esm/nodes/storage/storage-local-set.d.ts.map +1 -1
- package/dist/esm/nodes/storage/storage-local-set.js +4 -0
- package/dist/esm/nodes/storage/storage-local-set.js.map +1 -1
- package/dist/esm/segment-splitter.d.ts.map +1 -1
- package/dist/esm/segment-splitter.js +66 -28
- package/dist/esm/segment-splitter.js.map +1 -1
- package/dist/esm/transactional-email-code.d.ts.map +1 -1
- package/dist/esm/transactional-email-code.js +32 -18
- package/dist/esm/transactional-email-code.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
- package/dist/esm/workflow-project-plugin.js +2 -0
- package/dist/esm/workflow-project-plugin.js.map +1 -1
- package/package.json +3 -3
- package/src/account-delete-route-generator.ts +3 -1
- package/src/auth-generator.ts +3 -1
- package/src/executor-generator.ts +9 -26
- package/src/graph-utils.ts +143 -11
- package/src/invoice/api-routes-code.ts +166 -21
- package/src/invoice/data-access-code.ts +139 -21
- package/src/invoice/email-sender-code.ts +15 -25
- package/src/invoice/index.ts +1 -1
- package/src/invoice/invoice-assembly-code.ts +10 -6
- package/src/invoice/invoice-html-code.ts +3 -0
- package/src/nodes/email/email-mailgun.ts +11 -2
- package/src/nodes/email/email-postmark.ts +12 -2
- package/src/nodes/email/email-resend.ts +12 -2
- package/src/nodes/email/email-sendgrid.ts +15 -2
- package/src/nodes/storage/storage-local-remove.ts +4 -0
- package/src/nodes/storage/storage-local-set.ts +6 -0
- package/src/segment-splitter.ts +90 -36
- package/src/transactional-email-code.ts +32 -21
- package/src/workflow-project-plugin.ts +2 -0
|
@@ -56,6 +56,39 @@ async function invoiceCaller(req) {
|
|
|
56
56
|
userId: userId != null ? String(userId) : null,
|
|
57
57
|
};
|
|
58
58
|
}`;
|
|
59
|
+
/**
|
|
60
|
+
* The order-history line of an invoice email the provider accepted: an
|
|
61
|
+
* `order-email-sent` line of the email's purpose, keyed on the invoice, so the
|
|
62
|
+
* email is on its order's history once, whichever route sent it. The strings
|
|
63
|
+
* are data in the merchant's database, owned by teleport-gui's
|
|
64
|
+
* `order-event-types.ts` and `EmailTemplatePurpose.INVOICE_EMAIL`.
|
|
65
|
+
*/
|
|
66
|
+
const INVOICE_EMAIL_EVENT = { type: 'order-email-sent', purpose: 'invoice-email' };
|
|
67
|
+
/** Who sent an invoice email, as the order's history names them. */
|
|
68
|
+
const INVOICE_EMAIL_SENDERS = {
|
|
69
|
+
// The store's own code: the payment webhook's invoice step, the checkout.
|
|
70
|
+
store: { actor: '', actorType: 'system' },
|
|
71
|
+
// A signed-in admin: the admin panel's Regenerate, or an invoice issued by hand.
|
|
72
|
+
admin: { actor: 'Store admin', actorType: 'merchant' },
|
|
73
|
+
};
|
|
74
|
+
/** `recordInvoiceEmailSent(invoiceData, sender)`, as emitted source; needs `dataAccess`. */
|
|
75
|
+
const RECORD_INVOICE_EMAIL_CODE = `
|
|
76
|
+
var INVOICE_EMAIL_EVENT = ${JSON.stringify(INVOICE_EMAIL_EVENT)};
|
|
77
|
+
var INVOICE_EMAIL_SENDERS = ${JSON.stringify(INVOICE_EMAIL_SENDERS)};
|
|
78
|
+
|
|
79
|
+
// Writes the order's history line for an invoice email the provider accepted.
|
|
80
|
+
// The key is the invoice's, so the line is written once per invoice email.
|
|
81
|
+
async function recordInvoiceEmailSent(invoiceData, sender) {
|
|
82
|
+
if (!invoiceData.orderId) return;
|
|
83
|
+
await dataAccess.recordOrderEvent({
|
|
84
|
+
type: INVOICE_EMAIL_EVENT.type,
|
|
85
|
+
dedupeKey: INVOICE_EMAIL_EVENT.type + ':' + invoiceData.id + ':' + INVOICE_EMAIL_EVENT.purpose,
|
|
86
|
+
orderId: invoiceData.orderId,
|
|
87
|
+
payload: { purpose: INVOICE_EMAIL_EVENT.purpose, to: invoiceData.customerEmail },
|
|
88
|
+
actor: sender.actor,
|
|
89
|
+
actorType: sender.actorType,
|
|
90
|
+
});
|
|
91
|
+
}`;
|
|
59
92
|
const generateInvoiceGenerateRouteCode = (settings) => {
|
|
60
93
|
var _a;
|
|
61
94
|
const prefix = settings.invoicePrefix || 'INV-';
|
|
@@ -89,6 +122,7 @@ var INVOICE_PREFIX = ${JSON.stringify(prefix)};
|
|
|
89
122
|
var UNFINISHED_INVOICE_STALE_SECONDS = 900;
|
|
90
123
|
|
|
91
124
|
${INVOICE_CALLER_CODE}
|
|
125
|
+
${emailEnabled ? RECORD_INVOICE_EMAIL_CODE : ''}
|
|
92
126
|
|
|
93
127
|
// ---------------------------------------------------------------------------
|
|
94
128
|
// Waiting for the order's line items to be fully written.
|
|
@@ -124,6 +158,21 @@ function sleepMs(ms) {
|
|
|
124
158
|
return new Promise(function (resolve) { setTimeout(resolve, ms); });
|
|
125
159
|
}
|
|
126
160
|
|
|
161
|
+
// The answer for an invoice the order already has: its number and its PDF.
|
|
162
|
+
function issuedInvoiceAnswer(invoice, currency) {
|
|
163
|
+
var pdfUrl = invoice.pdf_url || ('/api/invoices/' + invoice.id + '/pdf');
|
|
164
|
+
return {
|
|
165
|
+
success: true,
|
|
166
|
+
alreadyIssued: true,
|
|
167
|
+
invoiceId: invoice.id,
|
|
168
|
+
invoiceNumber: invoice.invoice_number,
|
|
169
|
+
storageUrl: pdfUrl.indexOf('/api/invoices/') === 0 ? '' : pdfUrl,
|
|
170
|
+
pdfUrl: pdfUrl,
|
|
171
|
+
total: Number(invoice.total) || 0,
|
|
172
|
+
currency: invoice.currency || currency,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
127
176
|
async function hydrateOrderWhenSettled(orderId) {
|
|
128
177
|
var deadline = Date.now() + SETTLE_TIMEOUT_MS;
|
|
129
178
|
var lastCount = -1;
|
|
@@ -264,17 +313,7 @@ module.exports = async function handler(req, res) {
|
|
|
264
313
|
if (!reservation.created) {
|
|
265
314
|
if (Number(held.pdf_size_bytes) > 0) {
|
|
266
315
|
console.info('[invoice] Order ' + body.orderId + ' already has invoice ' + held.invoice_number + ' — returning it');
|
|
267
|
-
|
|
268
|
-
res.status(200).json({
|
|
269
|
-
success: true,
|
|
270
|
-
alreadyIssued: true,
|
|
271
|
-
invoiceId: held.id,
|
|
272
|
-
invoiceNumber: held.invoice_number,
|
|
273
|
-
storageUrl: heldPdfUrl.indexOf('/api/invoices/') === 0 ? '' : heldPdfUrl,
|
|
274
|
-
pdfUrl: heldPdfUrl,
|
|
275
|
-
total: Number(held.total) || 0,
|
|
276
|
-
currency: held.currency || currency,
|
|
277
|
-
});
|
|
316
|
+
res.status(200).json(issuedInvoiceAnswer(held, currency));
|
|
278
317
|
return;
|
|
279
318
|
}
|
|
280
319
|
// Reserved, never finished: another request is rendering it now, or the
|
|
@@ -308,7 +347,18 @@ ${emailEnabled
|
|
|
308
347
|
console.info('[invoice] PDF generated: ' + pdfBuffer.length + ' bytes for ' + invoiceData.invoiceNumber);
|
|
309
348
|
|
|
310
349
|
invoiceData.pdfUrl = '/api/invoices/' + invoiceData.id + '/pdf';
|
|
311
|
-
|
|
350
|
+
// The PDF is written only on an invoice that has none, and the invoice's
|
|
351
|
+
// first PDF is what its email is claimed by (see storeInvoicePdf). A
|
|
352
|
+
// regeneration that gave a reserved invoice its PDF while this request
|
|
353
|
+
// rendered it — a retried payment finishing a stale reservation — emailed
|
|
354
|
+
// the buyer itself, so this request answers with that invoice and sends
|
|
355
|
+
// nothing.
|
|
356
|
+
var stored = await dataAccess.storeInvoicePdf(invoiceData.id, pdfBuffer, invoiceData.pdfUrl);
|
|
357
|
+
if (!stored.firstPdf) {
|
|
358
|
+
console.info('[invoice] Invoice ' + invoiceNumber + ' was given its PDF by a regeneration meanwhile — returning it');
|
|
359
|
+
res.status(200).json(issuedInvoiceAnswer((await dataAccess.getInvoiceById(invoiceData.id)) || held, currency));
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
312
362
|
console.info('[invoice] PDF stored — teleport_invoices.id=' + invoiceData.id + ', number=' + invoiceData.invoiceNumber + ', pdf_size_bytes=' + pdfBuffer.length + ', items=' + items.length + ' (accessible at ' + invoiceData.pdfUrl + ')');
|
|
313
363
|
|
|
314
364
|
var safeFileName = String(invoiceNumber || invoiceData.id).replace(/[^a-zA-Z0-9._-]/g, '_') + '.pdf';
|
|
@@ -376,9 +426,11 @@ ${emailEnabled
|
|
|
376
426
|
${emailEnabled
|
|
377
427
|
? `
|
|
378
428
|
if (invoiceData.customerEmail) {
|
|
429
|
+
var emailed = false;
|
|
379
430
|
try {
|
|
380
431
|
var emailResult = await emailSender.sendInvoiceEmail(invoiceData, pdfBuffer);
|
|
381
|
-
|
|
432
|
+
emailed = !!(emailResult && emailResult.success);
|
|
433
|
+
if (emailed) {
|
|
382
434
|
console.info('[invoice] Email delivery OK — to=' + invoiceData.customerEmail + ', messageId=' + (emailResult.messageId || '(empty)'));
|
|
383
435
|
} else {
|
|
384
436
|
console.error('[invoice] Email delivery FAILED — to=' + invoiceData.customerEmail + ', error=' + (emailResult && emailResult.error ? emailResult.error : 'unknown'));
|
|
@@ -386,6 +438,13 @@ ${emailEnabled
|
|
|
386
438
|
} catch (emailErr) {
|
|
387
439
|
console.error('[invoice] Email delivery threw — to=' + invoiceData.customerEmail + ', error=' + (emailErr && emailErr.message ? emailErr.message : emailErr));
|
|
388
440
|
}
|
|
441
|
+
if (emailed) {
|
|
442
|
+
try {
|
|
443
|
+
await recordInvoiceEmailSent(invoiceData, caller.admin ? INVOICE_EMAIL_SENDERS.admin : INVOICE_EMAIL_SENDERS.store);
|
|
444
|
+
} catch (recordErr) {
|
|
445
|
+
console.error('[invoice] Invoice ' + invoiceNumber + ' was emailed, but the order history could not record it — ' + (recordErr && recordErr.message));
|
|
446
|
+
}
|
|
447
|
+
}
|
|
389
448
|
} else {
|
|
390
449
|
console.info('[invoice] Skipping email delivery — invoiceData.customerEmail is empty. (Check teleport_orders.billing_email for order ' + (body.orderId || '(no orderId)') + ')');
|
|
391
450
|
}
|
|
@@ -440,6 +499,36 @@ ${emailEnabled
|
|
|
440
499
|
exports.generateInvoiceGenerateRouteCode = generateInvoiceGenerateRouteCode;
|
|
441
500
|
/** The roles allowed to rebuild an invoice (the admin panel is the only caller). */
|
|
442
501
|
const REGENERATE_INVOICE_ROLES = INVOICE_ADMIN_ROLES;
|
|
502
|
+
/** The regenerate route's `emailFirstInvoice`, as emitted source. */
|
|
503
|
+
const generateFirstInvoiceEmailCode = () => `${RECORD_INVOICE_EMAIL_CODE}
|
|
504
|
+
|
|
505
|
+
var REGENERATE_SOURCE_REF = 'api/invoices/[id]/regenerate';
|
|
506
|
+
|
|
507
|
+
// The invoice email the payment would have sent: the same sender, template,
|
|
508
|
+
// attachment and link, in the buyer's language — the one stamped on the order
|
|
509
|
+
// at checkout, else the store's main language, never the language of this
|
|
510
|
+
// request, which is the merchant's. The sender records it in the sent-email
|
|
511
|
+
// ledger; the order's history records it once the provider accepted it. A
|
|
512
|
+
// failure is logged and goes no further: the merchant has the PDF either way.
|
|
513
|
+
async function emailFirstInvoice(invoiceData, pdfBuffer, order) {
|
|
514
|
+
if (!invoiceData.customerEmail) return;
|
|
515
|
+
invoiceData.locale = emailLocale.normalizeEmailLocale(order && order.locale) || emailLocale.DEFAULT_EMAIL_LOCALE;
|
|
516
|
+
try {
|
|
517
|
+
var sent = await emailSender.sendInvoiceEmail(invoiceData, pdfBuffer, REGENERATE_SOURCE_REF);
|
|
518
|
+
if (!sent || !sent.success) {
|
|
519
|
+
throw new Error((sent && sent.error) || 'the email provider did not accept it');
|
|
520
|
+
}
|
|
521
|
+
} catch (sendErr) {
|
|
522
|
+
console.error('[invoice] Regenerate: invoice ' + invoiceData.invoiceNumber + ' could not be emailed to its customer — ' + (sendErr && sendErr.message));
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
await recordInvoiceEmailSent(invoiceData, INVOICE_EMAIL_SENDERS.admin);
|
|
527
|
+
} catch (recordErr) {
|
|
528
|
+
console.error('[invoice] Regenerate: invoice ' + invoiceData.invoiceNumber + ' was emailed, but the order history could not record it — ' + (recordErr && recordErr.message));
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
`;
|
|
443
532
|
/**
|
|
444
533
|
* POST /api/invoices/[id]/regenerate — the admin panel's "Regenerate" action.
|
|
445
534
|
*
|
|
@@ -449,23 +538,43 @@ const REGENERATE_INVOICE_ROLES = INVOICE_ADMIN_ROLES;
|
|
|
449
538
|
* against it keep pointing at a valid invoice. What a merchant corrected on the
|
|
450
539
|
* invoice itself (customer details, notes, payment method) wins over the order;
|
|
451
540
|
* the lines and every figure are recomputed from the order. The old PDF is
|
|
452
|
-
* replaced — and its runtime-storage copy deleted
|
|
453
|
-
*
|
|
541
|
+
* replaced — and its runtime-storage copy deleted.
|
|
542
|
+
*
|
|
543
|
+
* The customer is emailed once: by the regeneration that gives an invoice its
|
|
544
|
+
* FIRST PDF — one whose PDF failed at payment, so the payment's invoice email
|
|
545
|
+
* never went out — and only when the store emails invoices (Invoice Email
|
|
546
|
+
* Delivery). It is the payment's email: the same sender, template, attachment,
|
|
547
|
+
* link and language, recorded in the sent-email ledger and on the order's
|
|
548
|
+
* history. Which write gives the first PDF, the database decides (see
|
|
549
|
+
* `replaceInvoice` and `storeInvoicePdf`), so a second regeneration, a double
|
|
550
|
+
* click, two requests at once or a retried payment finishing the same invoice
|
|
551
|
+
* never send it again; a failed send costs the merchant nothing.
|
|
454
552
|
*
|
|
455
553
|
* Unlike `/generate`, which the payment webhook calls server-to-server, this
|
|
456
554
|
* route is reached from the merchant's browser only, so it checks the session
|
|
457
555
|
* itself: signed in, with an admin role.
|
|
458
556
|
*/
|
|
459
|
-
const generateInvoiceRegenerateRouteCode = () => {
|
|
557
|
+
const generateInvoiceRegenerateRouteCode = (settings) => {
|
|
558
|
+
var _a;
|
|
559
|
+
const emailEnabled = ((_a = settings.emailDelivery) === null || _a === void 0 ? void 0 : _a.enabled) === true;
|
|
460
560
|
return `/**
|
|
461
561
|
* POST /api/invoices/[id]/regenerate
|
|
462
562
|
* Rebuilds one invoice from its order, in place, for the admin panel. Same
|
|
463
|
-
* number, id and dates; a freshly rendered PDF replaces the old one
|
|
563
|
+
* number, id and dates; a freshly rendered PDF replaces the old one.${emailEnabled
|
|
564
|
+
? `
|
|
565
|
+
* The first PDF an invoice ever gets is emailed to its customer, once.`
|
|
566
|
+
: `
|
|
567
|
+
* No email: this store does not email invoices.`}
|
|
464
568
|
*/
|
|
465
569
|
|
|
466
570
|
var dataAccess = require('../../../../utils/invoices/data-access');
|
|
467
571
|
var pdfGenerator = require('../../../../utils/invoices/pdf-generator');
|
|
468
572
|
var invoiceAssembly = require('../../../../utils/invoices/invoice-assembly');
|
|
573
|
+
${emailEnabled
|
|
574
|
+
? `var emailSender = require('../../../../utils/invoices/email-sender');
|
|
575
|
+
var sentEmailLog = require('../../../../utils/email/sent-email-log');
|
|
576
|
+
var emailLocale = require('../../../../utils/email/email-locale');`
|
|
577
|
+
: ''}
|
|
469
578
|
|
|
470
579
|
${(0, session_cookie_resolver_1.generateCommonJsSessionTokenResolverCode)()}
|
|
471
580
|
${workflow_auth_generator_1.ROLE_OF_TOKEN_CODE}
|
|
@@ -551,7 +660,7 @@ async function findInvoice(invoiceId) {
|
|
|
551
660
|
throw err;
|
|
552
661
|
}
|
|
553
662
|
}
|
|
554
|
-
|
|
663
|
+
${emailEnabled ? generateFirstInvoiceEmailCode() : ''}
|
|
555
664
|
module.exports = async function handler(req, res) {
|
|
556
665
|
if (req.method !== 'POST') {
|
|
557
666
|
res.setHeader('Allow', 'POST');
|
|
@@ -610,7 +719,12 @@ module.exports = async function handler(req, res) {
|
|
|
610
719
|
invoiceData.pdfSizeBytes = pdfBuffer.length;
|
|
611
720
|
invoiceData.pdfUrl = '/api/invoices/' + invoiceData.id + '/pdf';
|
|
612
721
|
|
|
613
|
-
|
|
722
|
+
${emailEnabled
|
|
723
|
+
? ` var replaced = await dataAccess.replaceInvoice(invoiceData.id, invoiceData, invoiceData.items);
|
|
724
|
+
// This regeneration gave the invoice its first PDF, so the payment's
|
|
725
|
+
// invoice email never went out: this one sends it.
|
|
726
|
+
var emailsCustomer = !!(replaced && replaced.firstPdf);`
|
|
727
|
+
: ` await dataAccess.replaceInvoice(invoiceData.id, invoiceData, invoiceData.items);`}
|
|
614
728
|
console.info('[invoice] Regenerated ' + invoiceData.invoiceNumber + ' (id=' + invoiceData.id + ', items=' + invoiceData.items.length + ', pdf_size_bytes=' + pdfBuffer.length + ')');
|
|
615
729
|
|
|
616
730
|
// The new PDF's public copy. The row already serves the new bytes through
|
|
@@ -633,7 +747,15 @@ module.exports = async function handler(req, res) {
|
|
|
633
747
|
if (storageKey) {
|
|
634
748
|
await invoiceAssembly.deleteStoredInvoicePdf(storageKey);
|
|
635
749
|
}
|
|
636
|
-
|
|
750
|
+
${emailEnabled
|
|
751
|
+
? ` // The invoice has its first PDF all the same — served from the database,
|
|
752
|
+
// its public copy just went — and no later regeneration will send it.
|
|
753
|
+
if (emailsCustomer) {
|
|
754
|
+
await emailFirstInvoice(invoiceData, pdfBuffer, hydrated.order);
|
|
755
|
+
}
|
|
756
|
+
await sentEmailLog.settleSentEmailLog();
|
|
757
|
+
`
|
|
758
|
+
: ''} res.status(500).json({ success: false, error: MESSAGES.orderNotUpdated });
|
|
637
759
|
return;
|
|
638
760
|
}
|
|
639
761
|
|
|
@@ -651,7 +773,16 @@ module.exports = async function handler(req, res) {
|
|
|
651
773
|
if (previousStorageKey && previousStorageKey !== storageKey) {
|
|
652
774
|
await invoiceAssembly.deleteStoredInvoicePdf(previousStorageKey);
|
|
653
775
|
}
|
|
654
|
-
|
|
776
|
+
${emailEnabled
|
|
777
|
+
? `
|
|
778
|
+
if (emailsCustomer) {
|
|
779
|
+
await emailFirstInvoice(invoiceData, pdfBuffer, hydrated.order);
|
|
780
|
+
}
|
|
781
|
+
// The email's ledger row is written in the background — land it before
|
|
782
|
+
// replying, a serverless function may be frozen the instant it responds.
|
|
783
|
+
await sentEmailLog.settleSentEmailLog();
|
|
784
|
+
`
|
|
785
|
+
: ''}
|
|
655
786
|
res.status(200).json({
|
|
656
787
|
success: true,
|
|
657
788
|
invoiceId: invoiceData.id,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-routes-code.js","sourceRoot":"","sources":["../../../src/invoice/api-routes-code.ts"],"names":[],"mappings":";;;AACA,wEAAqF;AACrF,wEAA+D;AAE/D;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,CAAC,OAAO,CAAC,CAAA;AAErC;;;;;;;;;GASG;AACH,MAAM,mBAAmB,GAAG,GAAG,IAAA,kEAAwC,GAAE;EACvE,4CAAkB;;4BAEQ,IAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiC7D,CAAA;AAEK,MAAM,gCAAgC,GAAG,CAAC,QAA6B,EAAU,EAAE;;IACxF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,IAAI,MAAM,CAAA;IAC/C,MAAM,YAAY,GAAG,QAAQ,CAAC,qBAAqB,KAAK,KAAK,CAAA;IAC7D,MAAM,YAAY,GAAG,CAAA,MAAA,QAAQ,CAAC,aAAa,0CAAE,OAAO,MAAK,IAAI,CAAA;IAE7D,OAAO;;;;;;;;;;;;;;;;EAiBP,YAAY;QACV,CAAC,CAAC;;gEAE0D;QAC5D,CAAC,CAAC,EACN;;uBAEuB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;;;;;EAK3C,mBAAmB
|
|
1
|
+
{"version":3,"file":"api-routes-code.js","sourceRoot":"","sources":["../../../src/invoice/api-routes-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-access-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhF,eAAO,MAAM,sBAAsB,aACvB,mBAAmB,kBACb,cAAc,GAAG,IAAI,oBACnB,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KAC/C,
|
|
1
|
+
{"version":3,"file":"data-access-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAEhF,eAAO,MAAM,sBAAsB,aACvB,mBAAmB,kBACb,cAAc,GAAG,IAAI,oBACnB,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,KAC/C,MA8CF,CAAA;AAmxBD,eAAO,MAAM,oBAAoB,YAAa,MAAM,KAAG,MAsItD,CAAA"}
|
|
@@ -24,7 +24,7 @@ ${generateGetInvoiceByIdCode(dsType, invoicesTable)}
|
|
|
24
24
|
|
|
25
25
|
${generateUpdateInvoiceCode(dsType, invoicesTable)}
|
|
26
26
|
|
|
27
|
-
${generateStoreInvoicePdfCode(dsType)}
|
|
27
|
+
${generateStoreInvoicePdfCode(dsType, invoicesTable)}
|
|
28
28
|
|
|
29
29
|
${generateGetOrderWithItemsCode(dsType)}
|
|
30
30
|
|
|
@@ -32,6 +32,8 @@ ${generateReplaceInvoiceCode(dsType, invoicesTable, invoiceItemsTable)}
|
|
|
32
32
|
|
|
33
33
|
${generateLinkOrderToInvoiceCode(dsType)}
|
|
34
34
|
|
|
35
|
+
${generateRecordOrderEventCode(dsType)}
|
|
36
|
+
|
|
35
37
|
module.exports = {
|
|
36
38
|
getClient: getClient,
|
|
37
39
|
reserveInvoice: reserveInvoice,
|
|
@@ -42,6 +44,7 @@ module.exports = {
|
|
|
42
44
|
getOrderWithItems: getOrderWithItems,
|
|
43
45
|
replaceInvoice: replaceInvoice,
|
|
44
46
|
linkOrderToInvoice: linkOrderToInvoice,
|
|
47
|
+
recordOrderEvent: recordOrderEvent,
|
|
45
48
|
};
|
|
46
49
|
`;
|
|
47
50
|
};
|
|
@@ -338,18 +341,45 @@ ${cutoff}
|
|
|
338
341
|
return result.rowCount > 0;
|
|
339
342
|
}`;
|
|
340
343
|
}
|
|
341
|
-
// Puts the rendered PDF on the reserved row
|
|
342
|
-
// the invoice
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
344
|
+
// Puts the rendered PDF on the reserved row — only while the row has none —
|
|
345
|
+
// and resolves to `{ firstPdf }`: whether this write gave the invoice its
|
|
346
|
+
// first PDF. `pdf_size_bytes` marks the invoice finished (see
|
|
347
|
+
// `claimStaleInvoice`), and the invoice's first PDF is what its email is
|
|
348
|
+
// claimed by: `replaceInvoice` writes first under the same condition, so of a
|
|
349
|
+
// retried payment finishing a stale invoice and a regeneration racing it, one
|
|
350
|
+
// writes the PDF and emails the buyer, and the other is told it was not first.
|
|
351
|
+
function generateStoreInvoicePdfCode(dsType, table) {
|
|
352
|
+
if (dsType === 'supabase') {
|
|
353
|
+
return `
|
|
346
354
|
async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
|
|
347
|
-
|
|
348
|
-
pdf_data:
|
|
355
|
+
var result = await getClient().from('${table}').update({
|
|
356
|
+
pdf_data: pdfBuffer.toString('base64'),
|
|
349
357
|
pdf_size_bytes: pdfBuffer.length,
|
|
350
358
|
pdf_content_type: 'application/pdf',
|
|
351
359
|
pdf_url: pdfUrl,
|
|
352
|
-
|
|
360
|
+
updated_at: new Date().toISOString(),
|
|
361
|
+
}).eq('id', invoiceId).is('pdf_size_bytes', null).select('id');
|
|
362
|
+
if (result.error) throw new Error(result.error.message);
|
|
363
|
+
return { firstPdf: !!(result.data && result.data.length > 0) };
|
|
364
|
+
}`;
|
|
365
|
+
}
|
|
366
|
+
if (dsType === 'mysql' || dsType === 'mariadb' || dsType === 'tidb') {
|
|
367
|
+
return `
|
|
368
|
+
async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
|
|
369
|
+
var [result] = await getClient().execute(
|
|
370
|
+
'UPDATE ${table} SET pdf_data = ?, pdf_size_bytes = ?, pdf_content_type = ?, pdf_url = ?, updated_at = ? WHERE id = ? AND pdf_size_bytes IS NULL',
|
|
371
|
+
[pdfBuffer, pdfBuffer.length, 'application/pdf', pdfUrl, new Date().toISOString(), invoiceId]
|
|
372
|
+
);
|
|
373
|
+
return { firstPdf: !!(result && result.affectedRows > 0) };
|
|
374
|
+
}`;
|
|
375
|
+
}
|
|
376
|
+
return `
|
|
377
|
+
async function storeInvoicePdf(invoiceId, pdfBuffer, pdfUrl) {
|
|
378
|
+
var result = await getClient().query(
|
|
379
|
+
'UPDATE ${table} SET pdf_data = $1, pdf_size_bytes = $2, pdf_content_type = $3, pdf_url = $4, updated_at = $5 WHERE id = $6 AND pdf_size_bytes IS NULL',
|
|
380
|
+
[pdfBuffer, pdfBuffer.length, 'application/pdf', pdfUrl, new Date().toISOString(), invoiceId]
|
|
381
|
+
);
|
|
382
|
+
return { firstPdf: result.rowCount > 0 };
|
|
353
383
|
}`;
|
|
354
384
|
}
|
|
355
385
|
function generateInsertInvoiceItemsCode(dsType, table) {
|
|
@@ -534,6 +564,15 @@ async function getOrderWithItems(orderId) {
|
|
|
534
564
|
// points at it (the order, the sent-email ledger) stays valid. Postgres and
|
|
535
565
|
// MySQL do it in one transaction, and Supabase undoes its steps, so a failure
|
|
536
566
|
// leaves the old invoice whole.
|
|
567
|
+
//
|
|
568
|
+
// Resolves to `{ firstPdf }`: whether this write gave the invoice its first
|
|
569
|
+
// PDF — one whose PDF never came at payment, so its buyer was never emailed
|
|
570
|
+
// it. The database decides: the row is first written only where it has no PDF
|
|
571
|
+
// (the `pdf_size_bytes IS NULL` that `claimStaleInvoice` reads as
|
|
572
|
+
// "unfinished"), and of two regenerations racing for the same invoice the
|
|
573
|
+
// second waits for the first's row lock, then finds the PDF and matches
|
|
574
|
+
// nothing. `storeInvoicePdf` writes the payment's PDF under the same
|
|
575
|
+
// condition, so exactly one write is ever told `firstPdf: true`.
|
|
537
576
|
function generateReplaceInvoiceCode(dsType, table, itemsTable) {
|
|
538
577
|
if (dsType === 'supabase') {
|
|
539
578
|
return `
|
|
@@ -553,18 +592,23 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
|
|
|
553
592
|
var insertedIds = (inserted || []).map(function (row) { return row.id; });
|
|
554
593
|
var written = null;
|
|
555
594
|
try {
|
|
556
|
-
var
|
|
557
|
-
var
|
|
558
|
-
if (
|
|
559
|
-
|
|
595
|
+
var outcome = await writeInvoiceRecord(mapInvoiceReplacementToRecord(invoiceData), async function (fields) {
|
|
596
|
+
var first = await client.from('${table}').update(fields).eq('id', invoiceId).is('pdf_size_bytes', null).select('id');
|
|
597
|
+
if (first.error) throw new Error(first.error.message);
|
|
598
|
+
var firstPdf = !!(first.data && first.data.length > 0);
|
|
599
|
+
if (!firstPdf) {
|
|
600
|
+
var result = await client.from('${table}').update(fields).eq('id', invoiceId).select('id');
|
|
601
|
+
if (result.error) throw new Error(result.error.message);
|
|
602
|
+
if (!result.data || result.data.length === 0) throw new Error('Invoice ' + invoiceId + ' no longer exists');
|
|
603
|
+
}
|
|
560
604
|
written = fields;
|
|
561
|
-
return
|
|
605
|
+
return { firstPdf: firstPdf };
|
|
562
606
|
});
|
|
563
607
|
if (previousIds.length > 0) {
|
|
564
608
|
var removed = await client.from('${itemsTable}').delete().in('id', previousIds);
|
|
565
609
|
if (removed.error) throw new Error(removed.error.message);
|
|
566
610
|
}
|
|
567
|
-
return
|
|
611
|
+
return outcome;
|
|
568
612
|
} catch (err) {
|
|
569
613
|
if (written) {
|
|
570
614
|
var restored = {};
|
|
@@ -592,12 +636,17 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
|
|
|
592
636
|
var setClauses = columns.map(function(k) { return quoteIdent(k) + ' = ?'; }).join(', ');
|
|
593
637
|
var values = columns.map(function(k) { return fields[k]; });
|
|
594
638
|
values.push(invoiceId);
|
|
595
|
-
var
|
|
596
|
-
|
|
639
|
+
var update = 'UPDATE ${table} SET ' + setClauses + ' WHERE id = ?';
|
|
640
|
+
var [first] = await conn.execute(update + ' AND pdf_size_bytes IS NULL', values);
|
|
641
|
+
var firstPdf = !!(first && first.affectedRows > 0);
|
|
642
|
+
if (!firstPdf) {
|
|
643
|
+
var [updated] = await conn.execute(update, values);
|
|
644
|
+
if (!updated || !updated.affectedRows) throw new Error('Invoice ' + invoiceId + ' no longer exists');
|
|
645
|
+
}
|
|
597
646
|
await conn.execute('DELETE FROM ${itemsTable} WHERE invoice_id = ?', [invoiceId]);
|
|
598
647
|
await insertInvoiceItemRows(conn, invoiceId, items);
|
|
599
648
|
await conn.commit();
|
|
600
|
-
return
|
|
649
|
+
return { firstPdf: firstPdf };
|
|
601
650
|
} catch (err) {
|
|
602
651
|
try { await conn.rollback(); } catch (_rollbackErr) {}
|
|
603
652
|
throw err;
|
|
@@ -620,12 +669,16 @@ async function replaceInvoice(invoiceId, invoiceData, items) {
|
|
|
620
669
|
values.push(invoiceId);
|
|
621
670
|
// The UPDATE takes the row lock first, so two regenerations of the same
|
|
622
671
|
// invoice run one after the other instead of interleaving their lines.
|
|
623
|
-
var
|
|
624
|
-
|
|
672
|
+
var update = 'UPDATE ${table} SET ' + setClauses + ' WHERE id = $' + values.length;
|
|
673
|
+
var firstPdf = (await client.query(update + ' AND pdf_size_bytes IS NULL', values)).rowCount > 0;
|
|
674
|
+
if (!firstPdf) {
|
|
675
|
+
var updated = await client.query(update, values);
|
|
676
|
+
if (!updated.rowCount) throw new Error('Invoice ' + invoiceId + ' no longer exists');
|
|
677
|
+
}
|
|
625
678
|
await client.query('DELETE FROM ${itemsTable} WHERE invoice_id = $1', [invoiceId]);
|
|
626
679
|
await insertInvoiceItemRows(client, invoiceId, items);
|
|
627
680
|
await client.query('COMMIT');
|
|
628
|
-
return
|
|
681
|
+
return { firstPdf: firstPdf };
|
|
629
682
|
} catch (err) {
|
|
630
683
|
try { await client.query('ROLLBACK'); } catch (_rollbackErr) {}
|
|
631
684
|
throw err;
|
|
@@ -682,6 +735,65 @@ async function linkOrderToInvoice(orderId, invoiceId, invoiceNumber, pdfUrl) {
|
|
|
682
735
|
return result.rowCount > 0;
|
|
683
736
|
}`;
|
|
684
737
|
}
|
|
738
|
+
// One line of an order's history: a row of the activity log the editor
|
|
739
|
+
// provisions (`teleport_events`) and both order timelines read. Written like
|
|
740
|
+
// every line the store's workflows write — teleport-gui's
|
|
741
|
+
// `constants/order-event-types.ts` owns the vocabulary — so a replay collides
|
|
742
|
+
// on the UNIQUE `dedupe_key` and adds nothing. `event` is
|
|
743
|
+
// `{ type, dedupeKey, orderId, payload, actor, actorType }`.
|
|
744
|
+
function generateRecordOrderEventCode(dsType) {
|
|
745
|
+
const row = `
|
|
746
|
+
var ORDER_EVENTS_TABLE = 'teleport_events';
|
|
747
|
+
var ORDER_EVENT_DEDUPE_KEY_MAX_LENGTH = 255;
|
|
748
|
+
|
|
749
|
+
function orderEventRow(event) {
|
|
750
|
+
return {
|
|
751
|
+
id: require('crypto').randomUUID(),
|
|
752
|
+
event_type: event.type,
|
|
753
|
+
dedupe_key: String(event.dedupeKey).slice(0, ORDER_EVENT_DEDUPE_KEY_MAX_LENGTH),
|
|
754
|
+
order_id: event.orderId || null,
|
|
755
|
+
payload: JSON.stringify(event.payload || {}),
|
|
756
|
+
actor: event.actor || '',
|
|
757
|
+
actor_type: event.actorType,
|
|
758
|
+
// Logged; a dispatcher claims the rows it delivers itself.
|
|
759
|
+
status: 'recorded',
|
|
760
|
+
};
|
|
761
|
+
}`;
|
|
762
|
+
if (dsType === 'supabase') {
|
|
763
|
+
return `${row}
|
|
764
|
+
|
|
765
|
+
async function recordOrderEvent(event) {
|
|
766
|
+
var result = await getClient()
|
|
767
|
+
.from(ORDER_EVENTS_TABLE)
|
|
768
|
+
.upsert(orderEventRow(event), { onConflict: 'dedupe_key', ignoreDuplicates: true });
|
|
769
|
+
if (result.error) throw new Error(result.error.message);
|
|
770
|
+
}`;
|
|
771
|
+
}
|
|
772
|
+
if (dsType === 'mysql' || dsType === 'mariadb' || dsType === 'tidb') {
|
|
773
|
+
return `${row}
|
|
774
|
+
|
|
775
|
+
async function recordOrderEvent(event) {
|
|
776
|
+
var record = orderEventRow(event);
|
|
777
|
+
var columns = Object.keys(record);
|
|
778
|
+
var placeholders = columns.map(function() { return '?'; }).join(', ');
|
|
779
|
+
await getClient().execute(
|
|
780
|
+
'INSERT INTO ' + ORDER_EVENTS_TABLE + ' (' + columns.join(', ') + ') VALUES (' + placeholders + ') ON DUPLICATE KEY UPDATE dedupe_key = dedupe_key',
|
|
781
|
+
columns.map(function(k) { return record[k]; })
|
|
782
|
+
);
|
|
783
|
+
}`;
|
|
784
|
+
}
|
|
785
|
+
return `${row}
|
|
786
|
+
|
|
787
|
+
async function recordOrderEvent(event) {
|
|
788
|
+
var record = orderEventRow(event);
|
|
789
|
+
var columns = Object.keys(record);
|
|
790
|
+
var placeholders = columns.map(function(_, i) { return '$' + (i + 1); }).join(', ');
|
|
791
|
+
await getClient().query(
|
|
792
|
+
'INSERT INTO ' + ORDER_EVENTS_TABLE + ' (' + columns.join(', ') + ') VALUES (' + placeholders + ') ON CONFLICT (dedupe_key) DO NOTHING',
|
|
793
|
+
columns.map(function(k) { return record[k]; })
|
|
794
|
+
);
|
|
795
|
+
}`;
|
|
796
|
+
}
|
|
685
797
|
const getRecordMappingCode = (dsType) => `
|
|
686
798
|
function mapInvoiceToRecord(data) {
|
|
687
799
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-access-code.js","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":";;;AAEO,MAAM,sBAAsB,GAAG,CACpC,QAA6B,EAC7B,cAAqC,EACrC,gBAAgD,EACxC,EAAE;;IACV,MAAM,aAAa,GAAG,CAAA,MAAA,QAAQ,CAAC,MAAM,0CAAE,aAAa,KAAI,mBAAmB,CAAA;IAC3E,MAAM,iBAAiB,GAAG,CAAA,MAAA,QAAQ,CAAC,MAAM,0CAAE,iBAAiB,KAAI,wBAAwB,CAAA;IACxF,MAAM,MAAM,GAAG,cAAc,IAAI,YAAY,CAAA;IAE7C,OAAO;;uBAEc,MAAM;aAChB,aAAa,KAAK,iBAAiB;;;EAG9C,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,CAAC;;EAEhD,8BAA8B,CAAC,MAAM,EAAE,iBAAiB,CAAC;;EAEzD,0BAA0B,CAAC,MAAM,EAAE,aAAa,CAAC;;EAEjD,6BAA6B,CAAC,MAAM,EAAE,aAAa,CAAC;;EAEpD,0BAA0B,CAAC,MAAM,EAAE,aAAa,CAAC;;EAEjD,yBAAyB,CAAC,MAAM,EAAE,aAAa,CAAC;;EAEhD,2BAA2B,CAAC,MAAM,CAAC;;
|
|
1
|
+
{"version":3,"file":"data-access-code.js","sourceRoot":"","sources":["../../../src/invoice/data-access-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-sender-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/email-sender-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"email-sender-code.d.ts","sourceRoot":"","sources":["../../../src/invoice/email-sender-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AAGrE,eAAO,MAAM,uBAAuB,kBAAmB,wBAAwB,KAAG,MA2GjF,CAAA;AAoMD,eAAO,MAAM,4BAA4B,aAAc,MAAM,GAAG,IAAI,KAAG,OAAO,MAAM,EAAE,MAAM,CAkB3F,CAAA"}
|