feat(core): initial release of SKR03/SKR04 German accounting standards implementation
- Complete implementation of German standard charts of accounts - SKR03 (Process Structure Principle) for trading/service companies - SKR04 (Financial Classification Principle) for manufacturing companies - Double-entry bookkeeping with MongoDB persistence - Comprehensive reporting suite with DATEV export - Full TypeScript support and type safety
This commit is contained in:
159
test/test.skr03.ts
Normal file
159
test/test.skr03.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import * as skr from '../ts/index.js';
|
||||
|
||||
let api: skr.SkrApi;
|
||||
|
||||
tap.test('should initialize SKR03 API', async () => {
|
||||
api = new skr.SkrApi({
|
||||
mongoDbUrl: 'mongodb://localhost:27017',
|
||||
dbName: 'test_skr03',
|
||||
});
|
||||
|
||||
await api.initialize('SKR03');
|
||||
expect(api.getSKRType()).toEqual('SKR03');
|
||||
});
|
||||
|
||||
tap.test('should have SKR03 accounts initialized', async () => {
|
||||
const accounts = await api.listAccounts();
|
||||
expect(accounts.length).toBeGreaterThan(50);
|
||||
|
||||
// Check specific SKR03 accounts exist
|
||||
const kasse = await api.getAccount('1000');
|
||||
expect(kasse).not.toBeNull();
|
||||
expect(kasse.accountName).toEqual('Kasse');
|
||||
expect(kasse.accountType).toEqual('asset');
|
||||
|
||||
const umsatz = await api.getAccount('4000');
|
||||
expect(umsatz).not.toBeNull();
|
||||
expect(umsatz.accountName).toEqual('Umsatzerlöse');
|
||||
expect(umsatz.accountType).toEqual('revenue');
|
||||
});
|
||||
|
||||
tap.test('should verify SKR03 process structure principle', async () => {
|
||||
// SKR03 organizes accounts by business process
|
||||
// Class 4: Operating Income
|
||||
// Class 5: Material Costs
|
||||
// Class 6: Personnel Costs
|
||||
// Class 7: Other Operating Expenses
|
||||
|
||||
const class4 = await api.getAccountsByClass(4);
|
||||
expect(class4.length).toBeGreaterThan(0);
|
||||
expect(class4[0].accountType).toEqual('revenue');
|
||||
|
||||
const class5 = await api.getAccountsByClass(5);
|
||||
expect(class5.length).toBeGreaterThan(0);
|
||||
expect(class5[0].accountType).toEqual('expense');
|
||||
|
||||
const class6 = await api.getAccountsByClass(6);
|
||||
expect(class6.length).toBeGreaterThan(0);
|
||||
expect(class6[0].accountType).toEqual('expense');
|
||||
});
|
||||
|
||||
tap.test('should create custom SKR03 account', async () => {
|
||||
const customAccount = await api.createAccount({
|
||||
accountNumber: '4999',
|
||||
accountName: 'Custom Revenue Account',
|
||||
accountClass: 4,
|
||||
accountType: 'revenue',
|
||||
description: 'Test custom account',
|
||||
});
|
||||
|
||||
expect(customAccount.accountNumber).toEqual('4999');
|
||||
expect(customAccount.skrType).toEqual('SKR03');
|
||||
expect(customAccount.isActive).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('should post transaction in SKR03', async () => {
|
||||
const transaction = await api.postTransaction({
|
||||
date: new Date(),
|
||||
debitAccount: '1200', // Bank
|
||||
creditAccount: '4000', // Revenue
|
||||
amount: 1000,
|
||||
description: 'Test sale',
|
||||
reference: 'INV-001',
|
||||
skrType: 'SKR03',
|
||||
});
|
||||
|
||||
expect(transaction.status).toEqual('posted');
|
||||
expect(transaction.amount).toEqual(1000);
|
||||
expect(transaction.skrType).toEqual('SKR03');
|
||||
});
|
||||
|
||||
tap.test('should post journal entry in SKR03', async () => {
|
||||
const journalEntry = await api.postJournalEntry({
|
||||
date: new Date(),
|
||||
description: 'Test journal entry',
|
||||
reference: 'JE-001',
|
||||
lines: [
|
||||
{ accountNumber: '1000', debit: 500 }, // Cash
|
||||
{ accountNumber: '1200', debit: 500 }, // Bank
|
||||
{ accountNumber: '4000', credit: 1000 }, // Revenue
|
||||
],
|
||||
skrType: 'SKR03',
|
||||
});
|
||||
|
||||
expect(journalEntry.status).toEqual('posted');
|
||||
expect(journalEntry.isBalanced).toBeTrue();
|
||||
expect(journalEntry.totalDebits).toEqual(1000);
|
||||
expect(journalEntry.totalCredits).toEqual(1000);
|
||||
});
|
||||
|
||||
tap.test('should generate trial balance for SKR03', async () => {
|
||||
const trialBalance = await api.generateTrialBalance();
|
||||
|
||||
expect(trialBalance.skrType).toEqual('SKR03');
|
||||
expect(trialBalance.entries.length).toBeGreaterThan(0);
|
||||
expect(trialBalance.isBalanced).toBeTrue();
|
||||
expect(trialBalance.totalDebits).toEqual(trialBalance.totalCredits);
|
||||
});
|
||||
|
||||
tap.test('should generate income statement for SKR03', async () => {
|
||||
const incomeStatement = await api.generateIncomeStatement();
|
||||
|
||||
expect(incomeStatement.skrType).toEqual('SKR03');
|
||||
expect(incomeStatement.revenue.length).toBeGreaterThanOrEqual(0);
|
||||
expect(incomeStatement.expenses.length).toBeGreaterThanOrEqual(0);
|
||||
expect(incomeStatement.netIncome).toEqual(
|
||||
incomeStatement.totalRevenue - incomeStatement.totalExpenses,
|
||||
);
|
||||
});
|
||||
|
||||
tap.test('should generate balance sheet for SKR03', async () => {
|
||||
const balanceSheet = await api.generateBalanceSheet();
|
||||
|
||||
expect(balanceSheet.skrType).toEqual('SKR03');
|
||||
expect(balanceSheet.assets.totalAssets).toBeGreaterThanOrEqual(0);
|
||||
expect(balanceSheet.isBalanced).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('should search accounts in SKR03', async () => {
|
||||
const results = await api.searchAccounts('Bank');
|
||||
|
||||
expect(results.length).toBeGreaterThan(0);
|
||||
const bankAccount = results.find((a) => a.accountNumber === '1200');
|
||||
expect(bankAccount).not.toBeNull();
|
||||
});
|
||||
|
||||
tap.test('should export SKR03 accounts to CSV', async () => {
|
||||
const csv = await api.exportAccountsToCSV();
|
||||
|
||||
expect(csv).toInclude('"Account";"Name";"Description";"Type";"Active"');
|
||||
expect(csv).toInclude('1000');
|
||||
expect(csv).toInclude('Kasse');
|
||||
});
|
||||
|
||||
tap.test('should close API connection', async () => {
|
||||
await api.close();
|
||||
|
||||
// Verify API requires reinitialization
|
||||
let errorThrown = false;
|
||||
try {
|
||||
await api.listAccounts();
|
||||
} catch (error) {
|
||||
errorThrown = true;
|
||||
expect(error.message).toInclude('not initialized');
|
||||
}
|
||||
expect(errorThrown).toBeTrue();
|
||||
});
|
||||
|
||||
export default tap.start();
|
Reference in New Issue
Block a user