fix(exports): stabilize published types and compatibility with updated dependencies
This commit is contained in:
@@ -1,738 +1,321 @@
|
||||
# @fin.cx/skr 📊
|
||||
# @fin.cx/skr
|
||||
|
||||
> **Enterprise-grade German accounting standards implementation for SKR03 and SKR04**
|
||||
> Rock-solid double-entry bookkeeping with MongoDB persistence, e-invoice integration, and full TypeScript support
|
||||
`@fin.cx/skr` is a TypeScript library for German double-entry bookkeeping with built-in SKR03 and SKR04 chart initialization, MongoDB-backed persistence, reporting, DATEV export, GoBD-oriented Jahresabschluss export, and e-invoice workflows.
|
||||
|
||||
## 🚀 Why @fin.cx/skr?
|
||||
It is built for developers who need a programmable accounting core instead of a pile of CSV glue code: initialize a chart of accounts, post validated transactions and journal entries, generate reports, and archive year-end data in a structured export format.
|
||||
|
||||
Building compliant German accounting software? You've come to the right place! This module provides a **complete, type-safe implementation** of the German standard charts of accounts (Standardkontenrahmen) SKR03 and SKR04, the backbone of professional accounting in Germany.
|
||||
## Issue Reporting and Security
|
||||
|
||||
### 🎯 What makes it awesome?
|
||||
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||
|
||||
- **🏢 Enterprise-Ready**: Production-tested implementation following HGB/GoBD standards
|
||||
- **⚡ Lightning Fast**: MongoDB-powered with optimized indexing and real-time balance updates
|
||||
- **🔒 Type-Safe**: Full TypeScript support with comprehensive type definitions
|
||||
- **🎮 Developer-Friendly**: Intuitive API that makes complex accounting operations simple
|
||||
- **📈 Real-time Reporting**: Generate financial statements on-the-fly
|
||||
- **🔄 Transaction Safety**: Built-in double-entry validation and automatic reversals
|
||||
- **✅ Battle-Tested**: 65+ comprehensive tests covering all edge cases
|
||||
- **🛡️ SKR Validation**: Automatic validation against official SKR standards
|
||||
- **🧾 E-Invoice Support**: Full XRechnung/ZUGFeRD integration for modern invoice processing
|
||||
- **🔐 Cryptographic Security**: Merkle tree and digital signature support for audit trails
|
||||
- **📑 PDF Export**: Professional PDF report generation with customizable templates
|
||||
## What This Library Does
|
||||
|
||||
## 📦 Installation
|
||||
- Initializes SKR03 or SKR04 account sets in MongoDB
|
||||
- Enforces double-entry bookkeeping rules for transactions and journal entries
|
||||
- Supports DATEV posting keys and VAT-aware journal lines
|
||||
- Prevents direct posting to automatic accounts that require personal accounts
|
||||
- Generates trial balance, income statement, balance sheet, general ledger, and cash flow reports
|
||||
- Exports accounting data as CSV, DATEV, and GoBD-style Jahresabschluss packages
|
||||
- Imports, stores, searches, books, and exports EN16931-style e-invoices
|
||||
- Adds signing and timestamp helpers for audit-oriented export workflows
|
||||
|
||||
## Why It Is Useful
|
||||
|
||||
- You get a real accounting domain model, not just account lists
|
||||
- SKR03 and SKR04 are both supported behind one API
|
||||
- Tests cover initialization, posting, reversals, reports, pagination, DATEV export, and full year-end flows
|
||||
- The package exports the lower-level classes too, so you can stay high-level with `SkrApi` or build around the primitives
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 20+ with ESM support
|
||||
- A reachable MongoDB instance
|
||||
- `pnpm`
|
||||
|
||||
The test setup reads MongoDB connection details from `.nogit/` via `@push.rocks/qenv`, but the runtime API only needs a `mongoDbUrl` and an optional `dbName`.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Using npm
|
||||
npm install @fin.cx/skr
|
||||
|
||||
# Using pnpm (recommended)
|
||||
pnpm add @fin.cx/skr
|
||||
|
||||
# Using yarn
|
||||
yarn add @fin.cx/skr
|
||||
```
|
||||
|
||||
## 🎓 Quick Start
|
||||
## Quick Start
|
||||
|
||||
### Basic Setup
|
||||
|
||||
```typescript
|
||||
```ts
|
||||
import { SkrApi } from '@fin.cx/skr';
|
||||
|
||||
// Initialize the API
|
||||
const api = new SkrApi({
|
||||
mongoDbUrl: 'mongodb://localhost:27017',
|
||||
dbName: 'accounting' // optional, defaults to 'skr_accounting'
|
||||
dbName: 'accounting_demo',
|
||||
});
|
||||
|
||||
// Choose your SKR standard (SKR03 or SKR04)
|
||||
await api.initialize('SKR03');
|
||||
```
|
||||
|
||||
### 💰 Posting Transactions
|
||||
|
||||
```typescript
|
||||
// Simple transaction posting
|
||||
const transaction = await api.postTransaction({
|
||||
await api.postTransaction({
|
||||
date: new Date(),
|
||||
debitAccount: '1200', // Bank account
|
||||
creditAccount: '8400', // Revenue account
|
||||
amount: 1190.00,
|
||||
description: 'Invoice #2024-001 payment received',
|
||||
reference: 'INV-2024-001',
|
||||
vatAmount: 190.00
|
||||
});
|
||||
|
||||
// Complex journal entry with multiple lines
|
||||
const journalEntry = await api.postJournalEntry({
|
||||
date: new Date(),
|
||||
description: 'Monthly salary payments',
|
||||
reference: 'SAL-2024-03',
|
||||
lines: [
|
||||
{ accountNumber: '6000', debit: 5000.00, description: 'Gross salary' },
|
||||
{ accountNumber: '6100', debit: 1000.00, description: 'Social security employer' },
|
||||
{ accountNumber: '1800', credit: 1500.00, description: 'Tax withholding' },
|
||||
{ accountNumber: '1200', credit: 4500.00, description: 'Net payment' }
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
### 🧾 E-Invoice Integration
|
||||
|
||||
```typescript
|
||||
// Import electronic invoices (XRechnung/ZUGFeRD)
|
||||
const invoiceData = await api.importInvoice(xmlContent, {
|
||||
format: 'xrechnung',
|
||||
validateSchema: true,
|
||||
checkDuplicates: true
|
||||
});
|
||||
|
||||
// Automatically book invoice to accounting
|
||||
const booking = await api.bookInvoice(invoiceData.invoiceId, {
|
||||
autoDetectAccounts: true,
|
||||
splitVAT: true,
|
||||
createPaymentSchedule: true
|
||||
});
|
||||
|
||||
// Export invoice in various formats
|
||||
const xRechnung = await api.exportInvoice(invoiceId, {
|
||||
format: 'xrechnung',
|
||||
version: '3.0',
|
||||
includeAttachments: true
|
||||
});
|
||||
|
||||
// Search and filter invoices
|
||||
const invoices = await api.searchInvoices({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
status: 'booked',
|
||||
minAmount: 100,
|
||||
customerVATId: 'DE123456789'
|
||||
});
|
||||
|
||||
// Generate compliance reports
|
||||
const complianceReport = await api.createInvoiceComplianceReport({
|
||||
period: '2024-Q1',
|
||||
includeValidation: true,
|
||||
includeStatistics: true
|
||||
});
|
||||
```
|
||||
|
||||
### 📊 Generating Financial Reports
|
||||
|
||||
```typescript
|
||||
// Trial Balance (Summen- und Saldenliste)
|
||||
const trialBalance = await api.generateTrialBalance({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// Income Statement (GuV - Gewinn- und Verlustrechnung)
|
||||
const incomeStatement = await api.generateIncomeStatement({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// Balance Sheet (Bilanz)
|
||||
const balanceSheet = await api.generateBalanceSheet({
|
||||
date: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// General Ledger Export
|
||||
const generalLedger = await api.generateGeneralLedger({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// Cash Flow Statement
|
||||
const cashFlow = await api.generateCashFlowStatement({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
```
|
||||
|
||||
### 📑 Advanced Export Features
|
||||
|
||||
```typescript
|
||||
// Export complete annual closing package (Jahresabschluss)
|
||||
const jahresabschluss = await api.exportJahresabschluss({
|
||||
year: 2024,
|
||||
includeReports: ['balance_sheet', 'income_statement', 'cash_flow'],
|
||||
format: 'structured', // 'structured' | 'pdf' | 'csv'
|
||||
language: 'de',
|
||||
signatureRequired: true
|
||||
});
|
||||
|
||||
// Generate PDF reports with professional formatting
|
||||
const pdfReports = await api.generatePdfReports({
|
||||
reports: ['trial_balance', 'income_statement', 'balance_sheet'],
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
companyInfo: {
|
||||
name: 'Mustermann GmbH',
|
||||
address: 'Hauptstraße 1, 10115 Berlin',
|
||||
taxNumber: 'DE123456789',
|
||||
registrationNumber: 'HRB 12345'
|
||||
},
|
||||
outputPath: './reports/',
|
||||
template: 'professional' // Custom templates available
|
||||
});
|
||||
|
||||
// Export with cryptographic signatures for audit trail
|
||||
const signedExport = await api.signExport({
|
||||
data: jahresabschluss,
|
||||
privateKey: privateKeyPEM,
|
||||
certificate: certificatePEM,
|
||||
includeTimestamp: true,
|
||||
hashAlgorithm: 'SHA256'
|
||||
});
|
||||
|
||||
// Detailed account data export
|
||||
const accountExport = await api.exportAccountData({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
format: 'detailed', // 'summary' | 'detailed' | 'tree'
|
||||
includeTransactions: true,
|
||||
includeBalances: true
|
||||
});
|
||||
|
||||
// Balance history export for analysis
|
||||
const balanceHistory = await api.exportBalanceData({
|
||||
accounts: ['1200', '1000', '8400'],
|
||||
interval: 'monthly', // 'daily' | 'weekly' | 'monthly' | 'quarterly'
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
includeRunningTotals: true
|
||||
});
|
||||
|
||||
// Ledger export with filtering options
|
||||
const ledgerExport = await api.exportLedgerData({
|
||||
accounts: ['1000-1999'], // Range support
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
includeReversals: false,
|
||||
groupByAccount: true,
|
||||
format: 'journal' // 'journal' | 'T-account' | 'chronological'
|
||||
});
|
||||
```
|
||||
|
||||
## 🏗️ Core Features
|
||||
|
||||
### Account Management
|
||||
|
||||
```typescript
|
||||
// Create custom accounts
|
||||
const account = await api.createAccount({
|
||||
accountNumber: '1299',
|
||||
accountName: 'PayPal Business',
|
||||
accountClass: 1,
|
||||
accountType: 'asset',
|
||||
description: 'PayPal business account for online payments',
|
||||
isActive: true
|
||||
});
|
||||
|
||||
// Batch create multiple accounts for efficiency
|
||||
const accounts = await api.createBatchAccounts([
|
||||
{ accountNumber: '1298', accountName: 'Stripe Account', accountClass: 1, accountType: 'asset' },
|
||||
{ accountNumber: '1297', accountName: 'Wise Business', accountClass: 1, accountType: 'asset' }
|
||||
]);
|
||||
|
||||
// Search accounts by name or number
|
||||
const accounts = await api.searchAccounts('bank');
|
||||
|
||||
// Get account with full details
|
||||
const account = await api.getAccount('1200');
|
||||
|
||||
// Update account information
|
||||
await api.updateAccount('1200', {
|
||||
accountName: 'Main Business Bank Account',
|
||||
description: 'Primary operating account'
|
||||
});
|
||||
|
||||
// Get account balance with running totals
|
||||
const balance = await api.getAccountBalance('1200');
|
||||
console.log(`Balance: €${balance.balance}`);
|
||||
console.log(`Total Debits: €${balance.debitTotal}`);
|
||||
console.log(`Total Credits: €${balance.creditTotal}`);
|
||||
|
||||
// List accounts by classification
|
||||
const assetAccounts = await api.getAccountsByType('asset');
|
||||
const class4Accounts = await api.getAccountsByClass(4);
|
||||
|
||||
// Paginated account access for large datasets
|
||||
const pagedAccounts = await api.getAccountsPaginated({
|
||||
page: 1,
|
||||
limit: 50,
|
||||
sortBy: 'accountNumber',
|
||||
sortOrder: 'asc'
|
||||
});
|
||||
```
|
||||
|
||||
### Transaction Management
|
||||
|
||||
```typescript
|
||||
// Get transaction by ID
|
||||
const transaction = await api.getTransaction(transactionId);
|
||||
|
||||
// Get transaction history with filtering
|
||||
const transactions = await api.listTransactions({
|
||||
accountNumber: '1200',
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
minAmount: 100,
|
||||
maxAmount: 10000
|
||||
});
|
||||
|
||||
// Get all transactions for a specific account
|
||||
const accountTransactions = await api.getAccountTransactions('1200', {
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// Reverse transactions (Storno)
|
||||
const reversal = await api.reverseTransaction(transactionId);
|
||||
|
||||
// Reverse complex journal entries
|
||||
const journalReversal = await api.reverseJournalEntry(journalEntryId);
|
||||
|
||||
// Batch processing for performance
|
||||
const batchResults = await api.postBatchTransactions([
|
||||
{ date: new Date(), debitAccount: '1200', creditAccount: '8400', amount: 100 },
|
||||
{ date: new Date(), debitAccount: '1200', creditAccount: '8400', amount: 200 },
|
||||
{ date: new Date(), debitAccount: '1200', creditAccount: '8400', amount: 300 }
|
||||
]);
|
||||
|
||||
// Paginated access for large datasets
|
||||
const pagedTransactions = await api.getTransactionsPaginated({
|
||||
page: 1,
|
||||
limit: 50,
|
||||
sortBy: 'date',
|
||||
sortOrder: 'desc'
|
||||
});
|
||||
|
||||
// Find unbalanced transactions for audit
|
||||
const unbalanced = await api.getUnbalancedTransactions();
|
||||
```
|
||||
|
||||
## 📚 SKR03 vs SKR04: Which One to Choose?
|
||||
|
||||
### SKR03 - Process Structure Principle (Prozessgliederungsprinzip)
|
||||
**Best for:** 🛍️ Trading companies, 💼 Service providers, 🏪 Retail businesses
|
||||
|
||||
- Accounts organized by **business process flow**
|
||||
- Easier mapping to operational workflows
|
||||
- Natural progression from purchasing → inventory → sales
|
||||
- Popular with small to medium enterprises
|
||||
|
||||
### SKR04 - Financial Classification Principle (Abschlussgliederungsprinzip)
|
||||
**Best for:** 🏭 Manufacturing companies, 🏗️ Large corporations, 📈 Public companies
|
||||
|
||||
- Accounts organized by **financial statement structure**
|
||||
- Direct mapping to balance sheet and P&L positions
|
||||
- Simplified financial reporting and analysis
|
||||
- Preferred by auditors and financial institutions
|
||||
|
||||
## 🎯 Account Structure
|
||||
|
||||
Both SKR standards follow the same 4-digit hierarchical structure:
|
||||
|
||||
```
|
||||
[0-9] → Account Class (Kontenklasse)
|
||||
[0-9] → Account Group (Kontengruppe)
|
||||
[0-9] → Account Subgroup (Kontenuntergruppe)
|
||||
[0-9] → Individual Account (Einzelkonto)
|
||||
```
|
||||
|
||||
### Account Classes Overview
|
||||
|
||||
| Class | SKR03 Description | SKR04 Description | Type |
|
||||
|-------|------------------|-------------------|------|
|
||||
| **0** | Fixed Assets (Anlagevermögen) | Fixed Assets | Asset |
|
||||
| **1** | Current Assets (Umlaufvermögen) | Financial & Current Assets | Asset |
|
||||
| **2** | Equity (Eigenkapital) | Expenses Part 1 | Equity/Expense |
|
||||
| **3** | Liabilities (Fremdkapital) | Expenses Part 2 | Liability/Expense |
|
||||
| **4** | Operating Income (Betriebliche Erträge) | Revenues Part 1 | Revenue |
|
||||
| **5** | Material Costs (Materialaufwand) | Revenues Part 2 | Expense/Revenue |
|
||||
| **6** | Operating Expenses (Betriebsaufwand) | Special Accounts | Expense |
|
||||
| **7** | Other Costs (Weitere Aufwendungen) | Cost Accounting | Expense |
|
||||
| **8** | Income (Erträge) | Free for Use (Custom) | Revenue |
|
||||
| **9** | Closing Accounts (Abschlusskonten) | Equity & Closing | System |
|
||||
|
||||
## 🔧 Advanced Features
|
||||
|
||||
### Period Management
|
||||
|
||||
```typescript
|
||||
// Close accounting period with automatic adjustments
|
||||
await api.closePeriod('2024-01', {
|
||||
performYearEndAdjustments: true,
|
||||
generateReports: true
|
||||
});
|
||||
|
||||
// Recalculate all account balances
|
||||
await api.recalculateBalances();
|
||||
```
|
||||
|
||||
### Data Import/Export
|
||||
|
||||
```typescript
|
||||
// Import accounts from CSV
|
||||
const importedCount = await api.importAccountsFromCSV(csvContent);
|
||||
|
||||
// Export accounts to CSV
|
||||
const csvExport = await api.exportAccountsToCSV();
|
||||
|
||||
// Export to DATEV format (for tax advisors)
|
||||
const datevExport = await api.exportToDATEV({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// Export reports to CSV
|
||||
const reportCsv = await api.exportReportToCSV('income_statement', {
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
```
|
||||
|
||||
### Validation & Integrity
|
||||
|
||||
```typescript
|
||||
// Find unbalanced transactions
|
||||
const unbalanced = await api.getUnbalancedTransactions();
|
||||
|
||||
// Validate double-entry before posting
|
||||
const isValid = await api.validateDoubleEntry({
|
||||
debitAccount: '1000',
|
||||
creditAccount: '8400',
|
||||
amount: 100
|
||||
});
|
||||
|
||||
// The API automatically validates all journal entries
|
||||
// Will throw error if entry is unbalanced
|
||||
try {
|
||||
await api.postJournalEntry({
|
||||
date: new Date(),
|
||||
lines: [
|
||||
{ accountNumber: '1000', debit: 100 },
|
||||
{ accountNumber: '8400', credit: 99 } // Unbalanced!
|
||||
]
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Journal entry is not balanced!');
|
||||
}
|
||||
```
|
||||
|
||||
### Invoice Processing & Compliance
|
||||
|
||||
```typescript
|
||||
// Get invoice statistics and analytics
|
||||
const stats = await api.getInvoiceStatistics({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
groupBy: 'month',
|
||||
includeVATAnalysis: true
|
||||
});
|
||||
|
||||
// Generate invoices programmatically
|
||||
const invoice = await api.generateInvoice({
|
||||
invoiceNumber: 'INV-2024-001',
|
||||
date: new Date(),
|
||||
dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
|
||||
seller: {
|
||||
name: 'Your Company GmbH',
|
||||
vatId: 'DE123456789',
|
||||
address: 'Hauptstraße 1, 10115 Berlin'
|
||||
},
|
||||
buyer: {
|
||||
name: 'Customer AG',
|
||||
vatId: 'DE987654321',
|
||||
address: 'Kundenweg 5, 80331 München'
|
||||
},
|
||||
lines: [
|
||||
{
|
||||
description: 'Consulting Services',
|
||||
quantity: 10,
|
||||
unitPrice: 100,
|
||||
vatRate: 19
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Validate invoice compliance
|
||||
const validation = await api.validateInvoice(invoice, {
|
||||
standard: 'xrechnung',
|
||||
checkBusinessRules: true,
|
||||
checkVATRules: true
|
||||
});
|
||||
```
|
||||
|
||||
### Utility Functions
|
||||
|
||||
```typescript
|
||||
// Get SKR type description for account classes
|
||||
const classDesc = api.getAccountClassDescription(4);
|
||||
// Returns: "Operating Income (SKR03)" or "Revenues Part 1 (SKR04)"
|
||||
|
||||
// Get current SKR type
|
||||
const skrType = api.getSKRType(); // Returns: 'SKR03' or 'SKR04'
|
||||
```
|
||||
|
||||
## 🛡️ Type Safety
|
||||
|
||||
Full TypeScript support with comprehensive type definitions:
|
||||
|
||||
```typescript
|
||||
import type {
|
||||
TSKRType,
|
||||
IAccountData,
|
||||
ITransactionData,
|
||||
IJournalEntry,
|
||||
IJournalEntryLine,
|
||||
ITrialBalanceReport,
|
||||
IIncomeStatement,
|
||||
IBalanceSheet,
|
||||
IAccountFilter,
|
||||
ITransactionFilter,
|
||||
IPaginationParams,
|
||||
IAccountBalance,
|
||||
ICashFlowStatement,
|
||||
IGeneralLedger,
|
||||
IInvoice,
|
||||
IInvoiceLine,
|
||||
IInvoiceParty,
|
||||
IBookingRules,
|
||||
IValidationResult
|
||||
} from '@fin.cx/skr';
|
||||
|
||||
// All operations are fully typed
|
||||
const account: IAccountData = {
|
||||
accountNumber: '1200',
|
||||
accountName: 'Bank Account',
|
||||
accountClass: 1,
|
||||
accountType: 'asset',
|
||||
debitAccount: '1200',
|
||||
creditAccount: '4000',
|
||||
amount: 1000,
|
||||
description: 'Test sale',
|
||||
reference: 'INV-001',
|
||||
skrType: 'SKR03',
|
||||
isActive: true
|
||||
};
|
||||
});
|
||||
|
||||
// TypeScript will catch errors at compile time
|
||||
const filter: IAccountFilter = {
|
||||
accountType: 'asset',
|
||||
isActive: true,
|
||||
accountClass: 1
|
||||
};
|
||||
const trialBalance = await api.generateTrialBalance();
|
||||
|
||||
// Journal entries are validated at type level
|
||||
const journalEntry: IJournalEntry = {
|
||||
console.log(trialBalance.isBalanced);
|
||||
|
||||
await api.close();
|
||||
```
|
||||
|
||||
## SKR03 vs SKR04
|
||||
|
||||
`initialize('SKR03')` loads the process-oriented chart.
|
||||
|
||||
- Class 4: operating income
|
||||
- Class 5: material costs
|
||||
- Class 6: personnel costs
|
||||
- Class 7: other operating expenses
|
||||
|
||||
`initialize('SKR04')` loads the financial-statement-oriented chart.
|
||||
|
||||
- Class 2 and 3: expenses
|
||||
- Class 4 and 5: revenues
|
||||
- Class 8: reserved as `frei` for custom use
|
||||
|
||||
The test suite exercises both variants and includes full Jahresabschluss scenarios for each.
|
||||
|
||||
## Posting Model
|
||||
|
||||
Simple postings use `postTransaction()`.
|
||||
|
||||
```ts
|
||||
await api.postTransaction({
|
||||
date: new Date(),
|
||||
description: 'Year-end closing',
|
||||
debitAccount: '5400',
|
||||
creditAccount: '70001',
|
||||
amount: 119,
|
||||
description: 'Purchase including VAT',
|
||||
skrType: 'SKR03',
|
||||
vatAmount: 19,
|
||||
reference: 'VAT-001',
|
||||
});
|
||||
```
|
||||
|
||||
Complex bookings use `postJournalEntry()` with explicit DATEV posting keys.
|
||||
|
||||
```ts
|
||||
await api.postJournalEntry({
|
||||
date: new Date(),
|
||||
description: 'Complex distribution',
|
||||
reference: 'COMPLEX-001',
|
||||
lines: [
|
||||
{ accountNumber: '8400', debit: 0, credit: 1000 },
|
||||
{ accountNumber: '9000', debit: 1000, credit: 0 }
|
||||
]
|
||||
};
|
||||
{ accountNumber: '5000', debit: 500, description: 'Materials', postingKey: 40 },
|
||||
{ accountNumber: '6000', debit: 300, description: 'Wages', postingKey: 40 },
|
||||
{ accountNumber: '7100', debit: 200, description: 'Rent', postingKey: 40 },
|
||||
{ accountNumber: '1200', credit: 1000, description: 'Bank payment', postingKey: 40 },
|
||||
],
|
||||
skrType: 'SKR03',
|
||||
});
|
||||
```
|
||||
|
||||
## 🌟 Real-World Example: Complete Annual Closing
|
||||
Important behavior from the code and tests:
|
||||
|
||||
Here's how to perform a complete Jahresabschluss (annual financial closing):
|
||||
- debit and credit totals must balance
|
||||
- debit and credit account cannot be the same in a simple transaction
|
||||
- inactive accounts cannot be posted to
|
||||
- automatic accounts such as debtor or creditor control accounts are meant to be replaced by personal accounts for direct postings
|
||||
|
||||
```typescript
|
||||
import { SkrApi } from '@fin.cx/skr';
|
||||
## Common Workflows
|
||||
|
||||
async function performJahresabschluss() {
|
||||
const api = new SkrApi({
|
||||
mongoDbUrl: process.env.MONGODB_URL!,
|
||||
dbName: 'company_accounting'
|
||||
});
|
||||
|
||||
await api.initialize('SKR04'); // Using SKR04 for better reporting structure
|
||||
|
||||
// 1. Post year-end adjustments
|
||||
const adjustments = await api.postJournalEntry({
|
||||
date: new Date('2024-12-31'),
|
||||
description: 'Jahresabschlussbuchungen',
|
||||
reference: 'JA-2024',
|
||||
lines: [
|
||||
// Depreciation (AfA)
|
||||
{ accountNumber: '3700', debit: 10000, description: 'AfA auf Anlagen' },
|
||||
{ accountNumber: '0210', credit: 10000, description: 'Wertberichtigung Gebäude' },
|
||||
|
||||
// Provisions (Rückstellungen)
|
||||
{ accountNumber: '3500', debit: 5000, description: 'Bildung Rückstellungen' },
|
||||
{ accountNumber: '0800', credit: 5000, description: 'Sonstige Rückstellungen' },
|
||||
|
||||
// VAT clearing
|
||||
{ accountNumber: '1771', debit: 19000, description: 'USt-Saldo' },
|
||||
{ accountNumber: '1571', credit: 17000, description: 'Vorsteuer-Saldo' },
|
||||
{ accountNumber: '1700', credit: 2000, description: 'USt-Zahllast' }
|
||||
]
|
||||
});
|
||||
|
||||
// 2. Generate comprehensive annual closing package
|
||||
const jahresabschluss = await api.exportJahresabschluss({
|
||||
year: 2024,
|
||||
includeReports: ['balance_sheet', 'income_statement', 'cash_flow', 'trial_balance'],
|
||||
format: 'pdf',
|
||||
language: 'de',
|
||||
signatureRequired: true,
|
||||
companyInfo: {
|
||||
name: 'Mustermann GmbH',
|
||||
address: 'Hauptstraße 1, 10115 Berlin',
|
||||
taxNumber: 'DE123456789',
|
||||
registrationNumber: 'HRB 12345'
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Generate individual reports for analysis
|
||||
const incomeStatement = await api.generateIncomeStatement({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
const balanceSheet = await api.generateBalanceSheet({
|
||||
date: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
const cashFlow = await api.generateCashFlowStatement({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// 4. Export for tax advisor in DATEV format
|
||||
const datevExport = await api.exportToDATEV({
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31')
|
||||
});
|
||||
|
||||
// 5. Create signed export for audit trail
|
||||
const signedExport = await api.signExport({
|
||||
data: jahresabschluss,
|
||||
privateKey: process.env.PRIVATE_KEY!,
|
||||
certificate: process.env.CERTIFICATE!,
|
||||
includeTimestamp: true
|
||||
});
|
||||
|
||||
// 6. Close the period
|
||||
await api.closePeriod('2024-12', {
|
||||
performYearEndAdjustments: true,
|
||||
generateReports: true
|
||||
});
|
||||
|
||||
console.log('🎊 Jahresabschluss 2024 Complete!');
|
||||
console.log(`📈 Umsatz: €${incomeStatement.totalRevenue.toLocaleString('de-DE')}`);
|
||||
console.log(`💰 Aufwendungen: €${incomeStatement.totalExpenses.toLocaleString('de-DE')}`);
|
||||
console.log(`📊 Jahresergebnis: €${incomeStatement.netIncome.toLocaleString('de-DE')}`);
|
||||
console.log(`💼 Bilanzsumme: €${balanceSheet.assets.totalAssets.toLocaleString('de-DE')}`);
|
||||
console.log(`💵 Cash Flow: €${cashFlow.netCashFlow.toLocaleString('de-DE')}`);
|
||||
console.log(incomeStatement.netIncome > 0 ? '✅ Gewinn!' : '📉 Verlust');
|
||||
|
||||
await api.close();
|
||||
}
|
||||
Create custom accounts:
|
||||
|
||||
performJahresabschluss().catch(console.error);
|
||||
```ts
|
||||
await api.createAccount({
|
||||
accountNumber: '4999',
|
||||
accountName: 'Custom Revenue Account',
|
||||
accountClass: 4,
|
||||
accountType: 'revenue',
|
||||
description: 'Test custom account',
|
||||
});
|
||||
```
|
||||
|
||||
## 🚦 API Reference
|
||||
Batch operations:
|
||||
|
||||
### Main Classes
|
||||
```ts
|
||||
await api.createBatchAccounts([
|
||||
{
|
||||
accountNumber: '10001',
|
||||
accountName: 'Kunde Mustermann GmbH',
|
||||
accountClass: 1,
|
||||
accountType: 'asset',
|
||||
skrType: 'SKR03',
|
||||
},
|
||||
{
|
||||
accountNumber: '70001',
|
||||
accountName: 'Lieferant Test GmbH',
|
||||
accountClass: 7,
|
||||
accountType: 'liability',
|
||||
skrType: 'SKR03',
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
| Class | Description |
|
||||
|-------|-------------|
|
||||
| **`SkrApi`** | Main API entry point for all operations |
|
||||
| **`ChartOfAccounts`** | Account management and initialization |
|
||||
| **`Ledger`** | General ledger and transaction posting with SKR validation |
|
||||
| **`Reports`** | Financial reporting and exports |
|
||||
| **`Account`** | Account model with balance tracking |
|
||||
| **`Transaction`** | Double-entry transaction model |
|
||||
| **`JournalEntry`** | Complex multi-line journal entries |
|
||||
| **`InvoiceAdapter`** | XRechnung/ZUGFeRD invoice processing |
|
||||
| **`InvoiceBookingEngine`** | Automatic invoice to accounting booking |
|
||||
| **`InvoiceStorage`** | Invoice persistence and search |
|
||||
Pagination:
|
||||
|
||||
### Key Methods
|
||||
```ts
|
||||
const page1 = await api.getAccountsPaginated(1, 10);
|
||||
console.log(page1.total, page1.totalPages, page1.data.length);
|
||||
```
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `initialize(skrType)` | Initialize with SKR03 or SKR04 |
|
||||
| `postTransaction(data)` | Post a simple two-line transaction |
|
||||
| `postJournalEntry(data)` | Post complex multi-line journal entry |
|
||||
| `postBatchTransactions(transactions)` | Post multiple transactions efficiently |
|
||||
| `reverseTransaction(id)` | Create reversal (Storno) entry |
|
||||
| `reverseJournalEntry(id)` | Reverse complex journal entries |
|
||||
| `generateTrialBalance(params)` | Generate Summen- und Saldenliste |
|
||||
| `generateIncomeStatement(params)` | Generate GuV (P&L) statement |
|
||||
| `generateBalanceSheet(params)` | Generate Bilanz (balance sheet) |
|
||||
| `generateCashFlowStatement(params)` | Generate cash flow statement |
|
||||
| `generateGeneralLedger(params)` | Generate complete general ledger |
|
||||
| `exportToDATEV(params)` | Export DATEV-compatible data |
|
||||
| `exportJahresabschluss(params)` | Export complete annual closing package |
|
||||
| `generatePdfReports(params)` | Generate professional PDF reports |
|
||||
| `signExport(data)` | Create cryptographically signed exports |
|
||||
| `importInvoice(data, options)` | Import XRechnung/ZUGFeRD invoices |
|
||||
| `bookInvoice(invoiceId, rules)` | Book invoice to accounting |
|
||||
| `exportInvoice(id, options)` | Export invoice in various formats |
|
||||
| `searchInvoices(filter)` | Search and filter invoices |
|
||||
| `closePeriod(period, options)` | Close accounting period |
|
||||
| `recalculateBalances()` | Recalculate all account balances |
|
||||
| `validateDoubleEntry(data)` | Validate transaction before posting |
|
||||
| `getUnbalancedTransactions()` | Find integrity issues |
|
||||
| `createBatchAccounts(accounts)` | Create multiple accounts at once |
|
||||
Reversals and validation:
|
||||
|
||||
## 🏆 Why Developers Love It
|
||||
```ts
|
||||
const ok = api.validateDoubleEntry(100, 100);
|
||||
const reversed = await api.reverseTransaction(transactionId);
|
||||
```
|
||||
|
||||
- **🎯 Zero Configuration**: Pre-configured SKR03/SKR04 accounts out of the box
|
||||
- **🔄 Automatic Validation**: Never worry about unbalanced entries or wrong account types
|
||||
- **📊 Real-time Analytics**: Instant financial insights with live balance updates
|
||||
- **🛡️ SKR Compliance**: Validates against official SKR standards automatically
|
||||
- **🚀 High Performance**: Optimized MongoDB queries and batch operations
|
||||
- **📚 German Compliance**: Full HGB/GoBD compliance built-in
|
||||
- **🤝 Type Safety**: Complete TypeScript definitions prevent runtime errors
|
||||
- **🔍 Smart Validation**: Warns about non-standard accounts and type mismatches
|
||||
- **🧾 E-Invoice Ready**: Native XRechnung/ZUGFeRD support for modern workflows
|
||||
- **🔐 Audit-Proof**: Cryptographic signatures and Merkle trees for tamper-proof records
|
||||
- **📑 Professional Reports**: Generate PDF reports that impress auditors and stakeholders
|
||||
## Reports And Exports
|
||||
|
||||
## 📋 Requirements
|
||||
Available reporting methods on `SkrApi`:
|
||||
|
||||
- **Node.js** >= 18.0.0
|
||||
- **MongoDB** >= 5.0
|
||||
- **TypeScript** >= 5.0 (for development)
|
||||
- `generateTrialBalance()`
|
||||
- `generateIncomeStatement()`
|
||||
- `generateBalanceSheet()`
|
||||
- `generateGeneralLedger()`
|
||||
- `generateCashFlowStatement()`
|
||||
- `exportReportToCSV()`
|
||||
- `exportToDATEV()`
|
||||
|
||||
## 🔬 Testing
|
||||
Year-end archival export:
|
||||
|
||||
The module includes comprehensive test coverage with real-world scenarios:
|
||||
```ts
|
||||
const exportPath = await api.exportJahresabschluss({
|
||||
exportPath: './exports',
|
||||
fiscalYear: 2024,
|
||||
dateFrom: new Date('2024-01-01'),
|
||||
dateTo: new Date('2024-12-31'),
|
||||
includeDocuments: true,
|
||||
generatePdfReports: true,
|
||||
signExport: false,
|
||||
timestampExport: false,
|
||||
companyInfo: {
|
||||
name: 'Example GmbH',
|
||||
taxId: 'DE123456789',
|
||||
registrationNumber: 'HRB 12345',
|
||||
address: 'Example Street 1, 28195 Bremen',
|
||||
},
|
||||
});
|
||||
|
||||
console.log(exportPath);
|
||||
```
|
||||
|
||||
The export code creates a BagIt-style folder structure with metadata, accounting data, report output, document storage, and manifest hashes.
|
||||
|
||||
## E-Invoice Workflows
|
||||
|
||||
The package includes invoice types and API helpers for importing, storing, booking, searching, exporting, and generating e-invoices.
|
||||
|
||||
Supported invoice directions:
|
||||
|
||||
- `inbound`
|
||||
- `outbound`
|
||||
|
||||
Supported formats in the invoice model:
|
||||
|
||||
- `xrechnung`
|
||||
- `zugferd`
|
||||
- `facturx`
|
||||
- `peppol`
|
||||
- `ubl`
|
||||
|
||||
Example import and booking flow:
|
||||
|
||||
```ts
|
||||
const invoice = await api.importInvoice('./fixtures/invoice.xml', 'inbound', {
|
||||
autoBook: true,
|
||||
confidenceThreshold: 80,
|
||||
});
|
||||
|
||||
const hits = await api.searchInvoices({
|
||||
invoiceNumber: invoice.invoiceNumber,
|
||||
});
|
||||
|
||||
const exported = await api.exportInvoice(invoice, {
|
||||
format: 'xrechnung',
|
||||
embedInPdf: true,
|
||||
});
|
||||
```
|
||||
|
||||
The API also exposes:
|
||||
|
||||
- `bookInvoice()`
|
||||
- `getInvoice()`
|
||||
- `getInvoiceStatistics()`
|
||||
- `createInvoiceComplianceReport()`
|
||||
- `generateInvoice()`
|
||||
|
||||
## Public Exports
|
||||
|
||||
Top-level exports include:
|
||||
|
||||
- `SkrApi`
|
||||
- `Account`
|
||||
- `Transaction`
|
||||
- `JournalEntry`
|
||||
- `ChartOfAccounts`
|
||||
- `Ledger`
|
||||
- `Reports`
|
||||
- `SkrExport`
|
||||
- `LedgerExporter`
|
||||
- `AccountsExporter`
|
||||
- `BalancesExporter`
|
||||
- `PdfReportGenerator`
|
||||
- `SecurityManager`
|
||||
- `SKR03_ACCOUNTS`, `SKR04_ACCOUNTS`
|
||||
|
||||
This makes the package usable as both an application-facing API and a toolkit for custom accounting workflows.
|
||||
|
||||
## Development
|
||||
|
||||
Build:
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pnpm test
|
||||
|
||||
# Run specific test suites
|
||||
pnpm test test/test.skr03.ts # SKR03 functionality
|
||||
pnpm test test/test.skr04.ts # SKR04 functionality
|
||||
pnpm test test/test.jahresabschluss.skr03.ts # Annual closing SKR03
|
||||
pnpm test test/test.jahresabschluss.skr04.ts # Annual closing SKR04
|
||||
pnpm test test/test.invoice.ts # Invoice processing
|
||||
pnpm test test/test.export.ts # Export functionality
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Test:
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
```
|
||||
|
||||
Current project checks include:
|
||||
|
||||
- runtime tests for SKR03 and SKR04 flows
|
||||
- transaction and journal validation
|
||||
- report generation
|
||||
- DATEV export
|
||||
- published type consumption through `test/fixtures/strict-consumer`
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
||||
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [license](./license.md) file.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
||||
|
||||
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District court Bremen HRB 35230 HB, Germany
|
||||
Registered at District Court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
||||
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
||||
Reference in New Issue
Block a user