Skip to content

feat(procurement): наличие и срок поставки с сайта + честный остаток поставщиков - #848

Merged
ShaerWare merged 1 commit into
mainfrom
local/fix/supplier-stock-unknown
Sep 27, 2026
Merged

ShaerWare merged 1 commit into
mainfrom
local/fix/supplier-stock-unknown

Conversation

@ShaerWare

Copy link
Copy Markdown
Owner

Summary

  • Сайт всё-таки отдаёт наличие и срок — в мете _remote_stock_blocks (meta_data товара), которую публичный Store API не показывает. site_adapter._availability() читает её → in_stock, stock_qty, lead_time_days (худший срок из блоков), сырые блоки в extra. Полный скан 30 163 товаров: блок заполнен у 2 375 (7,9 %), пуст у 27 788 («по запросу»); склад один, срок везде 1–2 дн., поставщики CHINT/SUNWELL/AXIMA/PRSTH.
  • Пустой блок → None, а не False — «по запросу» это «уточняется», а не подтверждённое отсутствие. Умолчание WooCommerce (stock_status=instock у всех 30 163, manage_stock выключен) наличием по-прежнему не считается.
  • «Остаток не указан» больше не значит «НЕТ в наличии» — файлы остатков перечисляют только то, что ЕСТЬ (у SunWell/EKF 838 артикулов против 20 728 строк прайса; у Аксимы/Chint пустые ячейки без единого явного нуля). Прежнее (row.get("stock") or 0) > 0 помечало 20 738 строк как отсутствующие без оснований, и ассистент отказывал клиенту по товарам, которые поставляются — зеркальное нарушение того же §5.5, что чинили в fix(procurement): не выдавать умолчание WooCommerce за наличие #847.
  • Кросс-источник _attach_supply() — позиции сайта дополняются тем, что известно у поставщиков (18 015 из 30 163 артикулов каталога есть в прайсах) → «есть у поставщика — уточнить только СРОК». Имя поставщика, остаток и дату прайса видит только менеджер, клиентские каналы — нет.
  • Суточный синк перестанет падать — replace_source_offers() схлопывает дубли source_key. Пагинация WooCommerce (302 запроса, ~10 минут) сдвигается, если каталог меняется на ходу, и товар попадает на две страницы: 25.09 синк упал на UNIQUE constraint failed: product_offers.source, product_offers.source_key и сутки остались без обновления.
  • CLAUDE.md — причина нулевых цен исправлена: это не вариативные товары (все type: simple), и прайсами поставщиков они не покрыты (совпадает 1 артикул из 11 378).

Relates to #841

NEWS

📦 Ассистент теперь знает сроки поставки, а не только «уточняется»

Магазин хранил реальные остатки и сроки поставки прямо в карточках товаров — но ассистент их не читал и про каждую позицию отвечал «наличие уточняется». Теперь по 2 375 товарам он говорит конкретно: сколько штук есть и что срок поставки 1–2 дня. А ещё перестал отказывать клиентам по товарам, которые на самом деле поставляются: раньше 20 тысяч позиций из прайсов поставщиков он ошибочно считал отсутствующими просто потому, что в файле остатков не было строки. Теперь по таким позициям он уточняет только срок.

Test plan

  • pytest tests/unit/test_site_remote_stock.py — 9 тестов: заполненный блок → наличие+срок, JSON-строка, несколько складов (сумма + худший срок), пустой блок → None, отсутствие меты, stock_status=instock не наличие, явный outofstock → False, битый блок не падает, оффер несёт сырые блоки
  • pytest tests/unit/test_supplier_stock_unknown.py — 10 тестов: неизвестный остаток → None, явный ноль → False, положительный → True, формулировки _supply_label (имя поставщика клиенту не утекает), аннотация позиции сайта из прайса, дубль source_key не роняет синк
  • pytest tests/unit/test_offer_search_ranking.py tests/unit/test_offer_query_builder.py — регресс ранжирования зелёный (29)
  • Весь procurement-набор — 48 passed
  • ruff check . + ruff format --check . — чисто
  • Перепарсил реальные прайсы локально: False было 20 738 → стало 0 (sunwell 792/0/19936, aksima 1340/0/581, chint 1416/0/221 True/False/None)
  • После деплоя: ре-синк каталога → ожидаем 2 375 строк с in_stock=1 и непустым lead_time_days (сейчас в проде 0)

🤖 Generated with Claude Code

…поставщиков

Сайт хранит настоящие данные о наличии в мете `_remote_stock_blocks`
(`[{"warehouse":"Удалённый склад","supplier":"PRSTH","qty":2,
"lead_time_min":1,"lead_time_max":2}]`) и рендерит их в карточке как
«Наличие · В наличии · 2 шт. Срок поставки 1-2 дн.». Публичный Store API
эту мету не отдаёт, поэтому раньше казалось, что данных нет вообще.
Полный скан каталога: блок заполнен у 2 375 товаров из 30 163 (7,9 %),
срок везде 1–2 дн., склад один, поставщики CHINT/SUNWELL/AXIMA/PRSTH.

- site_adapter: `_availability()` читает блоки → `in_stock`, `stock_qty`,
  `lead_time_days` (ХУДШИЙ срок из блоков — обещать быстрее нельзя),
  сырые блоки в `extra`. Пустой блок → `None` («по запросу»), а не `False`.
  Умолчание WooCommerce наличием по-прежнему не считается.
- suppliers: «остаток не указан» больше не превращается в «НЕТ в наличии».
  Файлы остатков перечисляют только то, что ЕСТЬ (у SunWell/EKF 838
  артикулов против 20 728 строк прайса), а прежнее `(stock or 0) > 0`
  помечало 20 738 строк как отсутствующие без оснований — ассистент
  отказывал клиенту по товарам, которые поставляются.
- OfferService._attach_supply(): позиции сайта дополняются тем, что
  известно у поставщиков (18 015 из 30 163 артикулов есть в прайсах) →
  «есть у поставщика — уточнить только СРОК». Имя поставщика и остаток
  видит только менеджер.
- replace_source_offers(): схлопывает дубли `source_key`. Пагинация
  WooCommerce (302 запроса, ~10 минут) сдвигается, если каталог меняется
  на ходу, и товар попадает на две страницы — 25.09 суточный синк упал
  на UNIQUE(source, source_key) и сутки остались без обновления.
- CLAUDE.md: причина нулевых цен исправлена — это НЕ вариативные товары
  (все `type: simple`), и прайсами поставщиков они не покрыты.

Тесты: 19 новых (test_site_remote_stock.py, test_supplier_stock_unknown.py),
весь procurement-набор 48 passed.

## NEWS

📦 **Ассистент теперь знает сроки поставки, а не только «уточняется»**

Магазин хранил реальные остатки и сроки поставки прямо в карточках товаров —
но ассистент их не читал и про каждую позицию отвечал «наличие уточняется».
Теперь по 2 375 товарам он говорит конкретно: сколько штук есть и что срок
поставки 1–2 дня. А ещё перестал отказывать клиентам по товарам, которые
на самом деле поставляются: раньше 20 тысяч позиций из прайсов поставщиков
он ошибочно считал отсутствующими просто потому, что в файле остатков не
было строки. Теперь по таким позициям он уточняет только срок.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ShaerWare
ShaerWare merged commit a67faad into main Sep 27, 2026
3 checks passed
@ShaerWare
ShaerWare deleted the local/fix/supplier-stock-unknown branch September 27, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant