From 93cb6422d5f101252e562483cb8ed7ecd8b0be51 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 20 Mar 2026 23:16:49 +0700 Subject: [PATCH] Refactor inventory health calculations and enhance account mismatch detection - Renamed and refactored `ledgerBalanceInCurrency` to `ledgerRowsInAccountCurrency` for clarity. - Introduced `accountHasApiLedgerMismatch` function to streamline balance mismatch checks between API and ledger. - Updated `computeInventoryHealth` and `getBalanceMismatchAccountIds` to utilize the new mismatch detection logic. - Enhanced user feedback in `AccountsPage` regarding balance discrepancies and ledger activity. --- src/lib/inventory-health.js | 51 ++++++++++++++++++++----------------- src/pages/AccountsPage.jsx | 4 ++- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/lib/inventory-health.js b/src/lib/inventory-health.js index cc5e85c..4a3abdc 100644 --- a/src/lib/inventory-health.js +++ b/src/lib/inventory-health.js @@ -2,12 +2,15 @@ import { getPaidUntilDate } from './paid-until' const STALE_SYNC_HOURS = 48 -function ledgerBalanceInCurrency(account, balanceLedger) { +function ledgerRowsInAccountCurrency(account, balanceLedger) { const cur = (account.balance_currency || account.currency || '').trim() const rows = balanceLedger.filter((row) => row.providerAccountId === account.id) - const filtered = cur - ? rows.filter((row) => !row.currency || row.currency === cur) - : rows + if (!cur) return rows + return rows.filter((row) => !row.currency || row.currency === cur) +} + +function ledgerBalanceInCurrency(account, balanceLedger) { + const filtered = ledgerRowsInAccountCurrency(account, balanceLedger) const credits = filtered .filter((row) => row.direction === 'credit') .reduce((acc, row) => acc + Number(row.amount || 0), 0) @@ -17,6 +20,23 @@ function ledgerBalanceInCurrency(account, balanceLedger) { return credits - debits } +/** + * Сравниваем баланс из API с суммой по balance_ledger. + * Если в ledger нет ни одной строки по аккаунту (в валюте баланса) — не считаем расхождением: + * пользователь видит только API, а «0 из ledger» — не противоречие, а отсутствие учёта. + */ +export function accountHasApiLedgerMismatch(account, balanceLedger) { + if (account.balance_api == null || !Number.isFinite(Number(account.balance_api))) return false + const rows = ledgerRowsInAccountCurrency(account, balanceLedger) + if (rows.length === 0) return false + const ledger = ledgerBalanceInCurrency(account, balanceLedger) + if (!Number.isFinite(ledger)) return false + const api = Number(account.balance_api) + const diff = Math.abs(api - ledger) + const tol = Math.max(10, Math.abs(api) * 0.05) + return diff > tol +} + export function lastOkSyncFinishedAt(accountId, syncLog) { const rows = (syncLog || []).filter( (r) => r.accountId === accountId && r.status === 'ok' && r.finishedAt, @@ -108,21 +128,14 @@ export function computeInventoryHealth(input) { }) } - const mismatchAccounts = providerAccounts.filter((a) => { - if (a.balance_api == null || !Number.isFinite(Number(a.balance_api))) return false - const ledger = ledgerBalanceInCurrency(a, balanceLedger) - if (!Number.isFinite(ledger)) return false - const api = Number(a.balance_api) - const diff = Math.abs(api - ledger) - const tol = Math.max(10, Math.abs(api) * 0.05) - return diff > tol - }) + const mismatchAccounts = providerAccounts.filter((a) => accountHasApiLedgerMismatch(a, balanceLedger)) if (mismatchAccounts.length) { issues.push({ key: 'balance-mismatch', title: 'Баланс API и ledger расходятся', count: mismatchAccounts.length, to: '/accounts?health=balance-mismatch', + hint: 'Считается только если в журнале «Баланс и списания» есть движения по аккаунту', }) } @@ -152,17 +165,7 @@ export function getStaleSyncAccountIds(providerAccounts, syncLog, now = new Date * @param {object[]} balanceLedger */ export function getBalanceMismatchAccountIds(providerAccounts, balanceLedger) { - return providerAccounts - .filter((a) => { - if (a.balance_api == null || !Number.isFinite(Number(a.balance_api))) return false - const ledger = ledgerBalanceInCurrency(a, balanceLedger) - if (!Number.isFinite(ledger)) return false - const api = Number(a.balance_api) - const diff = Math.abs(api - ledger) - const tol = Math.max(10, Math.abs(api) * 0.05) - return diff > tol - }) - .map((a) => a.id) + return providerAccounts.filter((a) => accountHasApiLedgerMismatch(a, balanceLedger)).map((a) => a.id) } /** diff --git a/src/pages/AccountsPage.jsx b/src/pages/AccountsPage.jsx index 8ce88ac..9378289 100644 --- a/src/pages/AccountsPage.jsx +++ b/src/pages/AccountsPage.jsx @@ -262,7 +262,9 @@ export function AccountsPage({ db, actions, settings, ratesData }) { highlightAccountIds?.size ? (
- Подсвечены аккаунты, где баланс API заметно расходится с суммой по ledger (та же валюта). + В колонке «Баланс» для BILLmanager показывается сумма из API (в двух строках — с конвертацией и в валюте аккаунта). + Здесь же сверяется с журналом на странице «Баланс и списания» (те же движения в валюте баланса). + Подсветка только если в журнале уже есть записи по аккаунту, но итог заметно не совпадает с API. Сбросить фильтр