import { z } from "zod"; export const dbConnectionSchema = z.object({ host: z.string().min(1), port: z.coerce.number().int().positive(), database: z.string().min(1), user: z.string().min(1), password: z.string().min(1), }); export type DbConnectionConfig = z.infer; export interface TableConfig { incomeTable: string; expenseTable: string; debtTable: string; incomeSumColumn: string; expenseSumColumn: string; incomeColumns: string[]; expenseColumns: string[]; columnLabels: Record; } export interface IncomeRow { id: string; data: string | null; summa: number | null; stavkands: string | null; dogovorkontragenta: string | null; zakazchik: string | null; dogovorzakazchika: string | null; otvetstvenniipokontraktu: string | null; statyadop: string | null; kommentarii: string | null; statya: string | null; dochka: string | null; vnuchka: string | null; naznachenieplatezha: string | null; schetnaoplatu: string | null; overrideCategoryId?: string; overrideCategoryName?: string; } export interface ExpenseRow { id: string; data: string | null; summadokumenta: number | null; stavkands: string | null; dogovorkontragenta: string | null; zakazchik: string | null; dogovorzakazchika: string | null; otvetstvenniipokontraktu: string | null; statyadop: string | null; kommentarii: string | null; statya: string | null; dochka: string | null; vnuchka: string | null; naznachenieplatezha: string | null; ssilkanomervhodyaschegodokumenta: string | null; kontragent: string | null; dataobnovleniyazapisi: string | null; overrideCategoryId?: string; overrideCategoryName?: string; } export interface DebtRow { period: string | null; schet: string | null; kontragent: string | null; dogovor: string | null; dokumentraschetov: string | null; organizaciya: string | null; summadolga: number | null; summadolgaval: number | null; valyuta: string | null; otsrochkapodogovoru: number | null; kontragentinn: string | null; dataobrazovaniyadolga: string | null; summadokumenta: number | null; planovayadatapogasheniya: string | null; dneiprosrocheno: number | null; dneidolga: number | null; otvetstvennii: string | null; klassprosrochki: string | null; klassdolga: string | null; summaprosrocheno: number | null; summaoplacheno: number | null; } export interface DashboardStats { incomeTotal: number; incomeCount: number; expenseTotal: number; expenseCount: number; debtTotal: number; debtOverdue: number; debtCounterparts: number; monthlyIncome: { month: string; total: number }[]; monthlyExpense: { month: string; total: number }[]; debtByClass: { class: string; total: number }[]; billedVsPaid: { month: string; billed: number; paid: number; debt: number }[]; } export interface FilterOptions { statya: string[]; zakazchik: string[]; dochka: string[]; vnuchka: string[]; otvetstvennii?: string[]; organizaciya?: string[]; klassprosrochki?: string[]; } export interface PaginatedResult { rows: T[]; total: number; page: number; pageSize: number; totalPages: number; totalSum?: number; } export type RuleOperator = "equals" | "not_equals" | "contains" | "greater_than" | "less_than" | "equal_number"; export interface IncomeCategoryRule { column: string; operator: RuleOperator; value: string; } export const MAX_CATEGORY_DEPTH = 5; export interface IncomeCategory { id: string; name: string; rules: IncomeCategoryRule[]; ruleLogic?: "and" | "or"; excluded?: boolean; children?: IncomeCategory[]; autoDetected?: boolean; treeId?: string; } export const NUMERIC_OPERATORS: { value: RuleOperator; label: string }[] = [ { value: "equal_number", label: "равно (=)" }, { value: "greater_than", label: "больше (>)" }, { value: "less_than", label: "меньше (<)" }, ]; export const TEXT_OPERATORS: { value: RuleOperator; label: string }[] = [ { value: "equals", label: "равно (=)" }, { value: "not_equals", label: "не равно (≠)" }, { value: "contains", label: "содержит (∋)" }, ]; export interface ProfitabilityRow { zakazchik: string; totalIncome: number; totalExpense: number; profit: number; margin: number; contractCount: number; } export interface ContractProfitRow { dogovorzakazchika: string; totalIncome: number; totalExpense: number; profit: number; } export interface MonthlyProfitRow { month: string; income: number; expense: number; profit: number; } export interface ProfitabilitySummary { totalIncome: number; totalExpense: number; totalProfit: number; counterpartCount: number; } export interface ProfitabilityResponse { rows: ProfitabilityRow[]; total: number; page: number; pageSize: number; totalPages: number; summary: ProfitabilitySummary; } export interface DebtByEntity { name: string; total: number; cls0: number; cls1_30: number; cls31_60: number; cls61_90: number; cls91_365: number; cls365plus: number; } export interface DebtOverdueClass { cls: string; total: number; } export interface DebtAnalytics { summary: { updatedAt: string | null; totalDebt: number; totalOverdue: number; }; byKontragent: DebtByEntity[]; byManager: DebtByEntity[]; byOverdueClass: DebtOverdueClass[]; table: { rows: DebtTableGroup[]; total: number; page: number; pageSize: number; totalPages: number; }; } export interface DebtTableRow { dogovor: string; summadokumenta: number; dokumentraschetov: string; summaoplacheno: number; summadolga: number; summaprosrocheno: number; otsrochkapodogovoru: number; dneiprosrocheno: number; } export interface DebtTableGroup { kontragent: string; totalDebt: number; totalOverdue: number; rows: DebtTableRow[]; } export interface DebtDynamicsRow { period: string; totalDebt: number; totalOverdue: number; } export interface DebtDynamicsKontragent { kontragent: string; summadokumenta: number; summaoplacheno: number; summadolga: number; summaprosrocheno: number; dneiprosrocheno: number; } export interface DebtFiltersResponse { periods: string[]; klassprosrochki: string[]; organizaciya: string[]; otvetstvennii: string[]; kontragenty: string[]; } export const INCOME_FILTERABLE_COLUMNS = [ { key: "data", label: "Дата" }, { key: "summa", label: "Сумма" }, { key: "statya", label: "Статья" }, { key: "zakazchik", label: "Заказчик" }, { key: "dochka", label: "Дочка" }, { key: "vnuchka", label: "Внучка" }, { key: "otvetstvenniipokontraktu", label: "Ответственный" }, { key: "stavkands", label: "Ставка НДС" }, { key: "kommentarii", label: "Комментарий" }, { key: "dogovorkontragenta", label: "Договор контрагента" }, { key: "schetnaoplatu", label: "Счет на оплату" }, { key: "naznachenieplatezha", label: "Назначение платежа" }, { key: "dogovorzakazchika", label: "Договор заказчика" }, { key: "statyadop", label: "Статья (доп.)" }, { key: "nomervhodyaschegodokumenta", label: "Номер вх. документа" }, ] as const; export const ALL_INCOME_COLUMNS: { key: string; label: string; type: "date" | "number" | "text" }[] = [ { key: "data", label: "Дата", type: "date" }, { key: "summa", label: "Сумма", type: "number" }, { key: "statya", label: "Статья", type: "text" }, { key: "zakazchik", label: "Заказчик", type: "text" }, { key: "dochka", label: "Дочка", type: "text" }, { key: "vnuchka", label: "Внучка", type: "text" }, { key: "otvetstvenniipokontraktu", label: "Ответственный", type: "text" }, { key: "stavkands", label: "Ставка НДС", type: "text" }, { key: "kommentarii", label: "Комментарий", type: "text" }, { key: "dogovorkontragenta", label: "Договор контрагента", type: "text" }, { key: "schetnaoplatu", label: "Счет на оплату", type: "text" }, { key: "naznachenieplatezha", label: "Назначение платежа", type: "text" }, { key: "dogovorzakazchika", label: "Договор заказчика", type: "text" }, { key: "statyadop", label: "Статья (доп.)", type: "text" }, { key: "nomervhodyaschegodokumenta", label: "Номер вх. документа", type: "text" }, { key: "id", label: "ID", type: "text" }, ]; export const DEFAULT_VISIBLE_COLUMNS = ["data", "summa", "statya", "zakazchik", "dochka", "vnuchka", "kommentarii"]; export const ALL_EXPENSE_COLUMNS: { key: string; label: string; type: "date" | "number" | "text" }[] = [ { key: "data", label: "Дата", type: "date" }, { key: "summadokumenta", label: "Сумма документа", type: "number" }, { key: "statya", label: "Статья", type: "text" }, { key: "zakazchik", label: "Заказчик", type: "text" }, { key: "dochka", label: "Дочка", type: "text" }, { key: "vnuchka", label: "Внучка", type: "text" }, { key: "kommentarii", label: "Комментарий", type: "text" }, { key: "stavkands", label: "Ставка НДС", type: "text" }, { key: "naznachenieplatezha", label: "Назначение платежа", type: "text" }, { key: "otvetstvenniipokontraktu", label: "Ответственный", type: "text" }, { key: "dogovorkontragenta", label: "Договор контрагента", type: "text" }, { key: "dogovorzakazchika", label: "Договор заказчика", type: "text" }, { key: "statyadop", label: "Статья (доп.)", type: "text" }, { key: "ssilkanomervhodyaschegodokumenta", label: "Номер вх. документа", type: "text" }, { key: "kontragent", label: "Контрагент", type: "text" }, ]; export const EXPENSE_FILTERABLE_COLUMNS = [ { key: "data", label: "Дата" }, { key: "summadokumenta", label: "Сумма документа" }, { key: "statya", label: "Статья" }, { key: "zakazchik", label: "Заказчик" }, { key: "dochka", label: "Дочка" }, { key: "vnuchka", label: "Внучка" }, { key: "kommentarii", label: "Комментарий" }, { key: "stavkands", label: "Ставка НДС" }, { key: "naznachenieplatezha", label: "Назначение платежа" }, { key: "otvetstvenniipokontraktu", label: "Ответственный" }, { key: "dogovorkontragenta", label: "Договор контрагента" }, { key: "dogovorzakazchika", label: "Договор заказчика" }, { key: "statyadop", label: "Статья (доп.)" }, { key: "ssilkanomervhodyaschegodokumenta", label: "Номер вх. документа" }, { key: "kontragent", label: "Контрагент" }, ] as const; export const DEFAULT_VISIBLE_EXPENSE_COLUMNS = ["data", "summadokumenta", "statya", "zakazchik", "dochka", "vnuchka", "kommentarii"]; export const CATEGORY_RULE_COLUMNS = [ ...INCOME_FILTERABLE_COLUMNS.map(c => ({ ...c, type: "text" as const })), { key: "summa", label: "Сумма", type: "number" as const }, ]; export const EXPENSE_CATEGORY_RULE_COLUMNS = [ ...EXPENSE_FILTERABLE_COLUMNS.filter(c => c.key !== "summadokumenta").map(c => ({ ...c, type: "text" as const })), { key: "summadokumenta", label: "Сумма документа", type: "number" as const }, ]; export interface ExpenseCategory { id: string; name: string; rules: IncomeCategoryRule[]; ruleLogic?: "and" | "or"; excluded?: boolean; children?: ExpenseCategory[]; autoDetected?: boolean; treeId?: string; }