@liasse/factur-x 0.2.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/dist/index.d.ts +396 -0
- package/dist/index.js +269 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Liasse
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/** A postal address (EN 16931 BG-5 / BG-8). */
|
|
4
|
+
declare const AddressSchema: z.ZodObject<{
|
|
5
|
+
line1: z.ZodOptional<z.ZodString>;
|
|
6
|
+
line2: z.ZodOptional<z.ZodString>;
|
|
7
|
+
city: z.ZodString;
|
|
8
|
+
postcode: z.ZodString;
|
|
9
|
+
/** ISO 3166-1 alpha-2 country code (e.g. "FR"). */
|
|
10
|
+
countryCode: z.ZodDefault<z.ZodString>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
city: string;
|
|
13
|
+
postcode: string;
|
|
14
|
+
countryCode: string;
|
|
15
|
+
line1?: string | undefined;
|
|
16
|
+
line2?: string | undefined;
|
|
17
|
+
}, {
|
|
18
|
+
city: string;
|
|
19
|
+
postcode: string;
|
|
20
|
+
line1?: string | undefined;
|
|
21
|
+
line2?: string | undefined;
|
|
22
|
+
countryCode?: string | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
type Address = z.infer<typeof AddressSchema>;
|
|
25
|
+
/** A trade party — seller (BG-4) or buyer (BG-7). */
|
|
26
|
+
declare const PartySchema: z.ZodObject<{
|
|
27
|
+
name: z.ZodString;
|
|
28
|
+
/** Legal registration id, e.g. SIREN/SIRET (BT-30 / BT-47). */
|
|
29
|
+
registrationId: z.ZodOptional<z.ZodString>;
|
|
30
|
+
/** Scheme for the registration id (ISO 6523), e.g. "0002" for SIRENE. */
|
|
31
|
+
registrationScheme: z.ZodDefault<z.ZodString>;
|
|
32
|
+
/** VAT identifier, e.g. "FR40123456789" (BT-31 / BT-48). */
|
|
33
|
+
vatId: z.ZodOptional<z.ZodString>;
|
|
34
|
+
address: z.ZodObject<{
|
|
35
|
+
line1: z.ZodOptional<z.ZodString>;
|
|
36
|
+
line2: z.ZodOptional<z.ZodString>;
|
|
37
|
+
city: z.ZodString;
|
|
38
|
+
postcode: z.ZodString;
|
|
39
|
+
/** ISO 3166-1 alpha-2 country code (e.g. "FR"). */
|
|
40
|
+
countryCode: z.ZodDefault<z.ZodString>;
|
|
41
|
+
}, "strip", z.ZodTypeAny, {
|
|
42
|
+
city: string;
|
|
43
|
+
postcode: string;
|
|
44
|
+
countryCode: string;
|
|
45
|
+
line1?: string | undefined;
|
|
46
|
+
line2?: string | undefined;
|
|
47
|
+
}, {
|
|
48
|
+
city: string;
|
|
49
|
+
postcode: string;
|
|
50
|
+
line1?: string | undefined;
|
|
51
|
+
line2?: string | undefined;
|
|
52
|
+
countryCode?: string | undefined;
|
|
53
|
+
}>;
|
|
54
|
+
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
name: string;
|
|
56
|
+
registrationScheme: string;
|
|
57
|
+
address: {
|
|
58
|
+
city: string;
|
|
59
|
+
postcode: string;
|
|
60
|
+
countryCode: string;
|
|
61
|
+
line1?: string | undefined;
|
|
62
|
+
line2?: string | undefined;
|
|
63
|
+
};
|
|
64
|
+
registrationId?: string | undefined;
|
|
65
|
+
vatId?: string | undefined;
|
|
66
|
+
}, {
|
|
67
|
+
name: string;
|
|
68
|
+
address: {
|
|
69
|
+
city: string;
|
|
70
|
+
postcode: string;
|
|
71
|
+
line1?: string | undefined;
|
|
72
|
+
line2?: string | undefined;
|
|
73
|
+
countryCode?: string | undefined;
|
|
74
|
+
};
|
|
75
|
+
registrationId?: string | undefined;
|
|
76
|
+
registrationScheme?: string | undefined;
|
|
77
|
+
vatId?: string | undefined;
|
|
78
|
+
}>;
|
|
79
|
+
type Party = z.infer<typeof PartySchema>;
|
|
80
|
+
/** An invoice line (BG-25). */
|
|
81
|
+
declare const LineSchema: z.ZodObject<{
|
|
82
|
+
/** Line id; auto-numbered from 1 when omitted. */
|
|
83
|
+
id: z.ZodOptional<z.ZodString>;
|
|
84
|
+
name: z.ZodString;
|
|
85
|
+
quantity: z.ZodNumber;
|
|
86
|
+
/** UN/ECE Rec 20 unit code (default "C62" = one/piece). */
|
|
87
|
+
unitCode: z.ZodDefault<z.ZodString>;
|
|
88
|
+
/** Net unit price (BT-146). */
|
|
89
|
+
unitPrice: z.ZodNumber;
|
|
90
|
+
/** VAT rate as a percentage, e.g. 20 for 20 % (BT-152). */
|
|
91
|
+
vatRate: z.ZodNumber;
|
|
92
|
+
/** VAT category code (BT-151): S standard, Z zero, E exempt, … */
|
|
93
|
+
vatCategory: z.ZodDefault<z.ZodEnum<["S", "Z", "E", "AE", "K", "G", "O"]>>;
|
|
94
|
+
}, "strip", z.ZodTypeAny, {
|
|
95
|
+
name: string;
|
|
96
|
+
quantity: number;
|
|
97
|
+
unitCode: string;
|
|
98
|
+
unitPrice: number;
|
|
99
|
+
vatRate: number;
|
|
100
|
+
vatCategory: "S" | "Z" | "E" | "AE" | "K" | "G" | "O";
|
|
101
|
+
id?: string | undefined;
|
|
102
|
+
}, {
|
|
103
|
+
name: string;
|
|
104
|
+
quantity: number;
|
|
105
|
+
unitPrice: number;
|
|
106
|
+
vatRate: number;
|
|
107
|
+
id?: string | undefined;
|
|
108
|
+
unitCode?: string | undefined;
|
|
109
|
+
vatCategory?: "S" | "Z" | "E" | "AE" | "K" | "G" | "O" | undefined;
|
|
110
|
+
}>;
|
|
111
|
+
type Line = z.infer<typeof LineSchema>;
|
|
112
|
+
/** A Factur-X invoice (EN 16931 core). */
|
|
113
|
+
declare const InvoiceSchema: z.ZodObject<{
|
|
114
|
+
/** Invoice number (BT-1). */
|
|
115
|
+
number: z.ZodString;
|
|
116
|
+
/** Issue date as YYYY-MM-DD or a Date (BT-2). */
|
|
117
|
+
issueDate: z.ZodUnion<[z.ZodString, z.ZodDate]>;
|
|
118
|
+
/** Document type code (BT-3); 380 = commercial invoice. */
|
|
119
|
+
typeCode: z.ZodDefault<z.ZodNumber>;
|
|
120
|
+
/** Invoice currency, ISO 4217 (BT-5). */
|
|
121
|
+
currency: z.ZodDefault<z.ZodString>;
|
|
122
|
+
/** Buyer reference / order ref (BT-10) — often required (e.g. Chorus Pro). */
|
|
123
|
+
buyerReference: z.ZodOptional<z.ZodString>;
|
|
124
|
+
/** Payment due date as YYYY-MM-DD or a Date (BT-9). */
|
|
125
|
+
dueDate: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate]>>;
|
|
126
|
+
seller: z.ZodObject<{
|
|
127
|
+
name: z.ZodString;
|
|
128
|
+
/** Legal registration id, e.g. SIREN/SIRET (BT-30 / BT-47). */
|
|
129
|
+
registrationId: z.ZodOptional<z.ZodString>;
|
|
130
|
+
/** Scheme for the registration id (ISO 6523), e.g. "0002" for SIRENE. */
|
|
131
|
+
registrationScheme: z.ZodDefault<z.ZodString>;
|
|
132
|
+
/** VAT identifier, e.g. "FR40123456789" (BT-31 / BT-48). */
|
|
133
|
+
vatId: z.ZodOptional<z.ZodString>;
|
|
134
|
+
address: z.ZodObject<{
|
|
135
|
+
line1: z.ZodOptional<z.ZodString>;
|
|
136
|
+
line2: z.ZodOptional<z.ZodString>;
|
|
137
|
+
city: z.ZodString;
|
|
138
|
+
postcode: z.ZodString;
|
|
139
|
+
/** ISO 3166-1 alpha-2 country code (e.g. "FR"). */
|
|
140
|
+
countryCode: z.ZodDefault<z.ZodString>;
|
|
141
|
+
}, "strip", z.ZodTypeAny, {
|
|
142
|
+
city: string;
|
|
143
|
+
postcode: string;
|
|
144
|
+
countryCode: string;
|
|
145
|
+
line1?: string | undefined;
|
|
146
|
+
line2?: string | undefined;
|
|
147
|
+
}, {
|
|
148
|
+
city: string;
|
|
149
|
+
postcode: string;
|
|
150
|
+
line1?: string | undefined;
|
|
151
|
+
line2?: string | undefined;
|
|
152
|
+
countryCode?: string | undefined;
|
|
153
|
+
}>;
|
|
154
|
+
}, "strip", z.ZodTypeAny, {
|
|
155
|
+
name: string;
|
|
156
|
+
registrationScheme: string;
|
|
157
|
+
address: {
|
|
158
|
+
city: string;
|
|
159
|
+
postcode: string;
|
|
160
|
+
countryCode: string;
|
|
161
|
+
line1?: string | undefined;
|
|
162
|
+
line2?: string | undefined;
|
|
163
|
+
};
|
|
164
|
+
registrationId?: string | undefined;
|
|
165
|
+
vatId?: string | undefined;
|
|
166
|
+
}, {
|
|
167
|
+
name: string;
|
|
168
|
+
address: {
|
|
169
|
+
city: string;
|
|
170
|
+
postcode: string;
|
|
171
|
+
line1?: string | undefined;
|
|
172
|
+
line2?: string | undefined;
|
|
173
|
+
countryCode?: string | undefined;
|
|
174
|
+
};
|
|
175
|
+
registrationId?: string | undefined;
|
|
176
|
+
registrationScheme?: string | undefined;
|
|
177
|
+
vatId?: string | undefined;
|
|
178
|
+
}>;
|
|
179
|
+
buyer: z.ZodObject<{
|
|
180
|
+
name: z.ZodString;
|
|
181
|
+
/** Legal registration id, e.g. SIREN/SIRET (BT-30 / BT-47). */
|
|
182
|
+
registrationId: z.ZodOptional<z.ZodString>;
|
|
183
|
+
/** Scheme for the registration id (ISO 6523), e.g. "0002" for SIRENE. */
|
|
184
|
+
registrationScheme: z.ZodDefault<z.ZodString>;
|
|
185
|
+
/** VAT identifier, e.g. "FR40123456789" (BT-31 / BT-48). */
|
|
186
|
+
vatId: z.ZodOptional<z.ZodString>;
|
|
187
|
+
address: z.ZodObject<{
|
|
188
|
+
line1: z.ZodOptional<z.ZodString>;
|
|
189
|
+
line2: z.ZodOptional<z.ZodString>;
|
|
190
|
+
city: z.ZodString;
|
|
191
|
+
postcode: z.ZodString;
|
|
192
|
+
/** ISO 3166-1 alpha-2 country code (e.g. "FR"). */
|
|
193
|
+
countryCode: z.ZodDefault<z.ZodString>;
|
|
194
|
+
}, "strip", z.ZodTypeAny, {
|
|
195
|
+
city: string;
|
|
196
|
+
postcode: string;
|
|
197
|
+
countryCode: string;
|
|
198
|
+
line1?: string | undefined;
|
|
199
|
+
line2?: string | undefined;
|
|
200
|
+
}, {
|
|
201
|
+
city: string;
|
|
202
|
+
postcode: string;
|
|
203
|
+
line1?: string | undefined;
|
|
204
|
+
line2?: string | undefined;
|
|
205
|
+
countryCode?: string | undefined;
|
|
206
|
+
}>;
|
|
207
|
+
}, "strip", z.ZodTypeAny, {
|
|
208
|
+
name: string;
|
|
209
|
+
registrationScheme: string;
|
|
210
|
+
address: {
|
|
211
|
+
city: string;
|
|
212
|
+
postcode: string;
|
|
213
|
+
countryCode: string;
|
|
214
|
+
line1?: string | undefined;
|
|
215
|
+
line2?: string | undefined;
|
|
216
|
+
};
|
|
217
|
+
registrationId?: string | undefined;
|
|
218
|
+
vatId?: string | undefined;
|
|
219
|
+
}, {
|
|
220
|
+
name: string;
|
|
221
|
+
address: {
|
|
222
|
+
city: string;
|
|
223
|
+
postcode: string;
|
|
224
|
+
line1?: string | undefined;
|
|
225
|
+
line2?: string | undefined;
|
|
226
|
+
countryCode?: string | undefined;
|
|
227
|
+
};
|
|
228
|
+
registrationId?: string | undefined;
|
|
229
|
+
registrationScheme?: string | undefined;
|
|
230
|
+
vatId?: string | undefined;
|
|
231
|
+
}>;
|
|
232
|
+
lines: z.ZodArray<z.ZodObject<{
|
|
233
|
+
/** Line id; auto-numbered from 1 when omitted. */
|
|
234
|
+
id: z.ZodOptional<z.ZodString>;
|
|
235
|
+
name: z.ZodString;
|
|
236
|
+
quantity: z.ZodNumber;
|
|
237
|
+
/** UN/ECE Rec 20 unit code (default "C62" = one/piece). */
|
|
238
|
+
unitCode: z.ZodDefault<z.ZodString>;
|
|
239
|
+
/** Net unit price (BT-146). */
|
|
240
|
+
unitPrice: z.ZodNumber;
|
|
241
|
+
/** VAT rate as a percentage, e.g. 20 for 20 % (BT-152). */
|
|
242
|
+
vatRate: z.ZodNumber;
|
|
243
|
+
/** VAT category code (BT-151): S standard, Z zero, E exempt, … */
|
|
244
|
+
vatCategory: z.ZodDefault<z.ZodEnum<["S", "Z", "E", "AE", "K", "G", "O"]>>;
|
|
245
|
+
}, "strip", z.ZodTypeAny, {
|
|
246
|
+
name: string;
|
|
247
|
+
quantity: number;
|
|
248
|
+
unitCode: string;
|
|
249
|
+
unitPrice: number;
|
|
250
|
+
vatRate: number;
|
|
251
|
+
vatCategory: "S" | "Z" | "E" | "AE" | "K" | "G" | "O";
|
|
252
|
+
id?: string | undefined;
|
|
253
|
+
}, {
|
|
254
|
+
name: string;
|
|
255
|
+
quantity: number;
|
|
256
|
+
unitPrice: number;
|
|
257
|
+
vatRate: number;
|
|
258
|
+
id?: string | undefined;
|
|
259
|
+
unitCode?: string | undefined;
|
|
260
|
+
vatCategory?: "S" | "Z" | "E" | "AE" | "K" | "G" | "O" | undefined;
|
|
261
|
+
}>, "many">;
|
|
262
|
+
}, "strip", z.ZodTypeAny, {
|
|
263
|
+
number: string;
|
|
264
|
+
issueDate: string | Date;
|
|
265
|
+
typeCode: number;
|
|
266
|
+
currency: string;
|
|
267
|
+
seller: {
|
|
268
|
+
name: string;
|
|
269
|
+
registrationScheme: string;
|
|
270
|
+
address: {
|
|
271
|
+
city: string;
|
|
272
|
+
postcode: string;
|
|
273
|
+
countryCode: string;
|
|
274
|
+
line1?: string | undefined;
|
|
275
|
+
line2?: string | undefined;
|
|
276
|
+
};
|
|
277
|
+
registrationId?: string | undefined;
|
|
278
|
+
vatId?: string | undefined;
|
|
279
|
+
};
|
|
280
|
+
buyer: {
|
|
281
|
+
name: string;
|
|
282
|
+
registrationScheme: string;
|
|
283
|
+
address: {
|
|
284
|
+
city: string;
|
|
285
|
+
postcode: string;
|
|
286
|
+
countryCode: string;
|
|
287
|
+
line1?: string | undefined;
|
|
288
|
+
line2?: string | undefined;
|
|
289
|
+
};
|
|
290
|
+
registrationId?: string | undefined;
|
|
291
|
+
vatId?: string | undefined;
|
|
292
|
+
};
|
|
293
|
+
lines: {
|
|
294
|
+
name: string;
|
|
295
|
+
quantity: number;
|
|
296
|
+
unitCode: string;
|
|
297
|
+
unitPrice: number;
|
|
298
|
+
vatRate: number;
|
|
299
|
+
vatCategory: "S" | "Z" | "E" | "AE" | "K" | "G" | "O";
|
|
300
|
+
id?: string | undefined;
|
|
301
|
+
}[];
|
|
302
|
+
buyerReference?: string | undefined;
|
|
303
|
+
dueDate?: string | Date | undefined;
|
|
304
|
+
}, {
|
|
305
|
+
number: string;
|
|
306
|
+
issueDate: string | Date;
|
|
307
|
+
seller: {
|
|
308
|
+
name: string;
|
|
309
|
+
address: {
|
|
310
|
+
city: string;
|
|
311
|
+
postcode: string;
|
|
312
|
+
line1?: string | undefined;
|
|
313
|
+
line2?: string | undefined;
|
|
314
|
+
countryCode?: string | undefined;
|
|
315
|
+
};
|
|
316
|
+
registrationId?: string | undefined;
|
|
317
|
+
registrationScheme?: string | undefined;
|
|
318
|
+
vatId?: string | undefined;
|
|
319
|
+
};
|
|
320
|
+
buyer: {
|
|
321
|
+
name: string;
|
|
322
|
+
address: {
|
|
323
|
+
city: string;
|
|
324
|
+
postcode: string;
|
|
325
|
+
line1?: string | undefined;
|
|
326
|
+
line2?: string | undefined;
|
|
327
|
+
countryCode?: string | undefined;
|
|
328
|
+
};
|
|
329
|
+
registrationId?: string | undefined;
|
|
330
|
+
registrationScheme?: string | undefined;
|
|
331
|
+
vatId?: string | undefined;
|
|
332
|
+
};
|
|
333
|
+
lines: {
|
|
334
|
+
name: string;
|
|
335
|
+
quantity: number;
|
|
336
|
+
unitPrice: number;
|
|
337
|
+
vatRate: number;
|
|
338
|
+
id?: string | undefined;
|
|
339
|
+
unitCode?: string | undefined;
|
|
340
|
+
vatCategory?: "S" | "Z" | "E" | "AE" | "K" | "G" | "O" | undefined;
|
|
341
|
+
}[];
|
|
342
|
+
typeCode?: number | undefined;
|
|
343
|
+
currency?: string | undefined;
|
|
344
|
+
buyerReference?: string | undefined;
|
|
345
|
+
dueDate?: string | Date | undefined;
|
|
346
|
+
}>;
|
|
347
|
+
type Invoice = z.input<typeof InvoiceSchema>;
|
|
348
|
+
type ResolvedInvoice = z.infer<typeof InvoiceSchema>;
|
|
349
|
+
declare function round2(n: number): number;
|
|
350
|
+
interface VatGroup {
|
|
351
|
+
rate: number;
|
|
352
|
+
category: string;
|
|
353
|
+
basis: number;
|
|
354
|
+
tax: number;
|
|
355
|
+
}
|
|
356
|
+
interface InvoiceTotals {
|
|
357
|
+
lineTotal: number;
|
|
358
|
+
taxBasisTotal: number;
|
|
359
|
+
taxTotal: number;
|
|
360
|
+
grandTotal: number;
|
|
361
|
+
duePayable: number;
|
|
362
|
+
vatBreakdown: VatGroup[];
|
|
363
|
+
lineAmounts: number[];
|
|
364
|
+
}
|
|
365
|
+
/** Compute line amounts, the VAT breakdown by (rate, category) and the totals. */
|
|
366
|
+
declare function computeTotals(invoice: ResolvedInvoice): InvoiceTotals;
|
|
367
|
+
|
|
368
|
+
/** EN 16931 guideline identifier carried by the Factur-X "EN 16931" profile. */
|
|
369
|
+
declare const EN16931_GUIDELINE = "urn:cen.eu:en16931:2017";
|
|
370
|
+
/**
|
|
371
|
+
* Generate the Cross Industry Invoice (CII) XML for the **EN 16931** Factur-X
|
|
372
|
+
* profile from invoice data. This is the TS happy-path: it produces a
|
|
373
|
+
* well-formed, semantically-correct CII; full Schematron validation is left to
|
|
374
|
+
* the conformance sidecar.
|
|
375
|
+
*/
|
|
376
|
+
declare function generateCII(input: Invoice): string;
|
|
377
|
+
|
|
378
|
+
interface EmbedOptions {
|
|
379
|
+
/** Name of the embedded XML part. Factur-X requires `factur-x.xml`. */
|
|
380
|
+
filename?: string;
|
|
381
|
+
/** Factur-X conformance level declared in the XMP. */
|
|
382
|
+
conformanceLevel?: string;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Embed a CII XML string into a PDF, producing a Factur-X invoice: the XML is
|
|
386
|
+
* attached as an associated file and the Factur-X XMP metadata is written.
|
|
387
|
+
*
|
|
388
|
+
* This is the TS happy-path (recognised by Chorus Pro / common readers). Strict
|
|
389
|
+
* **PDF/A-3b conformance** (ICC profile, embedded fonts, Schematron validation)
|
|
390
|
+
* is the job of the conformance sidecar — not provided here.
|
|
391
|
+
*/
|
|
392
|
+
declare function embedFacturX(pdfBytes: Uint8Array, xml: string, options?: EmbedOptions): Promise<Uint8Array>;
|
|
393
|
+
/** Convenience: generate the CII for an invoice and embed it into a PDF. */
|
|
394
|
+
declare function facturX(invoice: Invoice, pdfBytes: Uint8Array, options?: EmbedOptions): Promise<Uint8Array>;
|
|
395
|
+
|
|
396
|
+
export { type Address, AddressSchema, EN16931_GUIDELINE, type EmbedOptions, type Invoice, InvoiceSchema, type InvoiceTotals, type Line, LineSchema, type Party, PartySchema, type ResolvedInvoice, type VatGroup, computeTotals, embedFacturX, facturX, generateCII, round2 };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// src/schema.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var AddressSchema = z.object({
|
|
4
|
+
line1: z.string().optional(),
|
|
5
|
+
line2: z.string().optional(),
|
|
6
|
+
city: z.string().min(1),
|
|
7
|
+
postcode: z.string().min(1),
|
|
8
|
+
/** ISO 3166-1 alpha-2 country code (e.g. "FR"). */
|
|
9
|
+
countryCode: z.string().length(2).default("FR")
|
|
10
|
+
});
|
|
11
|
+
var PartySchema = z.object({
|
|
12
|
+
name: z.string().min(1),
|
|
13
|
+
/** Legal registration id, e.g. SIREN/SIRET (BT-30 / BT-47). */
|
|
14
|
+
registrationId: z.string().optional(),
|
|
15
|
+
/** Scheme for the registration id (ISO 6523), e.g. "0002" for SIRENE. */
|
|
16
|
+
registrationScheme: z.string().default("0002"),
|
|
17
|
+
/** VAT identifier, e.g. "FR40123456789" (BT-31 / BT-48). */
|
|
18
|
+
vatId: z.string().optional(),
|
|
19
|
+
address: AddressSchema
|
|
20
|
+
});
|
|
21
|
+
var LineSchema = z.object({
|
|
22
|
+
/** Line id; auto-numbered from 1 when omitted. */
|
|
23
|
+
id: z.string().optional(),
|
|
24
|
+
name: z.string().min(1),
|
|
25
|
+
quantity: z.number(),
|
|
26
|
+
/** UN/ECE Rec 20 unit code (default "C62" = one/piece). */
|
|
27
|
+
unitCode: z.string().default("C62"),
|
|
28
|
+
/** Net unit price (BT-146). */
|
|
29
|
+
unitPrice: z.number(),
|
|
30
|
+
/** VAT rate as a percentage, e.g. 20 for 20 % (BT-152). */
|
|
31
|
+
vatRate: z.number().min(0),
|
|
32
|
+
/** VAT category code (BT-151): S standard, Z zero, E exempt, … */
|
|
33
|
+
vatCategory: z.enum(["S", "Z", "E", "AE", "K", "G", "O"]).default("S")
|
|
34
|
+
});
|
|
35
|
+
var InvoiceSchema = z.object({
|
|
36
|
+
/** Invoice number (BT-1). */
|
|
37
|
+
number: z.string().min(1),
|
|
38
|
+
/** Issue date as YYYY-MM-DD or a Date (BT-2). */
|
|
39
|
+
issueDate: z.union([z.string(), z.date()]),
|
|
40
|
+
/** Document type code (BT-3); 380 = commercial invoice. */
|
|
41
|
+
typeCode: z.number().int().default(380),
|
|
42
|
+
/** Invoice currency, ISO 4217 (BT-5). */
|
|
43
|
+
currency: z.string().length(3).default("EUR"),
|
|
44
|
+
/** Buyer reference / order ref (BT-10) — often required (e.g. Chorus Pro). */
|
|
45
|
+
buyerReference: z.string().optional(),
|
|
46
|
+
/** Payment due date as YYYY-MM-DD or a Date (BT-9). */
|
|
47
|
+
dueDate: z.union([z.string(), z.date()]).optional(),
|
|
48
|
+
seller: PartySchema,
|
|
49
|
+
buyer: PartySchema,
|
|
50
|
+
lines: z.array(LineSchema).min(1)
|
|
51
|
+
});
|
|
52
|
+
function round2(n) {
|
|
53
|
+
return Math.round((n + Number.EPSILON) * 100) / 100;
|
|
54
|
+
}
|
|
55
|
+
function computeTotals(invoice) {
|
|
56
|
+
const lineAmounts = invoice.lines.map((l) => round2(l.quantity * l.unitPrice));
|
|
57
|
+
const lineTotal = round2(lineAmounts.reduce((a, b) => a + b, 0));
|
|
58
|
+
const groups = /* @__PURE__ */ new Map();
|
|
59
|
+
invoice.lines.forEach((line, i) => {
|
|
60
|
+
const key = `${line.vatCategory}:${line.vatRate}`;
|
|
61
|
+
const g = groups.get(key) ?? { rate: line.vatRate, category: line.vatCategory, basis: 0, tax: 0 };
|
|
62
|
+
g.basis = round2(g.basis + lineAmounts[i]);
|
|
63
|
+
groups.set(key, g);
|
|
64
|
+
});
|
|
65
|
+
const vatBreakdown = [...groups.values()].map((g) => ({
|
|
66
|
+
...g,
|
|
67
|
+
tax: round2(g.basis * g.rate / 100)
|
|
68
|
+
}));
|
|
69
|
+
const taxBasisTotal = lineTotal;
|
|
70
|
+
const taxTotal = round2(vatBreakdown.reduce((a, g) => a + g.tax, 0));
|
|
71
|
+
const grandTotal = round2(taxBasisTotal + taxTotal);
|
|
72
|
+
return {
|
|
73
|
+
lineTotal,
|
|
74
|
+
taxBasisTotal,
|
|
75
|
+
taxTotal,
|
|
76
|
+
grandTotal,
|
|
77
|
+
duePayable: grandTotal,
|
|
78
|
+
vatBreakdown,
|
|
79
|
+
lineAmounts
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/cii.ts
|
|
84
|
+
import { create } from "xmlbuilder2";
|
|
85
|
+
var NS = {
|
|
86
|
+
rsm: "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100",
|
|
87
|
+
ram: "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100",
|
|
88
|
+
udt: "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
|
|
89
|
+
};
|
|
90
|
+
var EN16931_GUIDELINE = "urn:cen.eu:en16931:2017";
|
|
91
|
+
function amount(n) {
|
|
92
|
+
return n.toFixed(2);
|
|
93
|
+
}
|
|
94
|
+
function ciiDate(value) {
|
|
95
|
+
const d = value instanceof Date ? value : new Date(value);
|
|
96
|
+
if (Number.isNaN(d.getTime())) throw new Error(`Invalid date: ${String(value)}`);
|
|
97
|
+
const yyyy = d.getUTCFullYear();
|
|
98
|
+
const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
|
|
99
|
+
const dd = String(d.getUTCDate()).padStart(2, "0");
|
|
100
|
+
return `${yyyy}${mm}${dd}`;
|
|
101
|
+
}
|
|
102
|
+
function dateTimeString(value) {
|
|
103
|
+
return { "udt:DateTimeString": { "@format": "102", "#": ciiDate(value) } };
|
|
104
|
+
}
|
|
105
|
+
function party(p) {
|
|
106
|
+
return {
|
|
107
|
+
"ram:Name": p.name,
|
|
108
|
+
...p.registrationId ? {
|
|
109
|
+
"ram:SpecifiedLegalOrganization": {
|
|
110
|
+
"ram:ID": { "@schemeID": p.registrationScheme, "#": p.registrationId }
|
|
111
|
+
}
|
|
112
|
+
} : {},
|
|
113
|
+
"ram:PostalTradeAddress": {
|
|
114
|
+
"ram:PostcodeCode": p.address.postcode,
|
|
115
|
+
...p.address.line1 ? { "ram:LineOne": p.address.line1 } : {},
|
|
116
|
+
...p.address.line2 ? { "ram:LineTwo": p.address.line2 } : {},
|
|
117
|
+
"ram:CityName": p.address.city,
|
|
118
|
+
"ram:CountryID": p.address.countryCode
|
|
119
|
+
},
|
|
120
|
+
...p.vatId ? { "ram:SpecifiedTaxRegistration": { "ram:ID": { "@schemeID": "VA", "#": p.vatId } } } : {}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function generateCII(input) {
|
|
124
|
+
const invoice = InvoiceSchema.parse(input);
|
|
125
|
+
const totals = computeTotals(invoice);
|
|
126
|
+
const lineItems = invoice.lines.map((line, i) => ({
|
|
127
|
+
"ram:AssociatedDocumentLineDocument": { "ram:LineID": line.id ?? String(i + 1) },
|
|
128
|
+
"ram:SpecifiedTradeProduct": { "ram:Name": line.name },
|
|
129
|
+
"ram:SpecifiedLineTradeAgreement": {
|
|
130
|
+
"ram:NetPriceProductTradePrice": { "ram:ChargeAmount": amount(line.unitPrice) }
|
|
131
|
+
},
|
|
132
|
+
"ram:SpecifiedLineTradeDelivery": {
|
|
133
|
+
"ram:BilledQuantity": { "@unitCode": line.unitCode, "#": String(line.quantity) }
|
|
134
|
+
},
|
|
135
|
+
"ram:SpecifiedLineTradeSettlement": {
|
|
136
|
+
"ram:ApplicableTradeTax": {
|
|
137
|
+
"ram:TypeCode": "VAT",
|
|
138
|
+
"ram:CategoryCode": line.vatCategory,
|
|
139
|
+
"ram:RateApplicablePercent": String(line.vatRate)
|
|
140
|
+
},
|
|
141
|
+
"ram:SpecifiedTradeSettlementLineMonetarySummation": {
|
|
142
|
+
"ram:LineTotalAmount": amount(totals.lineAmounts[i])
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}));
|
|
146
|
+
const headerTax = totals.vatBreakdown.map((g) => ({
|
|
147
|
+
"ram:CalculatedAmount": amount(g.tax),
|
|
148
|
+
"ram:TypeCode": "VAT",
|
|
149
|
+
"ram:BasisAmount": amount(g.basis),
|
|
150
|
+
"ram:CategoryCode": g.category,
|
|
151
|
+
"ram:RateApplicablePercent": String(g.rate)
|
|
152
|
+
}));
|
|
153
|
+
const obj = {
|
|
154
|
+
"rsm:CrossIndustryInvoice": {
|
|
155
|
+
"@xmlns:rsm": NS.rsm,
|
|
156
|
+
"@xmlns:ram": NS.ram,
|
|
157
|
+
"@xmlns:udt": NS.udt,
|
|
158
|
+
"rsm:ExchangedDocumentContext": {
|
|
159
|
+
"ram:GuidelineSpecifiedDocumentContextParameter": { "ram:ID": EN16931_GUIDELINE }
|
|
160
|
+
},
|
|
161
|
+
"rsm:ExchangedDocument": {
|
|
162
|
+
"ram:ID": invoice.number,
|
|
163
|
+
"ram:TypeCode": String(invoice.typeCode),
|
|
164
|
+
"ram:IssueDateTime": dateTimeString(invoice.issueDate)
|
|
165
|
+
},
|
|
166
|
+
"rsm:SupplyChainTradeTransaction": {
|
|
167
|
+
"ram:IncludedSupplyChainTradeLineItem": lineItems,
|
|
168
|
+
"ram:ApplicableHeaderTradeAgreement": {
|
|
169
|
+
...invoice.buyerReference ? { "ram:BuyerReference": invoice.buyerReference } : {},
|
|
170
|
+
"ram:SellerTradeParty": party(invoice.seller),
|
|
171
|
+
"ram:BuyerTradeParty": party(invoice.buyer)
|
|
172
|
+
},
|
|
173
|
+
"ram:ApplicableHeaderTradeDelivery": {},
|
|
174
|
+
"ram:ApplicableHeaderTradeSettlement": {
|
|
175
|
+
"ram:InvoiceCurrencyCode": invoice.currency,
|
|
176
|
+
"ram:ApplicableTradeTax": headerTax,
|
|
177
|
+
...invoice.dueDate ? {
|
|
178
|
+
"ram:SpecifiedTradePaymentTerms": {
|
|
179
|
+
"ram:DueDateDateTime": dateTimeString(invoice.dueDate)
|
|
180
|
+
}
|
|
181
|
+
} : {},
|
|
182
|
+
"ram:SpecifiedTradeSettlementHeaderMonetarySummation": {
|
|
183
|
+
"ram:LineTotalAmount": amount(totals.lineTotal),
|
|
184
|
+
"ram:TaxBasisTotalAmount": amount(totals.taxBasisTotal),
|
|
185
|
+
"ram:TaxTotalAmount": { "@currencyID": invoice.currency, "#": amount(totals.taxTotal) },
|
|
186
|
+
"ram:GrandTotalAmount": amount(totals.grandTotal),
|
|
187
|
+
"ram:DuePayableAmount": amount(totals.duePayable)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
return create({ encoding: "UTF-8" }, obj).end({ prettyPrint: true });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/embed.ts
|
|
197
|
+
import { AFRelationship, PDFDocument, PDFName, PDFRawStream } from "pdf-lib";
|
|
198
|
+
function facturXXmp(filename, level) {
|
|
199
|
+
const prop = (name, desc) => `<rdf:li rdf:parseType="Resource"><pdfaProperty:name>${name}</pdfaProperty:name><pdfaProperty:valueType>Text</pdfaProperty:valueType><pdfaProperty:category>external</pdfaProperty:category><pdfaProperty:description>${desc}</pdfaProperty:description></rdf:li>`;
|
|
200
|
+
return `<?xpacket begin="\uFEFF" id="W5M0MpCehiHzreSzNTczkc9d"?>
|
|
201
|
+
<x:xmpmeta xmlns:x="adobe:ns:meta/">
|
|
202
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
|
203
|
+
<rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">
|
|
204
|
+
<pdfaid:part>3</pdfaid:part>
|
|
205
|
+
<pdfaid:conformance>B</pdfaid:conformance>
|
|
206
|
+
</rdf:Description>
|
|
207
|
+
<rdf:Description rdf:about="" xmlns:fx="urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#">
|
|
208
|
+
<fx:DocumentType>INVOICE</fx:DocumentType>
|
|
209
|
+
<fx:DocumentFileName>${filename}</fx:DocumentFileName>
|
|
210
|
+
<fx:Version>1.0</fx:Version>
|
|
211
|
+
<fx:ConformanceLevel>${level}</fx:ConformanceLevel>
|
|
212
|
+
</rdf:Description>
|
|
213
|
+
<rdf:Description rdf:about="" xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/" xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#" xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">
|
|
214
|
+
<pdfaExtension:schemas>
|
|
215
|
+
<rdf:Bag>
|
|
216
|
+
<rdf:li rdf:parseType="Resource">
|
|
217
|
+
<pdfaSchema:schema>Factur-X PDFA Extension Schema</pdfaSchema:schema>
|
|
218
|
+
<pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>
|
|
219
|
+
<pdfaSchema:prefix>fx</pdfaSchema:prefix>
|
|
220
|
+
<pdfaSchema:property>
|
|
221
|
+
<rdf:Seq>
|
|
222
|
+
${prop("DocumentFileName", "name of the embedded XML invoice file")}
|
|
223
|
+
${prop("DocumentType", "INVOICE")}
|
|
224
|
+
${prop("Version", "the actual version of the Factur-X data")}
|
|
225
|
+
${prop("ConformanceLevel", "the conformance level of the Factur-X data")}
|
|
226
|
+
</rdf:Seq>
|
|
227
|
+
</pdfaSchema:property>
|
|
228
|
+
</rdf:li>
|
|
229
|
+
</rdf:Bag>
|
|
230
|
+
</pdfaExtension:schemas>
|
|
231
|
+
</rdf:Description>
|
|
232
|
+
</rdf:RDF>
|
|
233
|
+
</x:xmpmeta>
|
|
234
|
+
<?xpacket end="w"?>`;
|
|
235
|
+
}
|
|
236
|
+
async function embedFacturX(pdfBytes, xml, options = {}) {
|
|
237
|
+
const filename = options.filename ?? "factur-x.xml";
|
|
238
|
+
const level = options.conformanceLevel ?? "EN 16931";
|
|
239
|
+
const pdf = await PDFDocument.load(pdfBytes);
|
|
240
|
+
await pdf.attach(new TextEncoder().encode(xml), filename, {
|
|
241
|
+
mimeType: "text/xml",
|
|
242
|
+
description: "Factur-X invoice",
|
|
243
|
+
afRelationship: AFRelationship.Alternative,
|
|
244
|
+
creationDate: /* @__PURE__ */ new Date(),
|
|
245
|
+
modificationDate: /* @__PURE__ */ new Date()
|
|
246
|
+
});
|
|
247
|
+
const metaStream = PDFRawStream.of(
|
|
248
|
+
pdf.context.obj({ Type: "Metadata", Subtype: "XML" }),
|
|
249
|
+
new TextEncoder().encode(facturXXmp(filename, level))
|
|
250
|
+
);
|
|
251
|
+
pdf.catalog.set(PDFName.of("Metadata"), pdf.context.register(metaStream));
|
|
252
|
+
return pdf.save({ useObjectStreams: false });
|
|
253
|
+
}
|
|
254
|
+
async function facturX(invoice, pdfBytes, options = {}) {
|
|
255
|
+
return embedFacturX(pdfBytes, generateCII(invoice), options);
|
|
256
|
+
}
|
|
257
|
+
export {
|
|
258
|
+
AddressSchema,
|
|
259
|
+
EN16931_GUIDELINE,
|
|
260
|
+
InvoiceSchema,
|
|
261
|
+
LineSchema,
|
|
262
|
+
PartySchema,
|
|
263
|
+
computeTotals,
|
|
264
|
+
embedFacturX,
|
|
265
|
+
facturX,
|
|
266
|
+
generateCII,
|
|
267
|
+
round2
|
|
268
|
+
};
|
|
269
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts","../src/cii.ts","../src/embed.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/** A postal address (EN 16931 BG-5 / BG-8). */\nexport const AddressSchema = z.object({\n line1: z.string().optional(),\n line2: z.string().optional(),\n city: z.string().min(1),\n postcode: z.string().min(1),\n /** ISO 3166-1 alpha-2 country code (e.g. \"FR\"). */\n countryCode: z.string().length(2).default(\"FR\"),\n});\nexport type Address = z.infer<typeof AddressSchema>;\n\n/** A trade party — seller (BG-4) or buyer (BG-7). */\nexport const PartySchema = z.object({\n name: z.string().min(1),\n /** Legal registration id, e.g. SIREN/SIRET (BT-30 / BT-47). */\n registrationId: z.string().optional(),\n /** Scheme for the registration id (ISO 6523), e.g. \"0002\" for SIRENE. */\n registrationScheme: z.string().default(\"0002\"),\n /** VAT identifier, e.g. \"FR40123456789\" (BT-31 / BT-48). */\n vatId: z.string().optional(),\n address: AddressSchema,\n});\nexport type Party = z.infer<typeof PartySchema>;\n\n/** An invoice line (BG-25). */\nexport const LineSchema = z.object({\n /** Line id; auto-numbered from 1 when omitted. */\n id: z.string().optional(),\n name: z.string().min(1),\n quantity: z.number(),\n /** UN/ECE Rec 20 unit code (default \"C62\" = one/piece). */\n unitCode: z.string().default(\"C62\"),\n /** Net unit price (BT-146). */\n unitPrice: z.number(),\n /** VAT rate as a percentage, e.g. 20 for 20 % (BT-152). */\n vatRate: z.number().min(0),\n /** VAT category code (BT-151): S standard, Z zero, E exempt, … */\n vatCategory: z.enum([\"S\", \"Z\", \"E\", \"AE\", \"K\", \"G\", \"O\"]).default(\"S\"),\n});\nexport type Line = z.infer<typeof LineSchema>;\n\n/** A Factur-X invoice (EN 16931 core). */\nexport const InvoiceSchema = z.object({\n /** Invoice number (BT-1). */\n number: z.string().min(1),\n /** Issue date as YYYY-MM-DD or a Date (BT-2). */\n issueDate: z.union([z.string(), z.date()]),\n /** Document type code (BT-3); 380 = commercial invoice. */\n typeCode: z.number().int().default(380),\n /** Invoice currency, ISO 4217 (BT-5). */\n currency: z.string().length(3).default(\"EUR\"),\n /** Buyer reference / order ref (BT-10) — often required (e.g. Chorus Pro). */\n buyerReference: z.string().optional(),\n /** Payment due date as YYYY-MM-DD or a Date (BT-9). */\n dueDate: z.union([z.string(), z.date()]).optional(),\n seller: PartySchema,\n buyer: PartySchema,\n lines: z.array(LineSchema).min(1),\n});\nexport type Invoice = z.input<typeof InvoiceSchema>;\nexport type ResolvedInvoice = z.infer<typeof InvoiceSchema>;\n\nexport function round2(n: number): number {\n return Math.round((n + Number.EPSILON) * 100) / 100;\n}\n\nexport interface VatGroup {\n rate: number;\n category: string;\n basis: number;\n tax: number;\n}\n\nexport interface InvoiceTotals {\n lineTotal: number;\n taxBasisTotal: number;\n taxTotal: number;\n grandTotal: number;\n duePayable: number;\n vatBreakdown: VatGroup[];\n lineAmounts: number[];\n}\n\n/** Compute line amounts, the VAT breakdown by (rate, category) and the totals. */\nexport function computeTotals(invoice: ResolvedInvoice): InvoiceTotals {\n const lineAmounts = invoice.lines.map((l) => round2(l.quantity * l.unitPrice));\n const lineTotal = round2(lineAmounts.reduce((a, b) => a + b, 0));\n\n const groups = new Map<string, VatGroup>();\n invoice.lines.forEach((line, i) => {\n const key = `${line.vatCategory}:${line.vatRate}`;\n const g = groups.get(key) ?? { rate: line.vatRate, category: line.vatCategory, basis: 0, tax: 0 };\n g.basis = round2(g.basis + lineAmounts[i]);\n groups.set(key, g);\n });\n const vatBreakdown = [...groups.values()].map((g) => ({\n ...g,\n tax: round2((g.basis * g.rate) / 100),\n }));\n\n const taxBasisTotal = lineTotal;\n const taxTotal = round2(vatBreakdown.reduce((a, g) => a + g.tax, 0));\n const grandTotal = round2(taxBasisTotal + taxTotal);\n\n return {\n lineTotal,\n taxBasisTotal,\n taxTotal,\n grandTotal,\n duePayable: grandTotal,\n vatBreakdown,\n lineAmounts,\n };\n}\n","import { create } from \"xmlbuilder2\";\nimport {\n InvoiceSchema,\n computeTotals,\n type Invoice,\n type Party,\n type ResolvedInvoice,\n} from \"./schema.js\";\n\nconst NS = {\n rsm: \"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\",\n ram: \"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\",\n udt: \"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\",\n};\n\n/** EN 16931 guideline identifier carried by the Factur-X \"EN 16931\" profile. */\nexport const EN16931_GUIDELINE = \"urn:cen.eu:en16931:2017\";\n\nfunction amount(n: number): string {\n return n.toFixed(2);\n}\n\nfunction ciiDate(value: string | Date): string {\n const d = value instanceof Date ? value : new Date(value);\n if (Number.isNaN(d.getTime())) throw new Error(`Invalid date: ${String(value)}`);\n const yyyy = d.getUTCFullYear();\n const mm = String(d.getUTCMonth() + 1).padStart(2, \"0\");\n const dd = String(d.getUTCDate()).padStart(2, \"0\");\n return `${yyyy}${mm}${dd}`;\n}\n\nfunction dateTimeString(value: string | Date): Record<string, unknown> {\n return { \"udt:DateTimeString\": { \"@format\": \"102\", \"#\": ciiDate(value) } };\n}\n\nfunction party(p: Party): Record<string, unknown> {\n return {\n \"ram:Name\": p.name,\n ...(p.registrationId\n ? {\n \"ram:SpecifiedLegalOrganization\": {\n \"ram:ID\": { \"@schemeID\": p.registrationScheme, \"#\": p.registrationId },\n },\n }\n : {}),\n \"ram:PostalTradeAddress\": {\n \"ram:PostcodeCode\": p.address.postcode,\n ...(p.address.line1 ? { \"ram:LineOne\": p.address.line1 } : {}),\n ...(p.address.line2 ? { \"ram:LineTwo\": p.address.line2 } : {}),\n \"ram:CityName\": p.address.city,\n \"ram:CountryID\": p.address.countryCode,\n },\n ...(p.vatId\n ? { \"ram:SpecifiedTaxRegistration\": { \"ram:ID\": { \"@schemeID\": \"VA\", \"#\": p.vatId } } }\n : {}),\n };\n}\n\n/**\n * Generate the Cross Industry Invoice (CII) XML for the **EN 16931** Factur-X\n * profile from invoice data. This is the TS happy-path: it produces a\n * well-formed, semantically-correct CII; full Schematron validation is left to\n * the conformance sidecar.\n */\nexport function generateCII(input: Invoice): string {\n const invoice: ResolvedInvoice = InvoiceSchema.parse(input);\n const totals = computeTotals(invoice);\n\n const lineItems = invoice.lines.map((line, i) => ({\n \"ram:AssociatedDocumentLineDocument\": { \"ram:LineID\": line.id ?? String(i + 1) },\n \"ram:SpecifiedTradeProduct\": { \"ram:Name\": line.name },\n \"ram:SpecifiedLineTradeAgreement\": {\n \"ram:NetPriceProductTradePrice\": { \"ram:ChargeAmount\": amount(line.unitPrice) },\n },\n \"ram:SpecifiedLineTradeDelivery\": {\n \"ram:BilledQuantity\": { \"@unitCode\": line.unitCode, \"#\": String(line.quantity) },\n },\n \"ram:SpecifiedLineTradeSettlement\": {\n \"ram:ApplicableTradeTax\": {\n \"ram:TypeCode\": \"VAT\",\n \"ram:CategoryCode\": line.vatCategory,\n \"ram:RateApplicablePercent\": String(line.vatRate),\n },\n \"ram:SpecifiedTradeSettlementLineMonetarySummation\": {\n \"ram:LineTotalAmount\": amount(totals.lineAmounts[i]),\n },\n },\n }));\n\n const headerTax = totals.vatBreakdown.map((g) => ({\n \"ram:CalculatedAmount\": amount(g.tax),\n \"ram:TypeCode\": \"VAT\",\n \"ram:BasisAmount\": amount(g.basis),\n \"ram:CategoryCode\": g.category,\n \"ram:RateApplicablePercent\": String(g.rate),\n }));\n\n const obj = {\n \"rsm:CrossIndustryInvoice\": {\n \"@xmlns:rsm\": NS.rsm,\n \"@xmlns:ram\": NS.ram,\n \"@xmlns:udt\": NS.udt,\n \"rsm:ExchangedDocumentContext\": {\n \"ram:GuidelineSpecifiedDocumentContextParameter\": { \"ram:ID\": EN16931_GUIDELINE },\n },\n \"rsm:ExchangedDocument\": {\n \"ram:ID\": invoice.number,\n \"ram:TypeCode\": String(invoice.typeCode),\n \"ram:IssueDateTime\": dateTimeString(invoice.issueDate),\n },\n \"rsm:SupplyChainTradeTransaction\": {\n \"ram:IncludedSupplyChainTradeLineItem\": lineItems,\n \"ram:ApplicableHeaderTradeAgreement\": {\n ...(invoice.buyerReference ? { \"ram:BuyerReference\": invoice.buyerReference } : {}),\n \"ram:SellerTradeParty\": party(invoice.seller),\n \"ram:BuyerTradeParty\": party(invoice.buyer),\n },\n \"ram:ApplicableHeaderTradeDelivery\": {},\n \"ram:ApplicableHeaderTradeSettlement\": {\n \"ram:InvoiceCurrencyCode\": invoice.currency,\n \"ram:ApplicableTradeTax\": headerTax,\n ...(invoice.dueDate\n ? {\n \"ram:SpecifiedTradePaymentTerms\": {\n \"ram:DueDateDateTime\": dateTimeString(invoice.dueDate),\n },\n }\n : {}),\n \"ram:SpecifiedTradeSettlementHeaderMonetarySummation\": {\n \"ram:LineTotalAmount\": amount(totals.lineTotal),\n \"ram:TaxBasisTotalAmount\": amount(totals.taxBasisTotal),\n \"ram:TaxTotalAmount\": { \"@currencyID\": invoice.currency, \"#\": amount(totals.taxTotal) },\n \"ram:GrandTotalAmount\": amount(totals.grandTotal),\n \"ram:DuePayableAmount\": amount(totals.duePayable),\n },\n },\n },\n },\n };\n\n return create({ encoding: \"UTF-8\" }, obj).end({ prettyPrint: true });\n}\n","import { AFRelationship, PDFDocument, PDFName, PDFRawStream } from \"pdf-lib\";\nimport { generateCII } from \"./cii.js\";\nimport type { Invoice } from \"./schema.js\";\n\nexport interface EmbedOptions {\n /** Name of the embedded XML part. Factur-X requires `factur-x.xml`. */\n filename?: string;\n /** Factur-X conformance level declared in the XMP. */\n conformanceLevel?: string;\n}\n\nfunction facturXXmp(filename: string, level: string): string {\n const prop = (name: string, desc: string) =>\n `<rdf:li rdf:parseType=\"Resource\"><pdfaProperty:name>${name}</pdfaProperty:name><pdfaProperty:valueType>Text</pdfaProperty:valueType><pdfaProperty:category>external</pdfaProperty:category><pdfaProperty:description>${desc}</pdfaProperty:description></rdf:li>`;\n return `<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n<x:xmpmeta xmlns:x=\"adobe:ns:meta/\">\n <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n <rdf:Description rdf:about=\"\" xmlns:pdfaid=\"http://www.aiim.org/pdfa/ns/id/\">\n <pdfaid:part>3</pdfaid:part>\n <pdfaid:conformance>B</pdfaid:conformance>\n </rdf:Description>\n <rdf:Description rdf:about=\"\" xmlns:fx=\"urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#\">\n <fx:DocumentType>INVOICE</fx:DocumentType>\n <fx:DocumentFileName>${filename}</fx:DocumentFileName>\n <fx:Version>1.0</fx:Version>\n <fx:ConformanceLevel>${level}</fx:ConformanceLevel>\n </rdf:Description>\n <rdf:Description rdf:about=\"\" xmlns:pdfaExtension=\"http://www.aiim.org/pdfa/ns/extension/\" xmlns:pdfaSchema=\"http://www.aiim.org/pdfa/ns/schema#\" xmlns:pdfaProperty=\"http://www.aiim.org/pdfa/ns/property#\">\n <pdfaExtension:schemas>\n <rdf:Bag>\n <rdf:li rdf:parseType=\"Resource\">\n <pdfaSchema:schema>Factur-X PDFA Extension Schema</pdfaSchema:schema>\n <pdfaSchema:namespaceURI>urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#</pdfaSchema:namespaceURI>\n <pdfaSchema:prefix>fx</pdfaSchema:prefix>\n <pdfaSchema:property>\n <rdf:Seq>\n ${prop(\"DocumentFileName\", \"name of the embedded XML invoice file\")}\n ${prop(\"DocumentType\", \"INVOICE\")}\n ${prop(\"Version\", \"the actual version of the Factur-X data\")}\n ${prop(\"ConformanceLevel\", \"the conformance level of the Factur-X data\")}\n </rdf:Seq>\n </pdfaSchema:property>\n </rdf:li>\n </rdf:Bag>\n </pdfaExtension:schemas>\n </rdf:Description>\n </rdf:RDF>\n</x:xmpmeta>\n<?xpacket end=\"w\"?>`;\n}\n\n/**\n * Embed a CII XML string into a PDF, producing a Factur-X invoice: the XML is\n * attached as an associated file and the Factur-X XMP metadata is written.\n *\n * This is the TS happy-path (recognised by Chorus Pro / common readers). Strict\n * **PDF/A-3b conformance** (ICC profile, embedded fonts, Schematron validation)\n * is the job of the conformance sidecar — not provided here.\n */\nexport async function embedFacturX(\n pdfBytes: Uint8Array,\n xml: string,\n options: EmbedOptions = {},\n): Promise<Uint8Array> {\n const filename = options.filename ?? \"factur-x.xml\";\n const level = options.conformanceLevel ?? \"EN 16931\";\n\n const pdf = await PDFDocument.load(pdfBytes);\n\n await pdf.attach(new TextEncoder().encode(xml), filename, {\n mimeType: \"text/xml\",\n description: \"Factur-X invoice\",\n afRelationship: AFRelationship.Alternative,\n creationDate: new Date(),\n modificationDate: new Date(),\n });\n\n const metaStream = PDFRawStream.of(\n pdf.context.obj({ Type: \"Metadata\", Subtype: \"XML\" }),\n new TextEncoder().encode(facturXXmp(filename, level)),\n );\n pdf.catalog.set(PDFName.of(\"Metadata\"), pdf.context.register(metaStream));\n\n // Avoid compressed object streams — friendlier for Factur-X / PDF-A readers.\n return pdf.save({ useObjectStreams: false });\n}\n\n/** Convenience: generate the CII for an invoice and embed it into a PDF. */\nexport async function facturX(\n invoice: Invoice,\n pdfBytes: Uint8Array,\n options: EmbedOptions = {},\n): Promise<Uint8Array> {\n return embedFacturX(pdfBytes, generateCII(invoice), options);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@liasse/factur-x",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Liasse Factur-X module — generate the EN 16931 CII XML and embed it into a PDF to produce a Factur-X invoice (TS happy-path).",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"pdf-lib": "^1.17.1",
|
|
25
|
+
"xmlbuilder2": "^4.0.3",
|
|
26
|
+
"zod": "^3.24.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^22.10.2",
|
|
30
|
+
"tsup": "^8.3.5",
|
|
31
|
+
"typescript": "^5.7.2",
|
|
32
|
+
"vitest": "^2.1.8"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"test": "vitest run"
|
|
38
|
+
}
|
|
39
|
+
}
|