import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as skr from '../ts/index.js'; let api: skr.SkrApi; tap.test('should initialize API for transaction tests', async () => { api = new skr.SkrApi({ mongoDbUrl: 'mongodb://localhost:27017', dbName: 'test_transactions', }); await api.initialize('SKR03'); expect(api.getSKRType()).toEqual('SKR03'); }); tap.test('should enforce double-entry bookkeeping rules', async () => { let errorThrown = false; try { // Try to post unbalanced journal entry await api.postJournalEntry({ date: new Date(), description: 'Unbalanced entry', reference: 'TEST-001', lines: [ { accountNumber: '1000', debit: 100 }, { accountNumber: '4000', credit: 50 }, // Unbalanced! ], skrType: 'SKR03', }); } catch (error) { errorThrown = true; expect(error.message).toInclude('not balanced'); } expect(errorThrown).toBeTrue(); }); tap.test('should prevent posting to same account', async () => { let errorThrown = false; try { await api.postTransaction({ date: new Date(), debitAccount: '1000', creditAccount: '1000', // Same account! amount: 100, description: 'Invalid transaction', skrType: 'SKR03', }); } catch (error) { errorThrown = true; expect(error.message).toInclude('cannot be the same'); } expect(errorThrown).toBeTrue(); }); tap.test('should prevent posting to inactive account', async () => { // First create and deactivate an account const customAccount = await api.createAccount({ accountNumber: '9998', accountName: 'Inactive Test Account', accountClass: 9, accountType: 'equity', isActive: false, }); let errorThrown = false; try { await api.postTransaction({ date: new Date(), debitAccount: '9998', // Inactive account creditAccount: '1000', amount: 100, description: 'Transaction to inactive account', skrType: 'SKR03', }); } catch (error) { errorThrown = true; expect(error.message).toInclude('not active'); } expect(errorThrown).toBeTrue(); }); tap.test( 'should handle complex journal entry with multiple lines', async () => { const journalEntry = await api.postJournalEntry({ date: new Date(), description: 'Complex distribution', reference: 'COMPLEX-001', lines: [ { accountNumber: '5000', debit: 500, description: 'Materials' }, { accountNumber: '6000', debit: 300, description: 'Wages' }, { accountNumber: '7100', debit: 200, description: 'Rent' }, { accountNumber: '1200', credit: 1000, description: 'Bank payment' }, ], skrType: 'SKR03', }); expect(journalEntry.lines.length).toEqual(4); expect(journalEntry.totalDebits).toEqual(1000); expect(journalEntry.totalCredits).toEqual(1000); expect(journalEntry.isBalanced).toBeTrue(); }, ); tap.test('should track transaction history for account', async () => { // Post multiple transactions await api.postTransaction({ date: new Date('2024-01-01'), debitAccount: '1000', creditAccount: '4000', amount: 100, description: 'Sale 1', skrType: 'SKR03', }); await api.postTransaction({ date: new Date('2024-01-02'), debitAccount: '1000', creditAccount: '4000', amount: 200, description: 'Sale 2', skrType: 'SKR03', }); await api.postTransaction({ date: new Date('2024-01-03'), debitAccount: '5000', creditAccount: '1000', amount: 50, description: 'Purchase', skrType: 'SKR03', }); // Get transaction history for cash account const history = await api.getAccountTransactions('1000'); expect(history.length).toBeGreaterThanOrEqual(3); // Check balance calculation const balance = await api.getAccountBalance('1000'); expect(balance.debitTotal).toBeGreaterThanOrEqual(300); expect(balance.creditTotal).toBeGreaterThanOrEqual(50); }); tap.test('should filter transactions by date range', async () => { const startDate = new Date('2024-01-01'); const endDate = new Date('2024-01-31'); const transactions = await api.listTransactions({ dateFrom: startDate, dateTo: endDate, }); for (const transaction of transactions) { expect(transaction.date.getTime()).toBeGreaterThanOrEqual( startDate.getTime(), ); expect(transaction.date.getTime()).toBeLessThanOrEqual(endDate.getTime()); } }); tap.test('should filter transactions by amount range', async () => { const transactions = await api.listTransactions({ minAmount: 100, maxAmount: 500, }); for (const transaction of transactions) { expect(transaction.amount).toBeGreaterThanOrEqual(100); expect(transaction.amount).toBeLessThanOrEqual(500); } }); tap.test('should handle batch transaction posting', async () => { const batchTransactions = [ { date: new Date(), debitAccount: '1200', creditAccount: '4000', amount: 100, description: 'Batch sale 1', skrType: 'SKR03' as skr.TSKRType, }, { date: new Date(), debitAccount: '1200', creditAccount: '4000', amount: 200, description: 'Batch sale 2', skrType: 'SKR03' as skr.TSKRType, }, { date: new Date(), debitAccount: '1200', creditAccount: '4000', amount: 300, description: 'Batch sale 3', skrType: 'SKR03' as skr.TSKRType, }, ]; const results = await api.postBatchTransactions(batchTransactions); expect(results.length).toEqual(3); expect(results[0].amount).toEqual(100); expect(results[1].amount).toEqual(200); expect(results[2].amount).toEqual(300); }); tap.test('should handle transaction with VAT', async () => { const transaction = await api.postTransaction({ date: new Date(), debitAccount: '5400', // Goods with 19% VAT creditAccount: '1600', // Trade payables amount: 119, description: 'Purchase including VAT', skrType: 'SKR03', vatAmount: 19, reference: 'VAT-001', }); expect(transaction.vatAmount).toEqual(19); expect(transaction.amount).toEqual(119); }); tap.test('should handle transaction with cost center', async () => { const transaction = await api.postTransaction({ date: new Date(), debitAccount: '6000', // Wages creditAccount: '1200', // Bank amount: 1000, description: 'Salary for marketing department', skrType: 'SKR03', costCenter: 'MARKETING', }); expect(transaction.costCenter).toEqual('MARKETING'); }); tap.test('should validate account numbers are 4 digits', async () => { let errorThrown = false; try { await api.createAccount({ accountNumber: '123', // Only 3 digits! accountName: 'Invalid Account', accountClass: 1, accountType: 'asset', }); } catch (error) { errorThrown = true; expect(error.message).toInclude('4 digits'); } expect(errorThrown).toBeTrue(); }); tap.test('should recalculate all balances', async () => { await api.recalculateBalances(); // Verify balances are consistent const trialBalance = await api.generateTrialBalance(); expect(trialBalance.isBalanced).toBeTrue(); }); tap.test('should close API connection', async () => { await api.close(); }); export default tap.start();