@ekwo-ai/core 0.5.0 → 0.7.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.
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Taking over books kept somewhere else: one function per surface and one
3
+ * function in the schema.
4
+ *
5
+ * A reader of `packages/formats/` turns an export into the same shape whatever
6
+ * produced it — accounts, parties, entries, a trial balance — and the schema's
7
+ * `import_books()` writes that shape whole or not at all, through
8
+ * `post_entry()`. What is left in between is what this file does, and it is
9
+ * the part only the user can settle: **which account of this company's chart
10
+ * each account of the old one becomes**, and which journal each old journal
11
+ * goes to. A correspondence is proposed, shown, saved by the caller and given
12
+ * back on the next run; nothing is posted while an account has no answer.
13
+ *
14
+ * Adding a source is adding a reader and one line to {@link BOOK_SOURCES}.
15
+ * There is no second command.
16
+ */
17
+ import { type ImportedBooks } from '@ekwo-ai/fec';
18
+ import { type DateOrder } from '@ekwo-ai/journal-report';
19
+ import { type Backend } from './backend.js';
20
+ export type { ImportedBooks, ImportedLine } from '@ekwo-ai/fec';
21
+ /** The sources an import reads, each by one brick of `packages/formats/`. */
22
+ export declare const BOOK_SOURCES: readonly ["trial-balance", "fec", "journal-items", "journal-report"];
23
+ export type BookSource = (typeof BOOK_SOURCES)[number];
24
+ /** What each source is, in one sentence, for a help text and a tool description. */
25
+ export declare const BOOK_SOURCE_DESCRIPTIONS: Record<BookSource, string>;
26
+ /** The journal an entry is mapped to when it is to become the opening balance rather than an entry. */
27
+ export declare const OPENING = "@opening";
28
+ /** The key of the journal of an entry whose source names none. */
29
+ export declare const NO_JOURNAL = "*";
30
+ /** One file as the caller holds it. */
31
+ export interface BookFile {
32
+ name: string;
33
+ content: string | Uint8Array;
34
+ }
35
+ export interface ReadBooksOptions {
36
+ /** How bytes are decoded, where a file arrives as bytes. Never guessed. */
37
+ encoding?: 'utf-8' | 'iso-8859-1' | 'iso-8859-15' | undefined;
38
+ /** For `journal-report`: how a date that is not ISO is written. Never guessed. */
39
+ date_order?: DateOrder | undefined;
40
+ }
41
+ /**
42
+ * The correspondence between the old books and this company. Saved as JSON by
43
+ * the caller and given back on the next run, so the second run posts what the
44
+ * first one showed. A null is an account nobody has answered for yet.
45
+ *
46
+ * `suggested` holds what the proposal could not settle on its own, each with
47
+ * its reason. It is read by the user, never given back: an account is settled
48
+ * by writing its code under `accounts`.
49
+ */
50
+ export interface ImportMapping {
51
+ version: 1;
52
+ source: string;
53
+ accounts: Record<string, string | null>;
54
+ journals: Record<string, string | null>;
55
+ suggested?: Record<string, {
56
+ target: string;
57
+ reason: string;
58
+ }>;
59
+ }
60
+ /** Reads the files of one source into the shape `import_books()` takes. */
61
+ export declare function readBooks(source: BookSource, files: BookFile[], options?: ReadBooksOptions): ImportedBooks;
62
+ /** sha256 of the files, in the order given: what `book_imports` keys an import on. */
63
+ export declare function booksChecksum(files: BookFile[]): string;
64
+ interface ChartAccount {
65
+ code: string;
66
+ name: string;
67
+ account_type: string;
68
+ deprecated: boolean;
69
+ }
70
+ /**
71
+ * How a proposed account was settled, so the user knows how much to trust it:
72
+ * `given` by the caller, `exact` — the same code, and nothing in the files
73
+ * says it is another kind of account — `suggested`, which waits for the user,
74
+ * or `none`.
75
+ */
76
+ export type MappingBasis = 'given' | 'exact' | 'suggested' | 'none';
77
+ /** How the account of the chart was found from the old one. */
78
+ export type MappingMatch = 'same-code' | 'same-digits' | 'prefix' | 'kind';
79
+ /** What the old books say of one of their accounts. */
80
+ export interface SourceAccount {
81
+ code: string;
82
+ name: string | null;
83
+ /** What the source calls its kind, verbatim, where the export gives it. */
84
+ type: string | null;
85
+ /** The side its lines leave it on in these files, or null when they balance or there are none. */
86
+ side: 'debit' | 'credit' | null;
87
+ }
88
+ export interface AccountProposal {
89
+ target: string | null;
90
+ basis: MappingBasis;
91
+ match: MappingMatch | null;
92
+ /** Why, in a sentence. Always given for `suggested` and `none`. */
93
+ reason: string | null;
94
+ /** True where the user has to read this line before anything is posted — or should, for an answer the files contradict. */
95
+ doubtful: boolean;
96
+ }
97
+ export interface ProposedAccount extends AccountProposal {
98
+ source: string;
99
+ name: string | null;
100
+ }
101
+ export interface Proposal {
102
+ mapping: ImportMapping;
103
+ accounts: ProposedAccount[];
104
+ unmapped_accounts: string[];
105
+ /** Accounts the lines use whose proposal waits for the user's confirmation. */
106
+ unconfirmed_accounts: string[];
107
+ unmapped_journals: string[];
108
+ /** The type of each account of the chart, by code: what says a party is a customer or a supplier. */
109
+ account_types: Record<string, string>;
110
+ }
111
+ /**
112
+ * The account of the chart an old account most probably is, and why.
113
+ *
114
+ * The codes give a candidate, never a country: the same code; the same digits
115
+ * once the zeros a chart pads with on the right are set aside (`411` and
116
+ * `411000`); else the account whose digits are the longest beginning of the old
117
+ * code, three at least (`401ACME` to `401000`). A tie is no answer. Then what
118
+ * the files say of the old account — its type, its name, the side of its
119
+ * balance — is held against what the chart says the candidate is, because two
120
+ * charts use the same digits for different things: `610` is a receivable in
121
+ * one and `6100` an expense in another.
122
+ *
123
+ * Only the same code, not contradicted, is `exact`. Anything else is
124
+ * `suggested`, with its reason, and waits for the user; a candidate the files
125
+ * contradict is dropped, and the one account of the chart of the kind the
126
+ * files say is suggested in its place when there is exactly one.
127
+ */
128
+ export declare function proposeAccount(source: SourceAccount, chart: readonly ChartAccount[]): AccountProposal;
129
+ /**
130
+ * The correspondence for these books in this company: what the caller gave,
131
+ * and a proposal for everything it did not. A suggestion stays out of
132
+ * `mapping.accounts` — it is kept beside it, under `suggested` — unless the
133
+ * caller accepts the suggestions as a whole.
134
+ */
135
+ export declare function proposeMapping(backend: Backend, companyId: string, books: ImportedBooks, given?: Partial<ImportMapping>, options?: {
136
+ accept_suggestions?: boolean | undefined;
137
+ }): Promise<Proposal>;
138
+ export interface ImportBooksArgs {
139
+ company_id: string;
140
+ source: BookSource;
141
+ files: BookFile[];
142
+ /** A correspondence saved from an earlier run. What it answers wins over the proposal. */
143
+ mapping?: Partial<ImportMapping> | undefined;
144
+ /** Show what would be written, write nothing. */
145
+ dry_run?: boolean | undefined;
146
+ /** Open the fiscal years the entries fall in, where the company has none. */
147
+ open_years?: boolean | undefined;
148
+ /** The first day of the year a trial balance opens, where the file says none. */
149
+ opening_date?: string | undefined;
150
+ /** Let a trial balance carry income and expense accounts: books taken over in the middle of a year. */
151
+ allow_result_accounts?: boolean | undefined;
152
+ /** Keep the numbers the entries had, where the country allows a number chosen by hand or the caller holds entries.import. */
153
+ keep_numbers?: boolean | undefined;
154
+ /** Take every suggested account as the answer. The user has read them; nothing else says so. */
155
+ accept_suggestions?: boolean | undefined;
156
+ encoding?: ReadBooksOptions['encoding'];
157
+ date_order?: DateOrder | undefined;
158
+ }
159
+ /**
160
+ * Reads the files, settles the correspondence and hands the books to
161
+ * `import_books()`. With `dry_run` the database rehearses the import and rolls
162
+ * it back; without, it posts all of it or nothing.
163
+ *
164
+ * Refused before the database is asked: books whose reader found something
165
+ * that does not add up, an account or a journal with no answer, a currency the
166
+ * file names that is not the company's.
167
+ */
168
+ export declare function importBooks(backend: Backend, args: ImportBooksArgs): Promise<Record<string, unknown>>;
169
+ //# sourceMappingURL=imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/books/imports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,629 @@
1
+ /**
2
+ * Taking over books kept somewhere else: one function per surface and one
3
+ * function in the schema.
4
+ *
5
+ * A reader of `packages/formats/` turns an export into the same shape whatever
6
+ * produced it — accounts, parties, entries, a trial balance — and the schema's
7
+ * `import_books()` writes that shape whole or not at all, through
8
+ * `post_entry()`. What is left in between is what this file does, and it is
9
+ * the part only the user can settle: **which account of this company's chart
10
+ * each account of the old one becomes**, and which journal each old journal
11
+ * goes to. A correspondence is proposed, shown, saved by the caller and given
12
+ * back on the next run; nothing is posted while an account has no answer.
13
+ *
14
+ * Adding a source is adding a reader and one line to {@link BOOK_SOURCES}.
15
+ * There is no second command.
16
+ */
17
+ import { createHash } from 'node:crypto';
18
+ import { readFec } from '@ekwo-ai/fec';
19
+ import { readTrialBalance } from '@ekwo-ai/trial-balance';
20
+ import { readJournalItems } from '@ekwo-ai/journal-items';
21
+ import { readJournalReport } from '@ekwo-ai/journal-report';
22
+ import { BooksError } from './backend.js';
23
+ /** The sources an import reads, each by one brick of `packages/formats/`. */
24
+ export const BOOK_SOURCES = ['trial-balance', 'fec', 'journal-items', 'journal-report'];
25
+ /** What each source is, in one sentence, for a help text and a tool description. */
26
+ export const BOOK_SOURCE_DESCRIPTIONS = {
27
+ 'trial-balance': 'a trial balance as CSV — account, debit, credit, or a signed balance — which becomes the opening entry of a year',
28
+ fec: 'a fichier des écritures comptables, the eighteen-column file of the arrêté of 29 July 2013',
29
+ 'journal-items': 'an export of journal items as CSV — one row per line of an entry, with its entry, journal, date, account, partner, debit and credit — optionally with the chart of accounts and the partners exported beside it',
30
+ 'journal-report': 'a journal report or a general ledger detail saved as CSV — date, journal number, account code, debit, credit — optionally with the chart of accounts and the contacts exported beside it',
31
+ };
32
+ /** The journal an entry is mapped to when it is to become the opening balance rather than an entry. */
33
+ export const OPENING = '@opening';
34
+ /** The key of the journal of an entry whose source names none. */
35
+ export const NO_JOURNAL = '*';
36
+ /** Reads the files of one source into the shape `import_books()` takes. */
37
+ export function readBooks(source, files, options = {}) {
38
+ if (files.length === 0)
39
+ throw new BooksError('missing_file: an import reads at least one file.');
40
+ const single = () => {
41
+ if (files.length !== 1) {
42
+ throw new BooksError(`too_many_files: ${source} reads one file, and ${files.length} were given.`);
43
+ }
44
+ return files[0];
45
+ };
46
+ switch (source) {
47
+ case 'trial-balance': {
48
+ const encoding = options.encoding === 'iso-8859-15' ? 'iso-8859-1' : options.encoding;
49
+ return readTrialBalance(single().content, encoding === undefined ? {} : { encoding });
50
+ }
51
+ case 'fec': {
52
+ const encoding = options.encoding === 'iso-8859-1' ? 'iso-8859-15' : options.encoding;
53
+ return readFec(single().content, encoding === undefined ? {} : { encoding });
54
+ }
55
+ case 'journal-items':
56
+ return readJournalItems(files.map((file) => file.content), options.encoding === undefined ? {} : { encoding: options.encoding === 'iso-8859-15' ? 'iso-8859-1' : options.encoding });
57
+ case 'journal-report':
58
+ return readJournalReport(files.map((file) => file.content), {
59
+ ...(options.encoding === undefined ? {} : { encoding: options.encoding === 'iso-8859-15' ? 'iso-8859-1' : options.encoding }),
60
+ ...(options.date_order === undefined ? {} : { dateOrder: options.date_order }),
61
+ });
62
+ }
63
+ }
64
+ /** sha256 of the files, in the order given: what `book_imports` keys an import on. */
65
+ export function booksChecksum(files) {
66
+ const hash = createHash('sha256');
67
+ for (const file of files)
68
+ hash.update(typeof file.content === 'string' ? Buffer.from(file.content, 'utf8') : file.content);
69
+ return `sha256:${hash.digest('hex')}`;
70
+ }
71
+ /** A code without the zeros it was padded with on the right: `411000` and `411` are one account. */
72
+ function unpadded(code) {
73
+ const stripped = code.replace(/0+$/, '');
74
+ return stripped === '' ? code : stripped;
75
+ }
76
+ /** What the chart says an account is: the group before the first underscore of its type, and the three kinds a party or a payment depends on. */
77
+ function natureOf(accountType) {
78
+ const group = (accountType === 'off_balance' ? 'off_balance' : accountType.split('_')[0]);
79
+ const kind = accountType === 'asset_receivable' ? 'receivable' : accountType === 'liability_payable' ? 'payable' : accountType === 'asset_cash' ? 'cash' : null;
80
+ return { group, kind, words: kind === null ? GROUP_WORDS[group] : KIND_WORDING[kind] };
81
+ }
82
+ const GROUP_WORDS = {
83
+ asset: 'an asset account',
84
+ liability: 'a liability account',
85
+ equity: 'an equity account',
86
+ income: 'an income account',
87
+ expense: 'an expense account',
88
+ off_balance: 'an off-balance account',
89
+ };
90
+ const KIND_GROUP = { receivable: 'asset', payable: 'liability', cash: 'asset' };
91
+ const KIND_WORDING = { receivable: 'a receivable account', payable: 'a payable account', cash: 'a bank or cash account' };
92
+ /** Lower case, without accents, cut into words. */
93
+ function words(text) {
94
+ return text
95
+ .normalize('NFD')
96
+ .replace(/\p{M}/gu, '')
97
+ .toLowerCase()
98
+ .split(/[^\p{L}\p{N}]+/u)
99
+ .filter((word) => word !== '');
100
+ }
101
+ /**
102
+ * The words that name a kind of account, in the languages a chart is kept in
103
+ * — none of them the default, and none needed for a proposal to be made: a
104
+ * word found here only confirms or contradicts the one the codes gave. A
105
+ * word is matched at the start of a word of the name, so `client` catches
106
+ * `clients` and `clientes`.
107
+ */
108
+ const KIND_WORDS = {
109
+ receivable: ['receivable', 'debtor', 'customer', 'client', 'kunde', 'klant', 'debiteur', 'deudor', 'creance', 'forderung', 'vordering', 'crediti'],
110
+ payable: ['payable', 'creditor', 'supplier', 'vendor', 'fournisseur', 'lieferant', 'verbindlichkeit', 'leverancier', 'crediteur', 'acreedor', 'proveedor', 'fornitor'],
111
+ cash: ['bank', 'banque', 'banco', 'banca', 'cash', 'caisse', 'kasse', 'kassa', 'caja', 'cassa'],
112
+ };
113
+ /**
114
+ * Words after which a name no longer says what its kind word says: an advance
115
+ * received from a customer is a liability, bank charges are an expense, a
116
+ * provision on receivables is not one.
117
+ */
118
+ const TURNING_WORDS = [
119
+ 'advance', 'avance', 'acompte', 'deposit', 'prepa', 'anzahlung', 'voorschot', 'anticipo',
120
+ 'doubtful', 'douteu', 'provision', 'allowance', 'impairment', 'deprecia', 'wertberichtigung', 'waardevermindering',
121
+ 'charge', 'fee', 'frais', 'interest', 'interet', 'kosten', 'gebuhr', 'commission', 'loan', 'emprunt', 'overdraft', 'decouvert',
122
+ 'transfer', 'virement', 'clearing', 'suspense', 'attente',
123
+ ];
124
+ function kindInName(name) {
125
+ if (name === null)
126
+ return null;
127
+ const said = words(name);
128
+ if (said.some((word) => TURNING_WORDS.some((turn) => word.startsWith(turn))))
129
+ return null;
130
+ const kinds = Object.keys(KIND_WORDS).filter((kind) => said.some((word) => KIND_WORDS[kind].some((k) => word.startsWith(k))));
131
+ return kinds.length === 1 ? kinds[0] : null;
132
+ }
133
+ /**
134
+ * What the type an export gives its account says: the vocabularies of the
135
+ * ledgers a reader reads, and this schema's own. Unknown, it says nothing.
136
+ */
137
+ function natureInType(type) {
138
+ if (type === null)
139
+ return null;
140
+ const text = words(type).join(' ');
141
+ if (text === '' || /off ?balance/.test(text))
142
+ return null;
143
+ const has = (pattern) => pattern.test(text);
144
+ if (has(/receivable|debtor|creance/))
145
+ return { groups: ['asset'], kind: 'receivable' };
146
+ if (has(/payable|creditor|dette fournisseur/))
147
+ return { groups: ['liability'], kind: 'payable' };
148
+ if (has(/\bbank|\bcash/))
149
+ return { groups: ['asset'], kind: 'cash' };
150
+ if (has(/equity|capital|earnings|reserve|unaffected/))
151
+ return { groups: ['equity'], kind: null };
152
+ if (has(/liabilit|credit card|creditcard/))
153
+ return { groups: ['liability'], kind: null };
154
+ if (has(/asset|prepayment|inventory|\bstock/))
155
+ return { groups: ['asset'], kind: null };
156
+ if (has(/revenue|income|sales|turnover|\bproduit|ertrag|ingreso|ricav|opbrengst/))
157
+ return { groups: ['income'], kind: null };
158
+ if (has(/expense|cost|overhead|depreciation|purchase|wage|salar|\bcharge|aufwand|gasto|kosten/))
159
+ return { groups: ['expense'], kind: null };
160
+ return null;
161
+ }
162
+ const STOP_WORDS = new Set(['the', 'and', 'for', 'des', 'les', 'aux', 'und', 'der', 'die', 'das', 'van', 'het', 'een', 'del', 'los', 'las', 'con', 'per']);
163
+ /**
164
+ * Two names that say the same thing: the same words, or most of them, cut to
165
+ * five letters, in common. A script that does not separate its words by
166
+ * spaces is compared whole.
167
+ */
168
+ function sameName(one, other) {
169
+ if (one === null)
170
+ return false;
171
+ if (words(one).join(' ') === words(other).join(' ') && words(one).length > 0)
172
+ return true;
173
+ const stems = (text) => new Set(words(text).filter((word) => word.length >= 3 && !STOP_WORDS.has(word) && !/^\d+$/.test(word)).map((word) => word.slice(0, 5)));
174
+ const a = stems(one);
175
+ const b = stems(other);
176
+ if (a.size === 0 || b.size === 0)
177
+ return false;
178
+ const shared = [...a].filter((stem) => b.has(stem)).length;
179
+ return shared / new Set([...a, ...b]).size > 0.5;
180
+ }
181
+ /**
182
+ * Whether an old account can be this account of the chart, from what the
183
+ * files say of it, strongest first: the type the export gives it, a name that
184
+ * is the chart's own, the kind its name says, the side its balance is on.
185
+ * `unknown` when the files say nothing, or only a side that disagrees — which
186
+ * is not a yes.
187
+ */
188
+ function judge(source, target) {
189
+ const nature = natureOf(target.account_type);
190
+ const it = `${target.code} ${target.name} is ${nature.words}`;
191
+ const fits = (groups, kind) => groups.includes(nature.group) && (kind === null || nature.kind === null || kind === nature.kind);
192
+ const typed = natureInType(source.type);
193
+ if (typed !== null) {
194
+ const ok = fits(typed.groups, typed.kind);
195
+ return { verdict: ok ? 'yes' : 'no', why: `the files call it "${source.type}", and ${it}` };
196
+ }
197
+ if (sameName(source.name, target.name))
198
+ return { verdict: 'yes', why: `its name is the one ${target.code} has in the chart` };
199
+ const named = kindInName(source.name);
200
+ if (named !== null) {
201
+ const ok = fits([KIND_GROUP[named]], named);
202
+ return { verdict: ok ? 'yes' : 'no', why: `its name, "${source.name}", says ${KIND_WORDING[named]}, and ${it}` };
203
+ }
204
+ if (source.side !== null) {
205
+ // The side is the weakest of the four: an accumulated depreciation is an
206
+ // asset with a credit balance, an overdrawn bank a debit one. It confirms,
207
+ // and where it disagrees it leaves the candidate to the user rather than
208
+ // dropping it.
209
+ const groups = source.side === 'debit' ? ['asset', 'expense'] : ['liability', 'equity', 'income'];
210
+ const ok = fits(groups, null);
211
+ return { verdict: ok ? 'yes' : 'unknown', why: `its balance in the files is on the ${source.side} side, and ${it}${ok ? '' : ', whose balance usually is not'}` };
212
+ }
213
+ return { verdict: 'unknown', why: 'nothing in the files says what kind of account it is' };
214
+ }
215
+ const MATCH_WORDS = {
216
+ 'same-code': 'the same code',
217
+ 'same-digits': 'the same digits once the padding zeros are set aside',
218
+ prefix: 'the longest beginning of the code the chart has',
219
+ };
220
+ /** The one account of the chart of the kind the files say, when the codes pointed elsewhere. */
221
+ function accountOfKind(source, live) {
222
+ const typed = natureInType(source.type);
223
+ const kind = typed === null ? kindInName(source.name) : typed.kind;
224
+ if (kind === null)
225
+ return null;
226
+ const ofKind = live.filter((account) => natureOf(account.account_type).kind === kind);
227
+ if (ofKind.length === 1)
228
+ return ofKind[0];
229
+ const named = ofKind.filter((account) => sameName(source.name, account.name));
230
+ return named.length === 1 ? named[0] : null;
231
+ }
232
+ /**
233
+ * The account of the chart an old account most probably is, and why.
234
+ *
235
+ * The codes give a candidate, never a country: the same code; the same digits
236
+ * once the zeros a chart pads with on the right are set aside (`411` and
237
+ * `411000`); else the account whose digits are the longest beginning of the old
238
+ * code, three at least (`401ACME` to `401000`). A tie is no answer. Then what
239
+ * the files say of the old account — its type, its name, the side of its
240
+ * balance — is held against what the chart says the candidate is, because two
241
+ * charts use the same digits for different things: `610` is a receivable in
242
+ * one and `6100` an expense in another.
243
+ *
244
+ * Only the same code, not contradicted, is `exact`. Anything else is
245
+ * `suggested`, with its reason, and waits for the user; a candidate the files
246
+ * contradict is dropped, and the one account of the chart of the kind the
247
+ * files say is suggested in its place when there is exactly one.
248
+ */
249
+ export function proposeAccount(source, chart) {
250
+ const live = chart.filter((account) => !account.deprecated);
251
+ const byCode = () => {
252
+ const same = live.find((account) => account.code === source.code);
253
+ if (same !== undefined)
254
+ return { account: same, match: 'same-code' };
255
+ const digits = live.filter((account) => unpadded(account.code) === unpadded(source.code));
256
+ if (digits.length === 1)
257
+ return { account: digits[0], match: 'same-digits' };
258
+ let best = [];
259
+ let length = 2;
260
+ for (const account of live) {
261
+ const stem = unpadded(account.code);
262
+ if (stem.length > length && source.code.startsWith(stem)) {
263
+ best = [account];
264
+ length = stem.length;
265
+ }
266
+ else if (stem.length === length && length > 2 && source.code.startsWith(stem)) {
267
+ best.push(account);
268
+ }
269
+ }
270
+ return best.length === 1 ? { account: best[0], match: 'prefix' } : null;
271
+ };
272
+ const found = byCode();
273
+ let refused = '';
274
+ if (found !== null) {
275
+ const { verdict, why } = judge(source, found.account);
276
+ if (verdict === 'yes' && found.match === 'same-code') {
277
+ return { target: found.account.code, basis: 'exact', match: 'same-code', reason: why, doubtful: false };
278
+ }
279
+ if (verdict !== 'no') {
280
+ return { target: found.account.code, basis: 'suggested', match: found.match, reason: `${MATCH_WORDS[found.match]}; ${why}`, doubtful: true };
281
+ }
282
+ refused = `${found.account.code}, ${MATCH_WORDS[found.match]}, is not proposed: ${why}`;
283
+ }
284
+ const kind = accountOfKind(source, live);
285
+ if (kind !== null && judge(source, kind).verdict === 'yes') {
286
+ const why = `${kind.code} ${kind.name} is the account of the chart of the kind the files say`;
287
+ return { target: kind.code, basis: 'suggested', match: 'kind', reason: refused === '' ? why : `${refused}. ${why}`, doubtful: true };
288
+ }
289
+ return {
290
+ target: null,
291
+ basis: 'none',
292
+ match: null,
293
+ reason: refused === '' ? 'no account of the chart has this code, its digits or its beginning' : refused,
294
+ doubtful: true,
295
+ };
296
+ }
297
+ /** Each account of these books with what the files say of it: its name and type, and the side its lines leave it on. */
298
+ function sourceAccounts(books) {
299
+ const known = new Map(books.accounts.map((account) => [account.code, account]));
300
+ const net = new Map();
301
+ const add = (line) => {
302
+ net.set(line.account, (net.get(line.account) ?? 0n) + millionths(line.debit) - millionths(line.credit));
303
+ };
304
+ for (const entry of books.entries)
305
+ for (const line of entry.lines)
306
+ add(line);
307
+ for (const line of books.opening)
308
+ add(line);
309
+ const codes = [...new Set([...known.keys(), ...net.keys()])].sort();
310
+ return codes.map((code) => {
311
+ const balance = net.get(code) ?? 0n;
312
+ return {
313
+ code,
314
+ name: known.get(code)?.name ?? null,
315
+ type: known.get(code)?.type ?? null,
316
+ side: balance > 0n ? 'debit' : balance < 0n ? 'credit' : null,
317
+ };
318
+ });
319
+ }
320
+ /** A decimal string as an integer of millionths, the way the readers add them: never through a float. */
321
+ function millionths(amount) {
322
+ if (amount === null || amount === '')
323
+ return 0n;
324
+ const [whole = '0', fraction = ''] = amount.split('.');
325
+ return BigInt(whole === '' ? '0' : whole) * 1000000n + BigInt((fraction + '000000').slice(0, 6));
326
+ }
327
+ /**
328
+ * The correspondence for these books in this company: what the caller gave,
329
+ * and a proposal for everything it did not. A suggestion stays out of
330
+ * `mapping.accounts` — it is kept beside it, under `suggested` — unless the
331
+ * caller accepts the suggestions as a whole.
332
+ */
333
+ export async function proposeMapping(backend, companyId, books, given = {}, options = {}) {
334
+ const [chart, journals, openingCode] = await Promise.all([
335
+ wholeChart(backend, companyId),
336
+ backend.select({
337
+ table: 'journals',
338
+ columns: ['code', 'journal_type'],
339
+ where: [
340
+ { column: 'company_id', op: 'eq', value: companyId },
341
+ { column: 'active', op: 'eq', value: true },
342
+ ],
343
+ order: [{ column: 'code' }],
344
+ }),
345
+ openingJournalCode(backend, companyId),
346
+ ]);
347
+ const byCode = new Map(chart.map((account) => [account.code, account]));
348
+ const accounts = sourceAccounts(books).map((source) => {
349
+ const answer = given.accounts?.[source.code];
350
+ if (answer !== undefined && answer !== null) {
351
+ // The user's answer is used as it is. Where the files contradict it,
352
+ // it is still said, so a correspondence saved from an older proposal
353
+ // is not trusted blind.
354
+ const target = byCode.get(answer);
355
+ const check = target === undefined ? null : judge(source, target);
356
+ return {
357
+ source: source.code, name: source.name, target: answer, basis: 'given', match: null,
358
+ reason: check?.verdict === 'no' ? `given, and yet ${check.why}` : null,
359
+ doubtful: check?.verdict === 'no',
360
+ };
361
+ }
362
+ return { source: source.code, name: source.name, ...proposeAccount(source, chart) };
363
+ });
364
+ const known = new Set(journals.map((journal) => journal.code));
365
+ const general = journals.find((journal) => journal.journal_type === 'general')?.code ?? null;
366
+ const journalMap = {};
367
+ for (const source of [...new Set(books.entries.map((entry) => entry.journal ?? NO_JOURNAL))].sort()) {
368
+ const answer = given.journals?.[source];
369
+ if (answer !== undefined && answer !== null)
370
+ journalMap[source] = answer;
371
+ else if (openingCode !== null && source.toUpperCase() === openingCode)
372
+ journalMap[source] = OPENING;
373
+ else if (known.has(source.toUpperCase()))
374
+ journalMap[source] = source.toUpperCase();
375
+ else
376
+ journalMap[source] = general;
377
+ }
378
+ const accept = options.accept_suggestions === true;
379
+ const settled = (account) => account.basis === 'given' || account.basis === 'exact' || (accept && account.basis === 'suggested') ? account.target : null;
380
+ const waiting = accounts.filter((account) => account.basis === 'suggested' && !accept);
381
+ // Only what these books use stops an import: an account of the chart file
382
+ // that no line names is shown and never posted to.
383
+ const used = new Set(usedAccounts(books));
384
+ return {
385
+ mapping: {
386
+ version: 1,
387
+ source: books.format,
388
+ accounts: Object.fromEntries(accounts.map((account) => [account.source, settled(account)])),
389
+ journals: journalMap,
390
+ ...(waiting.length === 0
391
+ ? {}
392
+ : { suggested: Object.fromEntries(waiting.map((account) => [account.source, { target: account.target, reason: account.reason }])) }),
393
+ },
394
+ accounts,
395
+ unmapped_accounts: accounts.filter((a) => a.basis === 'none' && used.has(a.source)).map((a) => a.source),
396
+ unconfirmed_accounts: waiting.filter((a) => used.has(a.source)).map((a) => a.source),
397
+ unmapped_journals: Object.entries(journalMap).filter(([, target]) => target === null).map(([source]) => source),
398
+ account_types: Object.fromEntries(chart.map((account) => [account.code, account.account_type])),
399
+ };
400
+ }
401
+ /**
402
+ * Every account of the chart, a page at a time. A chart transcribed from a
403
+ * regulation holds more than a thousand accounts, and a PostgREST project
404
+ * returns a thousand rows unless asked for the next ones: a proposal made on
405
+ * the first thousand would call an account missing that is not.
406
+ */
407
+ async function wholeChart(backend, companyId) {
408
+ const page = 1000;
409
+ const chart = [];
410
+ for (;;) {
411
+ const last = chart[chart.length - 1]?.code;
412
+ const rows = await backend.select({
413
+ table: 'accounts',
414
+ columns: ['code', 'name', 'account_type', 'deprecated'],
415
+ where: [
416
+ { column: 'company_id', op: 'eq', value: companyId },
417
+ ...(last === undefined ? [] : [{ column: 'code', op: 'gt', value: last }]),
418
+ ],
419
+ order: [{ column: 'code' }],
420
+ limit: page,
421
+ });
422
+ chart.push(...rows);
423
+ if (rows.length < page)
424
+ return chart;
425
+ }
426
+ }
427
+ /** Every account a line of these books names. */
428
+ function usedAccounts(books) {
429
+ const used = new Set();
430
+ for (const entry of books.entries)
431
+ for (const line of entry.lines)
432
+ used.add(line.account);
433
+ for (const line of books.opening)
434
+ used.add(line.account);
435
+ return [...used];
436
+ }
437
+ /** The code of the journal the pack of this company opens its years on, or null. */
438
+ async function openingJournalCode(backend, companyId) {
439
+ const rows = await backend.select({
440
+ table: 'journals',
441
+ columns: ['code'],
442
+ where: [
443
+ { column: 'company_id', op: 'eq', value: companyId },
444
+ { column: 'journal_type', op: 'eq', value: 'opening' },
445
+ { column: 'active', op: 'eq', value: true },
446
+ ],
447
+ order: [{ column: 'code' }],
448
+ });
449
+ return rows.length === 1 ? rows[0].code : null;
450
+ }
451
+ /**
452
+ * Reads the files, settles the correspondence and hands the books to
453
+ * `import_books()`. With `dry_run` the database rehearses the import and rolls
454
+ * it back; without, it posts all of it or nothing.
455
+ *
456
+ * Refused before the database is asked: books whose reader found something
457
+ * that does not add up, an account or a journal with no answer, a currency the
458
+ * file names that is not the company's.
459
+ */
460
+ export async function importBooks(backend, args) {
461
+ const books = readBooks(args.source, args.files, { encoding: args.encoding, date_order: args.date_order });
462
+ const proposal = await proposeMapping(backend, args.company_id, books, args.mapping ?? {}, { accept_suggestions: args.accept_suggestions });
463
+ const read = {
464
+ accounts: books.accounts.length,
465
+ contacts: books.contacts.length,
466
+ entries: books.entries.length,
467
+ lines: books.entries.reduce((sum, entry) => sum + entry.lines.length, 0),
468
+ opening_lines: books.opening.length,
469
+ };
470
+ const answer = {
471
+ dry_run: args.dry_run === true,
472
+ source: args.source,
473
+ read,
474
+ mapping: proposal.mapping,
475
+ accounts: proposal.accounts,
476
+ unmapped_accounts: proposal.unmapped_accounts,
477
+ unconfirmed_accounts: proposal.unconfirmed_accounts,
478
+ unmapped_journals: proposal.unmapped_journals,
479
+ violations: books.violations,
480
+ };
481
+ const company = await backend.select({
482
+ table: 'companies',
483
+ columns: ['currency_code'],
484
+ where: [{ column: 'id', op: 'eq', value: args.company_id }],
485
+ });
486
+ const currency = company[0]?.currency_code ?? null;
487
+ if (company[0] === undefined)
488
+ throw new BooksError(`not_found: company ${args.company_id}. Either it does not exist, or you are not a member of it.`);
489
+ const blocking = [];
490
+ if (books.currency !== null && currency !== null && books.currency.toUpperCase() !== currency) {
491
+ blocking.push(`import_currency_mismatch: the files are in ${books.currency} and the company keeps its books in ${currency}`);
492
+ }
493
+ if (books.violations.length > 0) {
494
+ blocking.push(`import_violations: the files do not add up in ${books.violations.length} place${books.violations.length === 1 ? '' : 's'}; ` +
495
+ books.violations.slice(0, 5).map((v) => `${v.row === null ? '' : `row ${v.row}: `}${v.message}`).join('; '));
496
+ }
497
+ if (proposal.unmapped_accounts.length > 0) {
498
+ blocking.push(`import_unmapped_accounts: no account of the chart answers for ${proposal.unmapped_accounts.join(', ')}. Say which in the correspondence`);
499
+ }
500
+ if (proposal.unconfirmed_accounts.length > 0) {
501
+ const suggested = proposal.mapping.suggested ?? {};
502
+ blocking.push(`import_unconfirmed_accounts: ${proposal.unconfirmed_accounts.length} account${proposal.unconfirmed_accounts.length === 1 ? ' is' : 's are'} only suggested — ` +
503
+ proposal.unconfirmed_accounts.map((code) => `${code} → ${suggested[code]?.target ?? '?'}`).join(', ') +
504
+ '. Write the code of each under accounts in the correspondence, or accept the suggestions once they are read (accept_suggestions)');
505
+ }
506
+ if (proposal.unmapped_journals.length > 0) {
507
+ blocking.push(`import_unmapped_journals: no journal answers for ${proposal.unmapped_journals.join(', ')}. Say which in the correspondence`);
508
+ }
509
+ if (blocking.length > 0) {
510
+ if (args.dry_run === true) {
511
+ return { ...answer, result: null, refusals: blocking, note: 'Nothing was written, and nothing would be: the refusals above come first. Fill the correspondence and run it again.' };
512
+ }
513
+ throw new BooksError(blocking.join('\n'), {
514
+ hint: 'Nothing was imported. Run the same import with dry_run to see the correspondence proposed, save it, answer what is missing, and give it back.',
515
+ });
516
+ }
517
+ const payload = buildPayload(books, proposal.mapping, proposal.account_types, currency, args);
518
+ payload['checksum'] = booksChecksum(args.files);
519
+ payload['file_names'] = args.files.map((file) => file.name);
520
+ const [result] = await backend.rpc('import_books', {
521
+ p_company_id: args.company_id,
522
+ p_books: payload,
523
+ p_dry_run: args.dry_run === true,
524
+ p_open_years: args.open_years === true,
525
+ p_allow_result_accounts: args.allow_result_accounts === true,
526
+ });
527
+ const written = (result?.['import_books'] ?? result);
528
+ return {
529
+ ...answer,
530
+ result: written ?? null,
531
+ refusals: [],
532
+ note: args.dry_run === true
533
+ ? 'Nothing was written. The database ran the import and took it back, so the numbers are the ones it would take now and a refusal would have been the real one. Keep the correspondence and run it again without dry_run.'
534
+ : 'Every entry is posted through post_entry() and numbered by the journal it went to; the numbers the old books used are kept as each entry\'s reference. Imported lines carry no tax, so they feed no box of a VAT return. The same files again are refused.',
535
+ };
536
+ }
537
+ /** The books, translated into this company's codes, in the shape `import_books()` takes. */
538
+ function buildPayload(books, mapping, accountTypes, currency, args) {
539
+ const account = (code) => mapping.accounts[code];
540
+ // What a party is follows from where its lines are booked: on a receivable
541
+ // it is a customer, on a payable a supplier, on both it is both.
542
+ const roles = new Map();
543
+ const line = (source) => {
544
+ if (source.contact !== null) {
545
+ const seen = roles.get(source.contact) ?? new Set();
546
+ const type = accountTypes[account(source.account)];
547
+ if (type === 'asset_receivable')
548
+ seen.add('customer');
549
+ if (type === 'liability_payable')
550
+ seen.add('supplier');
551
+ roles.set(source.contact, seen);
552
+ }
553
+ const foreign = source.currency !== null && source.amountCurrency !== null && source.currency.toUpperCase() !== currency;
554
+ return {
555
+ account_code: account(source.account),
556
+ contact_key: source.contact,
557
+ label: source.label,
558
+ debit: source.debit,
559
+ credit: source.credit,
560
+ currency_code: foreign ? source.currency.toUpperCase() : null,
561
+ amount_currency: foreign ? source.amountCurrency : null,
562
+ date_maturity: source.dueDate,
563
+ };
564
+ };
565
+ const entries = [];
566
+ const openingLines = [];
567
+ let openingDate = null;
568
+ for (const entry of books.entries) {
569
+ const journal = mapping.journals[entry.journal ?? NO_JOURNAL];
570
+ if (journal === OPENING) {
571
+ if (openingDate !== null && openingDate !== entry.date) {
572
+ throw new BooksError(`import_opening_dates: the entries mapped to the opening are dated ${openingDate} and ${entry.date}; an opening balance has one date, the first day of a year`);
573
+ }
574
+ openingDate = entry.date;
575
+ openingLines.push(...entry.lines.map(line));
576
+ continue;
577
+ }
578
+ entries.push({
579
+ journal_code: journal,
580
+ date: entry.date,
581
+ number: args.keep_numbers === true ? entry.number : null,
582
+ reference: entry.reference ?? entry.number,
583
+ description: entry.description,
584
+ lines: entry.lines.map(line),
585
+ });
586
+ }
587
+ if (books.opening.length > 0) {
588
+ if (openingLines.length > 0) {
589
+ throw new BooksError('import_two_openings: these books carry a trial balance and entries mapped to the opening; one opening per import');
590
+ }
591
+ if (args.opening_date === undefined) {
592
+ throw new BooksError('missing_opening_date: a trial balance says nothing of the day it opens. Give the first day of the fiscal year it opens (opening_date).');
593
+ }
594
+ openingDate = args.opening_date;
595
+ openingLines.push(...books.opening.map(line));
596
+ }
597
+ else if (args.opening_date !== undefined && openingDate === null) {
598
+ throw new BooksError('unexpected_opening_date: an opening date was given and these books carry no balance to open');
599
+ }
600
+ const typeOf = (key) => {
601
+ const seen = roles.get(key) ?? new Set();
602
+ return seen.size === 2 ? 'both' : seen.size === 1 ? [...seen][0] : 'other';
603
+ };
604
+ const contacts = books.contacts
605
+ .filter((contact) => roles.has(contact.code))
606
+ .map((contact) => ({
607
+ key: contact.code,
608
+ name: contact.name,
609
+ auxiliary_code: contact.code === contact.name ? null : contact.code,
610
+ contact_type: typeOf(contact.code),
611
+ vat_number: contact.vatNumber,
612
+ registration_number: contact.registrationNumber,
613
+ email: contact.email,
614
+ country: contact.country,
615
+ }));
616
+ // A party named on a line that the files list nowhere else is still a party.
617
+ for (const key of roles.keys()) {
618
+ if (!contacts.some((contact) => contact.key === key)) {
619
+ contacts.push({ key, name: key, auxiliary_code: null, contact_type: typeOf(key), vat_number: null, registration_number: null, email: null, country: null });
620
+ }
621
+ }
622
+ return {
623
+ source: books.format,
624
+ contacts,
625
+ entries,
626
+ opening: openingDate === null ? null : { date: openingDate, lines: openingLines },
627
+ };
628
+ }
629
+ //# sourceMappingURL=imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/books/imports.ts"],"names":[],"mappings":"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"}
@@ -16,4 +16,6 @@ export * from './contacts.js';
16
16
  export * from './documents.js';
