@taxora/sdk 1.9.0 → 1.10.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 CHANGED
@@ -4,6 +4,35 @@ All notable changes to `@taxora/sdk` are documented here. Versions follow [SemVe
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.10.0] - 2026-11-03
8
+
9
+ ### Added
10
+
11
+ - `ComplianceTax.rate()`, `zeroRated()`, `exempt()` and `reverseCharge()` build line taxes with the right category.
12
+ - `calculateInvoiceTotals(lines, { expectedTotal })` checks your own total against the lines and reports `roundingDifference`.
13
+
14
+ ### Changed
15
+
16
+ - `createTransaction()` refuses impossible input before the request: an unknown tax category, a category `E` tax
17
+ without its exemption code (`comment`), a percent outside 0–100, a currency or country code that is not letters
18
+ (currency, counterparty country and tax categories are upper-cased), a due date before the invoice date, a credit
19
+ note without `amendedNumber` (or `amendedNumber` without `isCreditNote`), a credit note reusing the number it corrects
20
+ and a corrected invoice dated after the credit note.
21
+
22
+ ### Added
23
+
24
+ - **`eReporting.createCreditNote(original, input)`** — credit an invoice you sent through Taxora. Buyer, lines, amounts,
25
+ currency and the reference to the corrected invoice (number and date) are taken from `original`; partial credits pass
26
+ `invoiceLines`, `subtotal`, `taxAmount` and `total` together. Refused up front for invoices that were never sent
27
+ (`not_required`) and for credit notes.
28
+ - **`eReporting.decideDelivery(country, id, scheme?)`** — `peppolLookup()` turned into an action
29
+ (`ComplianceDeliveryAction`: `einvoice`, `einvoice_pending`, `regular_invoice`) for a shop checkout.
30
+ - **`calculateInvoiceTotals(lines)`** — subtotal, VAT and total of invoice lines, rounded the way the e-invoice is built,
31
+ so the header amounts of `createTransaction()` always match the lines.
32
+ - **`ComplianceTaxCategory`** (`S`, `AA`, `AAA`, `K`, `G`, `AE`, `E`, `Z`) and `parseComplianceTaxCategory()`.
33
+ - **`billing.getEInvoicingQuota(months?)`** — `GET /billing/einvoicing-quota` as `EInvoicingQuota` (documents included,
34
+ used, still free and what is due per month); `null` without e-invoicing.
35
+
7
36
  ## [1.9.0] — 2026-10-27
8
37
 
9
38
  ### Added
package/README.md CHANGED
@@ -821,6 +821,41 @@ if (reach.isPending) {
821
821
  console.log(reach.status, reach.reachable, reach.documentTypes); // 'reachable' true [...]
822
822
  ```
823
823
 
824
+ Or let the SDK turn the answer into an action (shop checkout, one call):
825
+
826
+ ```ts
827
+ const decision = await client.eReporting.decideDelivery('NO', '974760673');
828
+ switch (decision.action) {
829
+ case 'einvoice': // create the transaction, Taxora sends the e-invoice
830
+ case 'einvoice_pending': // no answer yet: create it anyway, Taxora asks again before sending
831
+ break;
832
+ case 'regular_invoice': // not on Peppol: send your usual invoice, nothing is billed
833
+ break;
834
+ }
835
+ ```
836
+
837
+ The SDK refuses input that cannot be right before any request: unknown tax categories
838
+ (`ComplianceTaxCategory`: `S`, `AA`, `AAA`, `K`, `G`, `AE`, `E`, `Z`, any case), a category `E` line without its VATEX
839
+ exemption code, currency and country codes that are not letters (they are upper-cased), a due date before the invoice
840
+ date, and credit notes without (or invoices with) a corrected invoice. The API additionally checks that an e-invoice's
841
+ `subtotal`, `taxAmount` and `total` match its lines — compute them from the lines:
842
+
843
+ ```ts
844
+ import { calculateInvoiceTotals } from '@taxora/sdk';
845
+
846
+ const { subtotal, taxAmount, total } = calculateInvoiceTotals(invoiceLines); // rounded like the e-invoice
847
+ ```
848
+
849
+ Taxes without remembering category codes: `ComplianceTax.rate(25)` (category `S`, any rate above 0 %; in Norway 25/15/12 % are all `S`, for France's reduced rates pass `ComplianceTax.rate(10, 'TVA', 'AA')`), `zeroRated()` (`Z`),
850
+ `exempt('VATEX-EU-132')` (`E`, code mandatory) and `reverseCharge()` (`AE`). The rate itself is yours to know; the API checks
851
+ it against the country's catalogue. The tax name defaults to `VAT` (`ComplianceTax.rate(25, 'MVA')`).
852
+
853
+ If your own system already shows the buyer a total, pass it as a safety net:
854
+ `calculateInvoiceTotals(lines, { expectedTotal: 1249.99 })`. The totals always follow the lines, because the e-invoice is built
855
+ from them. A difference up to 0.05 is reported as `roundingDifference`; anything larger throws, since then quantities, prices or
856
+ rates are wrong. The invoice number is printed on the buyer's e-invoice and must be unique per enrollment (a different invoice
857
+ with a used number answers `409 invoice_number_taken`).
858
+
824
859
  **4. Send an invoice** — Norway requires `transactionType: 'b2b_domestic_outbound'`, the buyer's
825
860
  organisation number (`counterpartyRegisterId`) and `counterpartyName` (enforced server-side, 422):
826
861
 
@@ -877,6 +912,21 @@ const creditNote = await client.eReporting.createTransaction({
877
912
  });
878
913
  console.log(creditNote.isCreditNote); // true
879
914
 
915
+ // Shorter and harder to get wrong: credit an invoice you already sent. Buyer, lines, amounts,
916
+ // currency and the reference to the corrected invoice are taken from it.
917
+ const credit = await client.eReporting.createCreditNote(invoice, { creditNoteNumber: 'NO-2026-0001-CN' });
918
+
919
+ // Partial credit: pass the credited lines and all amounts together.
920
+ await client.eReporting.createCreditNote(invoice, {
921
+ creditNoteNumber: 'NO-2026-0001-CN2',
922
+ invoiceLines: [
923
+ { description: 'Consulting', quantity: 1, price: 1000, taxes: [{ name: 'MVA', percent: 25, category: 'S' }] },
924
+ ],
925
+ subtotal: 1000,
926
+ taxAmount: 250,
927
+ total: 1250,
928
+ });
929
+
880
930
  // All Norwegian documents
881
931
  const noDocs = await client.eReporting.listTransactions({ country: 'NO' });
882
932
  ```
@@ -972,6 +1022,10 @@ for (const summary of page) {
972
1022
 
973
1023
  const september = await client.billing.getUsageSummaries('2026-09'); // with events; 404 for a period without usage
974
1024
  console.log(september[0]?.events.length);
1025
+
1026
+ // E-invoicing allowance: documents included per month, used, still free, what is due beyond it (null without e-invoicing)
1027
+ const quota = await client.billing.getEInvoicingQuota();
1028
+ console.log(quota?.current.freeRemaining, 'of', quota?.current.included, 'documents free this month');
975
1029
  ```
976
1030
 
977
1031
  ---