@ekwo-ai/core 0.5.0 → 0.6.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/books/imports.d.ts +125 -0
- package/dist/books/imports.d.ts.map +1 -0
- package/dist/books/imports.js +385 -0
- package/dist/books/imports.js.map +1 -0
- package/dist/books/index.d.ts +2 -0
- package/dist/books/index.d.ts.map +1 -1
- package/dist/books/index.js +2 -0
- package/dist/books/index.js.map +1 -1
- package/dist/books/statements.d.ts +37 -0
- package/dist/books/statements.d.ts.map +1 -0
- package/dist/books/statements.js +89 -0
- package/dist/books/statements.js.map +1 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +1 -1
- package/package.json +9 -3
|
@@ -0,0 +1,125 @@
|
|
|
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
|
+
export interface ImportMapping {
|
|
47
|
+
version: 1;
|
|
48
|
+
source: string;
|
|
49
|
+
accounts: Record<string, string | null>;
|
|
50
|
+
journals: Record<string, string | null>;
|
|
51
|
+
}
|
|
52
|
+
/** Reads the files of one source into the shape `import_books()` takes. */
|
|
53
|
+
export declare function readBooks(source: BookSource, files: BookFile[], options?: ReadBooksOptions): ImportedBooks;
|
|
54
|
+
/** sha256 of the files, in the order given: what `book_imports` keys an import on. */
|
|
55
|
+
export declare function booksChecksum(files: BookFile[]): string;
|
|
56
|
+
interface ChartAccount {
|
|
57
|
+
code: string;
|
|
58
|
+
name: string;
|
|
59
|
+
account_type: string;
|
|
60
|
+
deprecated: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** How a proposed account was found, so the user knows how much to trust it. */
|
|
63
|
+
export type MappingBasis = 'given' | 'exact' | 'same-digits' | 'prefix' | 'none';
|
|
64
|
+
export interface ProposedAccount {
|
|
65
|
+
source: string;
|
|
66
|
+
name: string | null;
|
|
67
|
+
target: string | null;
|
|
68
|
+
basis: MappingBasis;
|
|
69
|
+
}
|
|
70
|
+
export interface Proposal {
|
|
71
|
+
mapping: ImportMapping;
|
|
72
|
+
accounts: ProposedAccount[];
|
|
73
|
+
unmapped_accounts: string[];
|
|
74
|
+
unmapped_journals: string[];
|
|
75
|
+
/** The type of each account of the chart, by code: what says a party is a customer or a supplier. */
|
|
76
|
+
account_types: Record<string, string>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The account of the chart a code of the old books most probably is, and why.
|
|
80
|
+
*
|
|
81
|
+
* Only what the two codes say is read, never a country: the same code; the
|
|
82
|
+
* same digits once the zeros a chart pads with on the right are set aside
|
|
83
|
+
* (`411` and `411000`); and else the account of the chart whose digits are the
|
|
84
|
+
* longest beginning of the old code, three at least (`401ACME` to `401000`).
|
|
85
|
+
* A tie is no answer. Whatever comes out is a proposal the user reads.
|
|
86
|
+
*/
|
|
87
|
+
export declare function proposeAccount(code: string, chart: readonly ChartAccount[]): {
|
|
88
|
+
target: string | null;
|
|
89
|
+
basis: MappingBasis;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* The correspondence for these books in this company: what the caller gave,
|
|
93
|
+
* and a proposal for everything it did not.
|
|
94
|
+
*/
|
|
95
|
+
export declare function proposeMapping(backend: Backend, companyId: string, books: ImportedBooks, given?: Partial<ImportMapping>): Promise<Proposal>;
|
|
96
|
+
export interface ImportBooksArgs {
|
|
97
|
+
company_id: string;
|
|
98
|
+
source: BookSource;
|
|
99
|
+
files: BookFile[];
|
|
100
|
+
/** A correspondence saved from an earlier run. What it answers wins over the proposal. */
|
|
101
|
+
mapping?: Partial<ImportMapping> | undefined;
|
|
102
|
+
/** Show what would be written, write nothing. */
|
|
103
|
+
dry_run?: boolean | undefined;
|
|
104
|
+
/** Open the fiscal years the entries fall in, where the company has none. */
|
|
105
|
+
open_years?: boolean | undefined;
|
|
106
|
+
/** The first day of the year a trial balance opens, where the file says none. */
|
|
107
|
+
opening_date?: string | undefined;
|
|
108
|
+
/** Let a trial balance carry income and expense accounts: books taken over in the middle of a year. */
|
|
109
|
+
allow_result_accounts?: boolean | undefined;
|
|
110
|
+
/** Keep the numbers the entries had, where the country allows a number chosen by hand or the caller holds entries.import. */
|
|
111
|
+
keep_numbers?: boolean | undefined;
|
|
112
|
+
encoding?: ReadBooksOptions['encoding'];
|
|
113
|
+
date_order?: DateOrder | undefined;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Reads the files, settles the correspondence and hands the books to
|
|
117
|
+
* `import_books()`. With `dry_run` the database rehearses the import and rolls
|
|
118
|
+
* it back; without, it posts all of it or nothing.
|
|
119
|
+
*
|
|
120
|
+
* Refused before the database is asked: books whose reader found something
|
|
121
|
+
* that does not add up, an account or a journal with no answer, a currency the
|
|
122
|
+
* file names that is not the company's.
|
|
123
|
+
*/
|
|
124
|
+
export declare function importBooks(backend: Backend, args: ImportBooksArgs): Promise<Record<string, unknown>>;
|
|
125
|
+
//# 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,385 @@
|
|
|
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
|
+
/**
|
|
77
|
+
* The account of the chart a code of the old books most probably is, and why.
|
|
78
|
+
*
|
|
79
|
+
* Only what the two codes say is read, never a country: the same code; the
|
|
80
|
+
* same digits once the zeros a chart pads with on the right are set aside
|
|
81
|
+
* (`411` and `411000`); and else the account of the chart whose digits are the
|
|
82
|
+
* longest beginning of the old code, three at least (`401ACME` to `401000`).
|
|
83
|
+
* A tie is no answer. Whatever comes out is a proposal the user reads.
|
|
84
|
+
*/
|
|
85
|
+
export function proposeAccount(code, chart) {
|
|
86
|
+
const live = chart.filter((account) => !account.deprecated);
|
|
87
|
+
if (live.some((account) => account.code === code))
|
|
88
|
+
return { target: code, basis: 'exact' };
|
|
89
|
+
const same = live.filter((account) => unpadded(account.code) === unpadded(code));
|
|
90
|
+
if (same.length === 1)
|
|
91
|
+
return { target: same[0].code, basis: 'same-digits' };
|
|
92
|
+
let best = [];
|
|
93
|
+
let length = 2;
|
|
94
|
+
for (const account of live) {
|
|
95
|
+
const digits = unpadded(account.code);
|
|
96
|
+
if (digits.length > length && code.startsWith(digits)) {
|
|
97
|
+
best = [account];
|
|
98
|
+
length = digits.length;
|
|
99
|
+
}
|
|
100
|
+
else if (digits.length === length && length > 2 && code.startsWith(digits)) {
|
|
101
|
+
best.push(account);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (best.length === 1)
|
|
105
|
+
return { target: best[0].code, basis: 'prefix' };
|
|
106
|
+
return { target: null, basis: 'none' };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The correspondence for these books in this company: what the caller gave,
|
|
110
|
+
* and a proposal for everything it did not.
|
|
111
|
+
*/
|
|
112
|
+
export async function proposeMapping(backend, companyId, books, given = {}) {
|
|
113
|
+
const [chart, journals, openingCode] = await Promise.all([
|
|
114
|
+
wholeChart(backend, companyId),
|
|
115
|
+
backend.select({
|
|
116
|
+
table: 'journals',
|
|
117
|
+
columns: ['code', 'journal_type'],
|
|
118
|
+
where: [
|
|
119
|
+
{ column: 'company_id', op: 'eq', value: companyId },
|
|
120
|
+
{ column: 'active', op: 'eq', value: true },
|
|
121
|
+
],
|
|
122
|
+
order: [{ column: 'code' }],
|
|
123
|
+
}),
|
|
124
|
+
openingJournalCode(backend, companyId),
|
|
125
|
+
]);
|
|
126
|
+
const names = new Map(books.accounts.map((account) => [account.code, account.name]));
|
|
127
|
+
const codes = [...new Set([...books.accounts.map((a) => a.code), ...usedAccounts(books)])].sort();
|
|
128
|
+
const accounts = codes.map((code) => {
|
|
129
|
+
const answer = given.accounts?.[code];
|
|
130
|
+
if (answer !== undefined && answer !== null)
|
|
131
|
+
return { source: code, name: names.get(code) ?? null, target: answer, basis: 'given' };
|
|
132
|
+
return { source: code, name: names.get(code) ?? null, ...proposeAccount(code, chart) };
|
|
133
|
+
});
|
|
134
|
+
const known = new Set(journals.map((journal) => journal.code));
|
|
135
|
+
const general = journals.find((journal) => journal.journal_type === 'general')?.code ?? null;
|
|
136
|
+
const journalMap = {};
|
|
137
|
+
for (const source of [...new Set(books.entries.map((entry) => entry.journal ?? NO_JOURNAL))].sort()) {
|
|
138
|
+
const answer = given.journals?.[source];
|
|
139
|
+
if (answer !== undefined && answer !== null)
|
|
140
|
+
journalMap[source] = answer;
|
|
141
|
+
else if (openingCode !== null && source.toUpperCase() === openingCode)
|
|
142
|
+
journalMap[source] = OPENING;
|
|
143
|
+
else if (known.has(source.toUpperCase()))
|
|
144
|
+
journalMap[source] = source.toUpperCase();
|
|
145
|
+
else
|
|
146
|
+
journalMap[source] = general;
|
|
147
|
+
}
|
|
148
|
+
// Only what these books use is kept: a saved correspondence from another
|
|
149
|
+
// file does not carry answers for accounts this one never names.
|
|
150
|
+
const used = new Set(usedAccounts(books));
|
|
151
|
+
return {
|
|
152
|
+
mapping: {
|
|
153
|
+
version: 1,
|
|
154
|
+
source: books.format,
|
|
155
|
+
accounts: Object.fromEntries(accounts.map((account) => [account.source, account.target])),
|
|
156
|
+
journals: journalMap,
|
|
157
|
+
},
|
|
158
|
+
accounts,
|
|
159
|
+
unmapped_accounts: accounts.filter((a) => a.target === null && used.has(a.source)).map((a) => a.source),
|
|
160
|
+
unmapped_journals: Object.entries(journalMap).filter(([, target]) => target === null).map(([source]) => source),
|
|
161
|
+
account_types: Object.fromEntries(chart.map((account) => [account.code, account.account_type])),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Every account of the chart, a page at a time. A chart transcribed from a
|
|
166
|
+
* regulation holds more than a thousand accounts, and a PostgREST project
|
|
167
|
+
* returns a thousand rows unless asked for the next ones: a proposal made on
|
|
168
|
+
* the first thousand would call an account missing that is not.
|
|
169
|
+
*/
|
|
170
|
+
async function wholeChart(backend, companyId) {
|
|
171
|
+
const page = 1000;
|
|
172
|
+
const chart = [];
|
|
173
|
+
for (;;) {
|
|
174
|
+
const last = chart[chart.length - 1]?.code;
|
|
175
|
+
const rows = await backend.select({
|
|
176
|
+
table: 'accounts',
|
|
177
|
+
columns: ['code', 'name', 'account_type', 'deprecated'],
|
|
178
|
+
where: [
|
|
179
|
+
{ column: 'company_id', op: 'eq', value: companyId },
|
|
180
|
+
...(last === undefined ? [] : [{ column: 'code', op: 'gt', value: last }]),
|
|
181
|
+
],
|
|
182
|
+
order: [{ column: 'code' }],
|
|
183
|
+
limit: page,
|
|
184
|
+
});
|
|
185
|
+
chart.push(...rows);
|
|
186
|
+
if (rows.length < page)
|
|
187
|
+
return chart;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/** Every account a line of these books names. */
|
|
191
|
+
function usedAccounts(books) {
|
|
192
|
+
const used = new Set();
|
|
193
|
+
for (const entry of books.entries)
|
|
194
|
+
for (const line of entry.lines)
|
|
195
|
+
used.add(line.account);
|
|
196
|
+
for (const line of books.opening)
|
|
197
|
+
used.add(line.account);
|
|
198
|
+
return [...used];
|
|
199
|
+
}
|
|
200
|
+
/** The code of the journal the pack of this company opens its years on, or null. */
|
|
201
|
+
async function openingJournalCode(backend, companyId) {
|
|
202
|
+
const rows = await backend.select({
|
|
203
|
+
table: 'journals',
|
|
204
|
+
columns: ['code'],
|
|
205
|
+
where: [
|
|
206
|
+
{ column: 'company_id', op: 'eq', value: companyId },
|
|
207
|
+
{ column: 'journal_type', op: 'eq', value: 'opening' },
|
|
208
|
+
{ column: 'active', op: 'eq', value: true },
|
|
209
|
+
],
|
|
210
|
+
order: [{ column: 'code' }],
|
|
211
|
+
});
|
|
212
|
+
return rows.length === 1 ? rows[0].code : null;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Reads the files, settles the correspondence and hands the books to
|
|
216
|
+
* `import_books()`. With `dry_run` the database rehearses the import and rolls
|
|
217
|
+
* it back; without, it posts all of it or nothing.
|
|
218
|
+
*
|
|
219
|
+
* Refused before the database is asked: books whose reader found something
|
|
220
|
+
* that does not add up, an account or a journal with no answer, a currency the
|
|
221
|
+
* file names that is not the company's.
|
|
222
|
+
*/
|
|
223
|
+
export async function importBooks(backend, args) {
|
|
224
|
+
const books = readBooks(args.source, args.files, { encoding: args.encoding, date_order: args.date_order });
|
|
225
|
+
const proposal = await proposeMapping(backend, args.company_id, books, args.mapping ?? {});
|
|
226
|
+
const read = {
|
|
227
|
+
accounts: books.accounts.length,
|
|
228
|
+
contacts: books.contacts.length,
|
|
229
|
+
entries: books.entries.length,
|
|
230
|
+
lines: books.entries.reduce((sum, entry) => sum + entry.lines.length, 0),
|
|
231
|
+
opening_lines: books.opening.length,
|
|
232
|
+
};
|
|
233
|
+
const answer = {
|
|
234
|
+
dry_run: args.dry_run === true,
|
|
235
|
+
source: args.source,
|
|
236
|
+
read,
|
|
237
|
+
mapping: proposal.mapping,
|
|
238
|
+
accounts: proposal.accounts,
|
|
239
|
+
unmapped_accounts: proposal.unmapped_accounts,
|
|
240
|
+
unmapped_journals: proposal.unmapped_journals,
|
|
241
|
+
violations: books.violations,
|
|
242
|
+
};
|
|
243
|
+
const company = await backend.select({
|
|
244
|
+
table: 'companies',
|
|
245
|
+
columns: ['currency_code'],
|
|
246
|
+
where: [{ column: 'id', op: 'eq', value: args.company_id }],
|
|
247
|
+
});
|
|
248
|
+
const currency = company[0]?.currency_code ?? null;
|
|
249
|
+
if (company[0] === undefined)
|
|
250
|
+
throw new BooksError(`not_found: company ${args.company_id}. Either it does not exist, or you are not a member of it.`);
|
|
251
|
+
const blocking = [];
|
|
252
|
+
if (books.currency !== null && currency !== null && books.currency.toUpperCase() !== currency) {
|
|
253
|
+
blocking.push(`import_currency_mismatch: the files are in ${books.currency} and the company keeps its books in ${currency}`);
|
|
254
|
+
}
|
|
255
|
+
if (books.violations.length > 0) {
|
|
256
|
+
blocking.push(`import_violations: the files do not add up in ${books.violations.length} place${books.violations.length === 1 ? '' : 's'}; ` +
|
|
257
|
+
books.violations.slice(0, 5).map((v) => `${v.row === null ? '' : `row ${v.row}: `}${v.message}`).join('; '));
|
|
258
|
+
}
|
|
259
|
+
if (proposal.unmapped_accounts.length > 0) {
|
|
260
|
+
blocking.push(`import_unmapped_accounts: no account of the chart answers for ${proposal.unmapped_accounts.join(', ')}. Say which in the correspondence`);
|
|
261
|
+
}
|
|
262
|
+
if (proposal.unmapped_journals.length > 0) {
|
|
263
|
+
blocking.push(`import_unmapped_journals: no journal answers for ${proposal.unmapped_journals.join(', ')}. Say which in the correspondence`);
|
|
264
|
+
}
|
|
265
|
+
if (blocking.length > 0) {
|
|
266
|
+
if (args.dry_run === true) {
|
|
267
|
+
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.' };
|
|
268
|
+
}
|
|
269
|
+
throw new BooksError(blocking.join('\n'), {
|
|
270
|
+
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.',
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
const payload = buildPayload(books, proposal.mapping, proposal.account_types, currency, args);
|
|
274
|
+
payload['checksum'] = booksChecksum(args.files);
|
|
275
|
+
payload['file_names'] = args.files.map((file) => file.name);
|
|
276
|
+
const [result] = await backend.rpc('import_books', {
|
|
277
|
+
p_company_id: args.company_id,
|
|
278
|
+
p_books: payload,
|
|
279
|
+
p_dry_run: args.dry_run === true,
|
|
280
|
+
p_open_years: args.open_years === true,
|
|
281
|
+
p_allow_result_accounts: args.allow_result_accounts === true,
|
|
282
|
+
});
|
|
283
|
+
const written = (result?.['import_books'] ?? result);
|
|
284
|
+
return {
|
|
285
|
+
...answer,
|
|
286
|
+
result: written ?? null,
|
|
287
|
+
refusals: [],
|
|
288
|
+
note: args.dry_run === true
|
|
289
|
+
? '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.'
|
|
290
|
+
: '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.',
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/** The books, translated into this company's codes, in the shape `import_books()` takes. */
|
|
294
|
+
function buildPayload(books, mapping, accountTypes, currency, args) {
|
|
295
|
+
const account = (code) => mapping.accounts[code];
|
|
296
|
+
// What a party is follows from where its lines are booked: on a receivable
|
|
297
|
+
// it is a customer, on a payable a supplier, on both it is both.
|
|
298
|
+
const roles = new Map();
|
|
299
|
+
const line = (source) => {
|
|
300
|
+
if (source.contact !== null) {
|
|
301
|
+
const seen = roles.get(source.contact) ?? new Set();
|
|
302
|
+
const type = accountTypes[account(source.account)];
|
|
303
|
+
if (type === 'asset_receivable')
|
|
304
|
+
seen.add('customer');
|
|
305
|
+
if (type === 'liability_payable')
|
|
306
|
+
seen.add('supplier');
|
|
307
|
+
roles.set(source.contact, seen);
|
|
308
|
+
}
|
|
309
|
+
const foreign = source.currency !== null && source.amountCurrency !== null && source.currency.toUpperCase() !== currency;
|
|
310
|
+
return {
|
|
311
|
+
account_code: account(source.account),
|
|
312
|
+
contact_key: source.contact,
|
|
313
|
+
label: source.label,
|
|
314
|
+
debit: source.debit,
|
|
315
|
+
credit: source.credit,
|
|
316
|
+
currency_code: foreign ? source.currency.toUpperCase() : null,
|
|
317
|
+
amount_currency: foreign ? source.amountCurrency : null,
|
|
318
|
+
date_maturity: source.dueDate,
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
const entries = [];
|
|
322
|
+
const openingLines = [];
|
|
323
|
+
let openingDate = null;
|
|
324
|
+
for (const entry of books.entries) {
|
|
325
|
+
const journal = mapping.journals[entry.journal ?? NO_JOURNAL];
|
|
326
|
+
if (journal === OPENING) {
|
|
327
|
+
if (openingDate !== null && openingDate !== entry.date) {
|
|
328
|
+
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`);
|
|
329
|
+
}
|
|
330
|
+
openingDate = entry.date;
|
|
331
|
+
openingLines.push(...entry.lines.map(line));
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
entries.push({
|
|
335
|
+
journal_code: journal,
|
|
336
|
+
date: entry.date,
|
|
337
|
+
number: args.keep_numbers === true ? entry.number : null,
|
|
338
|
+
reference: entry.reference ?? entry.number,
|
|
339
|
+
description: entry.description,
|
|
340
|
+
lines: entry.lines.map(line),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
if (books.opening.length > 0) {
|
|
344
|
+
if (openingLines.length > 0) {
|
|
345
|
+
throw new BooksError('import_two_openings: these books carry a trial balance and entries mapped to the opening; one opening per import');
|
|
346
|
+
}
|
|
347
|
+
if (args.opening_date === undefined) {
|
|
348
|
+
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).');
|
|
349
|
+
}
|
|
350
|
+
openingDate = args.opening_date;
|
|
351
|
+
openingLines.push(...books.opening.map(line));
|
|
352
|
+
}
|
|
353
|
+
else if (args.opening_date !== undefined && openingDate === null) {
|
|
354
|
+
throw new BooksError('unexpected_opening_date: an opening date was given and these books carry no balance to open');
|
|
355
|
+
}
|
|
356
|
+
const typeOf = (key) => {
|
|
357
|
+
const seen = roles.get(key) ?? new Set();
|
|
358
|
+
return seen.size === 2 ? 'both' : seen.size === 1 ? [...seen][0] : 'other';
|
|
359
|
+
};
|
|
360
|
+
const contacts = books.contacts
|
|
361
|
+
.filter((contact) => roles.has(contact.code))
|
|
362
|
+
.map((contact) => ({
|
|
363
|
+
key: contact.code,
|
|
364
|
+
name: contact.name,
|
|
365
|
+
auxiliary_code: contact.code === contact.name ? null : contact.code,
|
|
366
|
+
contact_type: typeOf(contact.code),
|
|
367
|
+
vat_number: contact.vatNumber,
|
|
368
|
+
registration_number: contact.registrationNumber,
|
|
369
|
+
email: contact.email,
|
|
370
|
+
country: contact.country,
|
|
371
|
+
}));
|
|
372
|
+
// A party named on a line that the files list nowhere else is still a party.
|
|
373
|
+
for (const key of roles.keys()) {
|
|
374
|
+
if (!contacts.some((contact) => contact.key === key)) {
|
|
375
|
+
contacts.push({ key, name: key, auxiliary_code: null, contact_type: typeOf(key), vat_number: null, registration_number: null, email: null, country: null });
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
source: books.format,
|
|
380
|
+
contacts,
|
|
381
|
+
entries,
|
|
382
|
+
opening: openingDate === null ? null : { date: openingDate, lines: openingLines },
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
//# 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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"}
|
package/dist/books/index.d.ts
CHANGED
|
@@ -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"}
|
package/dist/books/index.js
CHANGED
package/dist/books/index.js.map
CHANGED
|
@@ -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.
|
|
18
|
+
export declare const SCHEMA_MIN = "0.6.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.
|
|
18
|
+
export const SCHEMA_MIN = '0.6.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.
|
|
3
|
+
"version": "0.6.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.
|
|
14
|
+
"ekwo": { "schemaMin": "0.6.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/
|
|
26
|
+
"@ekwo-ai/camt053": "^0.6.0",
|
|
27
|
+
"@ekwo-ai/cfonb120": "^0.6.0",
|
|
28
|
+
"@ekwo-ai/coda": "^0.6.0",
|
|
29
|
+
"@ekwo-ai/fec": "^0.6.0",
|
|
30
|
+
"@ekwo-ai/journal-items": "^0.6.0",
|
|
31
|
+
"@ekwo-ai/journal-report": "^0.6.0",
|
|
32
|
+
"@ekwo-ai/trial-balance": "^0.6.0"
|
|
27
33
|
},
|
|
28
34
|
"peerDependencies": {
|
|
29
35
|
"@supabase/supabase-js": "^2.0.0"
|