Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
329 changes: 303 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,321 @@ npm install @pixeldrive/peppol-toolkit
### ESM

```typescript
import { PeppolToolkit, createToolkit } from '@pixeldrive/peppol-toolkit';
import { PeppolToolkit } from '@pixeldrive/peppol-toolkit';

// Using the class directly
const toolkit = new PeppolToolkit();

// Or using the factory function
// const toolkit = createToolkit();

// Generate PEPPOL UBL XML from invoice data
const invoiceData = {};
const peppolXML = toolkit.invoiceToPeppolUBL(invoiceData);
console.log(peppolXML);
```

### CommonJS

```javascript
const { PeppolToolkit, createToolkit } = require('@pixeldrive/peppol-toolkit');
const { PeppolToolkit } = require('@pixeldrive/peppol-toolkit');

const toolkit = new PeppolToolkit();
```

## Usage Examples

### Generate a PEPPOL UBL Invoice

```typescript
import { PeppolToolkit, Invoice } from '@pixeldrive/peppol-toolkit';

const toolkit = new PeppolToolkit();

const invoice: Invoice = {
ID: 'INV-2024-001',
issueDate: '2024-01-15',
dueDate: '2024-02-15',
invoiceTypeCode: 380,
documentCurrencyCode: 'EUR',
buyerReference: 'PO-12345',
seller: {
endPoint: { scheme: '9925', id: '0123456789' },
legalEntity: {
registrationName: 'Acme Corp',
companyId: '0123456789',
},
name: 'Acme Corp',
address: {
streetName: '123 Seller Street',
cityName: 'Brussels',
postalZone: '1000',
country: 'BE',
},
taxSchemeCompanyID: 'BE0123456789',
identification: [{ id: 'BE0123456789' }],
},
buyer: {
endPoint: { scheme: '9925', id: '9876543210' },
legalEntity: {
registrationName: 'Buyer Ltd',
companyId: '9876543210',
legalForm: 'SRL',
},
name: 'Buyer Ltd',
address: {
streetName: '456 Buyer Avenue',
cityName: 'Amsterdam',
postalZone: '1011',
country: 'NL',
},
taxSchemeCompanyID: 'NL9876543210',
identification: [{ id: 'NL9876543210' }],
},
paymentMeans: [
{
code: '30',
paymentId: 'INV-2024-001',
name: 'Bank Transfer',
financialAccount: {
id: 'BE71 0961 2345 6769',
name: 'Acme Corp',
financialInstitutionBranch: 'GEBABEBB',
},
},
],
paymentTermsNote: 'Payment due within 30 days.',
taxTotal: [
{
taxAmountCurrency: 'EUR',
taxAmount: 210.0,
subTotals: [
{
taxableAmount: 1000,
taxAmount: 210,
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
},
],
legalMonetaryTotal: {
currency: 'EUR',
lineExtensionAmount: 1000,
taxExclusiveAmount: 1000,
taxInclusiveAmount: 1210,
prepaidAmount: 0,
payableAmount: 1210,
},
invoiceLines: [
{
id: '1',
invoicedQuantity: 10,
unitCode: 'EA',
lineExtensionAmount: 1000,
price: 100,
name: 'Consulting Services',
currency: 'EUR',
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
};

const xml: string = toolkit.invoiceToPeppolUBL(invoice);
console.log(xml);
```

### Generate a PEPPOL UBL Credit Note

