@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.
- package/dist_ts/index.d.ts +10 -0
- package/dist_ts/index.js +11 -0
- package/dist_ts/plugins.d.ts +5 -0
- package/dist_ts/plugins.js +7 -0
- package/dist_ts/skr.api.d.ts +181 -0
- package/dist_ts/skr.api.js +402 -0
- package/dist_ts/skr.classes.account.d.ts +34 -0
- package/dist_ts/skr.classes.account.js +224 -0
- package/dist_ts/skr.classes.chartofaccounts.d.ts +99 -0
- package/dist_ts/skr.classes.chartofaccounts.js +377 -0
- package/dist_ts/skr.classes.journalentry.d.ts +33 -0
- package/dist_ts/skr.classes.journalentry.js +296 -0
- package/dist_ts/skr.classes.ledger.d.ts +61 -0
- package/dist_ts/skr.classes.ledger.js +363 -0
- package/dist_ts/skr.classes.reports.d.ts +55 -0
- package/dist_ts/skr.classes.reports.js +514 -0
- package/dist_ts/skr.classes.transaction.d.ts +37 -0
- package/dist_ts/skr.classes.transaction.js +263 -0
- package/dist_ts/skr.database.d.ts +5 -0
- package/dist_ts/skr.database.js +28 -0
- package/dist_ts/skr.types.d.ts +126 -0
- package/dist_ts/skr.types.js +2 -0
- package/dist_ts/skr03.data.d.ts +18 -0
- package/dist_ts/skr03.data.js +890 -0
- package/dist_ts/skr04.data.d.ts +18 -0
- package/dist_ts/skr04.data.js +912 -0
- package/npmextra.json +17 -0
- package/package.json +61 -0
- package/readme.hints.md +3 -0
- package/readme.md +409 -0
- package/readme.plan.md +243 -0
- package/ts/index.ts +10 -0
- package/ts/plugins.ts +7 -0
- package/ts/skr.api.ts +533 -0
- package/ts/skr.classes.account.ts +238 -0
- package/ts/skr.classes.chartofaccounts.ts +508 -0
- package/ts/skr.classes.journalentry.ts +318 -0
- package/ts/skr.classes.ledger.ts +528 -0
- package/ts/skr.classes.reports.ts +721 -0
- package/ts/skr.classes.transaction.ts +300 -0
- package/ts/skr.database.ts +39 -0
- package/ts/skr.types.ts +154 -0
- package/ts/skr03.data.ts +901 -0
- package/ts/skr04.data.ts +923 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { getDb, getDbSync } from './skr.database.js';
|
|
3
|
+
import type { TAccountType, TSKRType, IAccountData } from './skr.types.js';
|
|
4
|
+
|
|
5
|
+
const { SmartDataDbDoc, svDb, unI, index, searchable } = plugins.smartdata;
|
|
6
|
+
|
|
7
|
+
@plugins.smartdata.Collection(() => getDbSync())
|
|
8
|
+
export class Account extends SmartDataDbDoc<Account, Account> {
|
|
9
|
+
@unI()
|
|
10
|
+
public id: string;
|
|
11
|
+
|
|
12
|
+
@svDb()
|
|
13
|
+
@index()
|
|
14
|
+
public accountNumber: string;
|
|
15
|
+
|
|
16
|
+
@svDb()
|
|
17
|
+
@searchable()
|
|
18
|
+
public accountName: string;
|
|
19
|
+
|
|
20
|
+
@svDb()
|
|
21
|
+
@index()
|
|
22
|
+
public accountClass: number;
|
|
23
|
+
|
|
24
|
+
@svDb()
|
|
25
|
+
public accountGroup: number;
|
|
26
|
+
|
|
27
|
+
@svDb()
|
|
28
|
+
public accountSubgroup: number;
|
|
29
|
+
|
|
30
|
+
@svDb()
|
|
31
|
+
public accountType: TAccountType;
|
|
32
|
+
|
|
33
|
+
@svDb()
|
|
34
|
+
@index()
|
|
35
|
+
public skrType: TSKRType;
|
|
36
|
+
|
|
37
|
+
@svDb()
|
|
38
|
+
@searchable()
|
|
39
|
+
public description: string;
|
|
40
|
+
|
|
41
|
+
@svDb()
|
|
42
|
+
public vatRate: number;
|
|
43
|
+
|
|
44
|
+
@svDb()
|
|
45
|
+
public balance: number;
|
|
46
|
+
|
|
47
|
+
@svDb()
|
|
48
|
+
public debitTotal: number;
|
|
49
|
+
|
|
50
|
+
@svDb()
|
|
51
|
+
public creditTotal: number;
|
|
52
|
+
|
|
53
|
+
@svDb()
|
|
54
|
+
public isActive: boolean;
|
|
55
|
+
|
|
56
|
+
@svDb()
|
|
57
|
+
public isSystemAccount: boolean;
|
|
58
|
+
|
|
59
|
+
@svDb()
|
|
60
|
+
public createdAt: Date;
|
|
61
|
+
|
|
62
|
+
@svDb()
|
|
63
|
+
public updatedAt: Date;
|
|
64
|
+
|
|
65
|
+
constructor(data?: Partial<IAccountData>) {
|
|
66
|
+
super();
|
|
67
|
+
|
|
68
|
+
if (data) {
|
|
69
|
+
this.id = plugins.smartunique.shortId();
|
|
70
|
+
this.accountNumber = data.accountNumber || '';
|
|
71
|
+
this.accountName = data.accountName || '';
|
|
72
|
+
this.accountClass = data.accountClass || 0;
|
|
73
|
+
this.accountType = data.accountType || 'asset';
|
|
74
|
+
this.skrType = data.skrType || 'SKR03';
|
|
75
|
+
this.description = data.description || '';
|
|
76
|
+
this.vatRate = data.vatRate || 0;
|
|
77
|
+
this.isActive = data.isActive !== undefined ? data.isActive : true;
|
|
78
|
+
|
|
79
|
+
// Parse account structure from number
|
|
80
|
+
if (this.accountNumber && this.accountNumber.length === 4) {
|
|
81
|
+
this.accountClass = parseInt(this.accountNumber[0]);
|
|
82
|
+
this.accountGroup = parseInt(this.accountNumber[1]);
|
|
83
|
+
this.accountSubgroup = parseInt(this.accountNumber[2]);
|
|
84
|
+
} else {
|
|
85
|
+
this.accountGroup = 0;
|
|
86
|
+
this.accountSubgroup = 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.balance = 0;
|
|
90
|
+
this.debitTotal = 0;
|
|
91
|
+
this.creditTotal = 0;
|
|
92
|
+
this.isSystemAccount = true;
|
|
93
|
+
this.createdAt = new Date();
|
|
94
|
+
this.updatedAt = new Date();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public static async createAccount(data: IAccountData): Promise<Account> {
|
|
99
|
+
const account = new Account(data);
|
|
100
|
+
await account.save();
|
|
101
|
+
return account;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public static async getAccountByNumber(
|
|
105
|
+
accountNumber: string,
|
|
106
|
+
skrType: TSKRType,
|
|
107
|
+
): Promise<Account | null> {
|
|
108
|
+
const account = await Account.getInstance({
|
|
109
|
+
accountNumber,
|
|
110
|
+
skrType,
|
|
111
|
+
});
|
|
112
|
+
return account;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public static async getAccountsByClass(
|
|
116
|
+
accountClass: number,
|
|
117
|
+
skrType: TSKRType,
|
|
118
|
+
): Promise<Account[]> {
|
|
119
|
+
const accounts = await Account.getInstances({
|
|
120
|
+
accountClass,
|
|
121
|
+
skrType,
|
|
122
|
+
isActive: true,
|
|
123
|
+
});
|
|
124
|
+
return accounts;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public static async getAccountsByType(
|
|
128
|
+
accountType: TAccountType,
|
|
129
|
+
skrType: TSKRType,
|
|
130
|
+
): Promise<Account[]> {
|
|
131
|
+
const accounts = await Account.getInstances({
|
|
132
|
+
accountType,
|
|
133
|
+
skrType,
|
|
134
|
+
isActive: true,
|
|
135
|
+
});
|
|
136
|
+
return accounts;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public static async searchAccounts(
|
|
140
|
+
searchTerm: string,
|
|
141
|
+
skrType?: TSKRType,
|
|
142
|
+
): Promise<Account[]> {
|
|
143
|
+
const query: any = {};
|
|
144
|
+
if (skrType) {
|
|
145
|
+
query.skrType = skrType;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const accounts = await Account.getInstances(query);
|
|
149
|
+
|
|
150
|
+
// Filter by search term
|
|
151
|
+
const lowerSearchTerm = searchTerm.toLowerCase();
|
|
152
|
+
return accounts.filter(
|
|
153
|
+
(account) =>
|
|
154
|
+
account.accountNumber.includes(searchTerm) ||
|
|
155
|
+
account.accountName.toLowerCase().includes(lowerSearchTerm) ||
|
|
156
|
+
account.description.toLowerCase().includes(lowerSearchTerm),
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public async updateBalance(
|
|
161
|
+
debitAmount: number = 0,
|
|
162
|
+
creditAmount: number = 0,
|
|
163
|
+
): Promise<void> {
|
|
164
|
+
this.debitTotal += debitAmount;
|
|
165
|
+
this.creditTotal += creditAmount;
|
|
166
|
+
|
|
167
|
+
// Calculate balance based on account type
|
|
168
|
+
switch (this.accountType) {
|
|
169
|
+
case 'asset':
|
|
170
|
+
case 'expense':
|
|
171
|
+
// Normal debit accounts
|
|
172
|
+
this.balance = this.debitTotal - this.creditTotal;
|
|
173
|
+
break;
|
|
174
|
+
case 'liability':
|
|
175
|
+
case 'equity':
|
|
176
|
+
case 'revenue':
|
|
177
|
+
// Normal credit accounts
|
|
178
|
+
this.balance = this.creditTotal - this.debitTotal;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
this.updatedAt = new Date();
|
|
183
|
+
await this.save();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public async deactivate(): Promise<void> {
|
|
187
|
+
this.isActive = false;
|
|
188
|
+
this.updatedAt = new Date();
|
|
189
|
+
await this.save();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public async activate(): Promise<void> {
|
|
193
|
+
this.isActive = true;
|
|
194
|
+
this.updatedAt = new Date();
|
|
195
|
+
await this.save();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public getNormalBalance(): 'debit' | 'credit' {
|
|
199
|
+
switch (this.accountType) {
|
|
200
|
+
case 'asset':
|
|
201
|
+
case 'expense':
|
|
202
|
+
return 'debit';
|
|
203
|
+
case 'liability':
|
|
204
|
+
case 'equity':
|
|
205
|
+
case 'revenue':
|
|
206
|
+
return 'credit';
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
public async beforeSave(): Promise<void> {
|
|
211
|
+
// Validate account number format
|
|
212
|
+
if (!this.accountNumber || this.accountNumber.length !== 4) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Invalid account number format: ${this.accountNumber}. Must be 4 digits.`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Validate account number is numeric
|
|
219
|
+
if (!/^\d{4}$/.test(this.accountNumber)) {
|
|
220
|
+
throw new Error(
|
|
221
|
+
`Account number must contain only digits: ${this.accountNumber}`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Validate account class matches first digit
|
|
226
|
+
const firstDigit = parseInt(this.accountNumber[0]);
|
|
227
|
+
if (this.accountClass !== firstDigit) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Account class ${this.accountClass} does not match account number ${this.accountNumber}`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Validate SKR type
|
|
234
|
+
if (this.skrType !== 'SKR03' && this.skrType !== 'SKR04') {
|
|
235
|
+
throw new Error(`Invalid SKR type: ${this.skrType}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|