Files
einvoice/test/test.peppol-validator.ts

328 lines
9.6 KiB
TypeScript
Raw Normal View History

import { tap, expect } from '@git.zone/tstest/tapbundle';
import { PeppolValidator } from '../ts/formats/validation/peppol.validator.js';
import type { EInvoice } from '../ts/einvoice.js';
tap.test('PEPPOL Validator - basic instantiation', async () => {
const validator = PeppolValidator.create();
expect(validator).toBeInstanceOf(PeppolValidator);
// Singleton pattern
const validator2 = PeppolValidator.create();
expect(validator2).toEqual(validator);
});
tap.test('PEPPOL Validator - endpoint ID validation', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
sellerEndpointId: '0088:1234567890128', // Valid GLN
buyerEndpointId: '0192:123456789' // Valid Norwegian org
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const endpointErrors = results.filter(r => r.ruleId.startsWith('PEPPOL-T00'));
console.log('Endpoint validation results:', endpointErrors);
expect(endpointErrors.length).toEqual(0);
});
tap.test('PEPPOL Validator - invalid GLN endpoint', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
sellerEndpointId: '0088:123456789012', // Invalid GLN (wrong check digit)
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const endpointErrors = results.filter(r => r.ruleId === 'PEPPOL-T001');
expect(endpointErrors.length).toBeGreaterThan(0);
expect(endpointErrors[0].message).toInclude('Invalid seller endpoint ID');
});
tap.test('PEPPOL Validator - invalid endpoint format', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
sellerEndpointId: 'invalid-format', // No scheme
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const endpointErrors = results.filter(r => r.ruleId === 'PEPPOL-T001');
expect(endpointErrors.length).toBeGreaterThan(0);
expect(endpointErrors[0].severity).toEqual('error');
});
tap.test('PEPPOL Validator - document type validation', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
documentTypeId: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1'
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const docTypeErrors = results.filter(r => r.ruleId === 'PEPPOL-T003');
expect(docTypeErrors.length).toEqual(0);
});
tap.test('PEPPOL Validator - process ID validation', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
processId: 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0'
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const processErrors = results.filter(r => r.ruleId === 'PEPPOL-T004');
expect(processErrors.length).toEqual(0);
});
tap.test('PEPPOL Validator - invalid process ID', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
processId: 'invalid:process:id'
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const processErrors = results.filter(r => r.ruleId === 'PEPPOL-T004');
expect(processErrors.length).toBeGreaterThan(0);
expect(processErrors[0].severity).toEqual('warning');
});
tap.test('PEPPOL Validator - business rules', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
// Missing both buyer reference and purchase order reference
},
from: {
type: 'company',
name: 'Test Company'
// Missing email
}
};
const results = validator.validatePeppol(invoice as EInvoice);
// Should have error for missing buyer reference
const buyerRefErrors = results.filter(r => r.ruleId === 'PEPPOL-B-01');
expect(buyerRefErrors.length).toBeGreaterThan(0);
// Should have warning for missing seller email
const emailWarnings = results.filter(r => r.ruleId === 'PEPPOL-B-02');
expect(emailWarnings.length).toBeGreaterThan(0);
});
tap.test('PEPPOL Validator - buyer reference present', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
buyerReference: 'REF-12345'
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const buyerRefErrors = results.filter(r => r.ruleId === 'PEPPOL-B-01');
expect(buyerRefErrors.length).toEqual(0);
});
tap.test('PEPPOL Validator - purchase order reference present', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
purchaseOrderReference: 'PO-2025-001'
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const buyerRefErrors = results.filter(r => r.ruleId === 'PEPPOL-B-01');
expect(buyerRefErrors.length).toEqual(0);
});
tap.test('PEPPOL Validator - payment means validation', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
paymentMeans: {
paymentMeansCode: '30' // Valid code for credit transfer
}
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const paymentErrors = results.filter(r => r.ruleId === 'PEPPOL-B-04');
expect(paymentErrors.length).toEqual(0);
});
tap.test('PEPPOL Validator - invalid payment means', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
paymentMeans: {
paymentMeansCode: '999' // Invalid code
}
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const paymentErrors = results.filter(r => r.ruleId === 'PEPPOL-B-04');
expect(paymentErrors.length).toBeGreaterThan(0);
expect(paymentErrors[0].severity).toEqual('error');
});
tap.test('PEPPOL Validator - non-PEPPOL invoice skips validation', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:cen.eu:en16931:2017', // Not PEPPOL
}
};
const results = validator.validatePeppol(invoice as EInvoice);
expect(results.length).toEqual(0);
});
tap.test('PEPPOL Validator - scheme ID validation', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
buyerPartyId: {
schemeId: '0088', // Valid GLN scheme
id: '1234567890128'
}
}
},
from: {
type: 'company',
name: 'Test Company',
registrationDetails: {
partyIdentification: {
schemeId: '9906', // Valid IT:VAT scheme
id: 'IT12345678901'
}
}
} as any
};
const results = validator.validatePeppol(invoice as EInvoice);
const schemeErrors = results.filter(r =>
r.ruleId === 'PEPPOL-T005' || r.ruleId === 'PEPPOL-T006'
);
expect(schemeErrors.length).toEqual(0);
});
tap.test('PEPPOL Validator - invalid scheme ID', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
buyerPartyId: {
schemeId: '9999', // Invalid scheme
id: '12345'
}
}
}
};
const results = validator.validatePeppol(invoice as EInvoice);
const schemeErrors = results.filter(r => r.ruleId === 'PEPPOL-T006');
expect(schemeErrors.length).toBeGreaterThan(0);
expect(schemeErrors[0].severity).toEqual('warning');
});
tap.test('PEPPOL Validator - B2G detection', async () => {
const validator = PeppolValidator.create();
const invoice: Partial<EInvoice> = {
metadata: {
profileId: 'urn:fdc:peppol.eu:2017:poacc:billing:3.0',
extensions: {
buyerPartyId: {
schemeId: '0204', // German government Leitweg-ID
id: '991-12345-01'
},
buyerCategory: 'government'
}
},
to: {
type: 'company',
name: 'Government Agency'
}
};
const results = validator.validatePeppol(invoice as EInvoice);
// B2G should require endpoint IDs
const endpointErrors = results.filter(r =>
r.ruleId === 'PEPPOL-T001' || r.ruleId === 'PEPPOL-T002'
);
expect(endpointErrors.length).toBeGreaterThan(0);
expect(endpointErrors[0].message).toInclude('mandatory for PEPPOL B2G');
});
export default tap.start();