```typescript
import { PeppolToolkit, CreditNote } from '@pixeldrive/peppol-toolkit';

const toolkit = new PeppolToolkit();

const creditNote: CreditNote = {
ID: 'CN-2024-001',
issueDate: '2024-01-20',
creditNoteTypeCode: 381,
documentCurrencyCode: 'EUR',
buyerReference: 'PO-12345',
billingReference: {
invoiceDocReference: {
id: 'INV-2024-001',
issueDate: '2024-01-15',
},
},
seller: {
endPoint: { scheme: '9925', id: '0123456789' },
legalEntity: {
registrationName: 'Acme Corp',
companyId: '0123456789',
},
name: 'Acme Corp',
address: {
streetName: '123 Seller Street',
cityName: 'Brussels',
postalZone: '1000',
country: 'BE',
},
taxSchemeCompanyID: 'BE0123456789',
identification: [{ id: 'BE0123456789' }],
},
buyer: {
endPoint: { scheme: '9925', id: '9876543210' },
legalEntity: {
registrationName: 'Buyer Ltd',
companyId: '9876543210',
},
name: 'Buyer Ltd',
address: {
streetName: '456 Buyer Avenue',
cityName: 'Amsterdam',
postalZone: '1011',
country: 'NL',
},
taxSchemeCompanyID: 'NL9876543210',
identification: [{ id: 'NL9876543210' }],
},
taxTotal: [
{
taxAmountCurrency: 'EUR',
taxAmount: 21.0,
subTotals: [
{
taxableAmount: 100,
taxAmount: 21,
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
},
],
legalMonetaryTotal: {
currency: 'EUR',
lineExtensionAmount: 100,
taxExclusiveAmount: 100,
taxInclusiveAmount: 121,
prepaidAmount: 0,
payableAmount: 121,
},
creditNoteLines: [
{
id: '1',
invoicedQuantity: 1,
unitCode: 'EA',
lineExtensionAmount: 100,
price: 100,
name: 'Consulting Services (correction)',
currency: 'EUR',
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
};

const xml: string = toolkit.creditNoteToPeppolUBL(creditNote);
console.log(xml);
```

### Parse a PEPPOL UBL XML back to an Invoice or CreditNote

```typescript
import { PeppolToolkit, Invoice, CreditNote } from '@pixeldrive/peppol-toolkit';

const toolkit = new PeppolToolkit();

// Parse an invoice XML string back into a structured Invoice object
const invoiceXml = '<?xml version="1.0"?>...'; // your UBL XML string
const invoice: Invoice = toolkit.peppolUBLToInvoice(invoiceXml);
console.log(invoice.ID); // 'INV-2024-001'
console.log(invoice.invoiceLines); // array of line items

// Parse a credit note XML string back into a CreditNote object
const creditNoteXml = '<?xml version="1.0"?>...'; // your UBL credit note XML
const creditNote: CreditNote = toolkit.peppolUBLToCreditNote(creditNoteXml);
console.log(creditNote.ID);
```

### Compute Invoice Totals

Use the static `computeTotals` helper to calculate line totals, tax amounts, and the grand total from a list of line items — following EN 16931 rounding rules.

```typescript
import { PeppolToolkit } from '@pixeldrive/peppol-toolkit';

const items = [
{ price: 100, quantity: 10, taxPercent: 21 }, // 1 000.00 + 210.00 VAT
{ price: 49.99, quantity: 3, taxPercent: 21 }, // 149.97 + 31.49 VAT
{ price: 200, quantity: 2, taxPercent: 0 }, // 400.00 + 0.00 VAT (exempt)
];

const totals = PeppolToolkit.computeTotals(items);

console.log(totals.baseAmount.toNumber()); // 1549.97
console.log(totals.taxAmount.toNumber()); // 241.49
console.log(totals.totalAmount.toNumber()); // 1791.46

// Tax amounts grouped by rate
for (const [rate, taxableAmount] of totals.taxableAmountPerRate) {
console.log(`${rate}% → taxable: ${taxableAmount}`);
}
```

### Look up an EAS Endpoint Scheme from a VAT Number

`getEASFromTaxId` resolves the correct EAS (Electronic Address Scheme) identifier for a given country-prefixed VAT number.

```typescript
import { PeppolToolkit } from '@pixeldrive/peppol-toolkit';

const scheme = PeppolToolkit.getEASFromTaxId('BE0123456789');
console.log(scheme); // '9925'

const scheme2 = PeppolToolkit.getEASFromTaxId('NL9876543210');
console.log(scheme2); // '9944'
```

