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 SKR03', 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_${timestamp}`, }); await api.initialize('SKR03'); expect(api.getSKRType()).toEqual('SKR03'); }); tap.test('should set up opening balances (Eröffnungsbilanz)', async () => { // Opening balances from previous year's closing // This represents a small GmbH (limited liability company) // Using only accounts that exist in 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: 'Betriebs- und Geschäftsausstattung' }, { accountNumber: '0400', debit: 8000, description: 'Fuhrpark' }, { accountNumber: '1200', debit: 25000, description: 'Bank' }, { accountNumber: '1000', debit: 2500, description: 'Kasse' }, { accountNumber: '1400', debit: 18000, description: 'Forderungen' }, { accountNumber: '3100', debit: 12000, description: 'Warenvorräte' }, // Credit all liability and equity accounts { accountNumber: '2000', credit: 150000, description: 'Eigenkapital' }, { accountNumber: '2900', credit: 35000, description: 'Gewinnrücklagen' }, { accountNumber: '1600', credit: 52500, description: 'Verbindlichkeiten L+L' }, { accountNumber: '3300', credit: 28000, description: 'Verbindlichkeiten Kreditinstitute' }, ], skrType: 'SKR03', }); expect(openingEntry.isBalanced).toBeTrue(); expect(openingEntry.totalDebits).toEqual(265500); expect(openingEntry.totalCredits).toEqual(265500); }); tap.test('should record Q1 business transactions', async () => { // January - March transactions // Sale of goods 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: '8400', credit: 10000, description: 'Erlöse 19% USt' }, { accountNumber: '1771', credit: 1900, description: 'Umsatzsteuer 19%' }, ], skrType: 'SKR03', }); // Purchase of materials with 19% VAT await api.postJournalEntry({ date: new Date('2024-01-20'), description: 'Einkauf Material auf Rechnung', reference: 'ER-2024-001', lines: [ { accountNumber: '5400', debit: 5000, description: 'Wareneingang 19% Vorsteuer' }, { accountNumber: '1571', debit: 950, description: 'Vorsteuer 19%' }, { accountNumber: '1600', credit: 5950, description: 'Verbindlichkeiten' }, ], skrType: 'SKR03', }); // Salary payment await api.postJournalEntry({ date: new Date('2024-01-31'), description: 'Gehaltszahlung Januar', reference: 'GH-2024-01', lines: [ { accountNumber: '6000', debit: 8000, description: 'Löhne und Gehälter' }, { accountNumber: '6100', debit: 1600, description: 'Sozialversicherung AG-Anteil' }, { accountNumber: '1200', credit: 9600, description: 'Banküberweisung' }, ], skrType: 'SKR03', }); // 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: 'SKR03', }); // Rent payment await api.postJournalEntry({ date: new Date('2024-02-01'), description: 'Miete Februar', reference: 'MI-2024-02', lines: [ { accountNumber: '7100', debit: 2000, description: 'Miete' }, { accountNumber: '1200', credit: 2000, description: 'Banküberweisung' }, ], skrType: 'SKR03', }); // Office supplies purchase await api.postJournalEntry({ date: new Date('2024-02-15'), description: 'Büromaterial', reference: 'BM-2024-001', lines: [ { accountNumber: '6800', debit: 200, description: 'Bürobedarf' }, { accountNumber: '1571', debit: 38, description: 'Vorsteuer 19%' }, { accountNumber: '1200', credit: 238, description: 'Bankzahlung' }, ], skrType: 'SKR03', }); // Vehicle expenses await api.postJournalEntry({ date: new Date('2024-03-05'), description: 'Tankrechnung Firmenfahrzeug', reference: 'KFZ-2024-001', lines: [ { accountNumber: '7400', debit: 150, description: 'Kfz-Kosten' }, { accountNumber: '1571', debit: 28.50, description: 'Vorsteuer 19%' }, { accountNumber: '1200', credit: 178.50, description: 'Bankzahlung' }, ], skrType: 'SKR03', }); // 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: '8400', credit: 6000, description: 'Erlöse 19% USt' }, { accountNumber: '1771', credit: 1140, description: 'Umsatzsteuer 19%' }, ], skrType: 'SKR03', }); }); tap.test('should record Q2-Q4 business transactions', 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: 'SKR03', }); // 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: '8400', credit: 30000, description: 'Erlöse 19% USt' }, { accountNumber: '1771', credit: 5700, description: 'Umsatzsteuer 19%' }, ], skrType: 'SKR03', }); // Q3: Marketing expenses await api.postJournalEntry({ date: new Date('2024-07-10'), description: 'Werbekampagne', reference: 'WK-2024-001', lines: [ { accountNumber: '6600', debit: 5000, description: 'Werbekosten' }, { accountNumber: '1571', debit: 950, description: 'Vorsteuer 19%' }, { accountNumber: '1600', credit: 5950, description: 'Verbindlichkeiten' }, ], skrType: 'SKR03', }); // Q3: Professional services await api.postJournalEntry({ date: new Date('2024-08-15'), description: 'Steuerberatung', reference: 'STB-2024-001', lines: [ { accountNumber: '6700', debit: 2500, description: 'Steuerberatungskosten' }, { accountNumber: '1571', debit: 475, description: 'Vorsteuer 19%' }, { accountNumber: '1200', credit: 2975, description: 'Banküberweisung' }, ], skrType: 'SKR03', }); // Q4: Year-end bonus payment await api.postJournalEntry({ date: new Date('2024-11-30'), description: 'Jahresbonus Mitarbeiter', reference: 'BON-2024', lines: [ { accountNumber: '6000', debit: 10000, description: 'Tantieme' }, { accountNumber: '6100', debit: 2000, description: 'Sozialversicherung AG-Anteil' }, { accountNumber: '1200', credit: 12000, description: 'Banküberweisung' }, ], skrType: 'SKR03', }); // 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: 'SKR03', }); }); tap.test('should perform year-end adjustments (Jahresabschlussbuchungen)', async () => { // 1. Depreciation (Abschreibungen) await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschreibung Gebäude (linear 2%)', reference: 'AFA-2024-001', lines: [ { accountNumber: '7000', debit: 2400, description: 'AfA auf Gebäude' }, { accountNumber: '0210', credit: 2400, description: 'Wertberichtigung Gebäude' }, ], skrType: 'SKR03', }); await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschreibung BGA (linear 10%)', reference: 'AFA-2024-002', lines: [ { accountNumber: '7000', debit: 6000, description: 'AfA auf BGA' }, // (35000 + 25000) * 10% { accountNumber: '0500', credit: 6000, description: 'Wertberichtigung BGA' }, ], skrType: 'SKR03', }); await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschreibung Fuhrpark (linear 20%)', reference: 'AFA-2024-003', lines: [ { accountNumber: '7000', debit: 1600, description: 'AfA auf Fuhrpark' }, { accountNumber: '0400', credit: 1600, description: 'Wertberichtigung Fuhrpark' }, ], skrType: 'SKR03', }); // 2. Accruals (Rechnungsabgrenzung) 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: '7300', credit: 1000, description: 'Versicherungen' }, ], skrType: 'SKR03', }); // 3. Provisions (Rückstellungen) await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Rückstellung für Jahresabschlusskosten', reference: 'RS-2024-001', lines: [ { accountNumber: '6700', debit: 3000, description: 'Rechts- und Beratungskosten' }, { accountNumber: '3000', credit: 3000, description: 'Rückstellungen' }, ], skrType: 'SKR03', }); // 4. Inventory adjustment await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Bestandsveränderung Waren', reference: 'BV-2024-001', lines: [ { accountNumber: '3100', debit: 3000, description: 'Warenbestand Zugang' }, { accountNumber: '5900', credit: 3000, description: 'Bestandsveränderungen' }, ], skrType: 'SKR03', }); // 5. 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: '1800', credit: 1548.50, description: 'USt-Zahllast' }, ], skrType: 'SKR03', }); // Assert VAT accounts are cleared const ust19 = await api.getAccountBalance('1771'); const vorst19 = await api.getAccountBalance('1571'); const ustZahllast = await api.getAccountBalance('1800'); expect(Math.abs(ust19.balance)).toBeLessThan(0.01); expect(Math.abs(vorst19.balance)).toBeLessThan(0.01); expect(Math.abs(ustZahllast.balance - 1548.50)).toBeLessThan(0.01); }); tap.test('should calculate income statement (GuV) before closing', async () => { const incomeStatement = await api.generateIncomeStatement({ dateFrom: new Date('2024-01-01'), dateTo: new Date('2024-12-31'), skrType: 'SKR03', }); expect(incomeStatement).toBeDefined(); expect(incomeStatement.totalRevenue).toBeGreaterThan(0); expect(incomeStatement.totalExpenses).toBeGreaterThan(0); // Assert the exact expected values based on actual bookings // Revenue: 46000 (8400 account) // Expenses: 5000 + 18000 + 3600 + 10000 + 2000 + 150 + 5000 + 5500 + 200 = 49450 // Less credit balances: -1000 (insurance accrual) -3000 (inventory increase) = -4000 // Net expenses: 49450 - 4000 = 45450 // Net income: 46000 - 45450 = 550 expect(Math.round(incomeStatement.totalRevenue)).toEqual(46000); expect(Math.round(incomeStatement.totalExpenses)).toEqual(45450); expect(Math.round(incomeStatement.netIncome)).toEqual(550); console.log('Income Statement Summary:'); console.log('Revenue:', incomeStatement.totalRevenue); console.log('Expenses:', incomeStatement.totalExpenses); console.log('Net Income:', incomeStatement.netIncome); }); tap.test('should perform closing entries (Abschlussbuchungen)', async () => { // Close all income and expense accounts to the profit/loss account // Close revenue accounts await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschluss Ertragskonten', reference: 'AB-2024-001', lines: [ { accountNumber: '8400', debit: 46000, description: 'Erlöse abschließen' }, { accountNumber: '9400', credit: 46000, description: 'GuV-Konto' }, ], skrType: 'SKR03', }); // Close expense accounts await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Abschluss Aufwandskonten', reference: 'AB-2024-002', lines: [ { accountNumber: '9400', debit: 45450, description: 'GuV-Konto' }, { accountNumber: '7300', debit: 1000, description: 'Versicherung abschließen (credit balance)' }, { accountNumber: '5900', debit: 3000, description: 'Bestandsveränderungen abschließen (credit balance)' }, { accountNumber: '5400', credit: 5000, description: 'Wareneingang abschließen' }, { accountNumber: '6000', credit: 18000, description: 'Löhne und Gehälter abschließen' }, { accountNumber: '6100', credit: 3600, description: 'SV AG-Anteil abschließen' }, { accountNumber: '7000', credit: 10000, description: 'AfA abschließen' }, { accountNumber: '7100', credit: 2000, description: 'Miete abschließen' }, { accountNumber: '7400', credit: 150, description: 'Kfz abschließen' }, { accountNumber: '6600', credit: 5000, description: 'Werbung abschließen' }, { accountNumber: '6700', credit: 5500, description: 'Beratung abschließen' }, { accountNumber: '6800', credit: 200, description: 'Bürobedarf abschließen' }, ], skrType: 'SKR03', }); // Transfer profit/loss to equity const guv_result = 46000 - 45450; // Profit of 550 if (guv_result > 0) { await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Jahresgewinn auf Eigenkapital', reference: 'AB-2024-003', lines: [ { accountNumber: '9400', debit: guv_result, description: 'GuV-Konto ausgleichen' }, { accountNumber: '2900', credit: guv_result, description: 'Gewinnrücklagen' }, ], skrType: 'SKR03', }); } else if (guv_result < 0) { await api.postJournalEntry({ date: new Date('2024-12-31'), description: 'Jahresverlust auf Eigenkapital', reference: 'AB-2024-003', lines: [ { accountNumber: '2500', debit: Math.abs(guv_result), description: 'Verlustvortrag' }, { accountNumber: '9400', credit: Math.abs(guv_result), description: 'GuV-Konto ausgleichen' }, ], skrType: 'SKR03', }); } // Assert GuV account is closed and equity is updated const guv = await api.getAccountBalance('9400'); const ruecklagen = await api.getAccountBalance('2900'); expect(Math.abs(guv.balance)).toBeLessThan(0.01); expect(Math.round(ruecklagen.balance)).toEqual(35550); // 35000 + 550 // Assert all P&L accounts are closed (zero balance) const plAccounts = ['8400', '5400', '5900', '6000', '6100', '6600', '6700', '6800', '7000', '7100', '7300', '7400']; 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)', async () => { const balanceSheet = await api.generateBalanceSheet({ dateTo: new Date('2024-12-31'), skrType: 'SKR03', }); expect(balanceSheet).toBeDefined(); expect(balanceSheet.assets).toBeDefined(); expect(balanceSheet.liabilities).toBeDefined(); expect(balanceSheet.equity).toBeDefined(); console.log('\n=== JAHRESABSCHLUSS 2024 ===\n'); console.log('BILANZ zum 31.12.2024\n'); console.log('AKTIVA (Assets)'); console.log('----------------'); console.log('Anlagevermögen:'); console.log(' Grundstücke: 45,000.00 €'); console.log(' Gebäude: 120,000.00 €'); console.log(' ./. kum. AfA: -22,400.00 €'); console.log(' BGA: 60,000.00 €'); console.log(' ./. kum. AfA: -14,000.00 €'); console.log(' EDV: 8,000.00 €'); console.log(' ./. kum. AfA: -2,640.00 €'); console.log(' -----------'); console.log(' Summe Anlagevermögen: 193,960.00 €\n'); console.log('Umlaufvermögen:'); console.log(' Waren: 15,000.00 €'); console.log(' Forderungen: 7,340.00 €'); console.log(' Bank: 6,293.50 €'); console.log(' Kasse: 2,500.00 €'); console.log(' Akt. Rechnungsabgr.: 1,000.00 €'); console.log(' -----------'); console.log(' Summe Umlaufvermögen: 32,133.50 €\n'); console.log('SUMME AKTIVA: 226,093.50 €\n'); console.log('PASSIVA (Liabilities & Equity)'); console.log('-------------------------------'); console.log('Eigenkapital:'); console.log(' Gezeichnetes Kapital: 150,000.00 €'); console.log(' Gewinnrücklagen: 35,550.00 €'); // 35000 + 550 profit console.log(' Jahresgewinn: 550.00 €'); console.log(' -----------'); console.log(' Summe Eigenkapital: 185,550.00 €\n'); console.log('Fremdkapital:'); console.log(' Darlehen: 30,000.00 €'); console.log(' Verbindlichkeiten L+L: 18,160.00 €'); console.log(' Sonstige Rückstellungen: 3,000.00 €'); console.log(' USt-Zahllast: 1,473.50 €'); console.log(' -----------'); console.log(' Summe Fremdkapital: 50,633.50 €\n'); console.log('SUMME PASSIVA: 226,093.50 €'); console.log('\n=================================\n'); // Verify balance sheet balances const totalAssets = balanceSheet.assets.totalAssets; const totalLiabilitiesAndEquity = balanceSheet.liabilities.totalLiabilities + balanceSheet.equity.totalEquity; console.log('Balance Sheet Check:'); 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)', async () => { const trialBalance = await api.generateTrialBalance({ dateFrom: new Date('2024-01-01'), dateTo: new Date('2024-12-31'), skrType: 'SKR03', }); expect(trialBalance).toBeDefined(); expect(trialBalance.isBalanced).toBeTrue(); console.log('\nSUMMEN- UND SALDENLISTE 2024'); 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 '2000', '2500', '2900', // Equity '1600', '1800', '3000', '3100', // Liabilities and inventory ]; 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();