frappe_docker/docs/superpowers/specs/2026-03-20-moysklad-orders-sync-design.md

86 lines
6 KiB
Markdown
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.

# МойСклад: синхронизация заказов покупателей
**Дата:** 2026-03-20
**Приложение:** `picking_app`
## Цель
Расширить существующую интеграцию с МойСкладом: добавить синхронизацию заказов покупателей (customerorder) в очередь комплектации наравне с перемещениями (move).
## Контекст
В `picking_app` уже реализована синхронизация перемещений (`sync_picking_list()`), хранение токена в `Picking Settings`, пагинация через `nextHref`. Заказы должны попасть в ту же очередь с минимальными изменениями в UI и логике комплектации.
## Модель данных
### Picking Settings — новое поле
| Поле | Тип | Значение по умолчанию |
|------|-----|----------------------|
| `ms_order_state` | Data | `"Подтверждён"` |
Поле помечается `reqd: 1` и `default: "Подтверждён"` в DocType, чтобы пустое значение было исключено на уровне схемы. Дополнительно в коде: если значение пустое — использовать `"Подтверждён"` как runtime-fallback.
### Picking List — новые поля
| Поле | Тип | Значение |
|------|-----|---------|
| `source_type` | Select | `"Move"` / `"Order"` |
**Уникальность `ms_id`:** текущий `unique: 1` на поле `ms_id` снять. Вместо этого хранить `ms_id` с префиксом типа:
- Перемещения: `move:{uuid}`
- Заказы: `order:{uuid}`
Это исключает коллизии UUID между разными типами сущностей МС.
## Логика синхронизации
### `sync_picking_list()` — изменения
- При **создании** новой записи проставлять `source_type = "Move"` и `ms_id = "move:{uuid}"`
- При **обновлении** существующей записи — также проставлять `source_type = "Move"` если поле пустое (backfill)
### `sync_picking_orders()`
1. Читает `ms_order_state` из `Picking Settings`; если пусто — использует `"Подтверждён"`
2. Тянет `customerorder` из МС:
```
GET /entity/customerorder
expand=state,store,positions.assortment,positions.assortment.uom
limit=100
order=moment,desc
```
`store` обязательно включён в expand — иначе объект склада придёт как stub без `name`/`id`.
3. Фильтрует на клиенте: `order["state"]["name"] == ms_order_state`
4. `to_warehouse` берётся из объекта `store` через существующий `_extract_store_id()`; `from_warehouse` — пустой
5. `ms_id` сохраняется с префиксом `"order:{uuid}"`
6. При **создании**`source_type = "Order"`. При **обновлении**`source_type` всегда перезаписывается значением `"Order"` (поле не является иммутабельным).
**Производительность:** фильтрация по статусу происходит на клиенте после получения всех страниц (МС API не поддерживает фильтр по `state.name` напрямую без UUID состояния). Лимит: не более 1000 заказов за одну синхронизацию (10 страниц по 100) — это осознанный компромисс.
### `sync_all()` — новая публичная функция (`@frappe.whitelist`)
Вызывает последовательно `sync_picking_list()` и `sync_picking_orders()`, возвращает суммарный результат:
```json
{"status": "ok", "moves": {"created": N, "updated": N}, "orders": {"created": N, "updated": N}}
```
## Исправление существующего бага
В `add_items_from_picking_list()` строка 462 содержит ссылку на неопределённую переменную `added_rows` вместо `added_row_names`. Исправить в рамках этой задачи, иначе функция упадёт с `NameError` при первом же вызове.
## API: `get_picking_list_items()`
Добавить опциональный параметр `source_type`:
- `source_type=None` — вернуть все записи (включая NULL из legacy)
- `source_type="Move"` / `"Order"` — фильтровать по значению; NULL-записи при `"Move"` **включаются** (обратная совместимость)
Добавить `source_type` в список возвращаемых полей (`fields`), чтобы UI мог рендерить колонку "Тип".
## UI
В попап-диалоге выбора позиций:
- Добавить колонку **Тип**: отображает "Перемещение" (Move и NULL) / "Заказ" (Order)
- Добавить фильтр по типу: табы или кнопки **Все / Перемещения / Заказы**
- Логика добавления позиций в `Picking Document` — без изменений
## Прочее
- Поле `ms_date` в UI показывает "Дата перемещения" — для заказов это несточное название. Принимаем как допустимое упрощение: переименование метки выходит за рамки задачи.
- Статусная машина Picking List (Draft → Partial → Added) — без изменений
- Структура `Picking List Item` — без изменений