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:
@@ -27,6 +27,14 @@ import { PDFExtractor } from './formats/pdf/pdf.extractor.js';
|
||||
// Import format detector
|
||||
import { FormatDetector } from './formats/utils/format.detector.js';
|
||||
|
||||
// Import enhanced validators
|
||||
import { EN16931BusinessRulesValidator } from './formats/validation/en16931.business-rules.validator.js';
|
||||
import { CodeListValidator } from './formats/validation/codelist.validator.js';
|
||||
import type { ValidationOptions } from './formats/validation/validation.types.js';
|
||||
|
||||
// Import EN16931 metadata interface
|
||||
import type { IEInvoiceMetadata } from './interfaces/en16931-metadata.js';
|
||||
|
||||
/**
|
||||
* Main class for working with electronic invoices.
|
||||
* Supports various invoice formats including Factur-X, ZUGFeRD, UBL, and XRechnung
|
||||
@@ -169,13 +177,7 @@ export class EInvoice implements TInvoice {
|
||||
}
|
||||
|
||||
// EInvoice specific properties
|
||||
public metadata?: {
|
||||
format?: InvoiceFormat;
|
||||
version?: string;
|
||||
profile?: string;
|
||||
customizationId?: string;
|
||||
extensions?: Record<string, any>;
|
||||
};
|
||||
public metadata?: IEInvoiceMetadata;
|
||||
|
||||
private xmlString: string = '';
|
||||
private detectedFormat: InvoiceFormat = InvoiceFormat.UNKNOWN;
|
||||
@@ -430,17 +432,64 @@ export class EInvoice implements TInvoice {
|
||||
* @param level The validation level to use
|
||||
* @returns The validation result
|
||||
*/
|
||||
public async validate(level: ValidationLevel = ValidationLevel.BUSINESS): Promise<ValidationResult> {
|
||||
public async validate(level: ValidationLevel = ValidationLevel.BUSINESS, options?: ValidationOptions): Promise<ValidationResult> {
|
||||
try {
|
||||
const format = this.detectedFormat || InvoiceFormat.UNKNOWN;
|
||||
if (format === InvoiceFormat.UNKNOWN) {
|
||||
throw new EInvoiceValidationError('Cannot validate: format unknown', []);
|
||||
}
|
||||
|
||||
const validator = ValidatorFactory.createValidator(this.xmlString);
|
||||
const result = validator.validate(level);
|
||||
// For programmatically created invoices without XML, skip XML-based validation
|
||||
let result: ValidationResult;
|
||||
|
||||
if (this.xmlString && this.detectedFormat !== InvoiceFormat.UNKNOWN) {
|
||||
// Use existing validator for XML-based validation
|
||||
const validator = ValidatorFactory.createValidator(this.xmlString);
|
||||
result = validator.validate(level);
|
||||
} else {
|
||||
// Create a basic result for programmatically created invoices
|
||||
result = {
|
||||
valid: true,
|
||||
errors: [],
|
||||
warnings: [],
|
||||
level: level
|
||||
};
|
||||
}
|
||||
|
||||
// Enhanced validation with feature flags
|
||||
if (options?.featureFlags?.includes('EN16931_BUSINESS_RULES')) {
|
||||
const businessRulesValidator = new EN16931BusinessRulesValidator();
|
||||
const businessResults = businessRulesValidator.validate(this, options);
|
||||
|
||||
// Merge results
|
||||
result.errors = result.errors.concat(
|
||||
businessResults
|
||||
.filter(r => r.severity === 'error')
|
||||
.map(r => ({ code: r.ruleId, message: r.message, field: r.field }))
|
||||
);
|
||||
|
||||
// Add warnings if not in report-only mode
|
||||
if (!options.reportOnly) {
|
||||
result.warnings = (result.warnings || []).concat(
|
||||
businessResults
|
||||
.filter(r => r.severity === 'warning')
|
||||
.map(r => ({ code: r.ruleId, message: r.message, field: r.field }))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Code list validation with feature flag
|
||||
if (options?.featureFlags?.includes('CODE_LIST_VALIDATION')) {
|
||||
const codeListValidator = new CodeListValidator();
|
||||
const codeListResults = codeListValidator.validate(this);
|
||||
|
||||
// Merge results
|
||||
result.errors = result.errors.concat(
|
||||
codeListResults
|
||||
.filter(r => r.severity === 'error')
|
||||
.map(r => ({ code: r.ruleId, message: r.message, field: r.field }))
|
||||
);
|
||||
}
|
||||
|
||||
// Update validation status
|
||||
this.validationErrors = result.errors;
|
||||
result.valid = result.errors.length === 0 || options?.reportOnly === true;
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
if (error instanceof EInvoiceError) {
|
||||
|
Reference in New Issue
Block a user