@fin.cx/skr 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist_ts/index.d.ts +10 -0
  2. package/dist_ts/index.js +11 -0
  3. package/dist_ts/plugins.d.ts +5 -0
  4. package/dist_ts/plugins.js +7 -0
  5. package/dist_ts/skr.api.d.ts +181 -0
  6. package/dist_ts/skr.api.js +402 -0
  7. package/dist_ts/skr.classes.account.d.ts +34 -0
  8. package/dist_ts/skr.classes.account.js +224 -0
  9. package/dist_ts/skr.classes.chartofaccounts.d.ts +99 -0
  10. package/dist_ts/skr.classes.chartofaccounts.js +377 -0
  11. package/dist_ts/skr.classes.journalentry.d.ts +33 -0
  12. package/dist_ts/skr.classes.journalentry.js +296 -0
  13. package/dist_ts/skr.classes.ledger.d.ts +61 -0
  14. package/dist_ts/skr.classes.ledger.js +363 -0
  15. package/dist_ts/skr.classes.reports.d.ts +55 -0
  16. package/dist_ts/skr.classes.reports.js +514 -0
  17. package/dist_ts/skr.classes.transaction.d.ts +37 -0
  18. package/dist_ts/skr.classes.transaction.js +263 -0
  19. package/dist_ts/skr.database.d.ts +5 -0
  20. package/dist_ts/skr.database.js +28 -0
  21. package/dist_ts/skr.types.d.ts +126 -0
  22. package/dist_ts/skr.types.js +2 -0
  23. package/dist_ts/skr03.data.d.ts +18 -0
  24. package/dist_ts/skr03.data.js +890 -0
  25. package/dist_ts/skr04.data.d.ts +18 -0
  26. package/dist_ts/skr04.data.js +912 -0
  27. package/npmextra.json +17 -0
  28. package/package.json +61 -0
  29. package/readme.hints.md +3 -0
  30. package/readme.md +409 -0
  31. package/readme.plan.md +243 -0
  32. package/ts/index.ts +10 -0
  33. package/ts/plugins.ts +7 -0
  34. package/ts/skr.api.ts +533 -0
  35. package/ts/skr.classes.account.ts +238 -0
  36. package/ts/skr.classes.chartofaccounts.ts +508 -0
  37. package/ts/skr.classes.journalentry.ts +318 -0
  38. package/ts/skr.classes.ledger.ts +528 -0
  39. package/ts/skr.classes.reports.ts +721 -0
  40. package/ts/skr.classes.transaction.ts +300 -0
  41. package/ts/skr.database.ts +39 -0
  42. package/ts/skr.types.ts +154 -0
  43. package/ts/skr03.data.ts +901 -0
  44. package/ts/skr04.data.ts +923 -0
