import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as skr from '../ts/index.js'; import { getTestConfig } from './helpers/setup.js'; let api: skr.SkrApi; let testConfig: Awaited>; tap.test('should demonstrate complete Jahresabschluss (Annual Financial Statement) for SKR04', async () => { testConfig = await getTestConfig(); // Use timestamp to ensure unique database for each test run const timestamp = Date.now(); api = new skr.SkrApi({ mongoDbUrl: testConfig.mongoDbUrl, dbName: `${testConfig.mongoDbName}_jahresabschluss_skr04_${timestamp}`, }); await api.initialize('SKR04'); expect(api.getSKRType()).toEqual('SKR04'); }); tap.test('should set up opening balances (Eröffnungsbilanz) for SKR04', async () => { // Opening balances from previous year's closing // SKR04 uses different account structure than SKR03 // Post opening journal entry (Eröffnungsbuchung) const openingEntry = await api.postJournalEntry({ date: new Date('2024-01-01'), description: 'Eröffnungsbilanz 2024', reference: 'EB-2024', lines: [ // Debit all asset accounts { accountNumber: '0200', debit: 45000, description: 'Grundstücke' }, { accountNumber: '0210', debit: 120000, description: 'Gebäude' }, { accountNumber: '0500', debit: 35000, description: 'BGA' }, { accountNumber: '0400', debit: 8000, description: 'Fuhrpark' }, { accountNumber: '1200', debit: 25000, description: 'Bank' }, { accountNumber: '1000', debit: 2500, description: 'Kasse' }, { accountNumber: '1400', debit: 18000, description: 'Forderungen' }, // Credit all liability and equity accounts { accountNumber: '9000', credit: 150000, description: 'Eigenkapital' }, { accountNumber: '9300', credit: 35000, description: 'Gewinnrücklagen' }, { accountNumber: '1600', credit: 40500, description: 'Verbindlichkeiten L+L' }, { accountNumber: '1700', credit: 28000, description: 'Sonstige Verbindlichkeiten' }, ], skrType: 'SKR04', }); expect(openingEntry.isBalanced).toBeTrue(); expect(openingEntry.totalDebits).toEqual(253500); expect(openingEntry.totalCredits).toEqual(253500); }); tap.test('should record Q1 business transactions for SKR04', async () => { // January - March transactions using SKR04 accounts // Sale of goods with 19% VAT - SKR04 uses 4300 for revenue with 19% VAT await api.postJournalEntry({ date: new Date('2024-01-15'), description: 'Verkauf Waren auf Rechnung', reference: 'RE-2024-001', lines: [ { accountNumber: '1400', debit: 11900, description: 'Forderungen inkl. USt' }, { accountNumber: '4300', credit: 10000, description: 'Erlöse 19% USt' }, { accountNumber: '1771', credit: 1900, description: 'Umsatzsteuer 19%' }, ], skrType: 'SKR04', }); // Purchase of materials with 19% VAT - SKR04 uses 2100 for goods purchases await api.postJournalEntry({ date: new Date('2024-01-20'), description: 'Einkauf Material auf Rechnung', reference: 'ER-2024-001', lines: [ { accountNumber: '2100', debit: 5000, description: 'Bezogene Waren' }, { accountNumber: '1571', debit: 950, description: 'Vorsteuer 19%' }, { accountNumber: '1600', credit: 5950, description: 'Verbindlichkeiten' }, ], skrType: 'SKR04', }); // Salary payment - SKR04 uses 2300 for wages await api.postJournalEntry({ date: new Date('2024-01-31'), description: 'Gehaltszahlung Januar', reference: 'GH-2024-01', lines: [ { accountNumber: '2300', debit: 8000, description: 'Löhne' }, { accountNumber: '2400', debit: 1600, description: 'Gehälter' }, { accountNumber: '1200', credit: 9600, description: 'Banküberweisung' }, ], skrType: 'SKR04', }); // Customer payment received await api.postJournalEntry({ date: new Date('2024-02-10'), description: 'Zahlungseingang Kunde', reference: 'ZE-2024-001', lines: [ { accountNumber: '1200', debit: 11900, description: 'Bankgutschrift' }, { accountNumber: '1400', credit: 11900, description: 'Forderungsausgleich' }, ], skrType: 'SKR04', }); // Rent payment - SKR04 uses 3000 for rent await api.postJournalEntry({ date: new Date('2024-02-01'), description: 'Miete Februar', reference: 'MI-2024-02', lines: [ { accountNumber: '3000', debit: 2000, description: 'Miete' }, { accountNumber: '1200', credit: 2000, description: 'Banküberweisung' }, ], skrType: 'SKR04', }); // Office supplies purchase - SKR04 uses 3100 for office supplies await api.postJournalEntry({ date: new Date('2024-02-15'), description: 'Büromaterial', reference: 'BM-2024-001', lines: [ { accountNumber: '3100', debit: 200, description: 'Bürobedarf' }, { accountNumber: '1571', debit: 38, description: 'Vorsteuer 19%' }, { accountNumber: '1200', credit: 238, description: 'Bankzahlung' }, ], skrType: 'SKR04', }); // Vehicle expenses - SKR04 uses 3300 for vehicle costs await api.postJournalEntry({ date: new Date('2024-03-05'), description: 'Tankrechnung Firmenfahrzeug', reference: 'KFZ-2024-001', lines: [ { accountNumber: '3300', debit: 150, description: 'Kfz-Kosten' }, { accountNumber: '1571', debit: 28.50, description: 'Vorsteuer 19%' }, { accountNumber: '1200', credit: 178.50, description: 'Bankzahlung' }, ], skrType: 'SKR04', }); // Another sale await api.postJournalEntry({ date: new Date('2024-03-20'), description: 'Verkauf Dienstleistung', reference: 'RE-2024-002', lines: [ { accountNumber: '1400', debit: 7140, description: 'Forderungen inkl. USt' }, { accountNumber: '4300', credit: 6000, description: 'Erlöse 19% USt' }, { accountNumber: '1771', credit: 1140, description: 'Umsatzsteuer 19%' }, ], skrType: 'SKR04', }); }); tap.test('should record Q2-Q4 business transactions for SKR04', async () => { // More transactions throughout the year // Q2: Investment in new equipment await api.postJournalEntry({ date: new Date('2024-04-15'), description: 'Kauf neue Produktionsmaschine', reference: 'INV-2024-001', lines: [ { accountNumber: '0500', debit: 25000, description: 'Neue Maschine' }, { accountNumber: '1571', debit: 4750, description: 'Vorsteuer 19%' }, { accountNumber: '1200', credit: 29750, description: 'Banküberweisung' }, ], skrType: 'SKR04', }); // Q2: Large sale await api.postJournalEntry({ date: new Date('2024-05-10'), description: 'Großauftrag Kunde ABC', reference: 'RE-2024-003', lines: [ { accountNumber: '1400', debit: 35700, description: 'Forderungen inkl. USt' }, { accountNumber: '4300', credit: 30000, description: 'Erlöse 19% USt' }, { accountNumber: '1771', credit: 5700, description: 'Umsatzsteuer 19%' }, ], skrType: 'SKR04', }); // Q3: Marketing expenses - SKR04 uses 3400 for advertising await api.postJournalEntry({ date: new Date('2024-07-10'), description: 'Werbekampagne', reference: 'WK-2024-001', lines: [ { accountNumber: '3400', debit: 5000, description: 'Werbekosten' }, { accountNumber: '1571', debit: 950, description: 'Vorsteuer 19%' }, { accountNumber: '1600', credit: 5950, description: 'Verbindlichkeiten' }, ], skrType: 'SKR04', }); // Q3: Professional services - SKR04 uses 3500 for legal/consulting await api.postJournalEntry({ date: new Date('2024-08-15'), description: 'Steuerberatung', reference: 'STB-2024-001', lines: [ { accountNumber: '3500', debit: 2500, description: 'Steuerberatungskosten' }, { accountNumber: '1571', debit: 475, description: 'Vorsteuer 19%' }, { accountNumber: '1200', credit: 2975, description: 'Banküberweisung' }, ], skrType: 'SKR04', }); // Q4: Year-end bonus payment await api.postJournalEntry({ date: new Date('2024-11-30'), description: 'Jahresbonus Mitarbeiter', reference: 'BON-2024', lines: [ { accountNumber: '2300', debit: 10000, description: 'Tantieme' }, { accountNumber: '2400', debit: 2000, description: 'Gehälter Bonus' }, { accountNumber: '1200', credit: 12000, description: 'Banküberweisung' }, ], skrType: 'SKR04', }); // Q4: Collection of outstanding receivables await api.postJournalEntry({ date: new Date('2024-12-15'), description: 'Zahlungseingang Großauftrag', reference: 'ZE-2024-003', lines: [ { accountNumber: '1200', debit: 35700, description: 'Bankgutschrift' }, { accountNumber: '1400', credit: 35700, description: 'Forderungsausgleich' }, ], skrType: 'SKR04', }); }); tap.test('should perform year-end adjustments (Jahresabschlussbuchungen) for SKR04', async () => { // 1. Depreciation (Abschreibungen) - SKR04 uses 3700 for depreciation await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschreibung Gebäude (linear 2%)', reference: 'AFA-2024-001', lines: [ { accountNumber: '3700', debit: 2400, description: 'AfA auf Gebäude' }, { accountNumber: '0210', credit: 2400, description: 'Wertberichtigung Gebäude' }, ], skrType: 'SKR04', }); await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschreibung BGA (linear 10%)', reference: 'AFA-2024-002', lines: [ { accountNumber: '3700', debit: 6000, description: 'AfA auf BGA' }, // (35000 + 25000) * 10% { accountNumber: '0500', credit: 6000, description: 'Wertberichtigung BGA' }, ], skrType: 'SKR04', }); await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschreibung Fuhrpark (linear 20%)', reference: 'AFA-2024-003', lines: [ { accountNumber: '3700', debit: 1600, description: 'AfA auf Fuhrpark' }, { accountNumber: '0400', credit: 1600, description: 'Wertberichtigung Fuhrpark' }, ], skrType: 'SKR04', }); // 2. Accruals (Rechnungsabgrenzung) - SKR04 uses 1900 for prepaid expenses await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Aktive Rechnungsabgrenzung - Vorausbezahlte Versicherung', reference: 'ARA-2024-001', lines: [ { accountNumber: '1900', debit: 1000, description: 'Aktive Rechnungsabgrenzung' }, { accountNumber: '3200', credit: 1000, description: 'Versicherungen' }, ], skrType: 'SKR04', }); // 3. Provisions (Rückstellungen) - SKR04 uses 0800 for provisions await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Rückstellung für Jahresabschlusskosten', reference: 'RS-2024-001', lines: [ { accountNumber: '3500', debit: 3000, description: 'Rechts- und Beratungskosten' }, { accountNumber: '0800', credit: 3000, description: 'Rückstellungen' }, ], skrType: 'SKR04', }); // 4. VAT clearing (Umsatzsteuer-Vorauszahlung) await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'USt-Abschluss Q4', reference: 'UST-2024-Q4', lines: [ { accountNumber: '1771', debit: 8740, description: 'USt-Saldo' }, // Total collected VAT { accountNumber: '1571', credit: 7191.50, description: 'Vorsteuer-Saldo' }, // Total input VAT { accountNumber: '1700', credit: 1548.50, description: 'USt-Zahllast' }, ], skrType: 'SKR04', }); // Assert VAT accounts are cleared const ust19 = await api.getAccountBalance('1771'); const vorst19 = await api.getAccountBalance('1571'); const ustZahllast = await api.getAccountBalance('1700'); expect(Math.abs(ust19.balance)).toBeLessThan(0.01); expect(Math.abs(vorst19.balance)).toBeLessThan(0.01); // Account 1700 started with 28000 from opening balance, plus 1548.50 from VAT clearing expect(Math.abs(ustZahllast.balance - 29548.50)).toBeLessThan(0.01); }); tap.test('should calculate income statement (GuV) before closing for SKR04', async () => { const incomeStatement = await api.generateIncomeStatement({ dateFrom: new Date('2024-01-01'), dateTo: new Date('2024-12-31'), skrType: 'SKR04', }); expect(incomeStatement).toBeDefined(); expect(incomeStatement.totalRevenue).toBeGreaterThan(0); expect(incomeStatement.totalExpenses).toBeGreaterThan(0); // Assert the exact expected values based on actual bookings // Revenue: 46000 (4300 account) // Expenses: 5000 + 18000 + 3600 + 10000 + 2000 + 150 + 5000 + 5500 + 200 = 49450 // Less credit balances: -1000 (insurance accrual) = -1000 // Net expenses: 49450 - 1000 = 48450 // Net income: 46000 - 48450 = -2450 (loss) expect(Math.round(incomeStatement.totalRevenue)).toEqual(46000); expect(Math.round(incomeStatement.totalExpenses)).toEqual(48450); expect(Math.round(incomeStatement.netIncome)).toEqual(-2450); console.log('Income Statement Summary (SKR04):'); console.log('Revenue:', incomeStatement.totalRevenue); console.log('Expenses:', incomeStatement.totalExpenses); console.log('Net Income:', incomeStatement.netIncome); }); tap.test('should perform closing entries (Abschlussbuchungen) for SKR04', async () => { // Close all income and expense accounts to the profit/loss account // SKR04 uses 9500 for annual P&L account // Close revenue accounts await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschluss Ertragskonten', reference: 'AB-2024-001', lines: [ { accountNumber: '4300', debit: 46000, description: 'Erlöse abschließen' }, { accountNumber: '9500', credit: 46000, description: 'GuV-Konto' }, ], skrType: 'SKR04', }); // Close expense accounts await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschluss Aufwandskonten', reference: 'AB-2024-002', lines: [ { accountNumber: '9500', debit: 48450, description: 'GuV-Konto' }, { accountNumber: '3200', debit: 1000, description: 'Versicherung abschließen (credit balance)' }, { accountNumber: '2100', credit: 5000, description: 'Bezogene Waren abschließen' }, { accountNumber: '2300', credit: 18000, description: 'Löhne abschließen' }, { accountNumber: '2400', credit: 3600, description: 'Gehälter abschließen' }, { accountNumber: '3700', credit: 10000, description: 'AfA abschließen' }, { accountNumber: '3000', credit: 2000, description: 'Miete abschließen' }, { accountNumber: '3300', credit: 150, description: 'Kfz abschließen' }, { accountNumber: '3400', credit: 5000, description: 'Werbung abschließen' }, { accountNumber: '3500', credit: 5500, description: 'Beratung abschließen' }, { accountNumber: '3100', credit: 200, description: 'Bürobedarf abschließen' }, ], skrType: 'SKR04', }); // Transfer profit/loss to equity const guv_result = 46000 - 48450; // Loss of 2450 if (guv_result > 0) { await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Jahresgewinn auf Eigenkapital', reference: 'AB-2024-003', lines: [ { accountNumber: '9500', debit: guv_result, description: 'GuV-Konto ausgleichen' }, { accountNumber: '9300', credit: guv_result, description: 'Gewinnrücklagen' }, ], skrType: 'SKR04', }); } else if (guv_result < 0) { await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Jahresverlust auf Eigenkapital', reference: 'AB-2024-003', lines: [ { accountNumber: '9400', debit: Math.abs(guv_result), description: 'Verlustvortrag' }, { accountNumber: '9500', credit: Math.abs(guv_result), description: 'GuV-Konto ausgleichen' }, ], skrType: 'SKR04', }); } // Assert GuV account is closed and equity is updated const guv = await api.getAccountBalance('9500'); const verlustvortrag = await api.getAccountBalance('9400'); expect(Math.abs(guv.balance)).toBeLessThan(0.01); expect(Math.round(verlustvortrag.balance)).toEqual(-2450); // Loss of 2450 (debit balance is negative) // Assert all P&L accounts are closed (zero balance) const plAccounts = ['4300', '2100', '2300', '2400', '3400', '3500', '3100', '3700', '3000', '3200', '3300']; for (const accNum of plAccounts) { const balance = await api.getAccountBalance(accNum); expect(Math.abs(balance.balance)).toBeLessThan(0.01); } }); tap.test('should generate final balance sheet (Schlussbilanz) for SKR04', async () => { const balanceSheet = await api.generateBalanceSheet({ dateTo: new Date('2024-12-31'), skrType: 'SKR04', }); expect(balanceSheet).toBeDefined(); expect(balanceSheet.assets).toBeDefined(); expect(balanceSheet.liabilities).toBeDefined(); expect(balanceSheet.equity).toBeDefined(); console.log('\n=== JAHRESABSCHLUSS 2024 (SKR04) ===\n'); console.log('BILANZ zum 31.12.2024\n'); // Verify balance sheet balances const totalAssets = balanceSheet.assets.totalAssets; const totalLiabilitiesAndEquity = balanceSheet.liabilities.totalLiabilities + balanceSheet.equity.totalEquity; console.log('Balance Sheet Check (SKR04):'); console.log(' Total Assets:', totalAssets); console.log(' Total Liabilities + Equity:', totalLiabilitiesAndEquity); console.log(' Difference:', Math.abs(totalAssets - totalLiabilitiesAndEquity)); expect(Math.abs(totalAssets - totalLiabilitiesAndEquity)).toBeLessThan(0.01); console.log('✓ Balance Sheet is balanced!'); }); tap.test('should generate trial balance (Summen- und Saldenliste) for SKR04', async () => { const trialBalance = await api.generateTrialBalance({ dateFrom: new Date('2024-01-01'), dateTo: new Date('2024-12-31'), skrType: 'SKR04', }); expect(trialBalance).toBeDefined(); expect(trialBalance.isBalanced).toBeTrue(); console.log('\nSUMMEN- UND SALDENLISTE 2024 (SKR04)'); console.log('====================================='); console.log('Konto | Bezeichnung | Soll | Haben | Saldo'); console.log('------|-------------|------|-------|-------'); // Display key accounts const keyAccounts = [ '0200', '0210', '0400', '0500', // Fixed assets '1000', '1200', '1400', '1900', // Current assets '9000', '9400', '9300', // Equity '1600', '1700', '0800', // Liabilities ]; for (const accountNumber of keyAccounts) { const account = await api.getAccount(accountNumber); if (account) { const balance = await api.getAccountBalance(accountNumber); console.log(`${accountNumber} | ${account.accountName.substring(0, 30).padEnd(30)} | ${balance.debitTotal.toFixed(2).padStart(12)} | ${balance.creditTotal.toFixed(2).padStart(12)} | ${balance.balance.toFixed(2).padStart(12)}`); } } }); tap.test('should close API connection', async () => { await api.close(); }); export default tap.start();