Оформление и оплата заказа
grocery_checkoutFinalize grocery ordering with delivery and real payment. Validates stock availability, shows final sum, and charges only after user confirms the order.
Instructions
Полный чекаут: доставка → заказ → оплата. РЕАЛЬНЫЕ ДЕНЬГИ. app_id/point_id — из grocery_stores() (обязательны, тот же магазин что в корзине).
Если корзина просит больше остатка (count > countAvailable), тул останавливается ДО доставки: отвечает CART_QUANTITY_CONFLICT с перечнем SKU, заказ не создаётся и деньги не двигаются. Это проверка по инварианту корзины, а не расшифровка кода магазина. Уменьши до «в наличии» или замени (с согласия пользователя) и повтори.
Подтверждение — кнопка, не текст: тул сам делает предпросмотр (только бэкенд знает, во что пересчитаются весовые товары), показывает пользователю кнопки «Оформить заказ на N ₽ / Отмена» с ФИНАЛЬНОЙ суммой и оформляет заказ ровно на неё. Покажи состав корзины ДО вызова (кнопка называет только итог), но НЕ спрашивай «да/нет» текстом — согласие даёт кнопка. Клиент без элиситации получает отказ «ПЛАТЁЖ НЕ ВЫПОЛНЕН» — деньги там не двигаются вообще.
dry_run=True — ПРЕДПРОСМОТР: доводит до доставки и возвращает финальную сумму, НЕ создавая заказ и НЕ списывая деньги. Работает в любом клиенте. Нужен, если хочешь назвать пользователю итог и слот доставки заранее; для оплаты не обязателен — чекаут делает свой предпросмотр сам.
СЧЁТ СПИСАНИЯ по умолчанию — тот, которым пользователь последний раз платил за продукты В ПРИЛОЖЕНИИ (банк отдаёт его сам), а НЕ первый счёт с балансом. Хочешь другой — передай account_id из list_accounts(). Списанный счёт печатается в ответе.
expected_sum — необязательная сверка: сумма, которую ты уже называл пользователю (из dry_run). Если она разошлась с предпросмотром чекаута, кнопка покажет ОБЕ суммы («… было N — банк пересчитал»), а спишется та, что на кнопке. Банк дважды пересчитывает корзину уже ПОСЛЕ кнопки (веб-корзина, затем доставка); расхождение с суммой на кнопке (допуск 0.01 ₽) отменяет чекаут ДО создания заказа.
При неопределённом результате (заказ мог создаться) повтор БЛОКИРУЕТСЯ — сначала grocery_attempts() и проверь заказ в приложении. force=True — только если пользователь ЯВНО подтвердил, что прошлого заказа нет; кнопка при повторе показывается снова.
Реализация: тул асинхронный и запускает браузер Playwright в отдельном worker-потоке
(asyncio.to_thread) — sync_playwright падает, если звать его внутри event-loop, а
FastMCP крутит sync-тулы именно в loop. Если тул падает с Playwright-ошибкой —
проверь python -m playwright install chromium (в окружении MCP).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| force | No | ||
| app_id | No | ||
| dry_run | No | ||
| point_id | No | ||
| account_id | No | ||
| expected_sum | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |