feat(validation): Implement EN16931 compliance validation types and VAT categories
- Added validation types for EN16931 compliance in `validation.types.ts`, including interfaces for `ValidationResult`, `ValidationOptions`, and `ValidationReport`. - Introduced `VATCategoriesValidator` in `vat-categories.validator.ts` to validate VAT categories according to EN16931 rules, including detailed checks for standard, zero-rated, exempt, reverse charge, intra-community, export, and out-of-scope services. - Enhanced `IEInvoiceMetadata` interface in `en16931-metadata.ts` to include additional fields required for full standards compliance, such as delivery information, payment information, allowances, and charges. - Implemented helper methods for VAT calculations and validation logic to ensure accurate compliance with EN16931 standards.
This commit is contained in:
128
test/test.currency-utils.ts
Normal file
128
test/test.currency-utils.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import {
|
||||
getCurrencyMinorUnits,
|
||||
roundToCurrency,
|
||||
getCurrencyTolerance,
|
||||
areMonetaryValuesEqual,
|
||||
CurrencyCalculator,
|
||||
RoundingMode
|
||||
} from '../ts/formats/utils/currency.utils.js';
|
||||
|
||||
tap.test('Currency Utils - should handle different currency decimal places', async () => {
|
||||
// Standard 2 decimal currencies
|
||||
expect(getCurrencyMinorUnits('EUR')).toEqual(2);
|
||||
expect(getCurrencyMinorUnits('USD')).toEqual(2);
|
||||
expect(getCurrencyMinorUnits('GBP')).toEqual(2);
|
||||
|
||||
// Zero decimal currencies
|
||||
expect(getCurrencyMinorUnits('JPY')).toEqual(0);
|
||||
expect(getCurrencyMinorUnits('KRW')).toEqual(0);
|
||||
|
||||
// Three decimal currencies
|
||||
expect(getCurrencyMinorUnits('KWD')).toEqual(3);
|
||||
expect(getCurrencyMinorUnits('TND')).toEqual(3);
|
||||
|
||||
// Unknown currency defaults to 2
|
||||
expect(getCurrencyMinorUnits('XXX')).toEqual(2);
|
||||
});
|
||||
|
||||
tap.test('Currency Utils - should round values correctly', async () => {
|
||||
// EUR - 2 decimals
|
||||
expect(roundToCurrency(10.234, 'EUR')).toEqual(10.23);
|
||||
expect(roundToCurrency(10.235, 'EUR')).toEqual(10.24); // Half-up
|
||||
expect(roundToCurrency(10.236, 'EUR')).toEqual(10.24);
|
||||
|
||||
// JPY - 0 decimals
|
||||
expect(roundToCurrency(1234.56, 'JPY')).toEqual(1235);
|
||||
expect(roundToCurrency(1234.49, 'JPY')).toEqual(1234);
|
||||
|
||||
// KWD - 3 decimals
|
||||
expect(roundToCurrency(10.2345, 'KWD')).toEqual(10.235); // Half-up
|
||||
expect(roundToCurrency(10.2344, 'KWD')).toEqual(10.234);
|
||||
});
|
||||
|
||||
tap.test('Currency Utils - should use different rounding modes', async () => {
|
||||
const value = 10.235;
|
||||
|
||||
// Half-up (default)
|
||||
expect(roundToCurrency(value, 'EUR', RoundingMode.HALF_UP)).toEqual(10.24);
|
||||
|
||||
// Half-down
|
||||
expect(roundToCurrency(value, 'EUR', RoundingMode.HALF_DOWN)).toEqual(10.23);
|
||||
|
||||
// Half-even (banker's rounding)
|
||||
expect(roundToCurrency(10.235, 'EUR', RoundingMode.HALF_EVEN)).toEqual(10.24); // 23 is odd, round up
|
||||
expect(roundToCurrency(10.245, 'EUR', RoundingMode.HALF_EVEN)).toEqual(10.24); // 24 is even, round down
|
||||
|
||||
// Always up
|
||||
expect(roundToCurrency(10.231, 'EUR', RoundingMode.UP)).toEqual(10.24);
|
||||
|
||||
// Always down (truncate)
|
||||
expect(roundToCurrency(10.239, 'EUR', RoundingMode.DOWN)).toEqual(10.23);
|
||||
});
|
||||
|
||||
tap.test('Currency Utils - should calculate correct tolerance', async () => {
|
||||
// EUR - tolerance is 0.005 (half of 0.01)
|
||||
expect(getCurrencyTolerance('EUR')).toEqual(0.005);
|
||||
|
||||
// JPY - tolerance is 0.5 (half of 1)
|
||||
expect(getCurrencyTolerance('JPY')).toEqual(0.5);
|
||||
|
||||
// KWD - tolerance is 0.0005 (half of 0.001)
|
||||
expect(getCurrencyTolerance('KWD')).toEqual(0.0005);
|
||||
});
|
||||
|
||||
tap.test('Currency Utils - should compare monetary values with tolerance', async () => {
|
||||
// EUR comparisons
|
||||
expect(areMonetaryValuesEqual(10.23, 10.234, 'EUR')).toEqual(true); // Within tolerance
|
||||
expect(areMonetaryValuesEqual(10.23, 10.236, 'EUR')).toEqual(false); // Outside tolerance
|
||||
|
||||
// JPY comparisons
|
||||
expect(areMonetaryValuesEqual(1234, 1234.4, 'JPY')).toEqual(true); // Within tolerance
|
||||
expect(areMonetaryValuesEqual(1234, 1235, 'JPY')).toEqual(false); // Outside tolerance
|
||||
|
||||
// KWD comparisons
|
||||
expect(areMonetaryValuesEqual(10.234, 10.2344, 'KWD')).toEqual(true); // Within tolerance
|
||||
expect(areMonetaryValuesEqual(10.234, 10.235, 'KWD')).toEqual(false); // Outside tolerance
|
||||
});
|
||||
|
||||
tap.test('CurrencyCalculator - should perform EN16931 calculations', async () => {
|
||||
// EUR calculator
|
||||
const eurCalc = new CurrencyCalculator('EUR');
|
||||
|
||||
// Line net calculation
|
||||
const lineNet = eurCalc.calculateLineNet(5, 19.99, 2.50);
|
||||
expect(lineNet).toEqual(97.45); // (5 * 19.99) - 2.50 = 97.45
|
||||
|
||||
// VAT calculation
|
||||
const vat = eurCalc.calculateVAT(100, 19);
|
||||
expect(vat).toEqual(19.00);
|
||||
|
||||
// JPY calculator (no decimals)
|
||||
const jpyCalc = new CurrencyCalculator('JPY');
|
||||
|
||||
const jpyLineNet = jpyCalc.calculateLineNet(3, 1234.56);
|
||||
expect(jpyLineNet).toEqual(3704); // Rounded to no decimals
|
||||
|
||||
const jpyVat = jpyCalc.calculateVAT(10000, 8);
|
||||
expect(jpyVat).toEqual(800);
|
||||
});
|
||||
|
||||
tap.test('CurrencyCalculator - should handle edge cases', async () => {
|
||||
const calc = new CurrencyCalculator('EUR');
|
||||
|
||||
// Rounding at exact midpoint
|
||||
expect(calc.round(10.235)).toEqual(10.24); // Half-up
|
||||
expect(calc.round(10.245)).toEqual(10.25); // Half-up
|
||||
|
||||
// Very small values
|
||||
expect(calc.round(0.001)).toEqual(0.00);
|
||||
expect(calc.round(0.004)).toEqual(0.00);
|
||||
expect(calc.round(0.005)).toEqual(0.01);
|
||||
|
||||
// Negative values
|
||||
expect(calc.round(-10.234)).toEqual(-10.23);
|
||||
expect(calc.round(-10.235)).toEqual(-10.24);
|
||||
});
|
||||
|
||||
tap.start();
|
Reference in New Issue
Block a user