@endora-commerce/mod-invoices 0.0.0-stage → 0.100.0
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/LICENSE +21 -0
- package/README.md +59 -2
- package/dist/admin/components/InvoiceSectionTabs.d.ts +22 -0
- package/dist/admin/components/InvoiceSectionTabs.d.ts.map +1 -0
- package/dist/admin/components/InvoiceSectionTabs.js +34 -0
- package/dist/admin/components/InvoiceSectionTabs.js.map +1 -0
- package/dist/admin/index.d.ts +34 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +69 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/InvoiceDetail.d.ts +10 -0
- package/dist/admin/pages/InvoiceDetail.d.ts.map +1 -0
- package/dist/admin/pages/InvoiceDetail.js +111 -0
- package/dist/admin/pages/InvoiceDetail.js.map +1 -0
- package/dist/admin/pages/InvoiceTemplateEditor.d.ts +11 -0
- package/dist/admin/pages/InvoiceTemplateEditor.d.ts.map +1 -0
- package/dist/admin/pages/InvoiceTemplateEditor.js +188 -0
- package/dist/admin/pages/InvoiceTemplateEditor.js.map +1 -0
- package/dist/admin/pages/InvoiceTemplatesPage.d.ts +10 -0
- package/dist/admin/pages/InvoiceTemplatesPage.d.ts.map +1 -0
- package/dist/admin/pages/InvoiceTemplatesPage.js +60 -0
- package/dist/admin/pages/InvoiceTemplatesPage.js.map +1 -0
- package/dist/admin/pages/InvoicesList.d.ts +9 -0
- package/dist/admin/pages/InvoicesList.d.ts.map +1 -0
- package/dist/admin/pages/InvoicesList.js +116 -0
- package/dist/admin/pages/InvoicesList.js.map +1 -0
- package/dist/admin/templates/described-blocks.d.ts +67 -0
- package/dist/admin/templates/described-blocks.d.ts.map +1 -0
- package/dist/admin/templates/described-blocks.js +83 -0
- package/dist/admin/templates/described-blocks.js.map +1 -0
- package/dist/admin/templates/invoice-builder-plugin.d.ts +4 -0
- package/dist/admin/templates/invoice-builder-plugin.d.ts.map +1 -0
- package/dist/admin/templates/invoice-builder-plugin.js +12 -0
- package/dist/admin/templates/invoice-builder-plugin.js.map +1 -0
- package/dist/admin/templates/invoice-puck-config.d.ts +37 -0
- package/dist/admin/templates/invoice-puck-config.d.ts.map +1 -0
- package/dist/admin/templates/invoice-puck-config.js +733 -0
- package/dist/admin/templates/invoice-puck-config.js.map +1 -0
- package/dist/backend/email-templates/invoice-issued.default.d.ts +10 -0
- package/dist/backend/email-templates/invoice-issued.default.d.ts.map +1 -0
- package/dist/backend/email-templates/invoice-issued.default.js +45 -0
- package/dist/backend/email-templates/invoice-issued.default.js.map +1 -0
- package/dist/backend/entities/invoice-external-attachment.entity.d.ts +20 -0
- package/dist/backend/entities/invoice-external-attachment.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-external-attachment.entity.js +77 -0
- package/dist/backend/entities/invoice-external-attachment.entity.js.map +1 -0
- package/dist/backend/entities/invoice-line.entity.d.ts +20 -0
- package/dist/backend/entities/invoice-line.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-line.entity.js +82 -0
- package/dist/backend/entities/invoice-line.entity.js.map +1 -0
- package/dist/backend/entities/invoice-number-counter.entity.d.ts +18 -0
- package/dist/backend/entities/invoice-number-counter.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-number-counter.entity.js +63 -0
- package/dist/backend/entities/invoice-number-counter.entity.js.map +1 -0
- package/dist/backend/entities/invoice-template.entity.d.ts +22 -0
- package/dist/backend/entities/invoice-template.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-template.entity.js +84 -0
- package/dist/backend/entities/invoice-template.entity.js.map +1 -0
- package/dist/backend/entities/invoice.entity.d.ts +64 -0
- package/dist/backend/entities/invoice.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice.entity.js +202 -0
- package/dist/backend/entities/invoice.entity.js.map +1 -0
- package/dist/backend/index.d.ts +111 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +291 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/pdf-components/descriptor.d.ts +29 -0
- package/dist/backend/pdf-components/descriptor.d.ts.map +1 -0
- package/dist/backend/pdf-components/descriptor.js +227 -0
- package/dist/backend/pdf-components/descriptor.js.map +1 -0
- package/dist/backend/pdf-components/embed-logo-images.d.ts +35 -0
- package/dist/backend/pdf-components/embed-logo-images.d.ts.map +1 -0
- package/dist/backend/pdf-components/embed-logo-images.js +101 -0
- package/dist/backend/pdf-components/embed-logo-images.js.map +1 -0
- package/dist/backend/pdf-components/sample.d.ts +4 -0
- package/dist/backend/pdf-components/sample.d.ts.map +1 -0
- package/dist/backend/pdf-components/sample.js +75 -0
- package/dist/backend/pdf-components/sample.js.map +1 -0
- package/dist/backend/pdf-components/sections.d.ts +34 -0
- package/dist/backend/pdf-components/sections.d.ts.map +1 -0
- package/dist/backend/pdf-components/sections.js +445 -0
- package/dist/backend/pdf-components/sections.js.map +1 -0
- package/dist/backend/pdf-components/tree-mapper.d.ts +37 -0
- package/dist/backend/pdf-components/tree-mapper.d.ts.map +1 -0
- package/dist/backend/pdf-components/tree-mapper.js +76 -0
- package/dist/backend/pdf-components/tree-mapper.js.map +1 -0
- package/dist/backend/plugin.d.ts +124 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +87 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +41 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +219 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.customer.d.ts +33 -0
- package/dist/backend/routes.customer.d.ts.map +1 -0
- package/dist/backend/routes.customer.js +124 -0
- package/dist/backend/routes.customer.js.map +1 -0
- package/dist/backend/seeds/generic-invoice-template.d.ts +18 -0
- package/dist/backend/seeds/generic-invoice-template.d.ts.map +1 -0
- package/dist/backend/seeds/generic-invoice-template.js +174 -0
- package/dist/backend/seeds/generic-invoice-template.js.map +1 -0
- package/dist/backend/services/amount-to-words.d.ts +20 -0
- package/dist/backend/services/amount-to-words.d.ts.map +1 -0
- package/dist/backend/services/amount-to-words.js +232 -0
- package/dist/backend/services/amount-to-words.js.map +1 -0
- package/dist/backend/services/auto-issue-reactor.d.ts +53 -0
- package/dist/backend/services/auto-issue-reactor.d.ts.map +1 -0
- package/dist/backend/services/auto-issue-reactor.js +122 -0
- package/dist/backend/services/auto-issue-reactor.js.map +1 -0
- package/dist/backend/services/corrective-invoice.d.ts +38 -0
- package/dist/backend/services/corrective-invoice.d.ts.map +1 -0
- package/dist/backend/services/corrective-invoice.js +257 -0
- package/dist/backend/services/corrective-invoice.js.map +1 -0
- package/dist/backend/services/cross-module-context.d.ts +82 -0
- package/dist/backend/services/cross-module-context.d.ts.map +1 -0
- package/dist/backend/services/cross-module-context.js +93 -0
- package/dist/backend/services/cross-module-context.js.map +1 -0
- package/dist/backend/services/duplicate-number-refusal.d.ts +33 -0
- package/dist/backend/services/duplicate-number-refusal.d.ts.map +1 -0
- package/dist/backend/services/duplicate-number-refusal.js +92 -0
- package/dist/backend/services/duplicate-number-refusal.js.map +1 -0
- package/dist/backend/services/erp-sale-document-write-port.d.ts +37 -0
- package/dist/backend/services/erp-sale-document-write-port.d.ts.map +1 -0
- package/dist/backend/services/erp-sale-document-write-port.js +192 -0
- package/dist/backend/services/erp-sale-document-write-port.js.map +1 -0
- package/dist/backend/services/invoice-attachment-fetch-registry.d.ts +75 -0
- package/dist/backend/services/invoice-attachment-fetch-registry.d.ts.map +1 -0
- package/dist/backend/services/invoice-attachment-fetch-registry.js +81 -0
- package/dist/backend/services/invoice-attachment-fetch-registry.js.map +1 -0
- package/dist/backend/services/invoice-copy-host.service.d.ts +9 -0
- package/dist/backend/services/invoice-copy-host.service.d.ts.map +1 -0
- package/dist/backend/services/invoice-copy-host.service.js +52 -0
- package/dist/backend/services/invoice-copy-host.service.js.map +1 -0
- package/dist/backend/services/invoice-email-dispatch.d.ts +89 -0
- package/dist/backend/services/invoice-email-dispatch.d.ts.map +1 -0
- package/dist/backend/services/invoice-email-dispatch.js +138 -0
- package/dist/backend/services/invoice-email-dispatch.js.map +1 -0
- package/dist/backend/services/invoice-line-builder.d.ts +29 -0
- package/dist/backend/services/invoice-line-builder.d.ts.map +1 -0
- package/dist/backend/services/invoice-line-builder.js +46 -0
- package/dist/backend/services/invoice-line-builder.js.map +1 -0
- package/dist/backend/services/invoice-number-collisions.d.ts +17 -0
- package/dist/backend/services/invoice-number-collisions.d.ts.map +1 -0
- package/dist/backend/services/invoice-number-collisions.js +154 -0
- package/dist/backend/services/invoice-number-collisions.js.map +1 -0
- package/dist/backend/services/invoice-number-generator.d.ts +96 -0
- package/dist/backend/services/invoice-number-generator.d.ts.map +1 -0
- package/dist/backend/services/invoice-number-generator.js +157 -0
- package/dist/backend/services/invoice-number-generator.js.map +1 -0
- package/dist/backend/services/invoice-pdf-block-registry.d.ts +65 -0
- package/dist/backend/services/invoice-pdf-block-registry.d.ts.map +1 -0
- package/dist/backend/services/invoice-pdf-block-registry.js +94 -0
- package/dist/backend/services/invoice-pdf-block-registry.js.map +1 -0
- package/dist/backend/services/invoice-pdf-renderer.d.ts +57 -0
- package/dist/backend/services/invoice-pdf-renderer.d.ts.map +1 -0
- package/dist/backend/services/invoice-pdf-renderer.js +158 -0
- package/dist/backend/services/invoice-pdf-renderer.js.map +1 -0
- package/dist/backend/services/invoice-pdf.d.ts +24 -0
- package/dist/backend/services/invoice-pdf.d.ts.map +1 -0
- package/dist/backend/services/invoice-pdf.js +52 -0
- package/dist/backend/services/invoice-pdf.js.map +1 -0
- package/dist/backend/services/invoice-placement-apply-port.d.ts +29 -0
- package/dist/backend/services/invoice-placement-apply-port.d.ts.map +1 -0
- package/dist/backend/services/invoice-placement-apply-port.js +40 -0
- package/dist/backend/services/invoice-placement-apply-port.js.map +1 -0
- package/dist/backend/services/invoice-read-port.d.ts +44 -0
- package/dist/backend/services/invoice-read-port.d.ts.map +1 -0
- package/dist/backend/services/invoice-read-port.js +95 -0
- package/dist/backend/services/invoice-read-port.js.map +1 -0
- package/dist/backend/services/invoice-service.d.ts +94 -0
- package/dist/backend/services/invoice-service.d.ts.map +1 -0
- package/dist/backend/services/invoice-service.js +374 -0
- package/dist/backend/services/invoice-service.js.map +1 -0
- package/dist/backend/services/invoice-template-service.d.ts +43 -0
- package/dist/backend/services/invoice-template-service.d.ts.map +1 -0
- package/dist/backend/services/invoice-template-service.js +147 -0
- package/dist/backend/services/invoice-template-service.js.map +1 -0
- package/dist/backend/services/numbering-configuration.d.ts +76 -0
- package/dist/backend/services/numbering-configuration.d.ts.map +1 -0
- package/dist/backend/services/numbering-configuration.js +176 -0
- package/dist/backend/services/numbering-configuration.js.map +1 -0
- package/dist/backend/services/numbering-write-validator.d.ts +22 -0
- package/dist/backend/services/numbering-write-validator.d.ts.map +1 -0
- package/dist/backend/services/numbering-write-validator.js +82 -0
- package/dist/backend/services/numbering-write-validator.js.map +1 -0
- package/dist/backend/services/seller-settings.d.ts +24 -0
- package/dist/backend/services/seller-settings.d.ts.map +1 -0
- package/dist/backend/services/seller-settings.js +38 -0
- package/dist/backend/services/seller-settings.js.map +1 -0
- package/dist/backend/services/vendor-number-hold.d.ts +10 -0
- package/dist/backend/services/vendor-number-hold.d.ts.map +1 -0
- package/dist/backend/services/vendor-number-hold.js +14 -0
- package/dist/backend/services/vendor-number-hold.js.map +1 -0
- package/dist/manifest.d.ts +203 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +390 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260629T125121_invoices_module.d.ts +17 -0
- package/dist/migrations/20260629T125121_invoices_module.d.ts.map +1 -0
- package/dist/migrations/20260629T125121_invoices_module.js +117 -0
- package/dist/migrations/20260629T125121_invoices_module.js.map +1 -0
- package/dist/migrations/20260801T111000_invoices_generic_template_reseed.d.ts +6 -0
- package/dist/migrations/20260801T111000_invoices_generic_template_reseed.d.ts.map +1 -0
- package/dist/migrations/20260801T111000_invoices_generic_template_reseed.js +25 -0
- package/dist/migrations/20260801T111000_invoices_generic_template_reseed.js.map +1 -0
- package/dist/migrations/20260817T201110_invoices_correction_idempotency_key.d.ts +20 -0
- package/dist/migrations/20260817T201110_invoices_correction_idempotency_key.d.ts.map +1 -0
- package/dist/migrations/20260817T201110_invoices_correction_idempotency_key.js +33 -0
- package/dist/migrations/20260817T201110_invoices_correction_idempotency_key.js.map +1 -0
- package/dist/migrations/20260903T101756_invoices_namespace_block_names.d.ts +6 -0
- package/dist/migrations/20260903T101756_invoices_namespace_block_names.d.ts.map +1 -0
- package/dist/migrations/20260903T101756_invoices_namespace_block_names.js +56 -0
- package/dist/migrations/20260903T101756_invoices_namespace_block_names.js.map +1 -0
- package/dist/migrations/20260914T133603_invoices_erp_imported_sale_documents.d.ts +12 -0
- package/dist/migrations/20260914T133603_invoices_erp_imported_sale_documents.d.ts.map +1 -0
- package/dist/migrations/20260914T133603_invoices_erp_imported_sale_documents.js +87 -0
- package/dist/migrations/20260914T133603_invoices_erp_imported_sale_documents.js.map +1 -0
- package/dist/migrations/20260926T230239_invoices_import_identity.d.ts +33 -0
- package/dist/migrations/20260926T230239_invoices_import_identity.d.ts.map +1 -0
- package/dist/migrations/20260926T230239_invoices_import_identity.js +83 -0
- package/dist/migrations/20260926T230239_invoices_import_identity.js.map +1 -0
- package/dist/migrations/index.d.ts +32 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +39 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/ports/index.d.ts +93 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +2 -0
- package/dist/ports/index.js.map +1 -0
- package/docs/invoices.md +113 -0
- package/i18n/en.json +45 -0
- package/i18n/pl.json +45 -0
- package/package.json +119 -3
- package/tailwind.css +14 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
2
|
+
import { ERROR_CODES, } from '@endora-commerce/contracts';
|
|
3
|
+
import { InvoiceExternalAttachment } from './entities/invoice-external-attachment.entity.js';
|
|
4
|
+
import { Invoice } from './entities/invoice.entity.js';
|
|
5
|
+
/**
|
|
6
|
+
* Storefront customer invoice routes (feature 047, US4). A customer lists and
|
|
7
|
+
* downloads invoices for an order they (or their organization) own. Only
|
|
8
|
+
* `ready` invoices are exposed.
|
|
9
|
+
*/
|
|
10
|
+
export async function registerInvoicesCustomerRoutes(app, deps) {
|
|
11
|
+
const { emFactory, orderReadPort, assetsLibrary, saleDocumentAttachments, requireCustomer, resolveCustomerContext, invoiceService, pdfRenderer, templateService, } = deps;
|
|
12
|
+
async function ownedOrderOr404(req, orderId) {
|
|
13
|
+
const ctx = resolveCustomerContext(req);
|
|
14
|
+
const order = await orderReadPort.findById(orderId);
|
|
15
|
+
if (!order ||
|
|
16
|
+
(order.placedByCustomerAccountId !== ctx.customerAccountId &&
|
|
17
|
+
order.organizationId !== ctx.organizationId)) {
|
|
18
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Order not found.');
|
|
19
|
+
}
|
|
20
|
+
return order;
|
|
21
|
+
}
|
|
22
|
+
app.get('/api/v1/orders/:id/invoices', { preHandler: requireCustomer }, async (request) => {
|
|
23
|
+
await ownedOrderOr404(request, request.params.id);
|
|
24
|
+
const em = emFactory();
|
|
25
|
+
const rows = await em.find(Invoice, { orderId: request.params.id, status: 'ready' }, { orderBy: { issuedAt: 'desc' } });
|
|
26
|
+
return {
|
|
27
|
+
data: rows.map((i) => ({
|
|
28
|
+
id: i.id,
|
|
29
|
+
kind: i.kind,
|
|
30
|
+
number: i.number,
|
|
31
|
+
issuedAt: i.issuedAt.toISOString(),
|
|
32
|
+
currency: i.currency,
|
|
33
|
+
total: Number(i.total),
|
|
34
|
+
downloadHref: `/api/v1/orders/${request.params.id}/invoices/${i.id}/pdf`,
|
|
35
|
+
})),
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
app.get('/api/v1/orders/:id/invoices/:invoiceId/pdf', { preHandler: requireCustomer, config: { streamingResponse: true } }, async (request, reply) => {
|
|
39
|
+
await ownedOrderOr404(request, request.params.id);
|
|
40
|
+
const em = emFactory();
|
|
41
|
+
const inv = await em.findOne(Invoice, {
|
|
42
|
+
id: request.params.invoiceId,
|
|
43
|
+
orderId: request.params.id,
|
|
44
|
+
status: 'ready',
|
|
45
|
+
});
|
|
46
|
+
if (!inv)
|
|
47
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Invoice not found.');
|
|
48
|
+
const detail = await invoiceService.buildDetail(inv.id);
|
|
49
|
+
const tree = await templateService.resolveTree(detail.salesChannelId, 'pl-PL');
|
|
50
|
+
const pdf = await pdfRenderer.render(detail, 'pl', tree);
|
|
51
|
+
reply
|
|
52
|
+
.header('content-type', 'application/pdf')
|
|
53
|
+
.header('content-disposition', `attachment; filename="invoice-${detail.number.replace(/\W+/g, '_')}.pdf"`);
|
|
54
|
+
return reply.send(pdf);
|
|
55
|
+
});
|
|
56
|
+
app.get('/api/v1/account/organization/invoices', { preHandler: requireCustomer }, async (request) => {
|
|
57
|
+
const ctx = resolveCustomerContext(request);
|
|
58
|
+
const em = emFactory();
|
|
59
|
+
const rows = await em.find(Invoice, { origin: 'erp_import', organizationId: ctx.organizationId, status: 'ready' }, { orderBy: { issuedAt: 'desc' } });
|
|
60
|
+
const attachmentsByInvoice = new Map();
|
|
61
|
+
if (rows.length > 0) {
|
|
62
|
+
const attachments = await em.find(InvoiceExternalAttachment, {
|
|
63
|
+
invoiceId: { $in: rows.map((row) => row.id) },
|
|
64
|
+
});
|
|
65
|
+
for (const attachment of attachments) {
|
|
66
|
+
const bucket = attachmentsByInvoice.get(attachment.invoiceId) ?? [];
|
|
67
|
+
bucket.push(attachment);
|
|
68
|
+
attachmentsByInvoice.set(attachment.invoiceId, bucket);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
data: rows.map((row) => ({
|
|
73
|
+
id: row.id,
|
|
74
|
+
kind: row.kind,
|
|
75
|
+
number: row.number,
|
|
76
|
+
documentKind: row.externalDocumentRef?.documentKind ?? 'invoice',
|
|
77
|
+
issuedAt: row.issuedAt.toISOString(),
|
|
78
|
+
currency: row.currency,
|
|
79
|
+
total: Number(row.total),
|
|
80
|
+
orderId: row.orderId ?? null,
|
|
81
|
+
attachments: (attachmentsByInvoice.get(row.id) ?? []).map((attachment) => ({
|
|
82
|
+
id: attachment.id,
|
|
83
|
+
fileName: attachment.fileName,
|
|
84
|
+
contentType: attachment.contentType ?? null,
|
|
85
|
+
downloadHref: `/api/v1/account/organization/invoices/${row.id}/attachments/${attachment.id}`,
|
|
86
|
+
})),
|
|
87
|
+
})),
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
app.get('/api/v1/account/organization/invoices/:invoiceId/attachments/:attachmentId', { preHandler: requireCustomer, config: { streamingResponse: true } }, async (request, reply) => {
|
|
91
|
+
const ctx = resolveCustomerContext(request);
|
|
92
|
+
const em = emFactory();
|
|
93
|
+
const invoice = await em.findOne(Invoice, {
|
|
94
|
+
id: request.params.invoiceId,
|
|
95
|
+
origin: 'erp_import',
|
|
96
|
+
organizationId: ctx.organizationId,
|
|
97
|
+
status: 'ready',
|
|
98
|
+
});
|
|
99
|
+
if (!invoice) {
|
|
100
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Sale document not found.');
|
|
101
|
+
}
|
|
102
|
+
const attachment = await em.findOne(InvoiceExternalAttachment, {
|
|
103
|
+
id: request.params.attachmentId,
|
|
104
|
+
invoiceId: invoice.id,
|
|
105
|
+
});
|
|
106
|
+
if (!attachment) {
|
|
107
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Attachment not found.');
|
|
108
|
+
}
|
|
109
|
+
if (!attachment.assetId) {
|
|
110
|
+
const ensured = await saleDocumentAttachments.ensureAttachmentBytes({
|
|
111
|
+
invoiceId: invoice.id,
|
|
112
|
+
attachmentId: attachment.id,
|
|
113
|
+
organizationId: ctx.organizationId,
|
|
114
|
+
});
|
|
115
|
+
if (!ensured) {
|
|
116
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, 'Attachment not found.');
|
|
117
|
+
}
|
|
118
|
+
attachment.assetId = ensured.assetId;
|
|
119
|
+
}
|
|
120
|
+
const asset = await assetsLibrary.getAsset(attachment.assetId);
|
|
121
|
+
return reply.redirect(asset.url);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=routes.customer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.customer.js","sourceRoot":"","sources":["../../src/backend/routes.customer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeded generic invoice template (feature 047, US6 / T027). A Puck content
|
|
3
|
+
* envelope composed of the bounded invoice component set.
|
|
4
|
+
*
|
|
5
|
+
* Props on each node MUST mirror `defaultProps` in
|
|
6
|
+
* `admin/.../invoice-puck-config.tsx` so the editor sidebar shows selected
|
|
7
|
+
* radios/selects when a template is created from this seed (Puck does not
|
|
8
|
+
* re-apply defaultProps onto already-persisted nodes).
|
|
9
|
+
*/
|
|
10
|
+
export declare const GENERIC_INVOICE_TEMPLATE_CODE = "generic";
|
|
11
|
+
export declare const GENERIC_INVOICE_TEMPLATE_LANGUAGES: string[];
|
|
12
|
+
/**
|
|
13
|
+
* Bump when the seeded Puck tree shape changes so `ensureGenericSeed` (and the
|
|
14
|
+
* matching data migration) refresh the system `generic` row on existing DBs.
|
|
15
|
+
*/
|
|
16
|
+
export declare const GENERIC_INVOICE_TEMPLATE_SEED_REVISION = 2;
|
|
17
|
+
export declare const GENERIC_INVOICE_TEMPLATE_CONTENT: Record<string, unknown>;
|
|
18
|
+
//# sourceMappingURL=generic-invoice-template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-invoice-template.d.ts","sourceRoot":"","sources":["../../../src/backend/seeds/generic-invoice-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,YAAY,CAAC;AACvD,eAAO,MAAM,kCAAkC,UAAqB,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,sCAAsC,IAAI,CAAC;AA2JxD,eAAO,MAAM,gCAAgC,EAMxC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeded generic invoice template (feature 047, US6 / T027). A Puck content
|
|
3
|
+
* envelope composed of the bounded invoice component set.
|
|
4
|
+
*
|
|
5
|
+
* Props on each node MUST mirror `defaultProps` in
|
|
6
|
+
* `admin/.../invoice-puck-config.tsx` so the editor sidebar shows selected
|
|
7
|
+
* radios/selects when a template is created from this seed (Puck does not
|
|
8
|
+
* re-apply defaultProps onto already-persisted nodes).
|
|
9
|
+
*/
|
|
10
|
+
export const GENERIC_INVOICE_TEMPLATE_CODE = 'generic';
|
|
11
|
+
export const GENERIC_INVOICE_TEMPLATE_LANGUAGES = ['pl-PL', 'en-US'];
|
|
12
|
+
/**
|
|
13
|
+
* Bump when the seeded Puck tree shape changes so `ensureGenericSeed` (and the
|
|
14
|
+
* matching data migration) refresh the system `generic` row on existing DBs.
|
|
15
|
+
*/
|
|
16
|
+
export const GENERIC_INVOICE_TEMPLATE_SEED_REVISION = 2;
|
|
17
|
+
const DEFAULT_FOOTER_TEXT = 'Thank you for your business.\n{{var seller.legalName}} · Tax ID {{var seller.taxId}}';
|
|
18
|
+
function genericTree() {
|
|
19
|
+
return {
|
|
20
|
+
root: { props: {} },
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
type: 'invoices.InvoiceLogo',
|
|
24
|
+
props: {
|
|
25
|
+
id: 'inv-logo',
|
|
26
|
+
imageSource: 'url',
|
|
27
|
+
src: '',
|
|
28
|
+
assetId: '',
|
|
29
|
+
width: 140,
|
|
30
|
+
maxHeight: 80,
|
|
31
|
+
align: 'center',
|
|
32
|
+
marginBottom: 12,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
type: 'invoices.InvoiceHeader',
|
|
37
|
+
props: {
|
|
38
|
+
id: 'inv-header',
|
|
39
|
+
titleSize: 14,
|
|
40
|
+
titleColor: '#0f172a',
|
|
41
|
+
titleBold: true,
|
|
42
|
+
align: 'left',
|
|
43
|
+
showIssuedAt: true,
|
|
44
|
+
showSaleDate: true,
|
|
45
|
+
showPaymentDue: true,
|
|
46
|
+
showPaymentMethod: true,
|
|
47
|
+
labelIssuedAt: 'Issue date',
|
|
48
|
+
labelSaleDate: 'Sale date',
|
|
49
|
+
labelPaymentDue: 'Payment due',
|
|
50
|
+
labelPaymentMethod: 'Payment method',
|
|
51
|
+
marginTop: 0,
|
|
52
|
+
marginBottom: 12,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: 'invoices.InvoiceSpacer',
|
|
57
|
+
props: { id: 'inv-spacer-1', height: 8, backgroundColor: '' },
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: 'invoices.InvoiceParties',
|
|
61
|
+
props: {
|
|
62
|
+
id: 'inv-parties',
|
|
63
|
+
sellerLabel: 'Seller',
|
|
64
|
+
buyerLabel: 'Buyer',
|
|
65
|
+
showSellerBank: true,
|
|
66
|
+
showSellerSwift: true,
|
|
67
|
+
showBuyerTaxId: true,
|
|
68
|
+
labelFontSize: 10,
|
|
69
|
+
bodyFontSize: 10,
|
|
70
|
+
columnGap: 16,
|
|
71
|
+
sellerWidthPercent: 50,
|
|
72
|
+
marginTop: 0,
|
|
73
|
+
marginBottom: 16,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: 'invoices.InvoiceLineItems',
|
|
78
|
+
props: {
|
|
79
|
+
id: 'inv-lines',
|
|
80
|
+
fontSize: 8,
|
|
81
|
+
headerBold: true,
|
|
82
|
+
headerBackground: '',
|
|
83
|
+
headerColor: '',
|
|
84
|
+
borderColor: '#cbd5e1',
|
|
85
|
+
zebra: false,
|
|
86
|
+
showUnit: true,
|
|
87
|
+
showQty: true,
|
|
88
|
+
showUnitNet: true,
|
|
89
|
+
showTaxRate: true,
|
|
90
|
+
showNet: true,
|
|
91
|
+
showGross: true,
|
|
92
|
+
marginTop: 0,
|
|
93
|
+
marginBottom: 12,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: 'invoices.InvoiceVatSummary',
|
|
98
|
+
props: {
|
|
99
|
+
id: 'inv-vat',
|
|
100
|
+
fontSize: 8,
|
|
101
|
+
headerBold: true,
|
|
102
|
+
headerBackground: '',
|
|
103
|
+
headerColor: '',
|
|
104
|
+
borderColor: '#cbd5e1',
|
|
105
|
+
showTotalRow: true,
|
|
106
|
+
totalLabel: 'Total',
|
|
107
|
+
marginTop: 0,
|
|
108
|
+
marginBottom: 12,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
type: 'invoices.InvoiceTotals',
|
|
113
|
+
props: {
|
|
114
|
+
id: 'inv-totals',
|
|
115
|
+
align: 'right',
|
|
116
|
+
fontSize: 10,
|
|
117
|
+
color: '#0f172a',
|
|
118
|
+
amountDueColor: '',
|
|
119
|
+
amountDueBold: true,
|
|
120
|
+
amountInWordsItalics: true,
|
|
121
|
+
showPaid: true,
|
|
122
|
+
showAmountDue: true,
|
|
123
|
+
showGross: true,
|
|
124
|
+
showAmountInWords: true,
|
|
125
|
+
labelPaid: 'Paid',
|
|
126
|
+
labelAmountDue: 'Amount due',
|
|
127
|
+
labelGross: 'Total',
|
|
128
|
+
labelInWords: 'In words',
|
|
129
|
+
marginTop: 0,
|
|
130
|
+
marginBottom: 16,
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
// A `ksef.InvoiceSection` node stood here until feature 134's T063, and
|
|
134
|
+
// this is the record of why it left. The comment that used to sit in
|
|
135
|
+
// `pdf-components/descriptor.ts` said it first: the descriptor's owner
|
|
136
|
+
// was *"derived from the name's owner segment rather than asserted: ten
|
|
137
|
+
// of the eleven are `invoices`' and the eleventh, `ksef.InvoiceSection`,
|
|
138
|
+
// is `ksef`'s (feature 096, T201). A literal here would have said
|
|
139
|
+
// `invoices` for a block `invoices` does not own."* The eleventh was
|
|
140
|
+
// different in kind — declared by another module and still seeded,
|
|
141
|
+
// rendered, described and previewed here — so it went to the module
|
|
142
|
+
// that declares it (`specs/134-paid-module-extraction/spec.md` §11.3,
|
|
143
|
+
// exit E4). A free instance has no KSeF, so its generic template has no
|
|
144
|
+
// KSeF section. Installing `ksef` does not put one back: the operator
|
|
145
|
+
// places the block in the builder. Templates seeded before the change
|
|
146
|
+
// keep their node — the seed revision is deliberately unchanged, so
|
|
147
|
+
// nothing rewrites them — and it renders wherever `ksef` is present.
|
|
148
|
+
{
|
|
149
|
+
type: 'invoices.InvoiceFooter',
|
|
150
|
+
props: {
|
|
151
|
+
id: 'inv-footer',
|
|
152
|
+
text: DEFAULT_FOOTER_TEXT,
|
|
153
|
+
align: 'center',
|
|
154
|
+
fontSize: 9,
|
|
155
|
+
color: '#0f172a',
|
|
156
|
+
bold: false,
|
|
157
|
+
italics: false,
|
|
158
|
+
showTopDivider: true,
|
|
159
|
+
marginTop: 0,
|
|
160
|
+
marginBottom: 8,
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
zones: {},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export const GENERIC_INVOICE_TEMPLATE_CONTENT = {
|
|
168
|
+
schema_version: GENERIC_INVOICE_TEMPLATE_SEED_REVISION,
|
|
169
|
+
languages: {
|
|
170
|
+
'pl-PL': genericTree(),
|
|
171
|
+
'en-US': genericTree(),
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=generic-invoice-template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-invoice-template.js","sourceRoot":"","sources":["../../../src/backend/seeds/generic-invoice-template.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Amount-in-words ("słownie") for invoice PDFs (feature 047, research R7).
|
|
3
|
+
*
|
|
4
|
+
* Renders a monetary amount as words for Polish (`pl`) and English (`en`),
|
|
5
|
+
* with the fractional part shown in the `NN/100` form used on Polish invoices
|
|
6
|
+
* (e.g. "sześć tysięcy sześćset czterdzieści osiem złotych 15/100"). A small
|
|
7
|
+
* self-contained util — no runtime dependency (Constitution Principle IV).
|
|
8
|
+
*/
|
|
9
|
+
export type AmountToWordsLocale = 'pl' | 'en';
|
|
10
|
+
/**
|
|
11
|
+
* Convert a numeric amount to words. The integer part is spelled out; the
|
|
12
|
+
* fractional (minor) part is shown as `NN/100`. The currency word follows the
|
|
13
|
+
* integer part (Polish: with correct plural; English: singular/plural).
|
|
14
|
+
*
|
|
15
|
+
* @param amount monetary amount (major units, may have 2 decimals)
|
|
16
|
+
* @param currency ISO-4217 code (PLN/EUR/USD recognised; others fall back to the code)
|
|
17
|
+
* @param locale 'pl' (default) or 'en'
|
|
18
|
+
*/
|
|
19
|
+
export declare function amountToWords(amount: number, currency: string, locale?: AmountToWordsLocale): string;
|
|
20
|
+
//# sourceMappingURL=amount-to-words.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amount-to-words.d.ts","sourceRoot":"","sources":["../../../src/backend/services/amount-to-words.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,IAAI,CAAC;AAkM9C;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,mBAA0B,GACjC,MAAM,CAgBR"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Amount-in-words ("słownie") for invoice PDFs (feature 047, research R7).
|
|
3
|
+
*
|
|
4
|
+
* Renders a monetary amount as words for Polish (`pl`) and English (`en`),
|
|
5
|
+
* with the fractional part shown in the `NN/100` form used on Polish invoices
|
|
6
|
+
* (e.g. "sześć tysięcy sześćset czterdzieści osiem złotych 15/100"). A small
|
|
7
|
+
* self-contained util — no runtime dependency (Constitution Principle IV).
|
|
8
|
+
*/
|
|
9
|
+
const PL_ONES = [
|
|
10
|
+
'zero',
|
|
11
|
+
'jeden',
|
|
12
|
+
'dwa',
|
|
13
|
+
'trzy',
|
|
14
|
+
'cztery',
|
|
15
|
+
'pięć',
|
|
16
|
+
'sześć',
|
|
17
|
+
'siedem',
|
|
18
|
+
'osiem',
|
|
19
|
+
'dziewięć',
|
|
20
|
+
'dziesięć',
|
|
21
|
+
'jedenaście',
|
|
22
|
+
'dwanaście',
|
|
23
|
+
'trzynaście',
|
|
24
|
+
'czternaście',
|
|
25
|
+
'piętnaście',
|
|
26
|
+
'szesnaście',
|
|
27
|
+
'siedemnaście',
|
|
28
|
+
'osiemnaście',
|
|
29
|
+
'dziewiętnaście',
|
|
30
|
+
];
|
|
31
|
+
const PL_TENS = [
|
|
32
|
+
'',
|
|
33
|
+
'',
|
|
34
|
+
'dwadzieścia',
|
|
35
|
+
'trzydzieści',
|
|
36
|
+
'czterdzieści',
|
|
37
|
+
'pięćdziesiąt',
|
|
38
|
+
'sześćdziesiąt',
|
|
39
|
+
'siedemdziesiąt',
|
|
40
|
+
'osiemdziesiąt',
|
|
41
|
+
'dziewięćdziesiąt',
|
|
42
|
+
];
|
|
43
|
+
const PL_HUNDREDS = [
|
|
44
|
+
'',
|
|
45
|
+
'sto',
|
|
46
|
+
'dwieście',
|
|
47
|
+
'trzysta',
|
|
48
|
+
'czterysta',
|
|
49
|
+
'pięćset',
|
|
50
|
+
'sześćset',
|
|
51
|
+
'siedemset',
|
|
52
|
+
'osiemset',
|
|
53
|
+
'dziewięćset',
|
|
54
|
+
];
|
|
55
|
+
// Polish scale words with the three plural forms [1, 2-4, 5+].
|
|
56
|
+
const PL_SCALES = [
|
|
57
|
+
['', '', ''],
|
|
58
|
+
['tysiąc', 'tysiące', 'tysięcy'],
|
|
59
|
+
['milion', 'miliony', 'milionów'],
|
|
60
|
+
['miliard', 'miliardy', 'miliardów'],
|
|
61
|
+
];
|
|
62
|
+
const EN_ONES = [
|
|
63
|
+
'zero',
|
|
64
|
+
'one',
|
|
65
|
+
'two',
|
|
66
|
+
'three',
|
|
67
|
+
'four',
|
|
68
|
+
'five',
|
|
69
|
+
'six',
|
|
70
|
+
'seven',
|
|
71
|
+
'eight',
|
|
72
|
+
'nine',
|
|
73
|
+
'ten',
|
|
74
|
+
'eleven',
|
|
75
|
+
'twelve',
|
|
76
|
+
'thirteen',
|
|
77
|
+
'fourteen',
|
|
78
|
+
'fifteen',
|
|
79
|
+
'sixteen',
|
|
80
|
+
'seventeen',
|
|
81
|
+
'eighteen',
|
|
82
|
+
'nineteen',
|
|
83
|
+
];
|
|
84
|
+
const EN_TENS = [
|
|
85
|
+
'',
|
|
86
|
+
'',
|
|
87
|
+
'twenty',
|
|
88
|
+
'thirty',
|
|
89
|
+
'forty',
|
|
90
|
+
'fifty',
|
|
91
|
+
'sixty',
|
|
92
|
+
'seventy',
|
|
93
|
+
'eighty',
|
|
94
|
+
'ninety',
|
|
95
|
+
];
|
|
96
|
+
const EN_SCALES = ['', 'thousand', 'million', 'billion'];
|
|
97
|
+
/** Polish plural index: 1 -> 0, 2-4 (not 12-14) -> 1, else -> 2. */
|
|
98
|
+
function plPluralIndex(n) {
|
|
99
|
+
if (n === 1)
|
|
100
|
+
return 0;
|
|
101
|
+
const lastTwo = n % 100;
|
|
102
|
+
const last = n % 10;
|
|
103
|
+
if (last >= 2 && last <= 4 && !(lastTwo >= 12 && lastTwo <= 14))
|
|
104
|
+
return 1;
|
|
105
|
+
return 2;
|
|
106
|
+
}
|
|
107
|
+
/** Safe array lookup — the input ranges are bounded by construction. */
|
|
108
|
+
function word(arr, i) {
|
|
109
|
+
return arr[i] ?? '';
|
|
110
|
+
}
|
|
111
|
+
function plThreeDigits(n) {
|
|
112
|
+
const parts = [];
|
|
113
|
+
const h = Math.floor(n / 100);
|
|
114
|
+
const t = Math.floor((n % 100) / 10);
|
|
115
|
+
const o = n % 10;
|
|
116
|
+
if (h)
|
|
117
|
+
parts.push(word(PL_HUNDREDS, h));
|
|
118
|
+
if (t >= 2) {
|
|
119
|
+
parts.push(word(PL_TENS, t));
|
|
120
|
+
if (o)
|
|
121
|
+
parts.push(word(PL_ONES, o));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const rest = t * 10 + o;
|
|
125
|
+
if (rest)
|
|
126
|
+
parts.push(word(PL_ONES, rest));
|
|
127
|
+
}
|
|
128
|
+
return parts.filter(Boolean).join(' ');
|
|
129
|
+
}
|
|
130
|
+
function plInteger(value) {
|
|
131
|
+
if (value === 0)
|
|
132
|
+
return word(PL_ONES, 0);
|
|
133
|
+
const groups = [];
|
|
134
|
+
let n = value;
|
|
135
|
+
while (n > 0) {
|
|
136
|
+
groups.push(n % 1000);
|
|
137
|
+
n = Math.floor(n / 1000);
|
|
138
|
+
}
|
|
139
|
+
const words = [];
|
|
140
|
+
for (let i = groups.length - 1; i >= 0; i--) {
|
|
141
|
+
const g = groups[i] ?? 0;
|
|
142
|
+
if (g === 0)
|
|
143
|
+
continue;
|
|
144
|
+
if (i === 0) {
|
|
145
|
+
words.push(plThreeDigits(g));
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// "jeden tysiąc" is conventionally just "tysiąc".
|
|
149
|
+
if (g !== 1)
|
|
150
|
+
words.push(plThreeDigits(g));
|
|
151
|
+
const scale = PL_SCALES[i];
|
|
152
|
+
if (scale)
|
|
153
|
+
words.push(word(scale, plPluralIndex(g)));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return words.filter(Boolean).join(' ');
|
|
157
|
+
}
|
|
158
|
+
function enThreeDigits(n) {
|
|
159
|
+
const parts = [];
|
|
160
|
+
const h = Math.floor(n / 100);
|
|
161
|
+
const rest = n % 100;
|
|
162
|
+
if (h) {
|
|
163
|
+
parts.push(`${word(EN_ONES, h)} hundred`);
|
|
164
|
+
}
|
|
165
|
+
if (rest) {
|
|
166
|
+
if (rest < 20) {
|
|
167
|
+
parts.push(word(EN_ONES, rest));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
const t = Math.floor(rest / 10);
|
|
171
|
+
const o = rest % 10;
|
|
172
|
+
parts.push(o ? `${word(EN_TENS, t)}-${word(EN_ONES, o)}` : word(EN_TENS, t));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return parts.filter(Boolean).join(' ');
|
|
176
|
+
}
|
|
177
|
+
function enInteger(value) {
|
|
178
|
+
if (value === 0)
|
|
179
|
+
return word(EN_ONES, 0);
|
|
180
|
+
const groups = [];
|
|
181
|
+
let n = value;
|
|
182
|
+
while (n > 0) {
|
|
183
|
+
groups.push(n % 1000);
|
|
184
|
+
n = Math.floor(n / 1000);
|
|
185
|
+
}
|
|
186
|
+
const words = [];
|
|
187
|
+
for (let i = groups.length - 1; i >= 0; i--) {
|
|
188
|
+
const g = groups[i] ?? 0;
|
|
189
|
+
if (g === 0)
|
|
190
|
+
continue;
|
|
191
|
+
words.push(enThreeDigits(g));
|
|
192
|
+
if (i > 0)
|
|
193
|
+
words.push(word(EN_SCALES, i));
|
|
194
|
+
}
|
|
195
|
+
return words.filter(Boolean).join(' ');
|
|
196
|
+
}
|
|
197
|
+
const PL_CURRENCY = {
|
|
198
|
+
PLN: ['złoty', 'złote', 'złotych'],
|
|
199
|
+
EUR: ['euro', 'euro', 'euro'],
|
|
200
|
+
USD: ['dolar', 'dolary', 'dolarów'],
|
|
201
|
+
};
|
|
202
|
+
const EN_CURRENCY = {
|
|
203
|
+
PLN: ['zloty', 'zlotys'],
|
|
204
|
+
EUR: ['euro', 'euro'],
|
|
205
|
+
USD: ['dollar', 'dollars'],
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* Convert a numeric amount to words. The integer part is spelled out; the
|
|
209
|
+
* fractional (minor) part is shown as `NN/100`. The currency word follows the
|
|
210
|
+
* integer part (Polish: with correct plural; English: singular/plural).
|
|
211
|
+
*
|
|
212
|
+
* @param amount monetary amount (major units, may have 2 decimals)
|
|
213
|
+
* @param currency ISO-4217 code (PLN/EUR/USD recognised; others fall back to the code)
|
|
214
|
+
* @param locale 'pl' (default) or 'en'
|
|
215
|
+
*/
|
|
216
|
+
export function amountToWords(amount, currency, locale = 'pl') {
|
|
217
|
+
const safe = Number.isFinite(amount) ? Math.abs(amount) : 0;
|
|
218
|
+
const integer = Math.floor(safe + 1e-9);
|
|
219
|
+
const minor = Math.round((safe - integer) * 100);
|
|
220
|
+
const code = currency.toUpperCase();
|
|
221
|
+
const fraction = `${minor.toString().padStart(2, '0')}/100`;
|
|
222
|
+
const sign = amount < 0 ? (locale === 'pl' ? 'minus ' : 'minus ') : '';
|
|
223
|
+
if (locale === 'pl') {
|
|
224
|
+
const words = plInteger(integer);
|
|
225
|
+
const cur = PL_CURRENCY[code]?.[plPluralIndex(integer)] ?? code;
|
|
226
|
+
return `${sign}${words} ${cur} ${fraction}`.trim();
|
|
227
|
+
}
|
|
228
|
+
const words = enInteger(integer);
|
|
229
|
+
const cur = EN_CURRENCY[code]?.[integer === 1 ? 0 : 1] ?? code;
|
|
230
|
+
return `${sign}${words} ${cur} ${fraction}`.trim();
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=amount-to-words.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"amount-to-words.js","sourceRoot":"","sources":["../../../src/backend/services/amount-to-words.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
2
|
+
import type { InvoiceService } from './invoice-service.js';
|
|
3
|
+
import type { InvoiceEmailDispatcher, InvoiceEmailLog } from './invoice-email-dispatch.js';
|
|
4
|
+
import type { SettingsReader } from './seller-settings.js';
|
|
5
|
+
export interface AutoIssueReactorDeps {
|
|
6
|
+
emFactory: () => EntityManager;
|
|
7
|
+
invoiceService: InvoiceService;
|
|
8
|
+
settingsService: SettingsReader;
|
|
9
|
+
/** Absent when this composition wired no transactional-email sender. */
|
|
10
|
+
emailDispatcher?: InvoiceEmailDispatcher | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Where an auto-issue that did not reach the customer is reported. Injectable
|
|
13
|
+
* so a test can read it; defaults to `console.warn`, which is what the rest of
|
|
14
|
+
* this layer uses.
|
|
15
|
+
*/
|
|
16
|
+
log?: InvoiceEmailLog;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* FR-002 — issue an invoice when an order reaches the configured status.
|
|
20
|
+
*
|
|
21
|
+
* The **subscription** lives in this module's `backend.ts` and goes through
|
|
22
|
+
* `ctx.subscribe` (issue #107). It was a bare `eventBus.on` in the plugin body,
|
|
23
|
+
* and of the twenty-two such registrations this was the heaviest write: a
|
|
24
|
+
* switched-off `invoices` module still issued a numbered legal document, took a
|
|
25
|
+
* number out of the invoice sequence and e-mailed the PDF to the customer, while
|
|
26
|
+
* the admin surface that would have shown it refused.
|
|
27
|
+
*
|
|
28
|
+
* Idempotent on `(orderId, kind='invoice')`, and still best-effort: a failed
|
|
29
|
+
* automatic attempt leaves manual issuance available. It is no longer *silent*
|
|
30
|
+
* (issue #115). This subscriber has no caller to answer, so "observed" means
|
|
31
|
+
* written to the log with the context only the reactor knows — which order
|
|
32
|
+
* triggered the issuance, and which number it drew. Three things were swallowed
|
|
33
|
+
* here and each now has a distinct outcome:
|
|
34
|
+
*
|
|
35
|
+
* - a **non-sent dispatch**: `{ sent, reason }` was discarded exactly as the
|
|
36
|
+
* plugin-body closure it was lifted out of discarded it, so an invoice that
|
|
37
|
+
* was issued and never delivered read as success. The reason is recorded.
|
|
38
|
+
* - a **switched-off module**: the outer `catch {}` absorbed
|
|
39
|
+
* `ModuleDisabledError`, which is fail-closed turned into fail-open. It is
|
|
40
|
+
* re-thrown; the EventBus isolates and logs handler throws, so the presence
|
|
41
|
+
* answer surfaces instead of being confused with a transient failure.
|
|
42
|
+
* - a **defective settings read**: `catch { trigger = '' }` made every failure
|
|
43
|
+
* read as "no trigger configured" — the same `''` sentinel D-43 removed from
|
|
44
|
+
* the dispatcher. Only the two conditions that genuinely mean "not
|
|
45
|
+
* configured" degrade now.
|
|
46
|
+
*
|
|
47
|
+
* An operator who switched send-on-issue off is *not* a loss and is not logged:
|
|
48
|
+
* that is a configured choice, not an undelivered message.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createAutoIssueReactor(deps: AutoIssueReactorDeps): {
|
|
51
|
+
onOrderStatusChanged: (payload: unknown) => Promise<void>;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=auto-issue-reactor.d.ts.map
|