- Копия DI2-сервера в server/finance-di2/ с правками: schema/db-client/cache/table-config/override-tables/google-auth/audit-agent/routes - db-client — обёртка над существующим пулом server/finance/db-client (второй пул не создаётся, добавлен экспорт isConnectionError) - ai-config.ts — чистое IO конфигов из ai-agent.ts без Telegram-поллинга; роуты /api/ai/toggle и /api/ai/status удалены, без compression/startAuditScheduler/autoStartIfEnabled - Обёртка registerDi2Routes с auth-gate (authenticateToken + finance.manage), регистрация строго перед registerFinanceRoutes - Статика /di2 из dist/public-di2 перед веткой vite/static (dev и prod) - Фикс предсуществующего бага DI2: buildGlobalExclusionConditions без cats в /api/profitability
155 lines
5.5 KiB
TypeScript
155 lines
5.5 KiB
TypeScript
import fs from "fs";
|
|
import path from "path";
|
|
import type { TableConfig } from "./schema";
|
|
|
|
const TABLE_CONFIG_FILE = path.join(process.cwd(), "data", "table-config.json");
|
|
|
|
const SYSTEM_COLUMNS = ["id", "dataobnovleniyazapisi"];
|
|
|
|
const DEFAULT_COLUMN_LABELS: Record<string, string> = {
|
|
data: "Дата",
|
|
summa: "Сумма",
|
|
summadokumenta: "Сумма документа",
|
|
statya: "Статья",
|
|
zakazchik: "Заказчик",
|
|
dochka: "Дочка",
|
|
vnuchka: "Внучка",
|
|
kommentarii: "Комментарий",
|
|
stavkands: "Ставка НДС",
|
|
naznachenieplatezha: "Назначение платежа",
|
|
otvetstvenniipokontraktu: "Ответственный",
|
|
dogovorkontragenta: "Договор контрагента",
|
|
dogovorzakazchika: "Договор заказчика",
|
|
statyadop: "Статья (доп.)",
|
|
schetnaoplatu: "Счет на оплату",
|
|
nomervhodyaschegodokumenta: "Номер вх. документа",
|
|
ssilkanomervhodyaschegodokumenta: "Номер вх. документа",
|
|
kontragent: "Контрагент",
|
|
dogovor: "Договор",
|
|
summadolga: "Сумма долга",
|
|
summaprosrocheno: "Сумма просрочено",
|
|
period: "Период",
|
|
klassprosrochki: "Класс просрочки",
|
|
otvetstvennii: "Ответственный",
|
|
organizaciya: "Организация",
|
|
dokumentraschetov: "Документ расчётов",
|
|
summaoplacheno: "Сумма оплачено",
|
|
dneiprosrocheno: "Дней просрочено",
|
|
dneidolga: "Дней долга",
|
|
dataobrazovaniyadolga: "Дата образования долга",
|
|
planovayadatapogasheniya: "Плановая дата погашения",
|
|
otsrochkapodogovoru: "Отсрочка по договору",
|
|
kontragentinn: "ИНН контрагента",
|
|
valyuta: "Валюта",
|
|
summadolgaval: "Сумма долга (вал.)",
|
|
schet: "Счёт",
|
|
klassdolga: "Класс долга",
|
|
dataobnovleniyazapisi: "Дата обновления",
|
|
};
|
|
|
|
export const DEFAULT_TABLE_CONFIG: TableConfig = {
|
|
incomeTable: "opdohodi",
|
|
expenseTable: "oprashodi",
|
|
debtTable: "vw_debt_active",
|
|
incomeSumColumn: "summa",
|
|
expenseSumColumn: "summadokumenta",
|
|
incomeColumns: ["id", "data", "summa", "statya", "zakazchik", "dochka", "vnuchka", "kommentarii", "stavkands", "naznachenieplatezha", "otvetstvenniipokontraktu", "dogovorkontragenta", "schetnaoplatu", "dogovorzakazchika", "statyadop", "nomervhodyaschegodokumenta", "dataobnovleniyazapisi"],
|
|
expenseColumns: ["id", "data", "summadokumenta", "statya", "zakazchik", "dochka", "vnuchka", "kommentarii", "stavkands", "naznachenieplatezha", "otvetstvenniipokontraktu", "dogovorkontragenta", "dogovorzakazchika", "statyadop", "ssilkanomervhodyaschegodokumenta", "kontragent", "dataobnovleniyazapisi"],
|
|
columnLabels: { ...DEFAULT_COLUMN_LABELS },
|
|
};
|
|
|
|
let cachedConfig: TableConfig | null = null;
|
|
|
|
export function loadTableConfig(): TableConfig {
|
|
if (cachedConfig) return cachedConfig;
|
|
try {
|
|
const raw = fs.readFileSync(TABLE_CONFIG_FILE, "utf-8");
|
|
const parsed = JSON.parse(raw);
|
|
cachedConfig = { ...DEFAULT_TABLE_CONFIG, ...parsed, columnLabels: { ...DEFAULT_COLUMN_LABELS, ...(parsed.columnLabels || {}) } };
|
|
return cachedConfig!;
|
|
} catch {
|
|
cachedConfig = { ...DEFAULT_TABLE_CONFIG };
|
|
return cachedConfig;
|
|
}
|
|
}
|
|
|
|
export function saveTableConfig(cfg: Partial<TableConfig>) {
|
|
const current = loadTableConfig();
|
|
const merged: TableConfig = {
|
|
...current,
|
|
...cfg,
|
|
columnLabels: { ...current.columnLabels, ...(cfg.columnLabels || {}) },
|
|
};
|
|
if (!fs.existsSync("data")) fs.mkdirSync("data", { recursive: true });
|
|
fs.writeFileSync(TABLE_CONFIG_FILE, JSON.stringify(merged, null, 2), "utf-8");
|
|
cachedConfig = merged;
|
|
}
|
|
|
|
export function getIncomeTable(): string {
|
|
return "vw_income_effective";
|
|
}
|
|
|
|
export function getExpenseTable(): string {
|
|
return "vw_expense_effective";
|
|
}
|
|
|
|
export function getIncomeBaseTable(): string {
|
|
return loadTableConfig().incomeTable;
|
|
}
|
|
|
|
export function getExpenseBaseTable(): string {
|
|
return loadTableConfig().expenseTable;
|
|
}
|
|
|
|
export function getIncomeEffectiveView(): string {
|
|
return "vw_income_effective";
|
|
}
|
|
|
|
export function getExpenseEffectiveView(): string {
|
|
return "vw_expense_effective";
|
|
}
|
|
|
|
export function getDebtTable(): string {
|
|
return loadTableConfig().debtTable;
|
|
}
|
|
|
|
export function getIncomeSumColumn(): string {
|
|
return loadTableConfig().incomeSumColumn;
|
|
}
|
|
|
|
export function getExpenseSumColumn(): string {
|
|
return loadTableConfig().expenseSumColumn;
|
|
}
|
|
|
|
export function getAllowedIncomeColumns(): string[] {
|
|
const cfg = loadTableConfig();
|
|
return cfg.incomeColumns.filter(c => !SYSTEM_COLUMNS.includes(c));
|
|
}
|
|
|
|
export function getAllowedExpenseColumns(): string[] {
|
|
const cfg = loadTableConfig();
|
|
return cfg.expenseColumns.filter(c => !SYSTEM_COLUMNS.includes(c));
|
|
}
|
|
|
|
export function getAutoDetectAllowedColumns(type: "income" | "expense"): string[] {
|
|
const allowed = type === "income" ? getAllowedIncomeColumns() : getAllowedExpenseColumns();
|
|
return allowed.filter(c => c !== "data" && c !== "id" && c !== "summa" && c !== "summadokumenta" && c !== "dataobnovleniyazapisi");
|
|
}
|
|
|
|
export function getColumnLabel(col: string): string {
|
|
const cfg = loadTableConfig();
|
|
return cfg.columnLabels[col] || col;
|
|
}
|
|
|
|
export function getAllIncomeColumns(): string[] {
|
|
return loadTableConfig().incomeColumns;
|
|
}
|
|
|
|
export function getAllExpenseColumns(): string[] {
|
|
return loadTableConfig().expenseColumns;
|
|
}
|
|
|
|
export function invalidateTableConfigCache() {
|
|
cachedConfig = null;
|
|
}
|