17
17
  export * from './entries.js';
18
18
  export * from './payments.js';
19
+ export * from './imports.js';
20
+ export * from './statements.js';
19
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/books/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,cAAc,CAAC;AAC7B,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/books/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,cAAc,CAAC;AAC7B,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
@@ -16,4 +16,6 @@ export * from './contacts.js';
16
16
  export * from './documents.js';
17
17
  export * from './entries.js';
18
18
  export * from './payments.js';
19
+ export * from './imports.js';
20
+ export * from './statements.js';
19
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/books/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,cAAc,CAAC;AAC7B,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/books/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,cAAc,CAAC;AAC7B,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * A bank statement file into `import_bank_statement()`.
3
+ *
4
+ * The three bricks that read a statement — `camt053`, `coda`, `cfonb120` —
5
+ * return the same shape, and the schema's `import_bank_statement()` takes it.
6
+ * What is here is the part both surfaces need: picking the brick by the format
7
+ * the caller names, never by the content, and the checksum and the size of the
8
+ * file the statement records as its source. It lived in the MCP server until
9
+ * the command line imported statements too, as `ekwo import camt.053 <file>`.
10
+ */
11
+ import type { StatementFormat } from '../bank.js';
12
+ import { type Backend } from './backend.js';
13
+ export interface ImportStatementFileArgs {
14
+ company_id: string;
15
+ format: StatementFormat;
16
+ /** The file as text (UTF-8). */
17
+ content: string;
18
+ file_name?: string | undefined;
19
+ storage_path?: string | undefined;
20
+ bank_account_id?: string | undefined;
21
+ /** Only for `cfonb120`, which names no country: the country the account is held in. Never guessed. */
22
+ iban_country?: string | undefined;
23
+ }
24
+ /**
25
+ * Reads a statement file with the brick of its format, and nothing else: no
26
+ * database. A file the brick cannot read is refused by name.
27
+ */
28
+ export declare function readStatementFile(format: StatementFormat, content: string, ibanCountry?: string | undefined): import("@ekwo-ai/coda").StatementFile | import("@ekwo-ai/cfonb120").StatementFile | import("@ekwo-ai/camt053").StatementFile;
29
+ /** What a statement file holds, counted: for a dry run, which writes nothing and asks nothing. */
30
+ export declare function describeStatementFile(format: StatementFormat, content: string, ibanCountry?: string | undefined): Record<string, unknown>;
31
+ /**
32
+ * Reads the file and imports its statements. A file the brick cannot read is
33
+ * refused with nothing written; what reads and does not add up comes back in
34
+ * `violations` beside what was imported.
35
+ */
36
+ export declare function importStatementFile(backend: Backend, args: ImportStatementFileArgs): Promise<Record<string, unknown>>;
37
+ //# sourceMappingURL=statements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statements.d.ts","sourceRoot":"","sources":["../../src/books/statements.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAc,KAAK,OAAO,EAAY,MAAM,cAAc,CAAC;AASlE,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,sGAAsG;IACtG,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,gIAkB3G;AAED,kGAAkG;AAClG,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzI;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAyB3H"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * A bank statement file into `import_bank_statement()`.
3
+ *
4
+ * The three bricks that read a statement — `camt053`, `coda`, `cfonb120` —
5
+ * return the same shape, and the schema's `import_bank_statement()` takes it.
6
+ * What is here is the part both surfaces need: picking the brick by the format
7
+ * the caller names, never by the content, and the checksum and the size of the
8
+ * file the statement records as its source. It lived in the MCP server until
9
+ * the command line imported statements too, as `ekwo import camt.053 <file>`.
10
+ */
11
+ import { createHash } from 'node:crypto';
12
+ import { StatementFileError, readCamt053 } from '@ekwo-ai/camt053';
13
+ import { StatementFileError as Cfonb120FileError, readCfonb120 } from '@ekwo-ai/cfonb120';
14
+ import { StatementFileError as CodaFileError, readCoda } from '@ekwo-ai/coda';
15
+ import { BooksError } from './backend.js';
16
+ /** What each format is delivered as, for the attachment the caller may have stored. */
17
+ const STATEMENT_MIME_TYPES = {
18
+ 'camt.053': 'application/xml',
19
+ coda: 'text/plain',
20
+ cfonb120: 'text/plain',
21
+ };
22
+ /**
23
+ * Reads a statement file with the brick of its format, and nothing else: no
24
+ * database. A file the brick cannot read is refused by name.
25
+ */
26
+ export function readStatementFile(format, content, ibanCountry) {
27
+ try {
28
+ if (format === 'coda')
29
+ return readCoda(content);
30
+ if (format === 'cfonb120')
31
+ return readCfonb120(content, ibanCountry === undefined ? {} : { ibanCountry });
32
+ return readCamt053(content);
33
+ }
34
+ catch (error) {
35
+ if (error instanceof StatementFileError ||
36
+ error instanceof CodaFileError ||
37
+ error instanceof Cfonb120FileError) {
38
+ throw new BooksError(`unreadable_statement_file: ${error.message}`, {
39
+ code: error.code,
40
+ hint: `Nothing was imported. The file is not a ${format} this server can read; the message says what stopped it.`,
41
+ });
42
+ }
43
+ throw error;
44
+ }
45
+ }
46
+ /** What a statement file holds, counted: for a dry run, which writes nothing and asks nothing. */
47
+ export function describeStatementFile(format, content, ibanCountry) {
48
+ const file = readStatementFile(format, content, ibanCountry);
49
+ return {
50
+ format,
51
+ version: file.version,
52
+ statements: file.statements.length,
53
+ lines: file.statements.reduce((sum, statement) => sum + statement.lines.length, 0),
54
+ accounts: [...new Set(file.statements.map((statement) => statement.account.identifier.value))],
55
+ violations: file.violations,
56
+ };
57
+ }
58
+ /**
59
+ * Reads the file and imports its statements. A file the brick cannot read is
60
+ * refused with nothing written; what reads and does not add up comes back in
61
+ * `violations` beside what was imported.
62
+ */
63
+ export async function importStatementFile(backend, args) {
64
+ const file = readStatementFile(args.format, args.content, args.iban_country);
65
+ const bytes = Buffer.from(args.content, 'utf8');
66
+ const source = {
67
+ file_name: args.file_name ?? null,
68
+ checksum: `sha256:${createHash('sha256').update(bytes).digest('hex')}`,
69
+ byte_size: bytes.byteLength,
70
+ mime_type: STATEMENT_MIME_TYPES[args.format],
71
+ storage_path: args.storage_path ?? null,
72
+ };
73
+ const statements = await backend.rpc('import_bank_statement', {
74
+ p_company_id: args.company_id,
75
+ p_file: file,
76
+ p_source: source,
77
+ ...(args.bank_account_id !== undefined ? { p_bank_account_id: args.bank_account_id } : {}),
78
+ });
79
+ return {
80
+ format: args.format,
81
+ version: file.version,
82
+ version_verified: 'versionVerified' in file ? file.versionVerified : null,
83
+ checksum: source.checksum,
84
+ statements,
85
+ violations: file.violations,
86
+ note: 'A statement is not an entry: every imported line waits as `pending`, and nothing was booked or paid. Importing the same file again creates nothing; a statement that overlaps an earlier one imports only what is new (`lines_known` is the rest). `warnings` names a missing statement — an opening balance that is not the previous closing one — which is signalled and never refused.',
87
+ };
88
+ }
89
+ //# sourceMappingURL=statements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"statements.js","sourceRoot":"","sources":["../../src/books/statements.ts"],"names":[],"mappings":"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"}
package/dist/schema.d.ts CHANGED
@@ -15,7 +15,7 @@
15
15
  * is not a script, it is a restore.
