@rvboris/sberparse 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +42 -0
- package/dist/balance-checker.d.ts +17 -0
- package/dist/balance-checker.d.ts.map +1 -0
- package/dist/balance-checker.js +34 -0
- package/dist/balance-checker.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +31 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/index.d.ts +17 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +70 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/converter.d.ts +9 -0
- package/dist/converter.d.ts.map +1 -0
- package/dist/converter.js +101 -0
- package/dist/converter.js.map +1 -0
- package/dist/csv-writer.d.ts +10 -0
- package/dist/csv-writer.d.ts.map +1 -0
- package/dist/csv-writer.js +71 -0
- package/dist/csv-writer.js.map +1 -0
- package/dist/exceptions.d.ts +31 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/exceptions.js +46 -0
- package/dist/exceptions.js.map +1 -0
- package/dist/extractor-selector.d.ts +16 -0
- package/dist/extractor-selector.d.ts.map +1 -0
- package/dist/extractor-selector.js +48 -0
- package/dist/extractor-selector.js.map +1 -0
- package/dist/extractor.d.ts +58 -0
- package/dist/extractor.d.ts.map +1 -0
- package/dist/extractor.js +65 -0
- package/dist/extractor.js.map +1 -0
- package/dist/extractors/index.d.ts +10 -0
- package/dist/extractors/index.d.ts.map +1 -0
- package/dist/extractors/index.js +14 -0
- package/dist/extractors/index.js.map +1 -0
- package/dist/extractors/sber-debit-2510.d.ts +15 -0
- package/dist/extractors/sber-debit-2510.d.ts.map +1 -0
- package/dist/extractors/sber-debit-2510.js +157 -0
- package/dist/extractors/sber-debit-2510.js.map +1 -0
- package/dist/extractors/sber-debit-2603.d.ts +16 -0
- package/dist/extractors/sber-debit-2603.d.ts.map +1 -0
- package/dist/extractors/sber-debit-2603.js +161 -0
- package/dist/extractors/sber-debit-2603.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/json-writer.d.ts +11 -0
- package/dist/json-writer.d.ts.map +1 -0
- package/dist/json-writer.js +38 -0
- package/dist/json-writer.js.map +1 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +21 -0
- package/dist/logger.js.map +1 -0
- package/dist/pdf-parser.d.ts +14 -0
- package/dist/pdf-parser.d.ts.map +1 -0
- package/dist/pdf-parser.js +31 -0
- package/dist/pdf-parser.js.map +1 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/unidecode.d.ts +6 -0
- package/dist/unidecode.d.ts.map +1 -0
- package/dist/unidecode.js +92 -0
- package/dist/unidecode.js.map +1 -0
- package/dist/utils.d.ts +27 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +65 -0
- package/dist/utils.js.map +1 -0
- package/package.json +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 sbertoactual contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# sberparse
|
|
2
|
+
|
|
3
|
+
Конвертация выписок Сбербанка из PDF в JSON/CSV формат.
|
|
4
|
+
|
|
5
|
+
## Установка
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -g @rvboris/sberparse
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Использование
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Конвертация в CSV (по умолчанию)
|
|
15
|
+
sberparse ./vypiska.pdf
|
|
16
|
+
|
|
17
|
+
# Конвертация в JSON
|
|
18
|
+
sberparse ./vypiska.pdf -t json
|
|
19
|
+
|
|
20
|
+
# Указать конкретный выходной файл
|
|
21
|
+
sberparse ./vypiska.pdf -o ./output/my-extract
|
|
22
|
+
|
|
23
|
+
# Принудительный формат (skip auto-detect)
|
|
24
|
+
sberparse ./vypiska.pdf -f SBER_DEBIT_2603
|
|
25
|
+
|
|
26
|
+
# Обратный порядок транзакций
|
|
27
|
+
sberparse ./vypiska.pdf -r
|
|
28
|
+
|
|
29
|
+
# Без проверки баланса
|
|
30
|
+
sberparse ./vypiska.pdf -b
|
|
31
|
+
|
|
32
|
+
# Сохранить промежуточный текстовый файл
|
|
33
|
+
sberparse ./vypiska.pdf --interm
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Поддерживаемые форматы
|
|
37
|
+
|
|
38
|
+
- SBER_DEBIT_2603 - Дебетовая карта образца марта 2026
|
|
39
|
+
|
|
40
|
+
## Лицензия
|
|
41
|
+
|
|
42
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Decimal } from "decimal.js";
|
|
2
|
+
import type { Transaction } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Проверяет баланс транзакций
|
|
5
|
+
* @param transactions Список транзакций
|
|
6
|
+
* @param balance Баланс из шапки выписки
|
|
7
|
+
* @param columnNameForBalance Название колонки для расчёта
|
|
8
|
+
* @throws {BalanceVerificationError} если баланс не совпадает
|
|
9
|
+
*/
|
|
10
|
+
export declare function checkTransactionsBalance(transactions: Transaction[], balance: Decimal, columnNameForBalance: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* Переворачивает порядок транзакций
|
|
13
|
+
* @param transactions Список транзакций
|
|
14
|
+
* @returns Перевёрнутый список
|
|
15
|
+
*/
|
|
16
|
+
export declare function reverseTransactions(transactions: Transaction[]): Transaction[];
|
|
17
|
+
//# sourceMappingURL=balance-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balance-checker.d.ts","sourceRoot":"","sources":["../src/balance-checker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,EAAE,OAAO,EAChB,oBAAoB,EAAE,MAAM,GAC3B,IAAI,CAoBN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAE9E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Decimal } from "decimal.js";
|
|
2
|
+
import { BalanceVerificationError } from "./exceptions.js";
|
|
3
|
+
/**
|
|
4
|
+
* Проверяет баланс транзакций
|
|
5
|
+
* @param transactions Список транзакций
|
|
6
|
+
* @param balance Баланс из шапки выписки
|
|
7
|
+
* @param columnNameForBalance Название колонки для расчёта
|
|
8
|
+
* @throws {BalanceVerificationError} если баланс не совпадает
|
|
9
|
+
*/
|
|
10
|
+
export function checkTransactionsBalance(transactions, balance, columnNameForBalance) {
|
|
11
|
+
let calculatedBalance = new Decimal(0);
|
|
12
|
+
for (const transaction of transactions) {
|
|
13
|
+
const value = transaction[columnNameForBalance];
|
|
14
|
+
if (typeof value === "number") {
|
|
15
|
+
calculatedBalance = calculatedBalance.plus(value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const difference = balance.minus(calculatedBalance).abs();
|
|
19
|
+
if (difference.greaterThan(0.01)) {
|
|
20
|
+
throw new BalanceVerificationError(`Ошибка проверки баланса по транзакциям:\n` +
|
|
21
|
+
` Вычисленный баланс по информации в шапке выписки = ${balance.toFixed(2)}\n` +
|
|
22
|
+
` Вычисленный баланс по всем транзакциям = ${calculatedBalance.toFixed(2)}\n` +
|
|
23
|
+
` Разница = ${difference.toFixed(2)}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Переворачивает порядок транзакций
|
|
28
|
+
* @param transactions Список транзакций
|
|
29
|
+
* @returns Перевёрнутый список
|
|
30
|
+
*/
|
|
31
|
+
export function reverseTransactions(transactions) {
|
|
32
|
+
return [...transactions].reverse();
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=balance-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"balance-checker.js","sourceRoot":"","sources":["../src/balance-checker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAG3D;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACtC,YAA2B,EAC3B,OAAgB,EAChB,oBAA4B;IAE5B,IAAI,iBAAiB,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAEvC,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,KAAK,GAAI,WAAiD,CAAC,oBAAoB,CAAC,CAAC;QACvF,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,iBAAiB,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,EAAE,CAAC;IAE1D,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,wBAAwB,CAChC,2CAA2C;YACzC,wDAAwD,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;YAC9E,8CAA8C,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;YAC9E,eAAe,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CACzC,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAA2B;IAC7D,OAAO,CAAC,GAAG,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC;AACrC,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { run } from "@oclif/core";
|
|
5
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
6
|
+
import { logger } from "./logger.js";
|
|
7
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
8
|
+
const root = path.resolve(path.dirname(currentFile), "..");
|
|
9
|
+
const isSource = currentFile.endsWith(`${path.sep}src${path.sep}cli.ts`);
|
|
10
|
+
const commandsTarget = isSource ? "./src/commands/index.ts" : "./dist/commands/index.js";
|
|
11
|
+
const pjson = {
|
|
12
|
+
...packageJson,
|
|
13
|
+
oclif: {
|
|
14
|
+
...packageJson.oclif,
|
|
15
|
+
commands: {
|
|
16
|
+
strategy: "single",
|
|
17
|
+
target: commandsTarget,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
await run(process.argv.slice(2), { root, pjson }).catch((error) => {
|
|
22
|
+
const hasOclif = typeof error === "object" &&
|
|
23
|
+
error !== null &&
|
|
24
|
+
"oclif" in error &&
|
|
25
|
+
typeof error.oclif === "object";
|
|
26
|
+
if (!hasOclif) {
|
|
27
|
+
logger.error `Неожиданная ошибка: ${error}`;
|
|
28
|
+
}
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,WAAW,MAAM,iBAAiB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACnD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;AAC3D,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;AACzE,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,0BAA0B,CAAC;AAEzF,MAAM,KAAK,GAAG;IACZ,GAAG,WAAW;IACd,KAAK,EAAE;QACL,GAAG,WAAW,CAAC,KAAK;QACpB,QAAQ,EAAE;YACR,QAAQ,EAAE,QAAiB;YAC3B,MAAM,EAAE,cAAc;SACvB;KACF;CACF,CAAC;AAEF,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACzE,MAAM,QAAQ,GACZ,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAO,IAAI,KAAK;QAChB,OAAQ,KAAuC,CAAC,KAAK,KAAK,QAAQ,CAAC;IAErE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,KAAK,CAAA,uBAAuB,KAAK,EAAE,CAAC;IAC7C,CAAC;IAED,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class Convert extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
inputFile: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
type: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
reverse: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
balanceCheck: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
interm: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,OAAO,EAAS,MAAM,aAAa,CAAC;AAMnD,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,OAAO;IAC1C,MAAM,CAAC,WAAW,SAAqD;IAEvE,MAAM,CAAC,IAAI;;MAKT;IAEF,MAAM,CAAC,KAAK;;;;;;;MA+BV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsB3B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Args, Command, Flags } from "@oclif/core";
|
|
2
|
+
import { convertPdf } from "../converter.js";
|
|
3
|
+
import { SberParseError } from "../exceptions.js";
|
|
4
|
+
import { extractorsList } from "../extractors/index.js";
|
|
5
|
+
import { logger } from "../logger.js";
|
|
6
|
+
export default class Convert extends Command {
|
|
7
|
+
static description = "Конвертация выписок Сбербанка из PDF в JSON/CSV";
|
|
8
|
+
static args = {
|
|
9
|
+
inputFile: Args.string({
|
|
10
|
+
description: "Входной PDF файл",
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static flags = {
|
|
15
|
+
output: Flags.string({
|
|
16
|
+
char: "o",
|
|
17
|
+
description: "Имя выходного файла (без расширения)",
|
|
18
|
+
}),
|
|
19
|
+
format: Flags.string({
|
|
20
|
+
char: "f",
|
|
21
|
+
description: `Принудительно использовать формат (${extractorsList
|
|
22
|
+
.map((e) => e.name)
|
|
23
|
+
.join(", ")})`,
|
|
24
|
+
}),
|
|
25
|
+
type: Flags.string({
|
|
26
|
+
char: "t",
|
|
27
|
+
description: "Тип выходного файла: json или csv",
|
|
28
|
+
options: ["json", "csv"],
|
|
29
|
+
default: "csv",
|
|
30
|
+
}),
|
|
31
|
+
reverse: Flags.boolean({
|
|
32
|
+
char: "r",
|
|
33
|
+
description: "Изменить порядок транзакций на обратный",
|
|
34
|
+
default: false,
|
|
35
|
+
}),
|
|
36
|
+
balanceCheck: Flags.boolean({
|
|
37
|
+
description: "Игнорировать результаты сверки баланса",
|
|
38
|
+
allowNo: true,
|
|
39
|
+
default: true,
|
|
40
|
+
}),
|
|
41
|
+
interm: Flags.boolean({
|
|
42
|
+
description: "Сохранить промежуточный текстовый файл",
|
|
43
|
+
default: false,
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
async run() {
|
|
47
|
+
const { args, flags } = await this.parse(Convert);
|
|
48
|
+
try {
|
|
49
|
+
await convertPdf(args.inputFile, {
|
|
50
|
+
output: flags.output,
|
|
51
|
+
format: flags.format,
|
|
52
|
+
type: flags.type,
|
|
53
|
+
reverse: flags.reverse,
|
|
54
|
+
balance_check: flags.balanceCheck,
|
|
55
|
+
interm: flags.interm,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error instanceof SberParseError) {
|
|
60
|
+
logger.error `Ошибка: ${error.message}`;
|
|
61
|
+
this.error(error.message, { exit: 1 });
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
logger.error `Неожиданная ошибка: ${error}`;
|
|
65
|
+
this.error("Unexpected error", { exit: 1 });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,OAAO;IAC1C,MAAM,CAAC,WAAW,GAAG,iDAAiD,CAAC;IAEvE,MAAM,CAAC,IAAI,GAAG;QACZ,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;YACrB,WAAW,EAAE,kBAAkB;YAC/B,QAAQ,EAAE,IAAI;SACf,CAAC;KACH,CAAC;IAEF,MAAM,CAAC,KAAK,GAAG;QACb,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,sCAAsC;SACpD,CAAC;QACF,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,sCAAsC,cAAc;iBAC9D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;iBAClB,IAAI,CAAC,IAAI,CAAC,GAAG;SACjB,CAAC;QACF,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;YACjB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,mCAAmC;YAChD,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;YACxB,OAAO,EAAE,KAAK;SACf,CAAC;QACF,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC;YACrB,IAAI,EAAE,GAAG;YACT,WAAW,EAAE,yCAAyC;YACtD,OAAO,EAAE,KAAK;SACf,CAAC;QACF,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC;YAC1B,WAAW,EAAE,wCAAwC;YACrD,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI;SACd,CAAC;QACF,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC;YACpB,WAAW,EAAE,wCAAwC;YACrD,OAAO,EAAE,KAAK;SACf,CAAC;KACH,CAAC;IAEF,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE;gBAC/B,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,IAAI,EAAE,KAAK,CAAC,IAAsB;gBAClC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,aAAa,EAAE,KAAK,CAAC,YAAY;gBACjC,MAAM,EAAE,KAAK,CAAC,MAAM;aACrB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;gBACpC,MAAM,CAAC,KAAK,CAAA,WAAW,KAAK,CAAC,OAAO,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,KAAK,CAAA,uBAAuB,KAAK,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CLIOptions, ExtractorResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Конвертирует PDF файл в JSON/CSV
|
|
4
|
+
* @param inputFileName Путь к входному PDF файлу
|
|
5
|
+
* @param options Опции CLI
|
|
6
|
+
* @returns Информация о результате
|
|
7
|
+
*/
|
|
8
|
+
export declare function convertPdf(inputFileName: string, options: CLIOptions): Promise<ExtractorResult>;
|
|
9
|
+
//# sourceMappingURL=converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converter.d.ts","sourceRoot":"","sources":["../src/converter.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE9D;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,eAAe,CAAC,CAoG1B"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { checkTransactionsBalance, reverseTransactions } from "./balance-checker.js";
|
|
4
|
+
import { writeTransactionsToCsv } from "./csv-writer.js";
|
|
5
|
+
import { BalanceVerificationError, UserInputError } from "./exceptions.js";
|
|
6
|
+
import { determineExtractorAuto, determineExtractorByName } from "./extractor-selector.js";
|
|
7
|
+
import { writeTransactionsToJson } from "./json-writer.js";
|
|
8
|
+
import { logger } from "./logger.js";
|
|
9
|
+
import { pdfToText } from "./pdf-parser.js";
|
|
10
|
+
/**
|
|
11
|
+
* Конвертирует PDF файл в JSON/CSV
|
|
12
|
+
* @param inputFileName Путь к входному PDF файлу
|
|
13
|
+
* @param options Опции CLI
|
|
14
|
+
* @returns Информация о результате
|
|
15
|
+
*/
|
|
16
|
+
export async function convertPdf(inputFileName, options) {
|
|
17
|
+
logger.info `${"*".repeat(30)}`;
|
|
18
|
+
logger.info `Конвертируем файл ${inputFileName}`;
|
|
19
|
+
// Проверяем расширение
|
|
20
|
+
const ext = path.extname(inputFileName).toLowerCase();
|
|
21
|
+
if (ext !== ".pdf") {
|
|
22
|
+
throw new UserInputError(`Неподдерживаемое расширение файла: ${ext}`);
|
|
23
|
+
}
|
|
24
|
+
// Конвертируем PDF в текст
|
|
25
|
+
const bankText = await pdfToText(inputFileName);
|
|
26
|
+
// Сохраняем промежуточный файл, если запрошено
|
|
27
|
+
if (options.interm) {
|
|
28
|
+
const txtFileName = inputFileName.replace(/\.pdf$/i, ".txt");
|
|
29
|
+
await fs.writeFile(txtFileName, bankText, "utf-8");
|
|
30
|
+
logger.info `Сохранён промежуточный файл: ${txtFileName}`;
|
|
31
|
+
}
|
|
32
|
+
// Определяем экстрактор
|
|
33
|
+
let extractorClass;
|
|
34
|
+
if (options.format) {
|
|
35
|
+
extractorClass = determineExtractorByName(options.format);
|
|
36
|
+
logger.info `Конвертируем файл как формат ${options.format}`;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
extractorClass = determineExtractorAuto(bankText);
|
|
40
|
+
logger.info `Формат файла определён как ${extractorClass.name}`;
|
|
41
|
+
}
|
|
42
|
+
// Создаём экземпляр экстрактора
|
|
43
|
+
const extractor = new extractorClass(bankText);
|
|
44
|
+
// Получаем транзакции
|
|
45
|
+
const transactions = extractor.getEntries();
|
|
46
|
+
logger.info `Найдено транзакций: ${transactions.length}`;
|
|
47
|
+
// Получаем баланс из шапки
|
|
48
|
+
const periodBalance = extractor.getPeriodBalance();
|
|
49
|
+
// Получаем информацию о колонках
|
|
50
|
+
const columnsInfo = extractor.getColumnsInfo();
|
|
51
|
+
// Проверяем баланс
|
|
52
|
+
let error = "";
|
|
53
|
+
try {
|
|
54
|
+
checkTransactionsBalance(transactions, periodBalance, extractor.getColumnNameForBalanceCalculation());
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
if (e instanceof BalanceVerificationError) {
|
|
58
|
+
if (options.balance_check) {
|
|
59
|
+
throw e;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
logger.warn `${e.message}`;
|
|
63
|
+
error = e.message;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
throw e;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Переворачиваем порядок, если запрошено
|
|
71
|
+
let finalTransactions = transactions;
|
|
72
|
+
if (options.reverse) {
|
|
73
|
+
finalTransactions = reverseTransactions(transactions);
|
|
74
|
+
}
|
|
75
|
+
// Определяем выходной файл
|
|
76
|
+
let outputFileName;
|
|
77
|
+
if (options.output) {
|
|
78
|
+
outputFileName = options.output;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
outputFileName = inputFileName.replace(/\.pdf$/i, "");
|
|
82
|
+
}
|
|
83
|
+
// Записываем результат
|
|
84
|
+
if (options.type === "json") {
|
|
85
|
+
const filename = await writeTransactionsToJson(finalTransactions, outputFileName, extractorClass.name, error);
|
|
86
|
+
logger.info `Создан файл ${filename}`;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
const filename = await writeTransactionsToCsv(finalTransactions, outputFileName, columnsInfo);
|
|
90
|
+
logger.info `Создан файл ${filename}`;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
extractor_name: extractorClass.name,
|
|
94
|
+
transactions: finalTransactions,
|
|
95
|
+
period_balance: periodBalance.toNumber(),
|
|
96
|
+
balance_column: extractor.getColumnNameForBalanceCalculation(),
|
|
97
|
+
columns_info: columnsInfo,
|
|
98
|
+
errors: error,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converter.js","sourceRoot":"","sources":["../src/converter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Transaction } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Записывает транзакции в CSV файл
|
|
4
|
+
* @param transactions Список транзакций
|
|
5
|
+
* @param filename Имя файла (без расширения)
|
|
6
|
+
* @param columnsInfo Информация о колонках
|
|
7
|
+
* @returns Имя созданного файла
|
|
8
|
+
*/
|
|
9
|
+
export declare function writeTransactionsToCsv(transactions: Transaction[], filename: string, columnsInfo: Record<string, string>): Promise<string>;
|
|
10
|
+
//# sourceMappingURL=csv-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-writer.d.ts","sourceRoot":"","sources":["../src/csv-writer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA2B9C;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,WAAW,EAAE,EAC3B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAClC,OAAO,CAAC,MAAM,CAAC,CA4CjB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Экранирует значение для CSV
|
|
4
|
+
* @param value Значение
|
|
5
|
+
* @returns Экранированное значение
|
|
6
|
+
*/
|
|
7
|
+
function escapeCsvValue(value) {
|
|
8
|
+
if (value === undefined || value === null) {
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
let strValue;
|
|
12
|
+
if (value instanceof Date) {
|
|
13
|
+
strValue = value.toISOString();
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
strValue = String(value);
|
|
17
|
+
}
|
|
18
|
+
// Экранируем кавычки и оборачиваем в кавычки если нужно
|
|
19
|
+
if (strValue.includes(";") || strValue.includes('"') || strValue.includes("\n")) {
|
|
20
|
+
return `"${strValue.replace(/"/g, '""')}"`;
|
|
21
|
+
}
|
|
22
|
+
return strValue;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Записывает транзакции в CSV файл
|
|
26
|
+
* @param transactions Список транзакций
|
|
27
|
+
* @param filename Имя файла (без расширения)
|
|
28
|
+
* @param columnsInfo Информация о колонках
|
|
29
|
+
* @returns Имя созданного файла
|
|
30
|
+
*/
|
|
31
|
+
export async function writeTransactionsToCsv(transactions, filename, columnsInfo) {
|
|
32
|
+
const outputFilename = filename.endsWith(".csv") ? filename : `${filename}.csv`;
|
|
33
|
+
// Заголовки
|
|
34
|
+
const headers = Object.keys(columnsInfo);
|
|
35
|
+
const headerRow = headers.map((key) => columnsInfo[key]).join(";");
|
|
36
|
+
// Данные
|
|
37
|
+
const dataRows = [];
|
|
38
|
+
for (const transaction of transactions) {
|
|
39
|
+
const rowValues = headers.map((key) => {
|
|
40
|
+
const value = transaction[key];
|
|
41
|
+
let formattedValue;
|
|
42
|
+
if (value instanceof Date) {
|
|
43
|
+
// Форматируем дату
|
|
44
|
+
if (key === "operation_date") {
|
|
45
|
+
formattedValue = value.toLocaleString("ru-RU", {
|
|
46
|
+
day: "2-digit",
|
|
47
|
+
month: "2-digit",
|
|
48
|
+
year: "numeric",
|
|
49
|
+
hour: "2-digit",
|
|
50
|
+
minute: "2-digit",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
formattedValue = value.toLocaleDateString("ru-RU");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
formattedValue = value;
|
|
59
|
+
}
|
|
60
|
+
return escapeCsvValue(formattedValue);
|
|
61
|
+
});
|
|
62
|
+
dataRows.push(rowValues.join(";"));
|
|
63
|
+
}
|
|
64
|
+
// Собираем CSV
|
|
65
|
+
const csvContent = [headerRow, ...dataRows].join("\n");
|
|
66
|
+
// Добавляем BOM для Excel
|
|
67
|
+
const bom = "\uFEFF";
|
|
68
|
+
await fs.writeFile(outputFilename, `${bom + csvContent}\n`, "utf-8");
|
|
69
|
+
return outputFilename;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=csv-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-writer.js","sourceRoot":"","sources":["../src/csv-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAGlC;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAyC;IAC/D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,QAAgB,CAAC;IACrB,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;QAC1B,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACjC,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,wDAAwD;IACxD,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAChF,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;IAC7C,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,YAA2B,EAC3B,QAAgB,EAChB,WAAmC;IAEnC,MAAM,cAAc,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,MAAM,CAAC;IAEhF,YAAY;IACZ,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEnE,SAAS;IACT,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACpC,MAAM,KAAK,GAAI,WAAkD,CAAC,GAAG,CAAC,CAAC;YACvE,IAAI,cAAkD,CAAC;YAEvD,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;gBAC1B,mBAAmB;gBACnB,IAAI,GAAG,KAAK,gBAAgB,EAAE,CAAC;oBAC7B,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE;wBAC7C,GAAG,EAAE,SAAS;wBACd,KAAK,EAAE,SAAS;wBAChB,IAAI,EAAE,SAAS;wBACf,IAAI,EAAE,SAAS;wBACf,MAAM,EAAE,SAAS;qBAClB,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,cAAc,GAAG,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,cAAc,GAAG,KAAoC,CAAC;YACxD,CAAC;YAED,OAAO,cAAc,CAAC,cAAc,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,eAAe;IACf,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEvD,0BAA0B;IAC1B,MAAM,GAAG,GAAG,QAAQ,CAAC;IACrB,MAAM,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,GAAG,GAAG,GAAG,UAAU,IAAI,EAAE,OAAO,CAAC,CAAC;IAErE,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Базовый класс для всех ошибок sberparse
|
|
3
|
+
*/
|
|
4
|
+
export declare class SberParseError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Ошибка структуры входного файла
|
|
9
|
+
*/
|
|
10
|
+
export declare class InputFileStructureError extends SberParseError {
|
|
11
|
+
constructor(message: string);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Ошибка проверки баланса
|
|
15
|
+
*/
|
|
16
|
+
export declare class BalanceVerificationError extends SberParseError {
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ошибка пользовательского ввода
|
|
21
|
+
*/
|
|
22
|
+
export declare class UserInputError extends SberParseError {
|
|
23
|
+
constructor(message: string);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Ошибка тестирования
|
|
27
|
+
*/
|
|
28
|
+
export declare class TestingError extends SberParseError {
|
|
29
|
+
constructor(message: string);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=exceptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceptions.d.ts","sourceRoot":"","sources":["../src/exceptions.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,cAAc;gBAC7C,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,cAAc;gBAC9C,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,cAAc;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,cAAc;gBAClC,OAAO,EAAE,MAAM;CAI5B"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Базовый класс для всех ошибок sberparse
|
|
3
|
+
*/
|
|
4
|
+
export class SberParseError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "SberParseError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Ошибка структуры входного файла
|
|
12
|
+
*/
|
|
13
|
+
export class InputFileStructureError extends SberParseError {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "InputFileStructureError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Ошибка проверки баланса
|
|
21
|
+
*/
|
|
22
|
+
export class BalanceVerificationError extends SberParseError {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "BalanceVerificationError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Ошибка пользовательского ввода
|
|
30
|
+
*/
|
|
31
|
+
export class UserInputError extends SberParseError {
|
|
32
|
+
constructor(message) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = "UserInputError";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Ошибка тестирования
|
|
39
|
+
*/
|
|
40
|
+
export class TestingError extends SberParseError {
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "TestingError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=exceptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../src/exceptions.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,uBAAwB,SAAQ,cAAc;IACzD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,wBAAyB,SAAQ,cAAc;IAC1D,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,cAAe,SAAQ,cAAc;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,YAAa,SAAQ,cAAc;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Extractor } from "./extractor.js";
|
|
2
|
+
/**
|
|
3
|
+
* Определяет подходящий экстрактор для текста выписки автоматически
|
|
4
|
+
* @param bankText Текст выписки
|
|
5
|
+
* @returns Класс экстрактора
|
|
6
|
+
* @throws {InputFileStructureError} если ни один экстрактор не подходит
|
|
7
|
+
*/
|
|
8
|
+
export declare function determineExtractorAuto(bankText: string): new (bank_text: string) => Extractor;
|
|
9
|
+
/**
|
|
10
|
+
* Возвращает экстрактор по имени
|
|
11
|
+
* @param extractorName Имя экстрактора
|
|
12
|
+
* @returns Класс экстрактора
|
|
13
|
+
* @throws {UserInputError} если экстрактор не найден
|
|
14
|
+
*/
|
|
15
|
+
export declare function determineExtractorByName(extractorName: string): new (bank_text: string) => Extractor;
|
|
16
|
+
//# sourceMappingURL=extractor-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor-selector.d.ts","sourceRoot":"","sources":["../src/extractor-selector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,SAAS,EAAE,MAAM,KAAK,SAAS,CAmC7F;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,GACpB,KACD,SAAS,EAAE,MAAM,KACd,SAAS,CAWb"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { InputFileStructureError, UserInputError } from "./exceptions.js";
|
|
2
|
+
import { extractorsList } from "./extractors/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Определяет подходящий экстрактор для текста выписки автоматически
|
|
5
|
+
* @param bankText Текст выписки
|
|
6
|
+
* @returns Класс экстрактора
|
|
7
|
+
* @throws {InputFileStructureError} если ни один экстрактор не подходит
|
|
8
|
+
*/
|
|
9
|
+
export function determineExtractorAuto(bankText) {
|
|
10
|
+
const supportedExtractors = extractorsList.filter((ExtractorClass) => {
|
|
11
|
+
try {
|
|
12
|
+
const quickCheck = ExtractorClass.quickCheck;
|
|
13
|
+
if (quickCheck && !quickCheck(bankText)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const extractor = new ExtractorClass(bankText);
|
|
17
|
+
return extractor.checkSupport();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
if (supportedExtractors.length === 0) {
|
|
24
|
+
throw new InputFileStructureError("Неизвестный формат выписки, ни один из экстракторов не подходят");
|
|
25
|
+
}
|
|
26
|
+
if (supportedExtractors.length > 1) {
|
|
27
|
+
throw new InputFileStructureError(`Непонятный формат выписки. Больше чем один экстрактор говорят, что понимают его: ${supportedExtractors
|
|
28
|
+
.map((e) => e.name)
|
|
29
|
+
.join(", ")}`);
|
|
30
|
+
}
|
|
31
|
+
return supportedExtractors[0];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Возвращает экстрактор по имени
|
|
35
|
+
* @param extractorName Имя экстрактора
|
|
36
|
+
* @returns Класс экстрактора
|
|
37
|
+
* @throws {UserInputError} если экстрактор не найден
|
|
38
|
+
*/
|
|
39
|
+
export function determineExtractorByName(extractorName) {
|
|
40
|
+
for (const ExtractorClass of extractorsList) {
|
|
41
|
+
if (ExtractorClass.name === extractorName) {
|
|
42
|
+
return ExtractorClass;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const availableNames = extractorsList.map((e) => e.name).join(", ");
|
|
46
|
+
throw new UserInputError(`Указанный формат файла "${extractorName}" неизвестен. Доступные форматы: ${availableNames}`);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=extractor-selector.js.map
|