diff --git a/test/test.jahresabschluss.ts b/test/test.jahresabschluss.ts index b4c179d..7b02ea2 100644 --- a/test/test.jahresabschluss.ts +++ b/test/test.jahresabschluss.ts @@ -317,37 +317,43 @@ tap.test('should perform year-end adjustments (Jahresabschlussbuchungen)', async reference: 'UST-2024-Q4', lines: [ { accountNumber: '1771', debit: 8740, description: 'USt-Saldo' }, // Total collected VAT - { accountNumber: '1571', credit: 7266.50, description: 'Vorsteuer-Saldo' }, // Total input VAT - { accountNumber: '1800', credit: 1473.50, description: 'USt-Zahllast' }, + { 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); - // The net income should be: - // Revenue: 46000 (sales) - // Less expenses: - // - Cost of goods: 5000 - // - Personnel: 29600 - // - Rent: 2000 - // - Office: 200 - // - Vehicle: 150 - // - Marketing: 5000 - // - Professional: 5500 - // - Depreciation: 11040 - // - Insurance: -1000 (accrual adjustment) - // - Inventory: -3000 (increase) - const expectedNetIncome = 46000 - 5000 - 29600 - 2000 - 200 - 150 - 5000 - 5500 - 11040 + 1000 + 3000; + // 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); @@ -365,8 +371,7 @@ tap.test('should perform closing entries (Abschlussbuchungen)', async () => { reference: 'AB-2024-001', lines: [ { accountNumber: '8400', debit: 46000, description: 'Erlöse abschließen' }, - { accountNumber: '5900', debit: 3000, description: 'Bestandsveränderungen abschließen' }, - { accountNumber: '9400', credit: 49000, description: 'GuV-Konto' }, + { accountNumber: '9400', credit: 46000, description: 'GuV-Konto' }, ], skrType: 'SKR03', }); @@ -378,23 +383,23 @@ tap.test('should perform closing entries (Abschlussbuchungen)', async () => { 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: '7300', debit: 1000, description: 'Versicherung abschließen (credit balance)' }, { 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' }, - { accountNumber: '5900', debit: 3000, description: 'Bestandsveränderungen abschließen (credit balance)' }, ], skrType: 'SKR03', }); // Transfer profit/loss to equity - const guv_result = 49000 - 45450; // Profit of 3550 + const guv_result = 46000 - 45450; // Profit of 550 if (guv_result > 0) { await api.postJournalEntry({ date: new Date('2024-12-31'), @@ -418,11 +423,26 @@ tap.test('should perform closing entries (Abschlussbuchungen)', async () => { 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({ - date: new Date('2024-12-31'), + dateTo: new Date('2024-12-31'), + skrType: 'SKR03', }); expect(balanceSheet).toBeDefined(); @@ -459,10 +479,10 @@ tap.test('should generate final balance sheet (Schlussbilanz)', async () => { console.log('-------------------------------'); console.log('Eigenkapital:'); console.log(' Gezeichnetes Kapital: 150,000.00 €'); - console.log(' Gewinnrücklagen: 38,550.00 €'); // 35000 + 3550 profit - console.log(' Jahresgewinn: 3,550.00 €'); + console.log(' Gewinnrücklagen: 35,550.00 €'); // 35000 + 550 profit + console.log(' Jahresgewinn: 550.00 €'); console.log(' -----------'); - console.log(' Summe Eigenkapital: 188,550.00 €\n'); + console.log(' Summe Eigenkapital: 185,550.00 €\n'); console.log('Fremdkapital:'); console.log(' Darlehen: 30,000.00 €'); @@ -478,6 +498,11 @@ tap.test('should generate final balance sheet (Schlussbilanz)', async () => { 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!'); }); @@ -486,6 +511,7 @@ 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(); diff --git a/ts/skr.classes.reports.ts b/ts/skr.classes.reports.ts index 08dc1cb..e774c07 100644 --- a/ts/skr.classes.reports.ts +++ b/ts/skr.classes.reports.ts @@ -122,11 +122,11 @@ export class Reports { const entry: IIncomeStatementEntry = { accountNumber: account.accountNumber, accountName: account.accountName, - amount: Math.abs(balance), + amount: balance, // Keep the sign for correct calculation }; revenueEntries.push(entry); - totalRevenue += Math.abs(balance); + totalRevenue += balance; // Revenue accounts normally have credit balance (positive) } } @@ -138,23 +138,24 @@ export class Reports { const entry: IIncomeStatementEntry = { accountNumber: account.accountNumber, accountName: account.accountName, - amount: Math.abs(balance), + amount: balance, // Keep the sign - negative balance reduces expenses }; expenseEntries.push(entry); - totalExpenses += Math.abs(balance); + totalExpenses += balance; // Expense accounts normally have debit balance (positive) + // But credit balances (negative) reduce total expenses } } - // Calculate percentages + // Calculate percentages using absolute values to avoid negative percentages revenueEntries.forEach((entry) => { entry.percentage = - totalRevenue > 0 ? (entry.amount / totalRevenue) * 100 : 0; + totalRevenue !== 0 ? (Math.abs(entry.amount) / Math.abs(totalRevenue)) * 100 : 0; }); expenseEntries.forEach((entry) => { entry.percentage = - totalRevenue > 0 ? (entry.amount / totalRevenue) * 100 : 0; + totalRevenue !== 0 ? (Math.abs(entry.amount) / Math.abs(totalRevenue)) * 100 : 0; }); // Sort entries by account number @@ -214,7 +215,7 @@ export class Reports { const entry: IBalanceSheetEntry = { accountNumber: account.accountNumber, accountName: account.accountName, - amount: Math.abs(balance), + amount: balance, // Keep the sign for display }; // Classify as current or fixed based on account class @@ -224,7 +225,7 @@ export class Reports { fixedAssets.push(entry); } - totalAssets += Math.abs(balance); + totalAssets += balance; // Add with sign to get correct total } } @@ -240,7 +241,7 @@ export class Reports { const entry: IBalanceSheetEntry = { accountNumber: account.accountNumber, accountName: account.accountName, - amount: Math.abs(balance), + amount: balance, // Keep the sign for display }; // Classify as current or long-term based on account number @@ -253,7 +254,7 @@ export class Reports { longTermLiabilities.push(entry); } - totalLiabilities += Math.abs(balance); + totalLiabilities += balance; // Add with sign to get correct total } } @@ -268,23 +269,27 @@ export class Reports { const entry: IBalanceSheetEntry = { accountNumber: account.accountNumber, accountName: account.accountName, - amount: Math.abs(balance), + amount: balance, // Keep the sign for display }; equityEntries.push(entry); - totalEquity += Math.abs(balance); + totalEquity += balance; // Add with sign to get correct total } } - // Add current year profit/loss + // Add current year profit/loss only if accounts haven't been closed + // Check if revenue/expense accounts have non-zero balances (indicates not closed) const incomeStatement = await this.getIncomeStatement(params); - if (incomeStatement.netIncome !== 0) { + + // Only add current year profit/loss if we have unclosed revenue/expense accounts + // (i.e., the income statement shows non-zero revenue or expenses) + if (incomeStatement.netIncome !== 0 && (incomeStatement.totalRevenue !== 0 || incomeStatement.totalExpenses !== 0)) { equityEntries.push({ accountNumber: '9999', accountName: 'Current Year Profit/Loss', - amount: Math.abs(incomeStatement.netIncome), + amount: incomeStatement.netIncome, // Keep the sign }); - totalEquity += Math.abs(incomeStatement.netIncome); + totalEquity += incomeStatement.netIncome; // Add with sign } // Sort entries