< Summary

Information
Class: Services.AiAssistant.BitrixStockSyncAiKnowledge
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/AiAssistant/BitrixStockSyncAiKnowledge.cs
Line coverage
100%
Covered lines: 61
Uncovered lines: 0
Coverable lines: 61
Total lines: 71
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
GetPromptSection()100%11100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/AiAssistant/BitrixStockSyncAiKnowledge.cs

#LineLine coverage
 1namespace Services.AiAssistant;
 2
 3/// <summary>
 4/// Сжатая база знаний BitrixStock для промпта LLM (этапы 1–5, правила остатков и цен).
 5/// Источник: AppRepository/BitrixStockServices/README.md, UI /Studio2/BitrixStock?tab=sync
 6/// </summary>
 7public static class BitrixStockSyncAiKnowledge
 8{
 9    public static string GetPromptSection() =>
 810        """
 811        ═══ BITRIXSTOCK — СИНХРОНИЗАЦИЯ OZON И 1С (/Studio2/BitrixStock?tab=sync) ═══
 812
 813        Цепочка этапов (PresetStageSettings в пресете):
 814        • Этап 1 — отчёт: сравнение остатков 1С (WarehouseStockSnapshot) и Ozon → строки с Action.
 815        • Этап 2 — накат остатков в Ozon (POST /v2/products/stocks) по строкам Push/Decrease/Clear.
 816        • Этап 3 — очистка лишних FBS-складов (CleanupExtra): обнуление складов Ozon, не входящих в «защищённые».
 817        • Этап 4 — накат цен: PriceOptimizationManager → ImportProductPrices (пакеты до 1000).
 818        • Этап 5 — сироты и партии [N]: фаза 5a (batch из ozon_products) → фаза 5b (сироты non-batch).
 819
 820        Правила Action на этапе 1 (определяют целевой остаток для этапа 2):
 821        • Push — остаток Ozon < 1С, цель = OneCQty (с учётом резерва ReservedQty и суммы LinkStores B1+B2→B12).
 822        • Decrease — Ozon > 1С, цель = OneCQty.
 823        • Clear — 1С=0, обнулить Ozon.
 824        • Match — уже совпадает, накат не нужен.
 825        • NotFound / FbsNoWarehouse / NotForSale — особые случаи (нет в Ozon, нет маппинга склада, снят с продажи).
 826        • CleanupExtra — этап 3: лишний FBS-склад обнулён.
 827        • BatchVariant / BatchVariantDisabledLink — этап 5a: партия [N], floor(1С/N) упаковок; disabled-связь → 0.
 828
 829        Маппинг складов: WarehouseMapping связывает склад 1С (OneCStore) с OzonWarehouseName.
 830        Коллизия B1+B2→один Ozon: остатки 1С СУММИРУЮТСЯ (GetLinkedOneCQuantity).
 831        FBS-fallback (SDS): если Ozon не отдаёт разбивку по складам — остаток на все маппинги клиента.
 832
 833        Партии [N] в OfferId (ARTICLE=BRAND[N], N≥2):
 834        • На Ozon продаётся упаковка из N шт.; в 1С — штучный остаток.
 835        • Целевой остаток на Ozon = floor(OneCQty / N).
 836        • Цена партии = winnerPrice × N (PriceOptimizationManager, этап 5a или 2 с BatchMultiplier).
 837        • [1] не считается партией.
 838
 839        Этап 4 — цены:
 840        • Снимок цен Ozon сохраняется на этапе 1 (BitrixStockSyncReportOzonPrices).
 841        • Победитель: PriceOptimizationManager.Calculate (C0 из 1С, комиссии, индекс цены).
 842        • Unchanged — если отличие < 1 ₽; Error — ошибка Ozon после VAT-ретрая.
 843        • Индексы: SUPER/GREEN (выгодный), YELLOW (умеренный), RED (невыгодный), WITHOUT_INDEX.
 844
 845        Этап 5 — сироты (5b):
 846        • Сирота = остаток на Ozon (offer_id+склад) без покрытия в отчёте/снэпшоте → OzonZero.
 847        • Сопоставление: exact offer_id, normalized [N], артикул+склад.
 848
 849        Мульти-клиент K1/K2: при коллизии одного товара у двух Ozon-клиентов приоритет у K1.
 850
 851        КОЛИЧЕСТВА — НЕ ПУТАТЬ ИСТОЧНИКИ:
 852        • Таблица WarehouseStock и карта движений 1С OData могут показывать ДРОБНЫЕ единицы (напр. 9.7).
 853        • Отчёт BitrixStock: OneCQty и OzonQty — ЦЕЛЫЕ (int); при построении отчёта остаток 1С округляется Math.Round.
 854        • Накат в Ozon API (/v2/products/stocks) принимает только целые — цель из OneCQty отчёта, не дробь из таблицы.
 855        • НЕ выдумывай «округление вверх до 10», если в строке отчёта OneCQty=9 — опирайся на поля отчёта.
 856        • Если в таблице 1С дробь, а в отчёте целое — явно раздели два источника и укажи правило Round.
 857
 858        ЦЕНЫ — НЕ ВЫДУМЫВАТЬ ФОРМУЛЫ:
 859        • Бери C0, TruePrice, пуши этапа 4 и индекс ТОЛЬКО из строк отчёта и хронологии цен.
 860        • Не придумывай «CostPrice × 1.25» — расчёт делает PriceOptimizationManager; цифры из данных.
 861
 862        КАК ОТВЕЧАТЬ НА «ПОЧЕМУ ТАКАЯ ЦЕНА / КОЛИЧЕСТВО»:
 863        1. Назови склад 1С и склад Ozon из строки отчёта.
 864        2. Укажи OneCQty, OzonQty, Action и правило этапа (см. выше).
 865        3. Если BatchMultiplier>1 или OfferId с [N] — объясни пересчёт floor(1С/N).
 866        4. Для цены — индекс, C0, пуш этапа 4/5a (было→стало) из хронологии.
 867        5. Сошлись на ВСЕ отчёты по артикулу — не только последний.
 868        6. В конце предложи «Актуально на Ozon» — live-данные из Ozon Seller API.
 869        7. Упоминай статусы в кавычках «…» для подсветки в чате.
 870        """;
 71}

Methods/Properties

GetPromptSection()