@@ -0,0 +1,363 @@
1
+ import * as plugins from './plugins.js';
2
+ import { Account } from './skr.classes.account.js';
3
+ import { Transaction } from './skr.classes.transaction.js';
4
+ import { JournalEntry } from './skr.classes.journalentry.js';
5
+ export class Ledger {
6
+ constructor(skrType) {
7
+ this.skrType = skrType;
8
+ this.logger = new plugins.smartlog.Smartlog({
9
+ logContext: {
10
+ company: 'fin.cx',
11
+ companyunit: 'skr',
12
+ containerName: 'Ledger',
13
+ environment: 'local',
14
+ runtime: 'node',
15
+ zone: 'local',
16
+ },
17
+ });
18
+ }
19
+ /**
20
+ * Post a transaction with validation
21
+ */
22
+ async postTransaction(transactionData) {
23
+ this.logger.log('info', `Posting transaction: ${transactionData.description}`);
24
+ // Ensure SKR type matches
25
+ const fullTransactionData = {
26
+ ...transactionData,
27
+ skrType: this.skrType,
28
+ };
29
+ // Validate accounts exist
30
+ await this.validateAccounts([
31
+ transactionData.debitAccount,
32
+ transactionData.creditAccount,
33
+ ]);
34
+ // Create and post transaction
35
+ const transaction = await Transaction.createTransaction(fullTransactionData);
36
+ this.logger.log('info', `Transaction ${transaction.transactionNumber} posted successfully`);
37
+ return transaction;
38
+ }
39
+ /**
40
+ * Post a journal entry with validation
41
+ */
42
+ async postJournalEntry(journalData) {
43
+ this.logger.log('info', `Posting journal entry: ${journalData.description}`);
44
+ // Ensure SKR type matches
45
+ const fullJournalData = {
46
+ ...journalData,
47
+ skrType: this.skrType,
48
+ };
49
+ // Validate all accounts exist
50
+ const accountNumbers = journalData.lines.map((line) => line.accountNumber);
51
+ await this.validateAccounts(accountNumbers);
52
+ // Validate journal entry is balanced
53
+ this.validateJournalBalance(journalData.lines);
54
+ // Create and post journal entry
55
+ const journalEntry = await JournalEntry.createJournalEntry(fullJournalData);
56
+ await journalEntry.post();
57
+ this.logger.log('info', `Journal entry ${journalEntry.journalNumber} posted successfully`);
58
+ return journalEntry;
59
+ }
60
+ /**
61
+ * Validate that accounts exist and are active
62
+ */
63
+ async validateAccounts(accountNumbers) {
64
+ const uniqueAccountNumbers = [...new Set(accountNumbers)];
65
+ for (const accountNumber of uniqueAccountNumbers) {
66
+ const account = await Account.getAccountByNumber(accountNumber, this.skrType);
67
+ if (!account) {
68
+ throw new Error(`Account ${accountNumber} not found for ${this.skrType}`);
69
+ }
70
+ if (!account.isActive) {
71
+ throw new Error(`Account ${accountNumber} is not active`);
72
+ }
73
+ }
74
+ }
75
+ /**
76
+ * Validate journal entry balance
77
+ */
78
+ validateJournalBalance(lines) {
79
+ let totalDebits = 0;
80
+ let totalCredits = 0;
81
+ for (const line of lines) {
82
+ if (line.debit)
83
+ totalDebits += line.debit;
84
+ if (line.credit)
85
+ totalCredits += line.credit;
86
+ }
87
+ const difference = Math.abs(totalDebits - totalCredits);
88
+ if (difference >= 0.01) {
89
+ throw new Error(`Journal entry is not balanced. Debits: ${totalDebits}, Credits: ${totalCredits}`);
90
+ }
91
+ }
92
+ /**
93
+ * Reverse a transaction
94
+ */
95
+ async reverseTransaction(transactionId) {
96
+ this.logger.log('info', `Reversing transaction: ${transactionId}`);
97
+ const transaction = await Transaction.getTransactionById(transactionId);
98
+ if (!transaction) {
99
+ throw new Error(`Transaction ${transactionId} not found`);
100
+ }
101
+ if (transaction.skrType !== this.skrType) {
102
+ throw new Error(`Transaction ${transactionId} belongs to different SKR type`);
103
+ }
104
+ const reversalTransaction = await transaction.reverseTransaction();
105
+ this.logger.log('info', `Transaction reversed: ${reversalTransaction.transactionNumber}`);
106
+ return reversalTransaction;
107
+ }
108
+ /**
109
+ * Reverse a journal entry
110
+ */
111
+ async reverseJournalEntry(journalId) {
112
+ this.logger.log('info', `Reversing journal entry: ${journalId}`);
113
+ const journalEntry = await JournalEntry.getInstance({ id: journalId });
114
+ if (!journalEntry) {
115
+ throw new Error(`Journal entry ${journalId} not found`);
116
+ }
117
+ if (journalEntry.skrType !== this.skrType) {
118
+ throw new Error(`Journal entry ${journalId} belongs to different SKR type`);
119
+ }
120
+ const reversalEntry = await journalEntry.reverse();
121
+ this.logger.log('info', `Journal entry reversed: ${reversalEntry.journalNumber}`);
122
+ return reversalEntry;
123
+ }
124
+ /**
125
+ * Get account history (all transactions for an account)
126
+ */
127
+ async getAccountHistory(accountNumber, dateFrom, dateTo) {
128
+ const account = await Account.getAccountByNumber(accountNumber, this.skrType);
129
+ if (!account) {
130
+ throw new Error(`Account ${accountNumber} not found`);
131
+ }
132
+ let transactions = await Transaction.getTransactionsByAccount(accountNumber, this.skrType);
133
+ // Apply date filter if provided
134
+ if (dateFrom || dateTo) {
135
+ transactions = transactions.filter((transaction) => {
136
+ if (dateFrom && transaction.date < dateFrom)
137
+ return false;
138
+ if (dateTo && transaction.date > dateTo)
139
+ return false;
140
+ return true;
141
+ });
142
+ }
143
+ // Sort by date
144
+ transactions.sort((a, b) => a.date.getTime() - b.date.getTime());
145
+ return transactions;
146
+ }
147
+ /**
148
+ * Get account balance at a specific date
149
+ */
150
+ async getAccountBalance(accountNumber, asOfDate) {
151
+ const account = await Account.getAccountByNumber(accountNumber, this.skrType);
152
+ if (!account) {
153
+ throw new Error(`Account ${accountNumber} not found`);
154
+ }
155
+ let transactions = await Transaction.getTransactionsByAccount(accountNumber, this.skrType);
156
+ // Filter transactions up to the specified date
157
+ if (asOfDate) {
158
+ transactions = transactions.filter((t) => t.date <= asOfDate);
159
+ }
160
+ // Calculate balance
161
+ let debitTotal = 0;
162
+ let creditTotal = 0;
163
+ for (const transaction of transactions) {
164
+ if (transaction.debitAccount === accountNumber) {
165
+ debitTotal += transaction.amount;
166
+ }
167
+ if (transaction.creditAccount === accountNumber) {
168
+ creditTotal += transaction.amount;
169
+ }
170
+ }
171
+ // Calculate net balance based on account type
172
+ let balance;
173
+ switch (account.accountType) {
174
+ case 'asset':
175
+ case 'expense':
176
+ // Normal debit accounts
177
+ balance = debitTotal - creditTotal;
178
+ break;
179
+ case 'liability':
180
+ case 'equity':
181
+ case 'revenue':
182
+ // Normal credit accounts
183
+ balance = creditTotal - debitTotal;
184
+ break;
185
+ }
186
+ return {
187
+ accountNumber,
188
+ debitTotal,
189
+ creditTotal,
190
+ balance,
191
+ lastUpdated: new Date(),
192
+ };
193
+ }
194
+ /**
195
+ * Close accounting period (create closing entries)
196
+ */
197
+ async closeAccountingPeriod(period, // Format: YYYY-MM
198
+ closingAccountNumber = '9400') {
199
+ this.logger.log('info', `Closing accounting period: ${period}`);
200
+ const closingEntries = [];
201
+ // Get all revenue and expense accounts
202
+ const revenueAccounts = await Account.getAccountsByType('revenue', this.skrType);
203
+ const expenseAccounts = await Account.getAccountsByType('expense', this.skrType);
204
+ // Calculate totals for each account in the period
205
+ const periodTransactions = await Transaction.getTransactionsByPeriod(period, this.skrType);
206
+ // Create closing entry for revenue accounts
207
+ const revenueLines = [];
208
+ let totalRevenue = 0;
209
+ for (const account of revenueAccounts) {
210
+ const balance = await this.getAccountBalanceForPeriod(account.accountNumber, periodTransactions);
211
+ if (balance !== 0) {
212
+ // Revenue accounts have credit balance, so debit to close
213
+ revenueLines.push({
214
+ accountNumber: account.accountNumber,
215
+ debit: Math.abs(balance),
216
+ description: `Closing ${account.accountName}`,
217
+ });
218
+ totalRevenue += Math.abs(balance);
219
+ }
220
+ }
221
+ if (totalRevenue > 0) {
222
+ // Credit the closing account
223
+ revenueLines.push({
224
+ accountNumber: closingAccountNumber,
225
+ credit: totalRevenue,
226
+ description: 'Revenue closing to P&L',
227
+ });
228
+ const revenueClosingEntry = await this.postJournalEntry({
229
+ date: new Date(),
230
+ description: `Closing revenue accounts for period ${period}`,
231
+ reference: `CLOSE-REV-${period}`,
232
+ lines: revenueLines,
233
+ skrType: this.skrType,
234
+ });
235
+ closingEntries.push(revenueClosingEntry);
236
+ }
237
+ // Create closing entry for expense accounts
238
+ const expenseLines = [];
239
+ let totalExpense = 0;
240
+ for (const account of expenseAccounts) {
241
+ const balance = await this.getAccountBalanceForPeriod(account.accountNumber, periodTransactions);
242
+ if (balance !== 0) {
243
+ // Expense accounts have debit balance, so credit to close
244
+ expenseLines.push({
245
+ accountNumber: account.accountNumber,
246
+ credit: Math.abs(balance),
247
+ description: `Closing ${account.accountName}`,
248
+ });
249
+ totalExpense += Math.abs(balance);
250
+ }
251
+ }
252
+ if (totalExpense > 0) {
253
+ // Debit the closing account
254
+ expenseLines.push({
255
+ accountNumber: closingAccountNumber,
256
+ debit: totalExpense,
257
+ description: 'Expense closing to P&L',
258
+ });
259
+ const expenseClosingEntry = await this.postJournalEntry({
260
+ date: new Date(),
261
+ description: `Closing expense accounts for period ${period}`,
262
+ reference: `CLOSE-EXP-${period}`,
263
+ lines: expenseLines,
264
+ skrType: this.skrType,
265
+ });
266
+ closingEntries.push(expenseClosingEntry);
267
+ }
268
+ this.logger.log('info', `Period ${period} closed with ${closingEntries.length} entries`);
269
+ return closingEntries;
270
+ }
271
+ /**
272
+ * Calculate account balance for a specific set of transactions
273
+ */
274
+ async getAccountBalanceForPeriod(accountNumber, transactions) {
275
+ const account = await Account.getAccountByNumber(accountNumber, this.skrType);
276
+ if (!account)
277
+ return 0;
278
+ let debitTotal = 0;
279
+ let creditTotal = 0;
280
+ for (const transaction of transactions) {
281
+ if (transaction.debitAccount === accountNumber) {
282
+ debitTotal += transaction.amount;
283
+ }
284
+ if (transaction.creditAccount === accountNumber) {
285
+ creditTotal += transaction.amount;
286
+ }
287
+ }
288
+ // Calculate net balance based on account type
289
+ switch (account.accountType) {
290
+ case 'asset':
291
+ case 'expense':
292
+ return debitTotal - creditTotal;
293
+ case 'liability':
294
+ case 'equity':
295
+ case 'revenue':
296
+ return creditTotal - debitTotal;
297
+ }
298
+ }
299
+ /**
300
+ * Validate double-entry rules
301
+ */
302
+ validateDoubleEntry(debitAmount, creditAmount) {
303
+ return Math.abs(debitAmount - creditAmount) < 0.01;
304
+ }
305
+ /**
306
+ * Get unbalanced transactions (for audit)
307
+ */
308
+ async getUnbalancedTransactions() {
309
+ // In a proper double-entry system, all posted transactions should be balanced
310
+ // This method is mainly for audit purposes
311
+ const allTransactions = await Transaction.getInstances({
312
+ skrType: this.skrType,
313
+ status: 'posted',
314
+ });
315
+ // Group transactions by journal entry if they have one
316
+ const unbalanced = [];
317
+ // Since our system ensures balance at posting time,
318
+ // this should typically return an empty array
319
+ // But we include it for completeness and audit purposes
320
+ return unbalanced;
321
+ }
322
+ /**
323
+ * Recalculate all account balances
324
+ */
325
+ async recalculateAllBalances() {
326
+ this.logger.log('info', 'Recalculating all account balances');
327
+ // Get all accounts
328
+ const accounts = await Account.getInstances({ skrType: this.skrType });
329
+ for (const account of accounts) {
330
+ // Reset balances
331
+ account.debitTotal = 0;
332
+ account.creditTotal = 0;
333
+ account.balance = 0;
334
+ // Get all transactions for this account
335
+ const transactions = await Transaction.getTransactionsByAccount(account.accountNumber, this.skrType);
336
+ // Recalculate totals
337
+ for (const transaction of transactions) {
338
+ if (transaction.debitAccount === account.accountNumber) {
339
+ account.debitTotal += transaction.amount;
340
+ }
341
+ if (transaction.creditAccount === account.accountNumber) {
342
+ account.creditTotal += transaction.amount;
343
+ }
344
+ }
345
+ // Calculate balance based on account type
346
+ switch (account.accountType) {
347
+ case 'asset':
348
+ case 'expense':
349
+ account.balance = account.debitTotal - account.creditTotal;
350
+ break;
351
+ case 'liability':
352
+ case 'equity':
353
+ case 'revenue':
354
+ account.balance = account.creditTotal - account.debitTotal;
355
+ break;
356
+ }
357
+ account.updatedAt = new Date();
358
+ await account.save();
359
+ }
360
+ this.logger.log('info', `Recalculated balances for ${accounts.length} accounts`);
361
+ }
362
+ }
363
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmNsYXNzZXMubGVkZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc2tyLmNsYXNzZXMubGVkZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNuRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDM0QsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBUzdELE1BQU0sT0FBTyxNQUFNO0lBR2pCLFlBQW9CLE9BQWlCO1FBQWpCLFlBQU8sR0FBUCxPQUFPLENBQVU7UUFDbkMsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDO1lBQzFDLFVBQVUsRUFBRTtnQkFDVixPQUFPLEVBQUUsUUFBUTtnQkFDakIsV0FBVyxFQUFFLEtBQUs7Z0JBQ2xCLGFBQWEsRUFBRSxRQUFRO2dCQUN2QixXQUFXLEVBQUUsT0FBTztnQkFDcEIsT0FBTyxFQUFFLE1BQU07Z0JBQ2YsSUFBSSxFQUFFLE9BQU87YUFDZDtTQUNGLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxlQUFlLENBQzFCLGVBQWlDO1FBRWpDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUNiLE1BQU0sRUFDTix3QkFBd0IsZUFBZSxDQUFDLFdBQVcsRUFBRSxDQUN0RCxDQUFDO1FBRUYsMEJBQTBCO1FBQzFCLE1BQU0sbUJBQW1CLEdBQXFCO1lBQzVDLEdBQUcsZUFBZTtZQUNsQixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87U0FDdEIsQ0FBQztRQUVGLDBCQUEwQjtRQUMxQixNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztZQUMxQixlQUFlLENBQUMsWUFBWTtZQUM1QixlQUFlLENBQUMsYUFBYTtT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
@@ -0,0 +1,55 @@
1
+ import type { TSKRType, ITrialBalanceReport, IIncomeStatement, IBalanceSheet, IReportParams } from './skr.types.js';
2
+ export declare class Reports {
3
+ private skrType;
4
+ private logger;
5
+ private ledger;
6
+ constructor(skrType: TSKRType);
7
+ /**
8
+ * Generate Trial Balance
9
+ */
10
+ getTrialBalance(params?: IReportParams): Promise<ITrialBalanceReport>;
11
+ /**
12
+ * Generate Income Statement (P&L)
13
+ */
14
+ getIncomeStatement(params?: IReportParams): Promise<IIncomeStatement>;
15
+ /**
16
+ * Generate Balance Sheet
17
+ */
18
+ getBalanceSheet(params?: IReportParams): Promise<IBalanceSheet>;
19
+ /**
20
+ * Get account balance for a specific period
21
+ */
22
+ private getAccountBalanceForPeriod;
23
+ /**
24
+ * Generate General Ledger report
25
+ */
26
+ getGeneralLedger(params?: IReportParams): Promise<any>;
27
+ /**
28
+ * Get account transactions for reporting
29
+ */
30
+ private getAccountTransactions;
31
+ /**
32
+ * Generate Cash Flow Statement
33
+ */
34
+ getCashFlowStatement(params?: IReportParams): Promise<any>;
35
+ /**
36
+ * Export report to CSV format
37
+ */
38
+ exportToCSV(reportType: 'trial_balance' | 'income_statement' | 'balance_sheet', params?: IReportParams): Promise<string>;
39
+ /**
40
+ * Convert trial balance to CSV
41
+ */
42
+ private trialBalanceToCSV;
43
+ /**
44
+ * Convert income statement to CSV
45
+ */
46
+ private incomeStatementToCSV;
47
+ /**
48
+ * Convert balance sheet to CSV
49
+ */
50
+ private balanceSheetToCSV;
51
+ /**
52
+ * Export to DATEV format
53
+ */
54
+ exportToDATEV(params?: IReportParams): Promise<string>;
55
+ }