Финансы: дебиторка (vw_debt_active), расчёты НДС/налога на прибыль, аудит целостности с автопланировщиком, синхронизация зарплат из Google Sheets, миграция настроек Data-Insight2

This commit is contained in:
2026-09-05 15:07:36 +03:00
parent d2c993b613
commit 7a8db03163
17 changed files with 4809 additions and 34 deletions

View File

@@ -23,6 +23,11 @@ import { tenantIsolation } from "../middleware/tenant.middleware";
import { previewCustomerSync, applyCustomerSync, type SyncApplyCustomer } from "./customer-sync";
import { previewContractSync, applyContractSync, type SyncApplyContract } from "./contract-sync";
import { getFinanceSettings, setFinanceSettings } from "./settings";
import { applyCategoryRules } from "./category-matching";
import { registerDebtRoutes } from "./debt";
import { registerCalculationRoutes } from "./calculations";
import { registerAuditRoutes, startAuditScheduler } from "./audit";
import { registerGoogleSheetsRoutes } from "./google-sheets";
// Rebuild status (in-memory)
let rebuildStatus = { inProgress: false, pendingRebuild: false, lastRebuiltAt: null as string | null };
@@ -59,39 +64,6 @@ function buildWhere(
return { clause, params, paramIndex: idx };
}
function applyCategoryRules(row: Record<string, any>, categories: any[]): string | null {
for (const cat of categories) {
const match = cat.ruleLogic === "or"
? cat.rules.some((r: any) => matchRule(row, r))
: cat.rules.every((r: any) => matchRule(row, r));
if (match) {
if (cat.children && cat.children.length > 0) {
const child = applyCategoryRules(row, cat.children);
if (child) return child;
}
return cat.id;
}
}
return null;
}
function matchRule(row: Record<string, any>, rule: { column: string; operator: string; value: string }): boolean {
const val = row[rule.column];
const strVal = val == null ? "" : String(val);
const numVal = parseFloat(strVal);
const ruleNum = parseFloat(rule.value);
switch (rule.operator) {
case "equals": return strVal === rule.value;
case "not_equals": return strVal !== rule.value;
case "contains": return strVal.toLowerCase().includes(rule.value.toLowerCase());
case "greater_than": return !isNaN(numVal) && !isNaN(ruleNum) && numVal > ruleNum;
case "less_than": return !isNaN(numVal) && !isNaN(ruleNum) && numVal < ruleNum;
case "equal_number": return !isNaN(numVal) && !isNaN(ruleNum) && numVal === ruleNum;
default: return false;
}
}
// =====================
// Connection & Config
// =====================
@@ -730,4 +702,9 @@ export async function registerFinanceRoutes(app: Express): Promise<void> {
registerAutoDetectRoutes(app);
registerTimeseriesRoutes(app);
await registerSalaryRoutes(app);
registerDebtRoutes(app);
registerCalculationRoutes(app);
registerAuditRoutes(app);
registerGoogleSheetsRoutes(app);
startAuditScheduler();
}