16
16
  */
17
17
  /** The oldest schema `@ekwo-ai/core` reads. */
18
- export declare const SCHEMA_MIN = "0.5.0";
18
+ export declare const SCHEMA_MIN = "0.7.0";
19
19
  /** `-1`, `0` or `1`, comparing two `major.minor.patch` versions numerically. */
20
20
  export declare function compareSchemaVersions(left: string, right: string): number;
21
21
  /** Whether a database at `installed` is new enough for a package needing `minimum`. */
package/dist/schema.js CHANGED
@@ -15,7 +15,7 @@
15
15
  * is not a script, it is a restore.
16
16
  */
17
17
  /** The oldest schema `@ekwo-ai/core` reads. */
18
- export const SCHEMA_MIN = '0.5.0';
18
+ export const SCHEMA_MIN = '0.7.0';
19
19
  /** `-1`, `0` or `1`, comparing two `major.minor.patch` versions numerically. */
20
20
  export function compareSchemaVersions(left, right) {
21
21
  const parse = (version) => version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekwo-ai/core",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "TypeScript row types and a typed Supabase client for the Ekwo OS accounting schema.",
5
5
  "keywords": ["accounting", "supabase", "postgres", "pcmn", "pcg", "bookkeeping", "ekwo"],
6
6
  "license": "AGPL-3.0-only",
@@ -11,7 +11,7 @@
11
11
  "type": "module",
12
12
  "sideEffects": false,
13
13
  "engines": { "node": ">=20" },
14
- "ekwo": { "schemaMin": "0.5.0" },
14
+ "ekwo": { "schemaMin": "0.7.0" },
15
15
  "files": ["dist", "README.md", "CHANGELOG.md"],
16
16
  "main": "./dist/index.js",
17
17
  "types": "./dist/index.d.ts",
@@ -23,7 +23,13 @@
23
23
  "typecheck": "tsc -p tsconfig.json --noEmit"
24
24
  },
25
25
  "dependencies": {
26
- "@ekwo-ai/fec": "^0.5.0"
26
+ "@ekwo-ai/camt053": "^0.7.0",
27
+ "@ekwo-ai/cfonb120": "^0.7.0",
28
+ "@ekwo-ai/coda": "^0.7.0",
29
+ "@ekwo-ai/fec": "^0.7.0",
30
+ "@ekwo-ai/journal-items": "^0.7.0",
31
+ "@ekwo-ai/journal-report": "^0.7.0",
32
+ "@ekwo-ai/trial-balance": "^0.7.0"
27
33
  },
28
34
  "peerDependencies": {
29
35
  "@supabase/supabase-js": "^2.0.0"