@stackforge-eu/factur-x 1.3.1 → 1.4.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/CHANGELOG.md +11 -0
- package/dist/index.cjs +18 -2
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +18 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.4.0] — 2026-09-03
|
|
11
|
+
|
|
12
|
+
- **Added the item price discount (BT-147).** A new optional `priceDiscount`
|
|
13
|
+
field on `InvoiceLineInput` emits `ram:AppliedTradeAllowanceCharge` inside
|
|
14
|
+
the gross price element, so a line can state the discount that connects the
|
|
15
|
+
gross unit price (BT-148) to the net unit price (BT-146) instead of leaving
|
|
16
|
+
it implied by their difference. Requires `grossUnitPrice` to be set; the
|
|
17
|
+
amount keeps up to four decimals for sub-cent discounts. Omitting the field
|
|
18
|
+
keeps the output byte-for-byte identical (#15).
|
|
19
|
+
|
|
10
20
|
## [1.3.1] — 2026-09-01
|
|
11
21
|
|
|
12
22
|
- **Dropped the unused `schema/cii-d22b/` code-list XSDs from the npm and JSR
|
|
@@ -235,6 +245,7 @@ This element is not expected`. Reordered the three blocks in
|
|
|
235
245
|
- Deno compatibility test suite
|
|
236
246
|
|
|
237
247
|
[Unreleased]: https://github.com/StackForge-EU/factur-x/commits/main
|
|
248
|
+
[1.4.0]: https://github.com/StackForge-EU/factur-x/compare/v1.3.1...v1.4.0
|
|
238
249
|
[1.3.1]: https://github.com/StackForge-EU/factur-x/compare/v1.3.0...v1.3.1
|
|
239
250
|
[1.3.0]: https://github.com/StackForge-EU/factur-x/compare/v1.2.1...v1.3.0
|
|
240
251
|
[1.2.1]: https://github.com/StackForge-EU/factur-x/compare/v1.2.0...v1.2.1
|
package/dist/index.cjs
CHANGED
|
@@ -307,6 +307,12 @@ function fmtAmt(n) {
|
|
|
307
307
|
}
|
|
308
308
|
return n.toFixed(2);
|
|
309
309
|
}
|
|
310
|
+
function fmtPrice(n) {
|
|
311
|
+
if (!Number.isFinite(n)) {
|
|
312
|
+
throw new Error(`Invalid amount value: ${n}. Expected a finite number.`);
|
|
313
|
+
}
|
|
314
|
+
return n.toFixed(4).replace(/(\.\d{2}\d*?)0+$/, "$1");
|
|
315
|
+
}
|
|
310
316
|
function tag(name, content, attrs) {
|
|
311
317
|
const a = attrs ? Object.entries(attrs).map(([k, v]) => ` ${k}="${escapeXml(v)}"`).join("") : "";
|
|
312
318
|
return `<${name}${a}>${content}</${name}>`;
|
|
@@ -406,11 +412,21 @@ function buildLineItem(line, profile) {
|
|
|
406
412
|
const basisQuantity = line.basisQuantity !== void 0 ? tag("ram:BasisQuantity", line.basisQuantity.toString(), {
|
|
407
413
|
unitCode: line.basisQuantityUnitCode ?? unitCode
|
|
408
414
|
}) : "";
|
|
409
|
-
if (line.
|
|
415
|
+
if (line.priceDiscount !== void 0 && line.grossUnitPrice === void 0) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
`buildXml: line "${line.id}" sets "priceDiscount" (BT-147) without "grossUnitPrice" (BT-148).`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
if (line.grossUnitPrice !== void 0) {
|
|
421
|
+
const discount = line.priceDiscount !== void 0 ? tag(
|
|
422
|
+
"ram:AppliedTradeAllowanceCharge",
|
|
423
|
+
tag("ram:ChargeIndicator", tag("udt:Indicator", "false")) + tag("ram:ActualAmount", fmtPrice(line.priceDiscount))
|
|
424
|
+
) : "";
|
|
410
425
|
agree += tag(
|
|
411
426
|
"ram:GrossPriceProductTradePrice",
|
|
412
|
-
tag("ram:ChargeAmount", fmtAmt(line.grossUnitPrice)) + basisQuantity
|
|
427
|
+
tag("ram:ChargeAmount", fmtAmt(line.grossUnitPrice)) + basisQuantity + discount
|
|
413
428
|
);
|
|
429
|
+
}
|
|
414
430
|
agree += tag(
|
|
415
431
|
"ram:NetPriceProductTradePrice",
|
|
416
432
|
tag("ram:ChargeAmount", fmtAmt(line.unitPrice)) + basisQuantity
|
package/dist/index.d.cts
CHANGED
|
@@ -573,6 +573,14 @@ interface InvoiceLineInput {
|
|
|
573
573
|
* @see EN 16931 BT-148
|
|
574
574
|
*/
|
|
575
575
|
grossUnitPrice?: number;
|
|
576
|
+
/**
|
|
577
|
+
* Item price discount — the amount subtracted from `grossUnitPrice`
|
|
578
|
+
* (BT-148) to arrive at `unitPrice` (BT-146). Emitted as
|
|
579
|
+
* `ram:AppliedTradeAllowanceCharge` inside the gross price element,
|
|
580
|
+
* so `grossUnitPrice` must be set alongside it.
|
|
581
|
+
* @see EN 16931 BT-147
|
|
582
|
+
*/
|
|
583
|
+
priceDiscount?: number;
|
|
576
584
|
/**
|
|
577
585
|
* Item price base quantity — the quantity the unit price (BT-146)
|
|
578
586
|
* applies to, e.g. a price per 10 square metres or per 1000 prints.
|
package/dist/index.d.ts
CHANGED
|
@@ -573,6 +573,14 @@ interface InvoiceLineInput {
|
|
|
573
573
|
* @see EN 16931 BT-148
|
|
574
574
|
*/
|
|
575
575
|
grossUnitPrice?: number;
|
|
576
|
+
/**
|
|
577
|
+
* Item price discount — the amount subtracted from `grossUnitPrice`
|
|
578
|
+
* (BT-148) to arrive at `unitPrice` (BT-146). Emitted as
|
|
579
|
+
* `ram:AppliedTradeAllowanceCharge` inside the gross price element,
|
|
580
|
+
* so `grossUnitPrice` must be set alongside it.
|
|
581
|
+
* @see EN 16931 BT-147
|
|
582
|
+
*/
|
|
583
|
+
priceDiscount?: number;
|
|
576
584
|
/**
|
|
577
585
|
* Item price base quantity — the quantity the unit price (BT-146)
|
|
578
586
|
* applies to, e.g. a price per 10 square metres or per 1000 prints.
|
package/dist/index.js
CHANGED
|
@@ -277,6 +277,12 @@ function fmtAmt(n) {
|
|
|
277
277
|
}
|
|
278
278
|
return n.toFixed(2);
|
|
279
279
|
}
|
|
280
|
+
function fmtPrice(n) {
|
|
281
|
+
if (!Number.isFinite(n)) {
|
|
282
|
+
throw new Error(`Invalid amount value: ${n}. Expected a finite number.`);
|
|
283
|
+
}
|
|
284
|
+
return n.toFixed(4).replace(/(\.\d{2}\d*?)0+$/, "$1");
|
|
285
|
+
}
|
|
280
286
|
function tag(name, content, attrs) {
|
|
281
287
|
const a = attrs ? Object.entries(attrs).map(([k, v]) => ` ${k}="${escapeXml(v)}"`).join("") : "";
|
|
282
288
|
return `<${name}${a}>${content}</${name}>`;
|
|
@@ -376,11 +382,21 @@ function buildLineItem(line, profile) {
|
|
|
376
382
|
const basisQuantity = line.basisQuantity !== void 0 ? tag("ram:BasisQuantity", line.basisQuantity.toString(), {
|
|
377
383
|
unitCode: line.basisQuantityUnitCode ?? unitCode
|
|
378
384
|
}) : "";
|
|
379
|
-
if (line.
|
|
385
|
+
if (line.priceDiscount !== void 0 && line.grossUnitPrice === void 0) {
|
|
386
|
+
throw new Error(
|
|
387
|
+
`buildXml: line "${line.id}" sets "priceDiscount" (BT-147) without "grossUnitPrice" (BT-148).`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
if (line.grossUnitPrice !== void 0) {
|
|
391
|
+
const discount = line.priceDiscount !== void 0 ? tag(
|
|
392
|
+
"ram:AppliedTradeAllowanceCharge",
|
|
393
|
+
tag("ram:ChargeIndicator", tag("udt:Indicator", "false")) + tag("ram:ActualAmount", fmtPrice(line.priceDiscount))
|
|
394
|
+
) : "";
|
|
380
395
|
agree += tag(
|
|
381
396
|
"ram:GrossPriceProductTradePrice",
|
|
382
|
-
tag("ram:ChargeAmount", fmtAmt(line.grossUnitPrice)) + basisQuantity
|
|
397
|
+
tag("ram:ChargeAmount", fmtAmt(line.grossUnitPrice)) + basisQuantity + discount
|
|
383
398
|
);
|
|
399
|
+
}
|
|
384
400
|
agree += tag(
|
|
385
401
|
"ram:NetPriceProductTradePrice",
|
|
386
402
|
tag("ram:ChargeAmount", fmtAmt(line.unitPrice)) + basisQuantity
|