### Use the Built-in Example Data

The toolkit ships ready-to-run example documents so you can test your integration without building a full document from scratch.

```typescript
import {
PeppolToolkit,
exampleInvoice,
exampleCreditNote,
} from '@pixeldrive/peppol-toolkit';

const toolkit = new PeppolToolkit();
const peppolXML = toolkit.invoiceToPeppolUBL({});

// Generate XML from the bundled example invoice
const invoiceXml = toolkit.invoiceToPeppolUBL(exampleInvoice);
console.log(invoiceXml);

// Generate XML from the bundled example credit note
const creditNoteXml = toolkit.creditNoteToPeppolUBL(exampleCreditNote);
console.log(creditNoteXml);
```

## API Reference

### PeppolToolkit
### `PeppolToolkit`

The main class that provides invoice and credit note conversion functionality.

#### Instance Methods

| Method | Description |
|--------|-------------|
| `invoiceToPeppolUBL(invoice: Invoice): string` | Converts an `Invoice` object to a PEPPOL-compliant UBL XML string |
| `creditNoteToPeppolUBL(creditNote: CreditNote): string` | Converts a `CreditNote` object to a PEPPOL-compliant UBL XML string |
| `peppolUBLToInvoice(xml: string): Invoice` | Parses a PEPPOL UBL XML string into an `Invoice` object |
| `peppolUBLToCreditNote(xml: string): CreditNote` | Parses a PEPPOL UBL XML string into a `CreditNote` object |

The main class that provides invoice conversion functionality.
#### Static Helpers

#### Methods
| Helper | Description |
|--------|-------------|
| `PeppolToolkit.computeTotals(items: UBLLineItem[]): Totals` | Calculates line totals, tax amounts and grand total following EN 16931 rules |
| `PeppolToolkit.getEASFromTaxId(taxId: string): string` | Returns the EAS scheme code for a country-prefixed VAT number |

- `invoiceToPeppolUBL(invoice: Invoice): string`
- Converts an invoice object to PEPPOL-compliant UBL XML
- Returns: XML string formatted for PEPPOL compliance
### `createToolkit()`

### createToolkit()
Factory function that creates a new instance of `PeppolToolkit`. Equivalent to `new PeppolToolkit()`.

Factory function that creates a new instance of PeppolToolkit.
```typescript
import { createToolkit } from '@pixeldrive/peppol-toolkit';

const toolkit = createToolkit();
```

## PEPPOL BIS UBL Invoice Elements Checklist

Expand Down Expand Up @@ -173,19 +450,19 @@ Starting from version 1.0.0, this library will follow [Semantic Versioning (SemV

## Roadmap

- [ ] Initial invoice-to-UBL XML generation API
- [ ] Define and export robust Invoice TypeScript types
- [ ] Add input validation helpers
- [ ] Support CreditNote documents
- [x] Initial invoice-to-UBL XML generation API
- [x] Define and export robust Invoice TypeScript types
- [x] Add input validation helpers
- [x] Support CreditNote documents
- [ ] Implement UBL 2.1 schema validation (offline)
- [ ] Implement PEPPOL BIS profile validation (offline)
- [ ] Enable online validation against remote services
- [ ] Support attachments/binary objects embedding (e.g., PDF)
- [ ] CLI: Convert JSON invoices to UBL XML
- [ ] Documentation: Examples and recipe-style guides
- [x] Documentation: Examples and recipe-style guides
- [ ] QA: Expand unit tests

Last updated: 2025-09-29
Last updated: 2026-03-10

## Development Scripts

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pixeldrive/peppol-toolkit",
"version": "0.5.0",
"version": "0.5.1",
"description": "A TypeScript toolkit for building and reading peppol UBL documents",
"keywords": [
"typescript",
Expand Down
Loading