fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
This commit is contained in:
114
server/finance/table-config.ts
Normal file
114
server/finance/table-config.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user