feat(invoice): add e-invoice support with XRechnung/ZUGFeRD and advanced export features
Some checks failed
Default (tags) / security (push) Successful in 48s
Default (tags) / test (push) Failing after 4m3s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped

This commit is contained in:
2025-08-12 12:37:01 +00:00
parent 08d7803be2
commit 73b46f7857
19 changed files with 6211 additions and 20 deletions

351
ts/skr.invoice.entity.ts Normal file
View File

@@ -0,0 +1,351 @@
import type { TSKRType } from './skr.types.js';
/**
* Invoice direction
*/
export type TInvoiceDirection = 'inbound' | 'outbound';
/**
* Supported e-invoice formats
*/
export type TInvoiceFormat = 'xrechnung' | 'zugferd' | 'facturx' | 'peppol' | 'ubl';
/**
* Invoice status in the system
*/
export type TInvoiceStatus = 'draft' | 'validated' | 'posted' | 'partially_paid' | 'paid' | 'cancelled' | 'error';
/**
* Tax scenario classification
*/
export type TTaxScenario =
| 'domestic_taxed' // Standard domestic with VAT
| 'domestic_exempt' // Domestic tax-exempt
| 'reverse_charge' // §13b UStG
| 'intra_eu_supply' // Intra-EU supply
| 'intra_eu_acquisition' // Intra-EU acquisition
| 'export' // Export outside EU
| 'small_business'; // §19 UStG small business
/**
* VAT rate categories
*/
export interface IVATCategory {
code: string; // S (Standard), Z (Zero), E (Exempt), AE (Reverse charge), etc.
rate: number; // Tax rate percentage
exemptionReason?: string;
}
/**
* Party information (supplier/customer)
*/
export interface IInvoiceParty {
id: string;
name: string;
address: {
street?: string;
city?: string;
postalCode?: string;
countryCode: string;
};
vatId?: string;
taxId?: string;
email?: string;
phone?: string;
bankAccount?: {
iban: string;
bic?: string;
accountHolder?: string;
};
}
/**
* Invoice line item
*/
export interface IInvoiceLine {
lineNumber: number;
description: string;
quantity: number;
unitPrice: number;
netAmount: number;
vatCategory: IVATCategory;
vatAmount: number;
grossAmount: number;
accountNumber?: string; // SKR account for booking
costCenter?: string;
productCode?: string;
allowances?: IAllowanceCharge[];
charges?: IAllowanceCharge[];
}
/**
* Allowance or charge
*/
export interface IAllowanceCharge {
reason: string;
amount: number;
percentage?: number;
vatCategory?: IVATCategory;
vatAmount?: number;
}
/**
* Payment terms
*/
export interface IPaymentTerms {
dueDate: Date;
paymentTermsNote?: string;
skonto?: {
percentage: number;
days: number;
baseAmount: number;
}[];
}
/**
* Validation result
*/
export interface IValidationResult {
isValid: boolean;
syntax: {
valid: boolean;
errors: string[];
warnings: string[];
};
semantic: {
valid: boolean;
errors: string[];
warnings: string[];
};
businessRules: {
valid: boolean;
errors: string[];
warnings: string[];
};
countrySpecific?: {
valid: boolean;
errors: string[];
warnings: string[];
};
validatedAt: Date;
validatorVersion: string;
}
/**
* Booking information
*/
export interface IBookingInfo {
journalEntryId: string;
transactionIds: string[];
bookedAt: Date;
bookedBy: string;
bookingRules: {
vendorAccount?: string;
customerAccount?: string;
expenseAccounts?: string[];
revenueAccounts?: string[];
vatAccounts?: string[];
};
confidence: number; // 0-100
autoBooked: boolean;
}
/**
* Payment information
*/
export interface IPaymentInfo {
paymentId: string;
paymentDate: Date;
amount: number;
currency: string;
bankTransactionId?: string;
endToEndId?: string;
remittanceInfo?: string;
skontoTaken?: number;
}
/**
* Main invoice entity
*/
export interface IInvoice {
// Identity
id: string;
direction: TInvoiceDirection;
format: TInvoiceFormat;
// EN16931 Business Terms
invoiceNumber: string; // BT-1
issueDate: Date; // BT-2
invoiceTypeCode?: string; // BT-3 (380=Invoice, 381=Credit note)
currencyCode: string; // BT-5
taxCurrencyCode?: string; // BT-6
taxPointDate?: Date; // BT-7 (Leistungsdatum)
paymentDueDate?: Date; // BT-9
buyerReference?: string; // BT-10
projectReference?: string; // BT-11
contractReference?: string; // BT-12
orderReference?: string; // BT-13
sellerOrderReference?: string; // BT-14
// Parties
supplier: IInvoiceParty;
customer: IInvoiceParty;
payee?: IInvoiceParty; // If different from supplier
// Line items
lines: IInvoiceLine[];
// Document level allowances/charges
allowances?: IAllowanceCharge[];
charges?: IAllowanceCharge[];
// Amounts
lineNetAmount: number; // Sum of line net amounts
allowanceTotalAmount?: number;
chargeTotalAmount?: number;
taxExclusiveAmount: number; // BT-109
taxInclusiveAmount: number; // BT-112
prepaidAmount?: number; // BT-113
payableAmount: number; // BT-115
// VAT breakdown
vatBreakdown: {
vatCategory: IVATCategory;
taxableAmount: number; // BT-116
taxAmount: number; // BT-117
}[];
totalVATAmount: number; // BT-110
// Payment
paymentTerms?: IPaymentTerms;
paymentMeans?: {
code: string; // 30=Bank transfer, 48=Card, etc.
account?: IInvoiceParty['bankAccount'];
};
payments?: IPaymentInfo[];
// Notes
invoiceNote?: string; // BT-22
// Processing metadata
status: TInvoiceStatus;
taxScenario?: TTaxScenario;
skrType?: TSKRType;
// Storage
contentHash: string; // SHA-256 of normalized XML
xmlContent?: string;
pdfHash?: string;
pdfContent?: Buffer;
// Validation
validationResult?: IValidationResult;
// Booking
bookingInfo?: IBookingInfo;
// Audit trail
createdAt: Date;
createdBy: string;
modifiedAt?: Date;
modifiedBy?: string;
// Additional metadata
metadata?: {
importSource?: string;
importedAt?: Date;
parserVersion?: string;
originalFilename?: string;
originalFormat?: string;
[key: string]: any;
};
}
/**
* Invoice import options
*/
export interface IInvoiceImportOptions {
autoBook?: boolean;
confidenceThreshold?: number;
validateOnly?: boolean;
skipDuplicateCheck?: boolean;
bookingRules?: {
vendorDefaults?: Record<string, string>;
customerDefaults?: Record<string, string>;
productCategoryMapping?: Record<string, string>;
};
}
/**
* Invoice export options
*/
export interface IInvoiceExportOptions {
format: TInvoiceFormat;
embedInPdf?: boolean;
sign?: boolean;
validate?: boolean;
}
/**
* Invoice search filter
*/
export interface IInvoiceFilter {
direction?: TInvoiceDirection;
status?: TInvoiceStatus;
format?: TInvoiceFormat;
dateFrom?: Date;
dateTo?: Date;
supplierId?: string;
customerId?: string;
minAmount?: number;
maxAmount?: number;
invoiceNumber?: string;
reference?: string;
isPaid?: boolean;
isOverdue?: boolean;
}
/**
* Duplicate check result
*/
export interface IDuplicateCheckResult {
isDuplicate: boolean;
matchedInvoiceId?: string;
matchedContentHash?: string;
matchedFields?: string[];
confidence: number;
}
/**
* Booking rules configuration
*/
export interface IBookingRules {
skrType: TSKRType;
// Control accounts
vendorControlAccount: string;
customerControlAccount: string;
// VAT accounts
vatAccounts: {
inputVAT19: string;
inputVAT7: string;
outputVAT19: string;
outputVAT7: string;
reverseChargeVAT: string;
};
// Default accounts
defaultExpenseAccount: string;
defaultRevenueAccount: string;
// Mappings
productCategoryMapping?: Record<string, string>;
vendorMapping?: Record<string, string>;
customerMapping?: Record<string, string>;
// Skonto
skontoMethod?: 'net' | 'gross';
skontoExpenseAccount?: string;
skontoRevenueAccount?: string;
}