using Deal.Modules.Kanban.Application.Models; using Deal.Modules.Settings.Application; namespace Deal.Modules.Kanban.Application.ColumnRules; /// /// Проверка попадания распознанных сумм в бюджетный диапазон правил колонки (rules.py _amount_in_range L147–173). /// /// /// «Интерфейс курсов» — чистый: сравнение в одной валюте не требует курсов, при разных валютах суммы /// конвертируются по словарю «код → курс к рублю» через чистую /// (Settings, rates.py L86–103): USDT приравнивается к USD, отсутствующая валюта → сумма пропускается. /// Курсы — параметр функции: чтение кэша ratesCache (Ruling 7) остаётся за вызывающим (CardsService и /// др.), модуль и функция не ходят в БД. Границы из null → диапазон без ограничений (True), как прототип. /// public static class BudgetInRange { /// /// Попадает ли хотя бы одна распознанная сумма в диапазон правил (rules.py L147–173). /// /// Суммы из текста (). /// Бюджет правил колонки (валюта пуста → USD, как в прототипе L157). /// Курсы к рублю «код → курс» либо null (конвертация невозможна). /// /// True — есть сумма, которая после конвертации (при необходимости) ≥ from и ≤ to; обе границы null → True; /// пустые amounts или непереводимая валюта → False. /// public static bool IsInRange(IReadOnlyList amounts, BudgetRangeDto budget, IReadOnlyDictionary? rates) { double? lo = budget.From; double? hi = budget.To; if (lo is null && hi is null) { return true; } string targetCurrency = string.IsNullOrWhiteSpace(budget.Cur) ? "USD" : budget.Cur.ToUpperInvariant(); foreach (AmountRange amount in amounts) { double? rawValue = amount.From ?? amount.To; if (rawValue is null) { continue; } double? value; if (string.Equals(amount.Cur, targetCurrency, StringComparison.OrdinalIgnoreCase)) { value = rawValue; } else if (rates is null) { continue; } else { value = RatesService.ConvertAmount(rawValue, amount.Cur, targetCurrency, rates); } if (value is null) { continue; } if (lo is not null && value < lo) { continue; } if (hi is not null && value > hi) { continue; } return true; } return false; } }