Files
Deal/src/core/Deal.Modules.Kanban/Application/ColumnRules/BudgetInRange.cs
T
Rustam Khalimov 9e07568ddd Инициализировать репозиторий «Дейл»
Первый коммит: модульный монолит ядра (.NET 10) и gRPC-сервисы
ai/ml/telegram, фронтенд Vue 3/Vite/Tailwind, документация (ТЗ,
инструкция пользователя, техдокументация, код-стайл), бэклог,
скрипты развёртывания и архив прототипа LeadRadar.
2026-09-11 02:50:17 +03:00

81 lines
3.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Deal.Modules.Kanban.Application.Models;
using Deal.Modules.Settings.Application;
namespace Deal.Modules.Kanban.Application.ColumnRules;
/// <summary>
/// Проверка попадания распознанных сумм в бюджетный диапазон правил колонки (rules.py _amount_in_range L147–173).
/// </summary>
/// <remarks>
/// «Интерфейс курсов» — чистый: сравнение в одной валюте не требует курсов, при разных валютах суммы
/// конвертируются по словарю «код → курс к рублю» через чистую <see cref="RatesService.ConvertAmount"/>
/// (Settings, rates.py L86–103): USDT приравнивается к USD, отсутствующая валюта → сумма пропускается.
/// Курсы — параметр функции: чтение кэша ratesCache (Ruling 7) остаётся за вызывающим (CardsService и
/// др.), модуль и функция не ходят в БД. Границы из null → диапазон без ограничений (True), как прототип.
/// </remarks>
public static class BudgetInRange
{
/// <summary>
/// Попадает ли хотя бы одна распознанная сумма в диапазон правил (rules.py L147–173).
/// </summary>
/// <param name="amounts">Суммы из текста (<see cref="AmountParser.Parse"/>).</param>
/// <param name="budget">Бюджет правил колонки (валюта пуста → USD, как в прототипе L157).</param>
/// <param name="rates">Курсы к рублю «код → курс» либо null (конвертация невозможна).</param>
/// <returns>
/// True — есть сумма, которая после конвертации (при необходимости) ≥ from и ≤ to; обе границы null → True;
/// пустые amounts или непереводимая валюта → False.
/// </returns>
public static bool IsInRange(IReadOnlyList<AmountRange> amounts, BudgetRangeDto budget, IReadOnlyDictionary<string, double>? 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;
}
}