@endora-commerce/mod-invoice-ledger 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 +57 -0
- package/dist/admin/api/ledger-client.d.ts +15 -0
- package/dist/admin/api/ledger-client.d.ts.map +1 -0
- package/dist/admin/api/ledger-client.js +35 -0
- package/dist/admin/api/ledger-client.js.map +1 -0
- package/dist/admin/index.d.ts +11 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +52 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/LedgerDeliveriesPage.d.ts +4 -0
- package/dist/admin/pages/LedgerDeliveriesPage.d.ts.map +1 -0
- package/dist/admin/pages/LedgerDeliveriesPage.js +101 -0
- package/dist/admin/pages/LedgerDeliveriesPage.js.map +1 -0
- package/dist/admin/pages/LedgerRoutingPage.d.ts +4 -0
- package/dist/admin/pages/LedgerRoutingPage.d.ts.map +1 -0
- package/dist/admin/pages/LedgerRoutingPage.js +67 -0
- package/dist/admin/pages/LedgerRoutingPage.js.map +1 -0
- package/dist/admin/pages/merge-delivery-pages.d.ts +3 -0
- package/dist/admin/pages/merge-delivery-pages.d.ts.map +1 -0
- package/dist/admin/pages/merge-delivery-pages.js +5 -0
- package/dist/admin/pages/merge-delivery-pages.js.map +1 -0
- package/dist/admin/zones/InvoiceLedgerRemoteIdPanel.d.ts +11 -0
- package/dist/admin/zones/InvoiceLedgerRemoteIdPanel.d.ts.map +1 -0
- package/dist/admin/zones/InvoiceLedgerRemoteIdPanel.js +36 -0
- package/dist/admin/zones/InvoiceLedgerRemoteIdPanel.js.map +1 -0
- package/dist/admin/zones/LedgerDeliveriesTab.d.ts +10 -0
- package/dist/admin/zones/LedgerDeliveriesTab.d.ts.map +1 -0
- package/dist/admin/zones/LedgerDeliveriesTab.js +15 -0
- package/dist/admin/zones/LedgerDeliveriesTab.js.map +1 -0
- package/dist/admin/zones/LedgerRoutingTab.d.ts +11 -0
- package/dist/admin/zones/LedgerRoutingTab.d.ts.map +1 -0
- package/dist/admin/zones/LedgerRoutingTab.js +16 -0
- package/dist/admin/zones/LedgerRoutingTab.js.map +1 -0
- package/dist/backend/commands/retry-delivery.command.d.ts +8 -0
- package/dist/backend/commands/retry-delivery.command.d.ts.map +1 -0
- package/dist/backend/commands/retry-delivery.command.js +26 -0
- package/dist/backend/commands/retry-delivery.command.js.map +1 -0
- package/dist/backend/commands/routing.commands.d.ts +7 -0
- package/dist/backend/commands/routing.commands.d.ts.map +1 -0
- package/dist/backend/commands/routing.commands.js +13 -0
- package/dist/backend/commands/routing.commands.js.map +1 -0
- package/dist/backend/entities/invoice-ledger-activation-lock.entity.d.ts +15 -0
- package/dist/backend/entities/invoice-ledger-activation-lock.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-ledger-activation-lock.entity.js +46 -0
- package/dist/backend/entities/invoice-ledger-activation-lock.entity.js.map +1 -0
- package/dist/backend/entities/invoice-ledger-client-map.entity.d.ts +18 -0
- package/dist/backend/entities/invoice-ledger-client-map.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-ledger-client-map.entity.js +72 -0
- package/dist/backend/entities/invoice-ledger-client-map.entity.js.map +1 -0
- package/dist/backend/entities/invoice-ledger-delivery.entity.d.ts +65 -0
- package/dist/backend/entities/invoice-ledger-delivery.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-ledger-delivery.entity.js +168 -0
- package/dist/backend/entities/invoice-ledger-delivery.entity.js.map +1 -0
- package/dist/backend/entities/invoice-ledger-document-map.entity.d.ts +25 -0
- package/dist/backend/entities/invoice-ledger-document-map.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-ledger-document-map.entity.js +80 -0
- package/dist/backend/entities/invoice-ledger-document-map.entity.js.map +1 -0
- package/dist/backend/entities/invoice-ledger-webhook-receipt.entity.d.ts +18 -0
- package/dist/backend/entities/invoice-ledger-webhook-receipt.entity.d.ts.map +1 -0
- package/dist/backend/entities/invoice-ledger-webhook-receipt.entity.js +71 -0
- package/dist/backend/entities/invoice-ledger-webhook-receipt.entity.js.map +1 -0
- package/dist/backend/index.d.ts +12 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +230 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +11 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +36 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/services/invoice-ledger-delivery-admin.service.d.ts +33 -0
- package/dist/backend/services/invoice-ledger-delivery-admin.service.d.ts.map +1 -0
- package/dist/backend/services/invoice-ledger-delivery-admin.service.js +104 -0
- package/dist/backend/services/invoice-ledger-delivery-admin.service.js.map +1 -0
- package/dist/backend/services/invoice-ledger-delivery.service.d.ts +55 -0
- package/dist/backend/services/invoice-ledger-delivery.service.d.ts.map +1 -0
- package/dist/backend/services/invoice-ledger-delivery.service.js +322 -0
- package/dist/backend/services/invoice-ledger-delivery.service.js.map +1 -0
- package/dist/backend/services/invoice-ledger-registry.service.d.ts +64 -0
- package/dist/backend/services/invoice-ledger-registry.service.d.ts.map +1 -0
- package/dist/backend/services/invoice-ledger-registry.service.js +119 -0
- package/dist/backend/services/invoice-ledger-registry.service.js.map +1 -0
- package/dist/backend/services/invoice-ledger-routing-write.service.d.ts +15 -0
- package/dist/backend/services/invoice-ledger-routing-write.service.d.ts.map +1 -0
- package/dist/backend/services/invoice-ledger-routing-write.service.js +85 -0
- package/dist/backend/services/invoice-ledger-routing-write.service.js.map +1 -0
- package/dist/backend/services/invoice-ledger-routing.service.d.ts +11 -0
- package/dist/backend/services/invoice-ledger-routing.service.d.ts.map +1 -0
- package/dist/backend/services/invoice-ledger-routing.service.js +20 -0
- package/dist/backend/services/invoice-ledger-routing.service.js.map +1 -0
- package/dist/backend/services/invoice-ledger-vendor-freeze-registry.d.ts +9 -0
- package/dist/backend/services/invoice-ledger-vendor-freeze-registry.d.ts.map +1 -0
- package/dist/backend/services/invoice-ledger-vendor-freeze-registry.js +13 -0
- package/dist/backend/services/invoice-ledger-vendor-freeze-registry.js.map +1 -0
- package/dist/backend/services/invoice-ledger-webhook.service.d.ts +30 -0
- package/dist/backend/services/invoice-ledger-webhook.service.d.ts.map +1 -0
- package/dist/backend/services/invoice-ledger-webhook.service.js +170 -0
- package/dist/backend/services/invoice-ledger-webhook.service.js.map +1 -0
- package/dist/backend/services/mapped-delivery-error.d.ts +25 -0
- package/dist/backend/services/mapped-delivery-error.d.ts.map +1 -0
- package/dist/backend/services/mapped-delivery-error.js +54 -0
- package/dist/backend/services/mapped-delivery-error.js.map +1 -0
- package/dist/manifest.d.ts +183 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +112 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260908T125013_invoice_ledger_init.d.ts +12 -0
- package/dist/migrations/20260908T125013_invoice_ledger_init.d.ts.map +1 -0
- package/dist/migrations/20260908T125013_invoice_ledger_init.js +167 -0
- package/dist/migrations/20260908T125013_invoice_ledger_init.js.map +1 -0
- package/dist/migrations/20260914T140000_invoice_ledger_row_organization.d.ts +64 -0
- package/dist/migrations/20260914T140000_invoice_ledger_row_organization.d.ts.map +1 -0
- package/dist/migrations/20260914T140000_invoice_ledger_row_organization.js +126 -0
- package/dist/migrations/20260914T140000_invoice_ledger_row_organization.js.map +1 -0
- package/dist/migrations/index.d.ts +13 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +16 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/invoice-ledger.md +22 -0
- package/i18n/en.json +50 -0
- package/i18n/pl.json +50 -0
- package/package.json +89 -0
- package/tailwind.css +14 -0
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { CAPABILITY_KEYS, defineModuleManifest, defineModuleSettingsManifest, INVOICE_LEDGER_READ_PERMISSION, INVOICE_LEDGER_SETTING_CODES, INVOICE_LEDGER_WRITE_PERMISSION, } from '@endora-commerce/contracts';
|
|
2
|
+
export const invoiceLedgerSettingsManifest = defineModuleSettingsManifest({
|
|
3
|
+
moduleCode: 'invoice_ledger',
|
|
4
|
+
groups: [{ code: 'invoice_ledger', name: 'Invoice ledger' }],
|
|
5
|
+
settings: [
|
|
6
|
+
{
|
|
7
|
+
code: INVOICE_LEDGER_SETTING_CODES.NUMBERING_MODE,
|
|
8
|
+
name: 'Invoice numbering source',
|
|
9
|
+
description: 'Whether issued VAT numbers stay Endora-assigned (mode A) or wait for the ledger vendor (mode B). Sales-channel value overrides the instance default.',
|
|
10
|
+
groupCode: 'invoice_ledger',
|
|
11
|
+
valueType: 'string',
|
|
12
|
+
enumOptions: ['endora', 'vendor'],
|
|
13
|
+
defaultValue: 'endora',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
code: INVOICE_LEDGER_SETTING_CODES.KSEF_ROUTING,
|
|
17
|
+
name: 'KSeF submission routing',
|
|
18
|
+
description: 'Native leaves submission to the platform (a KSeF submission module, when one is installed). Vendor skips native enqueue even when the ledger adapter is off. Sales-channel value overrides the instance default.',
|
|
19
|
+
groupCode: 'invoice_ledger',
|
|
20
|
+
valueType: 'string',
|
|
21
|
+
enumOptions: ['native', 'vendor'],
|
|
22
|
+
defaultValue: 'native',
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
});
|
|
26
|
+
export const manifest = defineModuleManifest({
|
|
27
|
+
id: 'invoice_ledger',
|
|
28
|
+
name: 'Invoice ledger',
|
|
29
|
+
description: 'Shared invoice-ledger rails: vendor mutex, numbering and KSeF routing, deliveries, and document maps. Vendor HTTP lives in the vendor adapter modules.',
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
dependencies: ['settings', 'organizations', 'admin_users', 'sales_channels'],
|
|
32
|
+
nonBindingDependencies: [
|
|
33
|
+
{
|
|
34
|
+
moduleId: 'invoices',
|
|
35
|
+
name: 'invoiceNumberingHostPort',
|
|
36
|
+
kind: 'refuses-without',
|
|
37
|
+
whenAbsent: 'Webhook apply cannot write vendor-assigned numbers while invoices is off.',
|
|
38
|
+
reason: 'invoice_ledger is non-deactivatable, so invoices cannot be a hard dependency.',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
moduleId: 'invoices',
|
|
42
|
+
name: 'invoicePaidHostPort',
|
|
43
|
+
kind: 'refuses-without',
|
|
44
|
+
whenAbsent: 'Webhook apply cannot stamp an invoice paid from the vendor while invoices is off.',
|
|
45
|
+
reason: 'invoice_ledger is non-deactivatable, so invoices cannot be a hard dependency.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
moduleId: 'invoices',
|
|
49
|
+
name: 'invoiceKsefAssignmentPort',
|
|
50
|
+
kind: 'refuses-without',
|
|
51
|
+
whenAbsent: 'Webhook apply cannot record a vendor-assigned KSeF number while invoices is off.',
|
|
52
|
+
reason: 'invoice_ledger is non-deactivatable, so invoices cannot be a hard dependency.',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
moduleId: 'invoices',
|
|
56
|
+
name: 'invoiceCopyHostPort',
|
|
57
|
+
kind: 'degrades-without',
|
|
58
|
+
whenAbsent: 'Delivery list shows invoice ids without numbers while invoices is off, and no new delivery is queued.',
|
|
59
|
+
reason: 'List reads invoice numbers through the invoices copy port, and the enqueue path reads the buyer organization it freezes on the delivery row through the same port — the two ledger tables carry their own tenant key rather than hanging off Invoice, because invoice_ledger is non-deactivatable and invoices cannot be a hard dependency. With invoices off nothing issues an invoice, so there is no delivery to queue and the degrade is the list alone.',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
activation: {
|
|
63
|
+
nonDeactivatable: true,
|
|
64
|
+
reason: 'The shared invoice ledger registry must stay available so operator activation of a ledger vendor can be refused when another is already active.',
|
|
65
|
+
},
|
|
66
|
+
settings: invoiceLedgerSettingsManifest,
|
|
67
|
+
i18n: { bundlesDir: 'i18n' },
|
|
68
|
+
docs: { dir: 'docs' },
|
|
69
|
+
/**
|
|
70
|
+
* Feature 132 — this module **owns** the invoice-ledger vendor capability and
|
|
71
|
+
* declares it mutually exclusive, minting the code an operator meets
|
|
72
|
+
* (`contracts/module-capabilities.md` R3.1). A vendor raises the code and must
|
|
73
|
+
* not declare it (D-95.2); it declares membership and nothing more.
|
|
74
|
+
*/
|
|
75
|
+
exclusiveCapabilities: [
|
|
76
|
+
{
|
|
77
|
+
key: CAPABILITY_KEYS.INVOICE_LEDGER_VENDOR,
|
|
78
|
+
errorCode: 'INVOICE_LEDGER_VENDOR_ALREADY_ACTIVE',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
errorCodes: [
|
|
82
|
+
{ code: 'INVOICE_LEDGER_VENDOR_ALREADY_ACTIVE' },
|
|
83
|
+
{ code: 'INVOICE_LEDGER_CREDENTIALS_MISSING' },
|
|
84
|
+
{ code: 'INVOICE_LEDGER_DELIVERY_NOT_RETRYABLE' },
|
|
85
|
+
],
|
|
86
|
+
permissions: [
|
|
87
|
+
{
|
|
88
|
+
code: INVOICE_LEDGER_READ_PERMISSION,
|
|
89
|
+
label: 'View invoice ledger deliveries',
|
|
90
|
+
description: 'Allows viewing ledger routing and delivery history.',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
code: INVOICE_LEDGER_WRITE_PERMISSION,
|
|
94
|
+
label: 'Manage invoice ledger',
|
|
95
|
+
description: 'Allows changing numbering and KSeF routing, and retrying deliveries.',
|
|
96
|
+
requires: [INVOICE_LEDGER_READ_PERMISSION],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
actions: [
|
|
100
|
+
{
|
|
101
|
+
id: 'open-invoice-ledger-deliveries',
|
|
102
|
+
labelKey: 'actions.openDeliveries.label',
|
|
103
|
+
descriptionKey: 'actions.openDeliveries.description',
|
|
104
|
+
icon: 'ClipboardList',
|
|
105
|
+
targetRoute: '/invoice-ledger/deliveries',
|
|
106
|
+
requiredPermission: INVOICE_LEDGER_READ_PERMISSION,
|
|
107
|
+
keywords: ['ledger', 'deliveries', 'invoices', 'faktury'],
|
|
108
|
+
weight: 245,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* Feature 119 — `invoice_ledger` shared rails (init).
|
|
4
|
+
*
|
|
5
|
+
* Five tables per data-model.md. Infakt owns none. UUID invoice ids only:
|
|
6
|
+
* no foreign key to `invoices` (locked ledger, switchable invoices).
|
|
7
|
+
*/
|
|
8
|
+
export declare class Migration20260908T125013InvoiceLedgerInit extends Migration {
|
|
9
|
+
up(): Promise<void>;
|
|
10
|
+
down(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=20260908T125013_invoice_ledger_init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260908T125013_invoice_ledger_init.d.ts","sourceRoot":"","sources":["../../src/migrations/20260908T125013_invoice_ledger_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;GAKG;AACH,qBAAa,yCAA0C,SAAQ,SAAS;IACvD,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAmKnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAOrC"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* Feature 119 — `invoice_ledger` shared rails (init).
|
|
4
|
+
*
|
|
5
|
+
* Five tables per data-model.md. Infakt owns none. UUID invoice ids only:
|
|
6
|
+
* no foreign key to `invoices` (locked ledger, switchable invoices).
|
|
7
|
+
*/
|
|
8
|
+
export class Migration20260908T125013InvoiceLedgerInit extends Migration {
|
|
9
|
+
async up() {
|
|
10
|
+
this.addSql(`
|
|
11
|
+
create table "invoice_ledger_activation_lock" (
|
|
12
|
+
"id" uuid not null,
|
|
13
|
+
"active_module_id" varchar(64) null,
|
|
14
|
+
"updated_at" timestamptz not null,
|
|
15
|
+
"updated_by_admin_id" uuid null,
|
|
16
|
+
constraint "invoice_ledger_activation_lock_pkey" primary key ("id"),
|
|
17
|
+
constraint "invoice_ledger_activation_lock_id_ck"
|
|
18
|
+
check ("id" = '00000000-0000-4000-8000-000000000001')
|
|
19
|
+
);
|
|
20
|
+
`);
|
|
21
|
+
this.addSql(`
|
|
22
|
+
alter table "invoice_ledger_activation_lock"
|
|
23
|
+
add constraint "invoice_ledger_activation_lock_updated_by_admin_id_foreign"
|
|
24
|
+
foreign key ("updated_by_admin_id") references "admin_users" ("id")
|
|
25
|
+
on update cascade on delete set null;
|
|
26
|
+
`);
|
|
27
|
+
this.addSql(`
|
|
28
|
+
create table "invoice_ledger_client_maps" (
|
|
29
|
+
"id" uuid not null,
|
|
30
|
+
"adapter_id" varchar(64) not null,
|
|
31
|
+
"organization_id" uuid not null,
|
|
32
|
+
"nip_used" varchar(32) not null,
|
|
33
|
+
"remote_client_id" varchar(64) not null,
|
|
34
|
+
"sales_channel_id" uuid null,
|
|
35
|
+
"credential_code" varchar(128) not null,
|
|
36
|
+
"environment" varchar(16) not null,
|
|
37
|
+
"updated_at" timestamptz not null,
|
|
38
|
+
constraint "invoice_ledger_client_maps_pkey" primary key ("id"),
|
|
39
|
+
constraint "invoice_ledger_client_maps_environment_ck"
|
|
40
|
+
check ("environment" in ('sandbox', 'production')),
|
|
41
|
+
constraint "invoice_ledger_client_maps_adapter_org_env_cred_uq"
|
|
42
|
+
unique ("adapter_id", "organization_id", "environment", "credential_code")
|
|
43
|
+
);
|
|
44
|
+
`);
|
|
45
|
+
this.addSql(`create index "invoice_ledger_client_maps_organization_id_idx" on "invoice_ledger_client_maps" ("organization_id");`);
|
|
46
|
+
this.addSql(`
|
|
47
|
+
alter table "invoice_ledger_client_maps"
|
|
48
|
+
add constraint "invoice_ledger_client_maps_organization_id_foreign"
|
|
49
|
+
foreign key ("organization_id") references "organizations" ("id")
|
|
50
|
+
on update cascade;
|
|
51
|
+
`);
|
|
52
|
+
this.addSql(`
|
|
53
|
+
alter table "invoice_ledger_client_maps"
|
|
54
|
+
add constraint "invoice_ledger_client_maps_sales_channel_id_foreign"
|
|
55
|
+
foreign key ("sales_channel_id") references "sales_channels" ("id")
|
|
56
|
+
on update cascade on delete set null;
|
|
57
|
+
`);
|
|
58
|
+
this.addSql(`
|
|
59
|
+
create table "invoice_ledger_document_maps" (
|
|
60
|
+
"id" uuid not null,
|
|
61
|
+
"adapter_id" varchar(64) not null,
|
|
62
|
+
"invoice_id" uuid not null,
|
|
63
|
+
"original_invoice_id" uuid null,
|
|
64
|
+
"remote_document_id" varchar(64) null,
|
|
65
|
+
"environment" varchar(16) not null,
|
|
66
|
+
"credential_code" varchar(128) not null,
|
|
67
|
+
"created_at" timestamptz not null,
|
|
68
|
+
constraint "invoice_ledger_document_maps_pkey" primary key ("id"),
|
|
69
|
+
constraint "invoice_ledger_document_maps_environment_ck"
|
|
70
|
+
check ("environment" in ('sandbox', 'production')),
|
|
71
|
+
constraint "invoice_ledger_document_maps_adapter_invoice_uq"
|
|
72
|
+
unique ("adapter_id", "invoice_id")
|
|
73
|
+
);
|
|
74
|
+
`);
|
|
75
|
+
this.addSql(`create index "invoice_ledger_document_maps_original_invoice_id_idx" on "invoice_ledger_document_maps" ("original_invoice_id");`);
|
|
76
|
+
this.addSql(`
|
|
77
|
+
create unique index "invoice_ledger_document_maps_remote_cred_uq"
|
|
78
|
+
on "invoice_ledger_document_maps" ("adapter_id", "remote_document_id", "environment", "credential_code")
|
|
79
|
+
where "remote_document_id" is not null;
|
|
80
|
+
`);
|
|
81
|
+
this.addSql(`
|
|
82
|
+
create table "invoice_ledger_deliveries" (
|
|
83
|
+
"id" uuid not null,
|
|
84
|
+
"adapter_id" varchar(64) not null,
|
|
85
|
+
"invoice_id" uuid not null,
|
|
86
|
+
"kind" varchar(16) not null,
|
|
87
|
+
"sales_channel_id" uuid null,
|
|
88
|
+
"credential_code" varchar(128) not null,
|
|
89
|
+
"environment" varchar(16) not null,
|
|
90
|
+
"numbering_mode" varchar(16) not null,
|
|
91
|
+
"ksef_routing" varchar(16) not null,
|
|
92
|
+
"status" varchar(24) not null,
|
|
93
|
+
"async_task_id" varchar(128) null,
|
|
94
|
+
"remote_document_id" varchar(64) null,
|
|
95
|
+
"idempotency_key" varchar(128) not null,
|
|
96
|
+
"attempt_count" int not null default 0,
|
|
97
|
+
"attempts" jsonb not null default '[]',
|
|
98
|
+
"last_error" text null,
|
|
99
|
+
"remote_paid_at" timestamptz null,
|
|
100
|
+
"ksef_delegated" boolean not null default false,
|
|
101
|
+
"created_at" timestamptz not null,
|
|
102
|
+
"updated_at" timestamptz not null,
|
|
103
|
+
constraint "invoice_ledger_deliveries_pkey" primary key ("id"),
|
|
104
|
+
constraint "invoice_ledger_deliveries_kind_ck"
|
|
105
|
+
check ("kind" in ('invoice', 'correction')),
|
|
106
|
+
constraint "invoice_ledger_deliveries_environment_ck"
|
|
107
|
+
check ("environment" in ('sandbox', 'production')),
|
|
108
|
+
constraint "invoice_ledger_deliveries_numbering_mode_ck"
|
|
109
|
+
check ("numbering_mode" in ('endora', 'vendor')),
|
|
110
|
+
constraint "invoice_ledger_deliveries_ksef_routing_ck"
|
|
111
|
+
check ("ksef_routing" in ('native', 'vendor')),
|
|
112
|
+
constraint "invoice_ledger_deliveries_status_ck"
|
|
113
|
+
check ("status" in ('queued', 'awaiting_remote', 'succeeded', 'failed', 'dead')),
|
|
114
|
+
constraint "invoice_ledger_deliveries_attempt_count_ck"
|
|
115
|
+
check ("attempt_count" >= 0),
|
|
116
|
+
constraint "invoice_ledger_deliveries_adapter_invoice_uq"
|
|
117
|
+
unique ("adapter_id", "invoice_id"),
|
|
118
|
+
constraint "invoice_ledger_deliveries_adapter_idempotency_uq"
|
|
119
|
+
unique ("adapter_id", "idempotency_key")
|
|
120
|
+
);
|
|
121
|
+
`);
|
|
122
|
+
this.addSql(`create index "invoice_ledger_deliveries_status_idx" on "invoice_ledger_deliveries" ("status");`);
|
|
123
|
+
this.addSql(`
|
|
124
|
+
create index "invoice_ledger_deliveries_remote_document_idx"
|
|
125
|
+
on "invoice_ledger_deliveries" ("adapter_id", "remote_document_id")
|
|
126
|
+
where "remote_document_id" is not null;
|
|
127
|
+
`);
|
|
128
|
+
this.addSql(`
|
|
129
|
+
create unique index "invoice_ledger_deliveries_async_task_uq"
|
|
130
|
+
on "invoice_ledger_deliveries" ("adapter_id", "async_task_id")
|
|
131
|
+
where "async_task_id" is not null;
|
|
132
|
+
`);
|
|
133
|
+
this.addSql(`
|
|
134
|
+
alter table "invoice_ledger_deliveries"
|
|
135
|
+
add constraint "invoice_ledger_deliveries_sales_channel_id_foreign"
|
|
136
|
+
foreign key ("sales_channel_id") references "sales_channels" ("id")
|
|
137
|
+
on update cascade on delete set null;
|
|
138
|
+
`);
|
|
139
|
+
this.addSql(`
|
|
140
|
+
create table "invoice_ledger_webhook_receipts" (
|
|
141
|
+
"id" uuid not null,
|
|
142
|
+
"adapter_id" varchar(64) not null,
|
|
143
|
+
"event_id" varchar(128) not null,
|
|
144
|
+
"event_type" varchar(64) not null,
|
|
145
|
+
"state" varchar(24) not null,
|
|
146
|
+
"attempts" int not null default 0,
|
|
147
|
+
"received_at" timestamptz not null,
|
|
148
|
+
"applied_at" timestamptz null,
|
|
149
|
+
"error" text null,
|
|
150
|
+
constraint "invoice_ledger_webhook_receipts_pkey" primary key ("id"),
|
|
151
|
+
constraint "invoice_ledger_webhook_receipts_state_ck"
|
|
152
|
+
check ("state" in ('received', 'processed', 'ignored', 'failed')),
|
|
153
|
+
constraint "invoice_ledger_webhook_receipts_adapter_event_uq"
|
|
154
|
+
unique ("adapter_id", "event_id")
|
|
155
|
+
);
|
|
156
|
+
`);
|
|
157
|
+
this.addSql(`create index "invoice_ledger_webhook_receipts_state_idx" on "invoice_ledger_webhook_receipts" ("state");`);
|
|
158
|
+
}
|
|
159
|
+
async down() {
|
|
160
|
+
this.addSql(`drop table if exists "invoice_ledger_webhook_receipts" cascade;`);
|
|
161
|
+
this.addSql(`drop table if exists "invoice_ledger_deliveries" cascade;`);
|
|
162
|
+
this.addSql(`drop table if exists "invoice_ledger_document_maps" cascade;`);
|
|
163
|
+
this.addSql(`drop table if exists "invoice_ledger_client_maps" cascade;`);
|
|
164
|
+
this.addSql(`drop table if exists "invoice_ledger_activation_lock" cascade;`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=20260908T125013_invoice_ledger_init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260908T125013_invoice_ledger_init.js","sourceRoot":"","sources":["../../src/migrations/20260908T125013_invoice_ledger_init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,OAAO,yCAA0C,SAAQ,SAAS;IAC7D,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;KAUX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC;;;;;KAKX,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;KAiBX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,oHAAoH,CACrH,CAAC;QACF,IAAI,CAAC,MAAM,CAAC;;;;;KAKX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC;;;;;KAKX,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;KAgBX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,gIAAgI,CACjI,CAAC;QACF,IAAI,CAAC,MAAM,CAAC;;;;KAIX,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwCX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,gGAAgG,CACjG,CAAC;QACF,IAAI,CAAC,MAAM,CAAC;;;;KAIX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC;;;;KAIX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC;;;;;KAKX,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;KAiBX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CACT,0GAA0G,CAC3G,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC,iEAAiE,CAAC,CAAC;QAC/E,IAAI,CAAC,MAAM,CAAC,2DAA2D,CAAC,CAAC;QACzE,IAAI,CAAC,MAAM,CAAC,8DAA8D,CAAC,CAAC;QAC5E,IAAI,CAAC,MAAM,CAAC,4DAA4D,CAAC,CAAC;QAC1E,IAAI,CAAC,MAAM,CAAC,gEAAgE,CAAC,CAAC;IAChF,CAAC;CACF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* `invoice_ledger` deliveries and document maps carry their own tenant key.
|
|
4
|
+
*
|
|
5
|
+
* Both tables were `@TransitivelyScoped('Invoice', 'invoiceId')` — a chain hop
|
|
6
|
+
* into a class `invoices` owns. `invoice_ledger` is `nonDeactivatable` and
|
|
7
|
+
* cannot declare `invoices` in its manifest `dependencies`
|
|
8
|
+
* (`module-composition.md` §4a: the entry would make `invoices.enabled` a dead
|
|
9
|
+
* switch), so an instance that installs the locked set without `invoices`
|
|
10
|
+
* composes these entities and no `Invoice`, and the tenancy reconciliation
|
|
11
|
+
* refuses the boot before a migration runs. That is A3 of the instance
|
|
12
|
+
* acceptance criterion, red on pipeline 13835.
|
|
13
|
+
*
|
|
14
|
+
* The organization is frozen on the row at enqueue, beside the credential, the
|
|
15
|
+
* environment, the numbering mode and the KSeF routing that already are, and
|
|
16
|
+
* the foreign key is to `organizations` — this module's own declared
|
|
17
|
+
* dependency, and the one `invoice_ledger_client_maps` already uses. There is
|
|
18
|
+
* still **no** foreign key to `invoices`
|
|
19
|
+
* (`specs/119-infakt-integration/data-model.md` §3, unchanged).
|
|
20
|
+
*
|
|
21
|
+
* ## The backfill reaches two tables this module does not own, and says so
|
|
22
|
+
*
|
|
23
|
+
* `invoice_ledger` shipped on 2026-09-08 and no deployment has run it, so the
|
|
24
|
+
* expected row count is zero everywhere. It is written as a real backfill all
|
|
25
|
+
* the same, because "there are no rows" is a claim about today.
|
|
26
|
+
*
|
|
27
|
+
* It joins `invoices` **and** `orders`, and the second hop is the same fact
|
|
28
|
+
* this migration exists for read from the other end: `invoices` carries no
|
|
29
|
+
* organization column either — `Invoice` is itself
|
|
30
|
+
* `@TransitivelyScoped('Order', 'orderId')`, so the tenant lives on `orders`.
|
|
31
|
+
* A first draft read `i."organization_id"` and PostgreSQL answered `42703`,
|
|
32
|
+
* which is the chain saying out loud that it grounds two tables away.
|
|
33
|
+
*
|
|
34
|
+
* Both are `migration-cross-module-sql.md` §4.1's R1 shape — a migration naming
|
|
35
|
+
* a table it does not own — and both are **reads inside an existence guard**,
|
|
36
|
+
* which is what makes them safe in the composition this column exists for:
|
|
37
|
+
* `to_regclass` answers `null` when the owning module was never installed, and
|
|
38
|
+
* the statement is `execute`d so its names resolve at run time rather than when
|
|
39
|
+
* the block is parsed. A row whose invoice or order has since gone is deleted
|
|
40
|
+
* rather than given an invented organization — Principle XI has no
|
|
41
|
+
* "no organization" path, and a work item for an invoice that is not there has
|
|
42
|
+
* nothing to deliver.
|
|
43
|
+
*
|
|
44
|
+
* **There is no ledger entry for them, and that is a fact about the instrument
|
|
45
|
+
* rather than a claim that they are not R1.** `check:module-boundary` attributes
|
|
46
|
+
* a migration's tables by reading SQL text, and this SQL is a single-quoted
|
|
47
|
+
* string inside a dollar-quoted `do` block, so the walk sees neither `invoices`
|
|
48
|
+
* nor `orders` here: measured on this branch, `cross-module DML` reads 43 with
|
|
49
|
+
* and without this file. The ledger is two-way, so an entry describing a finding
|
|
50
|
+
* the check does not report would fail the build as stale — an edge it cannot
|
|
51
|
+
* see cannot be recorded in it. The blind spot is real and is reported to the
|
|
52
|
+
* check's owner; this block is where a reader of *this* file learns what the
|
|
53
|
+
* ledger would otherwise have told them.
|
|
54
|
+
*
|
|
55
|
+
* The two tables are written out rather than looped for the same reason read the
|
|
56
|
+
* other way: a loop would put the table name in a template hole, and the `alter`
|
|
57
|
+
* and `create index` statements this file *does* own would become unattributable
|
|
58
|
+
* too.
|
|
59
|
+
*/
|
|
60
|
+
export declare class Migration20260914T140000InvoiceLedgerRowOrganization extends Migration {
|
|
61
|
+
up(): Promise<void>;
|
|
62
|
+
down(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=20260914T140000_invoice_ledger_row_organization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260914T140000_invoice_ledger_row_organization.d.ts","sourceRoot":"","sources":["../../src/migrations/20260914T140000_invoice_ledger_row_organization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,qBAAa,oDAAqD,SAAQ,SAAS;IAClE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IA8DnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAcrC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
/**
|
|
3
|
+
* `invoice_ledger` deliveries and document maps carry their own tenant key.
|
|
4
|
+
*
|
|
5
|
+
* Both tables were `@TransitivelyScoped('Invoice', 'invoiceId')` — a chain hop
|
|
6
|
+
* into a class `invoices` owns. `invoice_ledger` is `nonDeactivatable` and
|
|
7
|
+
* cannot declare `invoices` in its manifest `dependencies`
|
|
8
|
+
* (`module-composition.md` §4a: the entry would make `invoices.enabled` a dead
|
|
9
|
+
* switch), so an instance that installs the locked set without `invoices`
|
|
10
|
+
* composes these entities and no `Invoice`, and the tenancy reconciliation
|
|
11
|
+
* refuses the boot before a migration runs. That is A3 of the instance
|
|
12
|
+
* acceptance criterion, red on pipeline 13835.
|
|
13
|
+
*
|
|
14
|
+
* The organization is frozen on the row at enqueue, beside the credential, the
|
|
15
|
+
* environment, the numbering mode and the KSeF routing that already are, and
|
|
16
|
+
* the foreign key is to `organizations` — this module's own declared
|
|
17
|
+
* dependency, and the one `invoice_ledger_client_maps` already uses. There is
|
|
18
|
+
* still **no** foreign key to `invoices`
|
|
19
|
+
* (`specs/119-infakt-integration/data-model.md` §3, unchanged).
|
|
20
|
+
*
|
|
21
|
+
* ## The backfill reaches two tables this module does not own, and says so
|
|
22
|
+
*
|
|
23
|
+
* `invoice_ledger` shipped on 2026-09-08 and no deployment has run it, so the
|
|
24
|
+
* expected row count is zero everywhere. It is written as a real backfill all
|
|
25
|
+
* the same, because "there are no rows" is a claim about today.
|
|
26
|
+
*
|
|
27
|
+
* It joins `invoices` **and** `orders`, and the second hop is the same fact
|
|
28
|
+
* this migration exists for read from the other end: `invoices` carries no
|
|
29
|
+
* organization column either — `Invoice` is itself
|
|
30
|
+
* `@TransitivelyScoped('Order', 'orderId')`, so the tenant lives on `orders`.
|
|
31
|
+
* A first draft read `i."organization_id"` and PostgreSQL answered `42703`,
|
|
32
|
+
* which is the chain saying out loud that it grounds two tables away.
|
|
33
|
+
*
|
|
34
|
+
* Both are `migration-cross-module-sql.md` §4.1's R1 shape — a migration naming
|
|
35
|
+
* a table it does not own — and both are **reads inside an existence guard**,
|
|
36
|
+
* which is what makes them safe in the composition this column exists for:
|
|
37
|
+
* `to_regclass` answers `null` when the owning module was never installed, and
|
|
38
|
+
* the statement is `execute`d so its names resolve at run time rather than when
|
|
39
|
+
* the block is parsed. A row whose invoice or order has since gone is deleted
|
|
40
|
+
* rather than given an invented organization — Principle XI has no
|
|
41
|
+
* "no organization" path, and a work item for an invoice that is not there has
|
|
42
|
+
* nothing to deliver.
|
|
43
|
+
*
|
|
44
|
+
* **There is no ledger entry for them, and that is a fact about the instrument
|
|
45
|
+
* rather than a claim that they are not R1.** `check:module-boundary` attributes
|
|
46
|
+
* a migration's tables by reading SQL text, and this SQL is a single-quoted
|
|
47
|
+
* string inside a dollar-quoted `do` block, so the walk sees neither `invoices`
|
|
48
|
+
* nor `orders` here: measured on this branch, `cross-module DML` reads 43 with
|
|
49
|
+
* and without this file. The ledger is two-way, so an entry describing a finding
|
|
50
|
+
* the check does not report would fail the build as stale — an edge it cannot
|
|
51
|
+
* see cannot be recorded in it. The blind spot is real and is reported to the
|
|
52
|
+
* check's owner; this block is where a reader of *this* file learns what the
|
|
53
|
+
* ledger would otherwise have told them.
|
|
54
|
+
*
|
|
55
|
+
* The two tables are written out rather than looped for the same reason read the
|
|
56
|
+
* other way: a loop would put the table name in a template hole, and the `alter`
|
|
57
|
+
* and `create index` statements this file *does* own would become unattributable
|
|
58
|
+
* too.
|
|
59
|
+
*/
|
|
60
|
+
export class Migration20260914T140000InvoiceLedgerRowOrganization extends Migration {
|
|
61
|
+
async up() {
|
|
62
|
+
this.addSql(`alter table "invoice_ledger_deliveries" add column "organization_id" uuid null;`);
|
|
63
|
+
this.addSql(`
|
|
64
|
+
do $$
|
|
65
|
+
begin
|
|
66
|
+
if to_regclass('public.invoices') is not null
|
|
67
|
+
and to_regclass('public.orders') is not null then
|
|
68
|
+
execute 'update "invoice_ledger_deliveries" as t
|
|
69
|
+
set "organization_id" = o."organization_id"
|
|
70
|
+
from "invoices" as i
|
|
71
|
+
join "orders" as o on o."id" = i."order_id"
|
|
72
|
+
where i."id" = t."invoice_id"';
|
|
73
|
+
end if;
|
|
74
|
+
end
|
|
75
|
+
$$;
|
|
76
|
+
`);
|
|
77
|
+
this.addSql(`delete from "invoice_ledger_deliveries" where "organization_id" is null;`);
|
|
78
|
+
this.addSql(`alter table "invoice_ledger_deliveries" alter column "organization_id" set not null;`);
|
|
79
|
+
this.addSql(`create index "invoice_ledger_deliveries_organization_id_idx" on "invoice_ledger_deliveries" ("organization_id");`);
|
|
80
|
+
this.addSql(`
|
|
81
|
+
alter table "invoice_ledger_deliveries"
|
|
82
|
+
add constraint "invoice_ledger_deliveries_organization_id_foreign"
|
|
83
|
+
foreign key ("organization_id") references "organizations" ("id")
|
|
84
|
+
on update cascade;
|
|
85
|
+
`);
|
|
86
|
+
this.addSql(`alter table "invoice_ledger_document_maps" add column "organization_id" uuid null;`);
|
|
87
|
+
this.addSql(`
|
|
88
|
+
do $$
|
|
89
|
+
begin
|
|
90
|
+
if to_regclass('public.invoices') is not null
|
|
91
|
+
and to_regclass('public.orders') is not null then
|
|
92
|
+
execute 'update "invoice_ledger_document_maps" as t
|
|
93
|
+
set "organization_id" = o."organization_id"
|
|
94
|
+
from "invoices" as i
|
|
95
|
+
join "orders" as o on o."id" = i."order_id"
|
|
96
|
+
where i."id" = t."invoice_id"';
|
|
97
|
+
end if;
|
|
98
|
+
end
|
|
99
|
+
$$;
|
|
100
|
+
`);
|
|
101
|
+
this.addSql(`delete from "invoice_ledger_document_maps" where "organization_id" is null;`);
|
|
102
|
+
this.addSql(`alter table "invoice_ledger_document_maps" alter column "organization_id" set not null;`);
|
|
103
|
+
this.addSql(`create index "invoice_ledger_document_maps_organization_id_idx" on "invoice_ledger_document_maps" ("organization_id");`);
|
|
104
|
+
this.addSql(`
|
|
105
|
+
alter table "invoice_ledger_document_maps"
|
|
106
|
+
add constraint "invoice_ledger_document_maps_organization_id_foreign"
|
|
107
|
+
foreign key ("organization_id") references "organizations" ("id")
|
|
108
|
+
on update cascade;
|
|
109
|
+
`);
|
|
110
|
+
}
|
|
111
|
+
async down() {
|
|
112
|
+
this.addSql(`
|
|
113
|
+
alter table "invoice_ledger_deliveries"
|
|
114
|
+
drop constraint "invoice_ledger_deliveries_organization_id_foreign";
|
|
115
|
+
`);
|
|
116
|
+
this.addSql(`drop index "invoice_ledger_deliveries_organization_id_idx";`);
|
|
117
|
+
this.addSql(`alter table "invoice_ledger_deliveries" drop column "organization_id";`);
|
|
118
|
+
this.addSql(`
|
|
119
|
+
alter table "invoice_ledger_document_maps"
|
|
120
|
+
drop constraint "invoice_ledger_document_maps_organization_id_foreign";
|
|
121
|
+
`);
|
|
122
|
+
this.addSql(`drop index "invoice_ledger_document_maps_organization_id_idx";`);
|
|
123
|
+
this.addSql(`alter table "invoice_ledger_document_maps" drop column "organization_id";`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=20260914T140000_invoice_ledger_row_organization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260914T140000_invoice_ledger_row_organization.js","sourceRoot":"","sources":["../../src/migrations/20260914T140000_invoice_ledger_row_organization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,MAAM,OAAO,oDAAqD,SAAQ,SAAS;IACxE,KAAK,CAAC,EAAE;QACf,IAAI,CAAC,MAAM,CAAC,iFAAiF,CAAC,CAAC;QAC/F,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;KAaX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,0EAA0E,CAAC,CAAC;QACxF,IAAI,CAAC,MAAM,CACT,sFAAsF,CACvF,CAAC;QACF,IAAI,CAAC,MAAM,CACT,kHAAkH,CACnH,CAAC;QACF,IAAI,CAAC,MAAM,CAAC;;;;;KAKX,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CACT,oFAAoF,CACrF,CAAC;QACF,IAAI,CAAC,MAAM,CAAC;;;;;;;;;;;;;KAaX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,6EAA6E,CAAC,CAAC;QAC3F,IAAI,CAAC,MAAM,CACT,yFAAyF,CAC1F,CAAC;QACF,IAAI,CAAC,MAAM,CACT,wHAAwH,CACzH,CAAC;QACF,IAAI,CAAC,MAAM,CAAC;;;;;KAKX,CAAC,CAAC;IACL,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,IAAI,CAAC,MAAM,CAAC;;;KAGX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,6DAA6D,CAAC,CAAC;QAC3E,IAAI,CAAC,MAAM,CAAC,wEAAwE,CAAC,CAAC;QACtF,IAAI,CAAC,MAAM,CAAC;;;KAGX,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,gEAAgE,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `./migrations` subpath — every migration class this module owns, as one
|
|
3
|
+
* ordered `migrations` array.
|
|
4
|
+
*
|
|
5
|
+
* Listed in ascending timestamp, which is the order of this module's own
|
|
6
|
+
* migrations and of nothing else (feature 081).
|
|
7
|
+
*/
|
|
8
|
+
import { Migration20260908T125013InvoiceLedgerInit } from './20260908T125013_invoice_ledger_init.js';
|
|
9
|
+
import { Migration20260914T140000InvoiceLedgerRowOrganization } from './20260914T140000_invoice_ledger_row_organization.js';
|
|
10
|
+
export declare const migrations: (typeof Migration20260908T125013InvoiceLedgerInit)[];
|
|
11
|
+
export { Migration20260908T125013InvoiceLedgerInit };
|
|
12
|
+
export { Migration20260914T140000InvoiceLedgerRowOrganization };
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,yCAAyC,EAAE,MAAM,0CAA0C,CAAC;AACrG,OAAO,EAAE,oDAAoD,EAAE,MAAM,sDAAsD,CAAC;AAE5H,eAAO,MAAM,UAAU,sDAGtB,CAAC;AAEF,OAAO,EAAE,yCAAyC,EAAE,CAAC;AACrD,OAAO,EAAE,oDAAoD,EAAE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `./migrations` subpath — every migration class this module owns, as one
|
|
3
|
+
* ordered `migrations` array.
|
|
4
|
+
*
|
|
5
|
+
* Listed in ascending timestamp, which is the order of this module's own
|
|
6
|
+
* migrations and of nothing else (feature 081).
|
|
7
|
+
*/
|
|
8
|
+
import { Migration20260908T125013InvoiceLedgerInit } from './20260908T125013_invoice_ledger_init.js';
|
|
9
|
+
import { Migration20260914T140000InvoiceLedgerRowOrganization } from './20260914T140000_invoice_ledger_row_organization.js';
|
|
10
|
+
export const migrations = [
|
|
11
|
+
Migration20260908T125013InvoiceLedgerInit,
|
|
12
|
+
Migration20260914T140000InvoiceLedgerRowOrganization,
|
|
13
|
+
];
|
|
14
|
+
export { Migration20260908T125013InvoiceLedgerInit };
|
|
15
|
+
export { Migration20260914T140000InvoiceLedgerRowOrganization };
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,yCAAyC,EAAE,MAAM,0CAA0C,CAAC;AACrG,OAAO,EAAE,oDAAoD,EAAE,MAAM,sDAAsD,CAAC;AAE5H,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,yCAAyC;IACzC,oDAAoD;CACrD,CAAC;AAEF,OAAO,EAAE,yCAAyC,EAAE,CAAC;AACrD,OAAO,EAAE,oDAAoD,EAAE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Invoice ledger
|
|
3
|
+
description: Shared vendor mutex, numbering and KSeF routing, and durable invoice deliveries for ledger adapters.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Invoice ledger
|
|
7
|
+
|
|
8
|
+
The `invoice_ledger` module owns the shared rails every accounting adapter uses: mutual exclusion so only one vendor is operator-active, numbering and KSeF routing settings, client and document maps, deliveries, and webhook receipts.
|
|
9
|
+
|
|
10
|
+
Vendor adapter modules own the HTTP to their vendor. This module calls no vendor.
|
|
11
|
+
|
|
12
|
+
## Operators
|
|
13
|
+
|
|
14
|
+
- **Invoice ledger** in Sales opens deliveries. Routing is a tab on the same strip.
|
|
15
|
+
- A vendor adapter module adds its connection tab when that adapter is on.
|
|
16
|
+
- Routing (Endora vs vendor numbering, native vs vendor KSeF) is a confirmed write.
|
|
17
|
+
- Switching a vendor adapter off hides its tab. Delivery history on this module stays.
|
|
18
|
+
- Switching Invoice ledger off on `/platform/modules` also switches off every active adapter. Adapters cannot be switched on again until the ledger is on. Switching the ledger back on leaves adapters off.
|
|
19
|
+
|
|
20
|
+
## Engineers
|
|
21
|
+
|
|
22
|
+
Schema lives here. A vendor adapter ships no migration of its own. Invoice ids on maps and deliveries are UUIDs with no foreign key to the invoices module.
|
package/i18n/en.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"actions.openDeliveries.label": "Invoice ledger deliveries",
|
|
3
|
+
"actions.openDeliveries.description": "Vendor copy status, failures and retry",
|
|
4
|
+
"nav.deliveries.label": "Invoice ledger",
|
|
5
|
+
"tabs.deliveries": "Deliveries",
|
|
6
|
+
"tabs.routing": "Routing",
|
|
7
|
+
"deliveries.page.title": "Invoice ledger deliveries",
|
|
8
|
+
"deliveries.page.subtitle": "Copy status for invoices sent to the active ledger vendor.",
|
|
9
|
+
"routing.page.title": "Invoice ledger routing",
|
|
10
|
+
"routing.page.subtitle": "Numbering source and KSeF routing for the invoice ledger.",
|
|
11
|
+
"nav.routing.label": "Ledger routing",
|
|
12
|
+
"routing.form.title": "Instance routing",
|
|
13
|
+
"routing.numberingMode": "Invoice numbering",
|
|
14
|
+
"routing.numberingMode.endora": "Endora number (mode A)",
|
|
15
|
+
"routing.numberingMode.vendor": "Wait for vendor number (mode B)",
|
|
16
|
+
"routing.ksefRouting": "KSeF routing",
|
|
17
|
+
"routing.ksefRouting.native": "Native KSeF module",
|
|
18
|
+
"routing.ksefRouting.vendor": "Vendor send-to-ksef",
|
|
19
|
+
"routing.confirm": "I confirm changing the numbering source. Invoices already issued keep their numbers.",
|
|
20
|
+
"routing.save": "Save routing",
|
|
21
|
+
"routing.saved": "Routing saved.",
|
|
22
|
+
"error.load": "Could not load invoice ledger routing.",
|
|
23
|
+
"error.save": "Could not save invoice ledger routing.",
|
|
24
|
+
"error.loadDeliveries": "Could not load invoice ledger deliveries.",
|
|
25
|
+
"error.retry": "Could not retry this delivery.",
|
|
26
|
+
"deliveries.column.invoice": "Invoice",
|
|
27
|
+
"deliveries.column.adapter": "Adapter",
|
|
28
|
+
"deliveries.column.status": "Status",
|
|
29
|
+
"deliveries.column.lastError": "Reason",
|
|
30
|
+
"deliveries.column.environment": "Environment",
|
|
31
|
+
"deliveries.column.updated": "Updated",
|
|
32
|
+
"deliveries.status.queued": "Queued",
|
|
33
|
+
"deliveries.status.awaiting_remote": "Awaiting vendor",
|
|
34
|
+
"deliveries.status.succeeded": "Succeeded",
|
|
35
|
+
"deliveries.status.failed": "Failed",
|
|
36
|
+
"deliveries.status.dead": "Stopped",
|
|
37
|
+
"deliveries.filter.status.all": "All statuses",
|
|
38
|
+
"deliveries.retry": "Retry",
|
|
39
|
+
"deliveries.empty": "No deliveries yet.",
|
|
40
|
+
"deliveries.loading": "Loading deliveries.",
|
|
41
|
+
"deliveries.noError": "None",
|
|
42
|
+
"deliveries.loadMore": "Load more",
|
|
43
|
+
"invoicePanel.title": "Ledger document",
|
|
44
|
+
"invoicePanel.remoteDocumentId": "Remote document id",
|
|
45
|
+
"adminRoles.permission.invoice_ledger:read": "View invoice ledger deliveries",
|
|
46
|
+
"adminRoles.permission.invoice_ledger:write": "Manage invoice ledger",
|
|
47
|
+
"errors.INVOICE_LEDGER_VENDOR_ALREADY_ACTIVE": "Another invoice ledger vendor is already active ({activeModuleId}). Switch it off first.",
|
|
48
|
+
"errors.INVOICE_LEDGER_CREDENTIALS_MISSING": "The ledger vendor credentials for this invoice are missing.",
|
|
49
|
+
"errors.INVOICE_LEDGER_DELIVERY_NOT_RETRYABLE": "This delivery cannot be retried."
|
|
50
|
+
}
|