- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
115 lines
3.5 KiB
TypeScript
115 lines
3.5 KiB
TypeScript
import { readFileSync, existsSync, writeFileSync } from "fs";
|
|
import { resolve } from "path";
|
|
|
|
export interface TableConfig {
|
|
incomeTable: string;
|
|
expenseTable: string;
|
|
incomeSumColumn: string;
|
|
expenseSumColumn: string;
|
|
columnLabels: Record<string, string>;
|
|
}
|
|
|
|
export interface IncomeCategoryFile {
|
|
id: string;
|
|
name: string;
|
|
rules: Array<{ column: string; operator: string; value: string }>;
|
|
ruleLogic?: "and" | "or";
|
|
excluded?: boolean;
|
|
autoDetected?: boolean;
|
|
treeId?: string;
|
|
children: IncomeCategoryFile[];
|
|
}
|
|
|
|
export interface AutoDetectTree {
|
|
id: string;
|
|
name: string;
|
|
columns: string[];
|
|
autoRefresh: boolean;
|
|
isPrimary: boolean;
|
|
mode: "split" | "merge";
|
|
filters: Array<{ column: string; operator: string; value: string }>;
|
|
filterLogic: "and" | "or";
|
|
}
|
|
|
|
export interface AutoDetectConfig {
|
|
trees: AutoDetectTree[];
|
|
}
|
|
|
|
const DATA_DIR = resolve(process.cwd(), "data");
|
|
|
|
function readJson<T>(filename: string, defaultValue: T): T {
|
|
const path = resolve(DATA_DIR, filename);
|
|
if (!existsSync(path)) return defaultValue;
|
|
try {
|
|
return JSON.parse(readFileSync(path, "utf-8")) as T;
|
|
} catch {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
function writeJson<T>(filename: string, data: T): void {
|
|
const path = resolve(DATA_DIR, filename);
|
|
writeFileSync(path, JSON.stringify(data, null, 2), "utf-8");
|
|
}
|
|
|
|
export function getTableConfig(): TableConfig {
|
|
return readJson<TableConfig>("table-config.json", {
|
|
incomeTable: "income",
|
|
expenseTable: "expenses",
|
|
incomeSumColumn: "summa",
|
|
expenseSumColumn: "summadokumenta",
|
|
columnLabels: {
|
|
data: "Дата",
|
|
summa: "Сумма",
|
|
summadokumenta: "Сумма документа",
|
|
zakazchik: "Заказчик",
|
|
otvetstvenniipokontraktu: "Ответственный",
|
|
statya: "Статья",
|
|
dochka: "Дочка",
|
|
vnuchka: "Внучка",
|
|
kommentarii: "Комментарий",
|
|
stavkands: "Ставка НДС",
|
|
dogovorkontragenta: "Договор контрагента",
|
|
dogovorzakazchika: "Договор заказчика",
|
|
naznachenieplatezha: "Назначение платежа",
|
|
schetnaoplatu: "Счет на оплату",
|
|
statyadop: "Статья (доп.)",
|
|
nomervhodyaschegodokumenta: "Номер вх. документа",
|
|
kontragent: "Контрагент",
|
|
ssilkanomervhodyaschegodokumenta: "Номер вх. документа",
|
|
},
|
|
});
|
|
}
|
|
|
|
export function getIncomeCategories(): IncomeCategoryFile[] {
|
|
return readJson<IncomeCategoryFile[]>("income-categories.json", []);
|
|
}
|
|
|
|
export function setIncomeCategories(categories: IncomeCategoryFile[]): void {
|
|
writeJson("income-categories.json", categories);
|
|
}
|
|
|
|
export function getExpenseCategories(): IncomeCategoryFile[] {
|
|
return readJson<IncomeCategoryFile[]>("expense-categories.json", []);
|
|
}
|
|
|
|
export function setExpenseCategories(categories: IncomeCategoryFile[]): void {
|
|
writeJson("expense-categories.json", categories);
|
|
}
|
|
|
|
export function getIncomeAutoDetectConfig(): AutoDetectConfig {
|
|
return readJson<AutoDetectConfig>("income-auto-detect-config.json", { trees: [] });
|
|
}
|
|
|
|
export function setIncomeAutoDetectConfig(config: AutoDetectConfig): void {
|
|
writeJson("income-auto-detect-config.json", config);
|
|
}
|
|
|
|
export function getExpenseAutoDetectConfig(): AutoDetectConfig {
|
|
return readJson<AutoDetectConfig>("auto-detect-config.json", { trees: [] });
|
|
}
|
|
|
|
export function setExpenseAutoDetectConfig(config: AutoDetectConfig): void {
|
|
writeJson("auto-detect-config.json", config);
|
|
}
|