199 lines
5.9 KiB
TypeScript
199 lines
5.9 KiB
TypeScript
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<ReturnType<typeof getTestConfig>>;
|
|
|
|
tap.test('should initialize SKR04 API', async () => {
|
|
testConfig = await getTestConfig();
|
|
|
|
api = new skr.SkrApi({
|
|
mongoDbUrl: testConfig.mongoDbUrl,
|
|
dbName: `${testConfig.mongoDbName}_skr04`,
|
|
});
|
|
|
|
await api.initialize('SKR04');
|
|
expect(api.getSKRType()).toEqual('SKR04');
|
|
});
|
|
|
|
tap.test('should have SKR04 accounts initialized', async () => {
|
|
const accounts = await api.listAccounts();
|
|
expect(accounts.length).toBeGreaterThan(50);
|
|
|
|
// Check specific SKR04 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 SKR04 financial classification principle', async () => {
|
|
// SKR04 organizes accounts by financial statement structure
|
|
// Class 2: Expenses Part 1
|
|
// Class 3: Expenses Part 2
|
|
// Class 4: Revenues Part 1
|
|
// Class 5: Revenues Part 2
|
|
|
|
const class2 = await api.getAccountsByClass(2);
|
|
expect(class2.length).toBeGreaterThan(0);
|
|
expect(class2[0].accountType).toEqual('expense');
|
|
|
|
const class3 = await api.getAccountsByClass(3);
|
|
expect(class3.length).toBeGreaterThan(0);
|
|
expect(class3[0].accountType).toEqual('expense');
|
|
|
|
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('revenue');
|
|
});
|
|
|
|
tap.test('should handle Class 8 as free for use in SKR04', async () => {
|
|
// Class 8 in SKR04 is reserved for custom use
|
|
const class8 = await api.getAccountsByClass(8);
|
|
|
|
for (const account of class8) {
|
|
expect(account.accountName).toEqual('frei');
|
|
expect(account.description).toInclude('custom use');
|
|
}
|
|
});
|
|
|
|
tap.test('should post complex transaction in SKR04', async () => {
|
|
const transaction = await api.postTransaction({
|
|
date: new Date(),
|
|
debitAccount: '5400', // Goods with 19% VAT
|
|
creditAccount: '1600', // Trade payables
|
|
amount: 119,
|
|
description: 'Purchase with VAT',
|
|
reference: 'BILL-001',
|
|
skrType: 'SKR04',
|
|
vatAmount: 19,
|
|
});
|
|
|
|
expect(transaction.status).toEqual('posted');
|
|
expect(transaction.vatAmount).toEqual(19);
|
|
expect(transaction.skrType).toEqual('SKR04');
|
|
});
|
|
|
|
tap.test('should reverse transaction in SKR04', async () => {
|
|
// First create a transaction
|
|
const originalTransaction = await api.postTransaction({
|
|
date: new Date(),
|
|
debitAccount: '3000', // Rent expense
|
|
creditAccount: '1200', // Bank
|
|
amount: 500,
|
|
description: 'Rent payment',
|
|
reference: 'RENT-001',
|
|
skrType: 'SKR04',
|
|
});
|
|
|
|
// Then reverse it
|
|
const reversalTransaction = await api.reverseTransaction(
|
|
originalTransaction.id,
|
|
);
|
|
|
|
expect(reversalTransaction.reversalOf).toEqual(originalTransaction.id);
|
|
expect(reversalTransaction.debitAccount).toEqual(
|
|
originalTransaction.creditAccount,
|
|
);
|
|
expect(reversalTransaction.creditAccount).toEqual(
|
|
originalTransaction.debitAccount,
|
|
);
|
|
expect(reversalTransaction.amount).toEqual(originalTransaction.amount);
|
|
});
|
|
|
|
tap.test('should calculate correct balances in SKR04', async () => {
|
|
// Post several transactions
|
|
await api.postTransaction({
|
|
date: new Date(),
|
|
debitAccount: '1200', // Bank
|
|
creditAccount: '4300', // Revenue 19% VAT
|
|
amount: 1190,
|
|
description: 'Sale with VAT',
|
|
skrType: 'SKR04',
|
|
vatAmount: 190,
|
|
});
|
|
|
|
await api.postTransaction({
|
|
date: new Date(),
|
|
debitAccount: '2300', // Wages expense
|
|
creditAccount: '1200', // Bank
|
|
amount: 3000,
|
|
description: 'Salary payment',
|
|
skrType: 'SKR04',
|
|
});
|
|
|
|
// Check bank account balance
|
|
const bankBalance = await api.getAccountBalance('1200');
|
|
expect(bankBalance.accountNumber).toEqual('1200');
|
|
expect(bankBalance.balance).toEqual(
|
|
bankBalance.debitTotal - bankBalance.creditTotal,
|
|
);
|
|
});
|
|
|
|
tap.test('should export trial balance to CSV for SKR04', async () => {
|
|
const csv = await api.exportReportToCSV('trial_balance');
|
|
|
|
expect(csv).toInclude(
|
|
'"Account Number";"Account Name";"Debit";"Credit";"Balance"',
|
|
);
|
|
expect(csv).toInclude('TOTAL');
|
|
});
|
|
|
|
tap.test('should handle pagination for SKR04 accounts', async () => {
|
|
const page1 = await api.getAccountsPaginated(1, 10);
|
|
|
|
expect(page1.data.length).toBeLessThanOrEqual(10);
|
|
expect(page1.page).toEqual(1);
|
|
expect(page1.pageSize).toEqual(10);
|
|
expect(page1.total).toBeGreaterThan(50);
|
|
expect(page1.totalPages).toBeGreaterThan(5);
|
|
|
|
// Get second page
|
|
const page2 = await api.getAccountsPaginated(2, 10);
|
|
expect(page2.data[0].accountNumber).not.toEqual(page1.data[0].accountNumber);
|
|
});
|
|
|
|
tap.test('should validate double-entry rules', async () => {
|
|
const isValid1 = api.validateDoubleEntry(100, 100);
|
|
expect(isValid1).toBeTrue();
|
|
|
|
const isValid2 = api.validateDoubleEntry(100, 99);
|
|
expect(isValid2).toBeFalse();
|
|
|
|
const isValid3 = api.validateDoubleEntry(100.0, 100.001);
|
|
expect(isValid3).toBeTrue(); // Small rounding differences are acceptable
|
|
});
|
|
|
|
tap.test('should generate DATEV export for SKR04', async () => {
|
|
const datevExport = await api.exportToDATEV();
|
|
|
|
expect(datevExport).toInclude('EXTF');
|
|
expect(datevExport).toInclude('Buchungsstapel');
|
|
});
|
|
|
|
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();
|