From a21ce5d80e3ed0dd75917f0f248e676226b27c32 Mon Sep 17 00:00:00 2001 From: Sergey Martynov Date: Thu, 23 Apr 2026 16:39:17 +0300 Subject: [PATCH] docs(bitrix): loyalty and order integration guides Add Bitrix-focused documentation for customer checks, mobile confirmation, cart calculation, order creation (authorized/unauthorized), offline orders, customer orders list, and bonus points history. Update README index. Made-with: Cursor --- docs/bitrix/README.md | 8 +- docs/bitrix/cart-calculate.md | 167 +++++++++++++++++++++++++ docs/bitrix/customer-bonus-history.md | 76 +++++++++++ docs/bitrix/customer-check.md | 144 +++++++++++++++++++++ docs/bitrix/customer-mobile-confirm.md | 126 +++++++++++++++++++ docs/bitrix/customer-orders.md | 69 ++++++++++ docs/bitrix/order-create.md | 164 ++++++++++++++++++++---- docs/bitrix/order-offline.md | 74 +++++++++++ 8 files changed, 801 insertions(+), 27 deletions(-) create mode 100644 docs/bitrix/cart-calculate.md create mode 100644 docs/bitrix/customer-bonus-history.md create mode 100644 docs/bitrix/customer-check.md create mode 100644 docs/bitrix/customer-mobile-confirm.md create mode 100644 docs/bitrix/customer-orders.md create mode 100644 docs/bitrix/order-offline.md diff --git a/docs/bitrix/README.md b/docs/bitrix/README.md index b31b091..911f395 100644 --- a/docs/bitrix/README.md +++ b/docs/bitrix/README.md @@ -148,9 +148,12 @@ EventManager::getInstance()->addEventHandler( | Документ | Описание | | --------------------------------------------- | ---------------------------------------- | | [Регистрация клиента](./customer-register.md) | Создание нового клиента в Mindbox | +| [Проверка клиента](./customer-check.md) | CheckCustomer / по email / по телефону | | [Редактирование клиента](./customer-edit.md) | Обновление данных существующего клиента | +| [Подтверждение телефона](./customer-mobile-confirm.md) | `ConfirmMobilePhone`, повторная отправка кода | | [Авторизация клиента](./customer-auth.md) | Вход и привязка сессии к клиенту Mindbox | | [Подписка на рассылки](./customer-subscribe.md) | Подписка через форму (SubscriptionInFooter) | +| [История бонусов](./customer-bonus-history.md) | `GetCustomerBonusPointsHistory` | ### Списки продуктов @@ -159,6 +162,7 @@ EventManager::getInstance()->addEventHandler( | Документ | Описание | | ----------------------------------------- | ------------------------------------ | | [Список «Корзина»](./list-cart.md) | Установка и синхронизация корзины | +| [Расчёт корзины](./cart-calculate.md) | Preorder: CalculateCart / Authorized / Unauthorized | | [Список «Избранное»](./list-favorites.md) | Установка и синхронизация избранного | @@ -167,7 +171,9 @@ EventManager::getInstance()->addEventHandler( | Документ | Описание | | ------------------------------------ | ------------------------------- | -| [Создание заказа](./order-create.md) | Оформление заказа через Mindbox | +| [Создание заказа](./order-create.md) | CreateAuthorizedOrder / CreateUnauthorizedOrder | +| [Заказы клиента](./customer-orders.md) | `GetCustomerOrders` | +| [Офлайн-заказ](./order-offline.md) | `SaveOfflineOrder`, очередь, агент | Точные имена операций Mindbox и поля запросов — у менеджера и в [документации API](https://developers.mindbox.ru/docs/v3). \ No newline at end of file diff --git a/docs/bitrix/cart-calculate.md b/docs/bitrix/cart-calculate.md new file mode 100644 index 0000000..0c068d5 --- /dev/null +++ b/docs/bitrix/cart-calculate.md @@ -0,0 +1,167 @@ +# Расчёт корзины (preorder) (Битрикс + Mindbox) + +Запрос предварительного расчёта корзины в Mindbox: скидки, промо, итог до оформления заказа. В SDK это методы `**OrderHelper**` с телом `**PreorderRequestDTO**`. + +**Предусловия:** выполнен [быстрый старт](./README.md) (SDK, конфиг, `getMindboxClient()`). Состав корзины в Mindbox для других сценариев может синхронизироваться отдельно — см. [установка корзины](./list-cart.md). + +Точку вызова в Битрикс выбирайте сами: компонент оформления, AJAX при изменении корзины, шаг checkout и т.д. Ниже — только фрагменты вызова SDK, без регистрации обработчиков событий. + +--- + +## Рекомендации + +- **Скидки на сайте и Mindbox.** Если на витрине уже действуют **собственные** скидки (правила Битрикс, каталог, промокоды сайта и т.п.), **сначала** примените их к позициям и ценам **на своей стороне**, **затем** передайте актуальный состав и цены в `**CalculateAuthorizedCart`** (или другую операцию расчёта из вашего проекта), чтобы Mindbox выполнил **итоговый** расчёт персональных акций и промо поверх уже учтённых скидок. Иначе расчёт в Mindbox может не совпасть с тем, что видит пользователь до запроса. +- **Задержка и UX.** Один запрос расчёта обычно занимает порядка **200–300 мс**. Имеет смысл **не блокировать** отрисовку корзины и чекаута: сначала показать **базовые** цены (или последний известный итог), а вызов Mindbox выполнить **асинхронно** с точки зрения интерфейса — например, отдельным **AJAX** к вашему PHP-обработчику, который внутри вызывает SDK; по ответу обновить суммы и персональные скидки. На сервере вызов `OrderHelper` остаётся обычным синхронным HTTP к API Mindbox. + +--- + +## Операции и хелпер + +Имена `**Website.*`** — примеры; **уточните у менеджера Mindbox** для вашего endpoint. + + +| Операция Mindbox (пример) | Хелпер SDK | DeviceUUID в запросе (как в SDK) | +| ----------------------------------- | --------------------------------------------------- | -------------------------------- | +| `Website.CalculateCart` | `calculateCart($order, $operationName)` | Нет (`false`) | +| `Website.CalculateAuthorizedCart` | `calculateAuthorizedCart($order, $operationName)` | Да (`true`) | +| `Website.CalculateUnauthorizedCart` | `calculateUnauthorizedCart($order, $operationName)` | Да (`true`) | + + +Все три метода отправляют запрос **синхронно** (режим зашит в `OrderHelper`). Ответ ожидается как `**MindboxOrderResponse`**. + +Документация Mindbox: [предварительный расчёт (preorder)](https://developers.mindbox.ru/docs/preorderxml), [processing calculate](https://developers.mindbox.ru/docs/processing-calculate). + +--- + +## Входные данные + +`PreorderRequestDTO` наследует поля заказа: как минимум `**customer**` (`CustomerRequestDTO`) и `**lines**` (`LineRequestCollection` из `LineRequestDTO`) — полный набор полей зависит от операции в проекте. При необходимости используйте `**setCalculationDateTimeUtc()**` и другие поля из [общих примеров SDK](../examples/order_helper.md). + +--- + +## Пример: неавторизованный расчёт (`CalculateCart`) + +```php +setEmail('guest@example.com'); + +$line = new LineRequestDTO(); +$product = new ProductRequestDTO(); +$product->setId('productId', '12345'); +$product->setName('Товар'); +$product->setPrice(1000.0); +$line->setProduct($product); +$line->setQuantity(2); + +$order = new PreorderRequestDTO(); +$order->setCustomer($customer); +$order->setLines(new LineRequestCollection([$line])); + +try { + $response = getMindboxClient() + ->order() + ->calculateCart($order, 'Website.CalculateCart') + ->sendRequest(); +} catch (MindboxClientException $e) { + // Логирование +} +``` + +--- + +## Пример: расчёт для авторизованного пользователя (`CalculateAuthorizedCart`) + +```php +setId('bitrixId', (string)$userId); +$customer->setEmail($userEmail); + +$line = new LineRequestDTO(); +$product = new ProductRequestDTO(); +$product->setId('productId', '12345'); +$product->setName('Товар'); +$product->setPrice(1000.0); +$line->setProduct($product); +$line->setQuantity(2); + +$order = new PreorderRequestDTO(); +$order->setCustomer($customer); +$order->setLines(new LineRequestCollection([$line])); + +try { + $response = getMindboxClient() + ->order() + ->calculateAuthorizedCart($order, 'Website.CalculateAuthorizedCart') + ->sendRequest(); +} catch (MindboxClientException $e) { + // Логирование +} +``` + +--- + +## Пример: расчёт без авторизации с DeviceUUID (`CalculateUnauthorizedCart`) + +Используется, когда в проекте задействована операция `**Website.CalculateUnauthorizedCart**` (аналогично авторизованному по составу DTO, идентификация клиента — по правилам операции и DeviceUUID в SDK). + +```php +setEmail('guest@example.com'); + +$line = new LineRequestDTO(); +$product = new ProductRequestDTO(); +$product->setId('productId', '12345'); +$product->setName('Товар'); +$product->setPrice(1000.0); +$line->setProduct($product); +$line->setQuantity(1); + +$order = new PreorderRequestDTO(); +$order->setCustomer($customer); +$order->setLines(new LineRequestCollection([$line])); + +try { + $response = getMindboxClient() + ->order() + ->calculateUnauthorizedCart($order, 'Website.CalculateUnauthorizedCart') + ->sendRequest(); +} catch (MindboxClientException $e) { + // Логирование +} +``` + +--- + +## Ошибки и отладка + +- Сверка XML/JSON тела с контрактом операции в кабинете Mindbox. +- Несовпадение внешних id товаров с [установкой корзины](./list-cart.md) — везде используйте согласованный `productId`. +- Дополнительные сценарии процессинга: [OrderHelper в общих примерах](../examples/order_helper.md). + diff --git a/docs/bitrix/customer-bonus-history.md b/docs/bitrix/customer-bonus-history.md new file mode 100644 index 0000000..ce9fcb8 --- /dev/null +++ b/docs/bitrix/customer-bonus-history.md @@ -0,0 +1,76 @@ +# История изменений бонусного баланса (`GetCustomerBonusPointsHistory`) + +Операция `**Website.GetCustomerBonusPointsHistory**` возвращает историю начислений и списаний баллов лояльности для потребителя в Mindbox. + +**Предусловия:** выполнен [быстрый старт](./README.md) (SDK, конфиг, `getMindboxClient()`). + +--- + +## Параметры интеграции + + +| Параметр | Значение | +| ---------------- | --------------------------------------------------------------------------------------------------------- | +| Операция Mindbox | `Website.GetCustomerBonusPointsHistory` (имя **уточните у менеджера**) | +| Хелпер SDK | `getMindboxClient()->customer()->getBonusPointsHistory($customer, $page, $operationName, $addDeviceUUID)` | +| Вход | `CustomerRequestDTO` (идентификация клиента), `PageRequestDTO` (пагинация) | +| Ответ SDK | `MindboxBonusPointsResponse` | +| Синхронность | **Синхронно** (`isSync: true`), параметр задаётся внутри `CustomerHelper` | + + +Документация Mindbox: [получение истории изменений баланса](https://developers.mindbox.ru/docs/получение-истории-изменений-баланса-потребителя). + +Сигнатура: + +```php +public function getBonusPointsHistory( + CustomerRequestDTO $customer, + PageRequestDTO $page, + $operationName, + $addDeviceUUID = true +) +``` + +--- + +## Пример кода + +Идентификация клиента — как в других сценариях: например `setId('mindboxId', …)` или `setId('bitrixId', …)` по договорённости с проектом Mindbox. + +```php +setId('bitrixId', (string)$userId); + +$page = new PageRequestDTO(); +$page->setItemsPerPage(10); +$page->setPageNumber(1); + +try { + $response = getMindboxClient() + ->customer() + ->getBonusPointsHistory( + $customer, + $page, + 'Website.GetCustomerBonusPointsHistory', + true + ) + ->sendRequest(); +} catch (MindboxClientException $e) { + // Логирование +} +``` + +При необходимости задайте в `PageRequestDTO` фильтр по датам: `setSinceDateTimeUtc()`, `setTillDateTimeUtc()` — по контракту операции. + +--- + +## Ошибки и отладка + +- См. [CustomerHelper в общих примерах SDK](../examples/customer_helper.md), [исключения SDK](../examples/exceptions.md). + diff --git a/docs/bitrix/customer-check.md b/docs/bitrix/customer-check.md new file mode 100644 index 0000000..2a280e7 --- /dev/null +++ b/docs/bitrix/customer-check.md @@ -0,0 +1,144 @@ +# Проверка клиента в Mindbox (Битрикс + Mindbox) + +Операции **Check** запрашивают у Mindbox данные потребителя по идентификатору (email, телефон или универсальная проверка). Точное поведение (найден / не найден, состав полей в ответе) задаётся **операцией в проекте Mindbox** и сценарием на стороне Mindbox. + +**Предусловия:** выполнен [быстрый старт](./README.md) (SDK, конфиг, `getMindboxClient()`). + +--- + +## Параметры интеграции (типовые) + +Имена операций ниже — **стандартные примеры**; финальные строки (`Website.*`) **уточните у менеджера Mindbox** под ваш endpoint. + + +| Операция Mindbox (пример) | Хелпер SDK (`$mindbox->customer()->…`) | Идентификация в `CustomerRequestDTO` | +| ------------------------------------ | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Website.CheckCustomer` | `checkCustomer(...)` | Заполните поля по [документации операции](https://developers.mindbox.ru/docs/получение-данных-потребителя) (часто email и/или телефон, внешние id и т.д.) | +| `Website.CheckCustomerByMobilePhone` | `checkByPhone(...)` | `setMobilePhone()` (обычно только цифры) | +| `Website.CheckCustomerByEmail` | `checkByMail(...)` | `setEmail()` | + + +**Ответ SDK:** для всех трёх методов клиент ожидает `MindboxCustomerResponse` — после `sendRequest()` можно вызвать `$response->getCustomer()` (`CustomerResponseDTO|null`) и при необходимости `$response->getDiscountCards()`. + +**Синхронность:** в текущей версии SDK эти три метода вызывают API **только синхронно** (`prepareRequest` с фиксированным синхронным режимом). Учитывайте задержку HTTP при вызове из событий Битрикс. + +--- + +## События Битрикс и собственные обработчики + +Типовые точки, где нужна проверка «есть ли клиент в Mindbox» **до** создания пользователя в Битрикс: + + +| Точка | Документация | +| ----------------------------------------- | ---------------------------------------------------------------------------------------------- | +| До добавления пользователя (`CUser::Add`) | [OnBeforeUserAdd](https://dev.1c-bitrix.ru/api_help/main/events/onbeforeuseradd.php) | +| До регистрации (`CUser::Register`) | [OnBeforeUserRegister](https://dev.1c-bitrix.ru/api_help/main/events/onbeforeuserregister.php) | + + +По документации Битрикс, чтобы **отменить** добавление/регистрацию, в обработчике нужно вызвать `$APPLICATION->ThrowException('...')` и **вернуть `false`**. + +Альтернатива — не вешаться на события ядра, а вызывать проверку из **своего контроллера, AJAX или компонента** (например, перед отправкой формы регистрации): так проще управлять UX и таймаутами. + +--- + +## Полный пример: `OnBeforeUserRegister` + проверка по email + +Ниже — проверка через `Website.CheckCustomerByEmail`. Если в ответе есть клиент, регистрация отменяется с сообщением пользователю. Политику при `MindboxClientException` (блокировать или пропускать) задайте в проекте. + +```php +addEventHandler( + 'main', + 'OnBeforeUserRegister', + static function (&$arFields) { + $email = trim((string)($arFields['EMAIL'] ?? '')); + if ($email === '') { + return; + } + + $customer = new CustomerRequestDTO(); + $customer->setEmail($email); + + try { + $response = getMindboxClient() + ->customer() + ->checkByMail($customer, 'Website.CheckCustomerByEmail', true) + ->sendRequest(); + + if ($response->getCustomer() !== null) { + global $APPLICATION; + $APPLICATION->ThrowException('Указанный e-mail уже участвует в программе. Войдите или восстановите доступ.'); + return false; + } + } catch (MindboxClientException $e) { + // Пример: не блокируем регистрацию при недоступности Mindbox; иначе — ThrowException + return false + } + } +); +``` + +--- + +## Фрагмент: проверка по телефону + +Используйте `**checkByPhone**` и операцию `**Website.CheckCustomerByMobilePhone**`. (Для проверки по email — метод `**checkByMail**`: в SDK он назван с `Mail`, не `Email`.) + +```php +$customer = new CustomerRequestDTO(); +$phone = preg_replace('/\D+/', '', $rawPhone); +if ($phone === '') { + return; +} +$customer->setMobilePhone($phone); + +$response = getMindboxClient() + ->customer() + ->checkByPhone($customer, 'Website.CheckCustomerByMobilePhone', true) + ->sendRequest(); + +$mindboxCustomer = $response->getCustomer(); +``` + +--- + +## Фрагмент: универсальная операция `Website.CheckCustomer` + +Имя операции передаётся вторым аргументом; набор полей в `CustomerRequestDTO` должен соответствовать вашему сценарию Mindbox. + +```php +$customer = new CustomerRequestDTO(); +$customer->setEmail($email); +// при необходимости: $customer->setMobilePhone($phone); +// $customer->setId('bitrixId', (string)$bitrixUserId); + +$response = getMindboxClient() + ->customer() + ->checkCustomer($customer, 'Website.CheckCustomer', true) + ->sendRequest(); +``` + +--- + +## Сигнатуры хелпера + +Все три метода имеют одинаковые параметры после DTO: + +- `checkCustomer(CustomerRequestDTO $customer, $operationName, $addDeviceUUID = true)` +- `checkByPhone(CustomerRequestDTO $customer, $operationName, $addDeviceUUID = true)` +- `checkByMail(CustomerRequestDTO $customer, $operationName, $addDeviceUUID = true)` + +`**$addDeviceUUID**` — передавать ли DeviceUUID в запросе (`true` / `false` по правилам проекта). + +--- + +## Ошибки и отладка + +- Перехват `MindboxClientException`, логирование без утечки ПДн в публичные ответы. +- Сверка тела запроса и семантики ответа с [документацией Mindbox](https://developers.mindbox.ru/docs/v3) и описанием операции у менеджера. +- Дополнительные сценарии: [CustomerHelper в общих примерах SDK](../examples/customer_helper.md). + diff --git a/docs/bitrix/customer-mobile-confirm.md b/docs/bitrix/customer-mobile-confirm.md new file mode 100644 index 0000000..97c99d0 --- /dev/null +++ b/docs/bitrix/customer-mobile-confirm.md @@ -0,0 +1,126 @@ +# Подтверждение мобильного телефона (Битрикс + Mindbox) + +Документ покрывает операции `**Website.ConfirmMobilePhone**` и `**Website.ResendMobilePhoneConfirmationCode**` из типового ТЗ: ввод кода из SMS и повторная отправка SMS. + +**Предусловия:** выполнен [быстрый старт](./README.md) (SDK, конфиг, `getMindboxClient()`). Первичная отправка SMS **не** вызывается этими двумя операциями — она выполняется сценарием Mindbox раньше (например, после [регистрации](./customer-register.md) или после передачи нового номера при [редактировании](./customer-edit.md) клиента). + +--- + +## Сводка по операциям + + +| Операция Mindbox | Хелпер SDK | Ответ SDK | Синхронность (по умолчанию в хелпере) | +| ------------------------------------------- | ----------------------------- | ----------------------------------------- | ------------------------------------- | +| `Website.ConfirmMobilePhone` | `confirmMobile(...)` | `MindboxSmsConfirmationResponse` | Синхронно (`$isSync = true`) | +| `Website.ResendMobilePhoneConfirmationCode` | `resendConfirmationCode(...)` | `MindboxCustomerProcessingStatusResponse` | Синхронно (`$isSync = true`) | + + +Имена операций `**Website.`*** в проекте могут отличаться — **уточните у менеджера Mindbox**. + +--- + +## Входные данные + +### `ConfirmMobilePhone` + +- **Идентификация клиента** — через `CustomerRequestDTO` так же, как в других вызовах (например `setId('mindboxId', …)`, `setId('bitrixId', …)` — набор id зависит от вашей интеграции). +- **Код из SMS** — объект `SmsConfirmationRequestDTO`, поле кода: `setCode(...)`. + +### `ResendMobilePhoneConfirmationCode` + +- **Идентификация клиента** — достаточно `CustomerRequestDTO` с теми же идентификаторами, по которым Mindbox понимает, кому переотправить код (в контексте уже начатого подтверждения номера). + +Подробнее о полях — в [документации Mindbox](https://developers.mindbox.ru/docs/подтверждение-мобильного-телефона) и [примерах SDK](../examples/customer_helper.md). + +--- + +## Пример: подтверждение номера (`ConfirmMobilePhone`) + +Типичная точка вызова — **обработчик формы** или **AJAX** после ввода кода пользователем (не обязательно событие ядра Битрикс). + +```php +setId('bitrixId', (string)$bitrixUserId); + +$smsConfirmation = new SmsConfirmationRequestDTO(); +$smsConfirmation->setCode($codeFromUserInput); + +try { + $response = getMindboxClient() + ->customer() + ->confirmMobile( + $customer, + $smsConfirmation, + 'Website.ConfirmMobilePhone', + true, + true + ) + ->sendRequest(); + + $status = $response->getSmsConfirmation(); +} catch (MindboxClientException $e) { + // Логирование, сообщение пользователю +} +``` + +Параметры `confirmMobile`: +`confirmMobile($customer, $smsConfirmation, $operationName, $addDeviceUUID = true, $isSync = true)`. + +- `**$addDeviceUUID**` — передавать ли DeviceUUID (по правилам проекта). +- `**$isSync**` — для ТЗ «синхронно» оставьте `true`. + +--- + +## Пример: переотправка кода (`ResendMobilePhoneConfirmationCode`) + +```php +setId('bitrixId', (string)$bitrixUserId); + +try { + $response = getMindboxClient() + ->customer() + ->resendConfirmationCode( + $customer, + 'Website.ResendMobilePhoneConfirmationCode', + true, + true + ) + ->sendRequest(); +} catch (MindboxClientException $e) { + // Логирование, лимиты повторной отправки — по продуктовым правилам +} +``` + +Сигнатура: `resendConfirmationCode($customer, $operationName, $addDeviceUUID = true, $isSync = true)`. + +--- + +## Связь с сценариями из ТЗ + + +| Сценарий | Что делает сайт на Mindbox | Что уже сделано сценарием до вызовов ниже | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | +| Регистрация | После регистрации клиента в Mindbox на телефон уходит SMS; пользователь вводит код → `**ConfirmMobilePhone**` | Первичная отправка SMS | +| Смена телефона | Новый номер передаётся до подтверждения; SMS уходит автоматически; при необходимости `**ResendMobilePhoneConfirmationCode**`, затем `**ConfirmMobilePhone**` | Первичная отправка на новый номер (операция смены номера в вашем проекте — см. [редактирование](./customer-edit.md)) | + + +--- + +## Ошибки и отладка + +- Не подставляйте код из SMS в логи и публичные ответы. +- Разбор ответа и кодов ошибок Mindbox — по [общей документации API](https://developers.mindbox.ru/docs/v3) и логам SDK. +- Расширенные примеры: [CustomerHelper в общих примерах](../examples/customer_helper.md) (в т.ч. `sendAuthorizationCode` / `checkAuthorizationCode`, если понадобятся вне этого ТЗ). + diff --git a/docs/bitrix/customer-orders.md b/docs/bitrix/customer-orders.md new file mode 100644 index 0000000..08eb39b --- /dev/null +++ b/docs/bitrix/customer-orders.md @@ -0,0 +1,69 @@ +# Список заказов потребителя (`GetCustomerOrders`) + +Операция `**Website.GetCustomerOrders**` возвращает список заказов клиента из Mindbox (пагинация через query-параметры запроса). + +**Предусловия:** выполнен [быстрый старт](./README.md) (SDK, конфиг, `getMindboxClient()`). + +--- + +## Параметры интеграции + + +| Параметр | Значение | +| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Операция Mindbox | `Website.GetCustomerOrders` (имя **уточните у менеджера**) | +| Хелпер SDK | `getMindboxClient()->order()->getOrders($countToReturn, $mindbox, $startingIndex, $operationName)` | +| `countToReturn` | Максимальное число заказов в ответе | +| `mindbox` | **Идентификатор потребителя в Mindbox** (строка; обычно внутренний `mindboxId`, который вы храните у пользователя Битрикс после регистрации/синхронизации) | +| `startingIndex` | Порядковый номер заказа, **с которого** формируется страница списка (см. документацию API) | +| DeviceUUID | В реализации SDK для этого метода **не передаётся** (`addDeviceUUID: false`) | +| Ответ SDK | `MindboxOrdersResponse` | +| Синхронность | **Синхронно** (`isSync: true`) | + + +Документация Mindbox: [получение списка заказов потребителя](https://developers.mindbox.ru/docs/получение-списка-заказов-потребителя). + +Сигнатура: + +```php +public function getOrders($countToReturn, $mindbox, $startingIndex, $operationName) +``` + +--- + +## Пример кода + +`$mindboxCustomerId` должен соответствовать тому id, который Mindbox ожидает в параметре `mindbox` (часто это значение из ответа регистрации/проверки клиента или поле профиля в Битрикс). + +```php +order() + ->getOrders( + $countToReturn, + $mindboxCustomerId, + $startingIndex, + 'Website.GetCustomerOrders' + ) + ->sendRequest(); +} catch (MindboxClientException $e) { + // Логирование +} +``` + +Если `**mindboxId**` у пользователя ещё нет, сначала выполните идентификацию/регистрацию в Mindbox — см. [регистрация](./customer-register.md), [проверка клиента](./customer-check.md). + +--- + +## Ошибки и отладка + +- См. [OrderHelper в общих примерах SDK](../examples/order_helper.md), [исключения SDK](../examples/exceptions.md). + diff --git a/docs/bitrix/order-create.md b/docs/bitrix/order-create.md index 33584b3..a951cda 100644 --- a/docs/bitrix/order-create.md +++ b/docs/bitrix/order-create.md @@ -1,6 +1,6 @@ -# Создание заказа (CreateAuthorizedOrder) +# Создание заказа (CreateAuthorizedOrder / CreateUnauthorizedOrder) -После сохранения заказа в Битрикс вызывается операция **CreateAuthorizedOrder** в Mindbox (имя операции в проекте — **уточните у менеджера**). +После сохранения заказа в Битрикс в Mindbox вызывается операция создания заказа: для **авторизованного** покупателя — `**Website.CreateAuthorizedOrder`**, для **гостя** — `**Website.CreateUnauthorizedOrder`** (имена в проекте — **уточните у менеджера**). **Предусловия:** выполнен [быстрый старт](./README.md) (SDK, конфиг, `getMindboxClient()`). @@ -8,41 +8,69 @@ ## Параметры интеграции -| Параметр | Значение | -|----------|----------| -| Операция Mindbox | `Website.CreateAuthorizedOrder` | -| DeviceUUID | Да — в `createAuthorizedOrder` запрос к API v3 формируется **с DeviceUUID** (реализация в SDK) | -| Синхронность | **Асинхронно** (`isSync: false`) — задаётся внутри `OrderHelper::createAuthorizedOrder()`, отдельного параметра нет | -| Точка интеграции Битрикс | Обработчик **`sale:OnSaleOrderSaved`** (при необходимости отфильтруйте только **новый** заказ / первое сохранение — по правилам проекта) | -| Хелпер SDK | `$mindbox->order()->createAuthorizedOrder($order, $operationName)` — **два** аргумента | +### Авторизованный покупатель — `Website.CreateAuthorizedOrder` + + +| Параметр | Значение | +| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | +| Операция Mindbox | `Website.CreateAuthorizedOrder` | +| DeviceUUID | Да — в `createAuthorizedOrder` запрос к API v3 формируется **с DeviceUUID** (реализация в SDK) | +| Синхронность | **Асинхронно** (`isSync: false`) — задаётся внутри `OrderHelper::createAuthorizedOrder()`, отдельного параметра нет | +| Точка интеграции Битрикс | Обработчик `**sale:OnSaleOrderSaved`** (при необходимости отфильтруйте только **новый** заказ / первое сохранение — по правилам проекта) | +| Хелпер SDK | `$mindbox->order()->createAuthorizedOrder($order, $operationName)` | -Сигнатура в коде: ```php public function createAuthorizedOrder(OrderCreateRequestDTO $order, $operationName) ``` +### Гость — `Website.CreateUnauthorizedOrder` + + +| Параметр | Значение | +| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Операция Mindbox | `Website.CreateUnauthorizedOrder` | +| DeviceUUID | Да — в `createUnauthorizedOrder` в SDK так же передаётся **DeviceUUID** (`addDeviceUUID: true`), режим запроса к API **асинхронный** (`isSync: false`), отдельных параметров метода нет | +| Точка интеграции Битрикс | Тот же `**OnSaleOrderSaved`**, ветвление по `Order::getUserId()` (или аналогу): **0** — гость → `createUnauthorizedOrder` | +| Хелпер SDK | `$mindbox->order()->createUnauthorizedOrder($order, $operationName)` | + + +```php +public function createUnauthorizedOrder(OrderCreateRequestDTO $order, $operationName) +``` + +**Клиент в DTO:** для гостя заполните контактные данные по контракту операции (часто **email** и/или **телефон** без `bitrixId`); для авторизованного — как минимум `**setId('bitrixId', …)`** у `CustomerRequestDTO`. + --- ## Передаваемые данные заказа -| Поле | Описание | -|------|----------| -| `orderId` | Внешний ID заказа — `OrderCreateRequestDTO::setId('bitrixId', …)` (или другое имя внешнего id по договорённости с Mindbox) | -| `customer` | Покупатель — `CustomerRequestDTO`: email, телефон, `bitrixId` и др. | -| `lines` | Состав — `LineRequestCollection` из `LineRequestDTO` (товар, количество, цены — по полям операции) | -| `totalPrice` | Итог — при необходимости через поля операции / `customFields` (в базовом `OrderCreateRequestDTO` отдельного `setTotalPrice` может не быть — уточните у менеджера) | -| `discountAmount` | Скидки — `setDiscounts` / поля операции | -| `deliveryType` | Доставка — например `setDeliveryCost`, кастомные поля | -| `paymentType` | Оплата — `setPayments` (`PaymentRequestCollection`) | + +| Поле | Описание | +| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `orderId` | Внешний ID заказа — `OrderCreateRequestDTO::setId('bitrixId', …)` (или другое имя внешнего id по договорённости с Mindbox) | +| `customer` | Покупатель — `CustomerRequestDTO`: email, телефон, `bitrixId` и др. | +| `lines` | Состав — `LineRequestCollection` из `LineRequestDTO` (товар, количество, цены — по полям операции) | +| `totalPrice` | Итог — при необходимости через поля операции / `customFields` (в базовом `OrderCreateRequestDTO` отдельного `setTotalPrice` может не быть — уточните у менеджера) | +| `discountAmount` | Скидки — `setDiscounts` / поля операции | +| `deliveryType` | Доставка — например `setDeliveryCost`, кастомные поля | +| `paymentType` | Оплата — `setPayments` (`PaymentRequestCollection`) | + Конкретный набор полей зависит от настройки операции в Mindbox. --- +## Рекомендации + +- `**PriceHasBeenChanged`.** Если после успешного HTTP-ответа поле **статуса операции** Mindbox в теле ответа равно `**PriceHasBeenChanged`** (точная строка — по контракту операции; в SDK удобно смотреть `$response->getMindboxStatus()`), **не** считайте оформление в Mindbox успешным для пользователя: покажите понятную ошибку или предупреждение и **пересчитайте корзину** — для авторизованного пользователя `[CalculateAuthorizedCart](./cart-calculate.md)`, для гостя — `[CalculateCart` / `CalculateUnauthorizedCart](./cart-calculate.md)` по правилам проекта. +- **Ответы 5xx и повторы.** При недоступности API (в SDK типичные **500** и **503** приходят как `Mindbox\Exceptions\MindboxUnavailableException`) имеет смысл выполнить **до трёх повторов** той же операции с **паузой 5 секунд** между попытками. Если после **первой попытки + 3 повтора** успеха нет — **переходите к обработке заказа без процессинга Mindbox**: не блокируйте клиента на оплате/завершении в Битрикс, зафиксируйте ситуацию в логах и предусмотрите ручную или отложенную синхронизацию с Mindbox. Иные коды **5xx** в текущей версии SDK могут обрабатываться иначе (см. `AbstractMindboxClient::parseRawResponse`) — при политике «любой 5xx» уточните перехват исключений по логам. + +--- + ## Событие -Модуль **`sale`**, событие **`OnSaleOrderSaved`**. В обработчик передаётся **`Main\Event`**; объект заказа обычно доступен как **`$event->getParameter('ENTITY')`** (`\Bitrix\Sale\Order`). Уточните имя параметра в [документации событий sale](https://dev.1c-bitrix.ru/api_d7/bitrix/sale/) для вашей версии. +Модуль `**sale`**, событие `**OnSaleOrderSaved**`. В обработчик передаётся `**Main\Event**`; объект заказа обычно доступен как `**$event->getParameter('ENTITY')**` (`\Bitrix\Sale\Order`). Уточните имя параметра в [документации событий sale](https://dev.1c-bitrix.ru/api_d7/bitrix/sale/) для вашей версии. Событие может срабатывать при **каждом** сохранении заказа — добавьте условие, чтобы не дублировать создание в Mindbox (например только новый заказ или смена статуса). @@ -82,7 +110,11 @@ EventManager::getInstance()->addEventHandler( $orderDto->setId('bitrixId', (string)$saleOrder->getId()); $customer = new CustomerRequestDTO(); - $customer->setId('bitrixId', (string)$saleOrder->getUserId()); + $userId = (int)$saleOrder->getUserId(); + if ($userId > 0) { + $customer->setId('bitrixId', (string)$userId); + } + // Для гостя добавьте по ТЗ: email, мобильный телефон и т.д. $orderDto->setCustomer($customer); $lines = []; @@ -104,10 +136,16 @@ EventManager::getInstance()->addEventHandler( $orderDto->setLines(new LineRequestCollection($lines)); try { - getMindboxClient() - ->order() - ->createAuthorizedOrder($orderDto, 'Website.CreateAuthorizedOrder') - ->sendRequest(); + $mindboxOrder = getMindboxClient()->order(); + if ((int)$saleOrder->getUserId() > 0) { + $mindboxOrder + ->createAuthorizedOrder($orderDto, 'Website.CreateAuthorizedOrder') + ->sendRequest(); + } else { + $mindboxOrder + ->createUnauthorizedOrder($orderDto, 'Website.CreateUnauthorizedOrder') + ->sendRequest(); + } } catch (MindboxClientException $e) { // Логирование: $e->getMessage(), ID заказа } @@ -154,11 +192,85 @@ try { } ``` -`$arOrder['BASKET']` в Битрикс обычно **нет** в таком виде — строки берут из **`Sale\Order::getBasket()`**, как в полном примере выше. +**Гость** — тот же `OrderCreateRequestDTO`, но клиент без `bitrixId`, вызов `createUnauthorizedOrder`: + +```php +$order = new \Mindbox\DTO\V3\Requests\OrderCreateRequestDTO(); +$order->setId('bitrixId', (string)$orderId); + +$customer = new \Mindbox\DTO\V3\Requests\CustomerRequestDTO(); +$customer->setEmail($guestEmail); +// при необходимости: $customer->setMobilePhone(...); +$order->setCustomer($customer); + +$order->setLines(new \Mindbox\DTO\V3\Requests\LineRequestCollection($lines)); + +try { + $response = getMindboxClient() + ->order() + ->createUnauthorizedOrder($order, 'Website.CreateUnauthorizedOrder') + ->sendRequest(); +} catch (\Mindbox\Exceptions\MindboxClientException $e) { + // Логирование ошибки +} +``` + +`$arOrder['BASKET']` в Битрикс обычно **нет** в таком виде — строки берут из `**Sale\Order::getBasket()`**, как в полном примере выше. + +--- + +## Пример: проверка `PriceHasBeenChanged` и повторы при 5xx + +Фрагмент без привязки к событию Битрикс: соберите `$orderDto` так же, как в примерах выше. Статус операции сверяйте с документацией Mindbox для вашей операции. Для гостя подставьте `**Website.CreateUnauthorizedOrder**` и вызов `**createUnauthorizedOrder**` вместо авторизованного варианта. + +```php +order(); + $response = $orderClient->createAuthorizedOrder($orderDto, $operationName)->sendRequest(); + // Для гостя: $operationName = 'Website.CreateUnauthorizedOrder'; + // $response = $orderClient->createUnauthorizedOrder($orderDto, $operationName)->sendRequest(); + + $status = $response->getMindboxStatus(); + if ($status === 'PriceHasBeenChanged') { + // Сообщение пользователю + пересчёт корзины (CalculateAuthorizedCart), не продолжать как успешное создание в Mindbox. + break; + } + + // Успешный сценарий (статус не PriceHasBeenChanged — уточните ожидаемое значение, например Success). + break; + } catch (MindboxUnavailableException $e) { + if ($attempt >= $maxAttempts) { + // Обработка без процессинга Mindbox: завершить сценарий в Битрикс, залогировать $e->getMessage(). + break; + } + sleep($retryDelaySec); + } catch (MindboxClientException $e) { + // Ошибки 4xx и прочие — по правилам проекта (обычно без повторов как для 5xx). + throw $e; + } +} +``` --- ## Ошибки и отладка - Идемпотентность: не создавайте дубликаты в Mindbox при повторном `OnSaleOrderSaved`. +- Поведение при `**PriceHasBeenChanged**` и **5xx** — см. раздел **«Рекомендации»** выше. - См. [OrderHelper в общих примерах SDK](../examples/order_helper.md), [исключения SDK](../examples/exceptions.md). + diff --git a/docs/bitrix/order-offline.md b/docs/bitrix/order-offline.md new file mode 100644 index 0000000..4515e26 --- /dev/null +++ b/docs/bitrix/order-offline.md @@ -0,0 +1,74 @@ +# Офлайн-создание заказа в Mindbox (`SaveOfflineOrder`) + +Операция `**Website.SaveOfflineOrder**` передаёт в Mindbox заказ, оформленный **без онлайн-процессинга** (типовой сценарий — догоняющая синхронизация после того, как сайт завершил заказ при недоступности API). По контракту операции в Mindbox выполняется сохранение заказа и **начисление баллов**. + +**Предусловия:** выполнен [быстрый старт](./README.md) (SDK, конфиг, `getMindboxClient()`). Состав заказа в DTO собирается так же, как для [обычного создания заказа](./order-create.md) (`OrderCreateRequestDTO`, строки, покупатель). + +--- + +## Параметры интеграции (типовые) + + +| Параметр | Значение | +| ---------------- | ----------------------------------------------------------------------------------- | +| Операция Mindbox | `Website.SaveOfflineOrder` | +| Описание | Сохраняет заказ в Mindbox и начисляет баллы (по настройке операции в проекте) | +| Хелпер SDK | `$mindbox->order()->saveOfflineOrder($order, $operationName)` | +| DeviceUUID | В текущей версии SDK запрос формируется **без** DeviceUUID (`addDeviceUUID: false`) | +| Синхронность | **Асинхронно** (`isSync: false`) — зашито в `OrderHelper::saveOfflineOrder()` | + + +Сигнатура: + +```php +public function saveOfflineOrder(OrderCreateRequestDTO $order, $operationName) +``` + +Документация Mindbox: [processing offline order](https://developers.mindbox.ru/docs/processing-offline-order). + +--- + +## Процессинг при недоступности Mindbox + +Пока Mindbox **недоступен**, на сайте **недоступны** расчёт персональных скидок в Mindbox, **оплата бонусами**, применение **промокодов** и прочие возможности, завязанные на оперативный ответ API. **Заказ при этом можно оформить** по **базовым ценам** каталога (и собственным правилам Битрикс, если они не требуют Mindbox). + +После восстановления связи или фоном нужно **догнать** данные в Mindbox — для этого и используется `**SaveOfflineOrder`** (или согласованная с менеджером альтернатива). + +--- + +## Рекомендация: очередь в Битрикс и агент + +Имеет смысл **не терять** неотправленные вызовы `SaveOfflineOrder`: + +- Сохраняйте в **highload-блоке** (или другой удобной сущности) записи вида: идентификатор заказа Битрикс, сериализованное тело/параметры для Mindbox, число попыток, время следующей отправки, статус. +- Подключите **агент** Битрикс (или cron + скрипт), который **раз в 15 минут** выбирает записи к отправке и вызывает `saveOfflineOrder` + `sendRequest()`. При успехе помечайте запись выполненной; при ошибке увеличивайте счётчик попыток и откладывайте следующий запуск. +- Не храните в HL **секреты** и избыточные ПДн; логируйте ошибки без утечки данных в публичную зону. + +--- + +## Пример вызова SDK + +Тот же `OrderCreateRequestDTO`, что и для `CreateAuthorizedOrder` / `CreateUnauthorizedOrder` — см. [создание заказа](./order-create.md). + +```php +order() + ->saveOfflineOrder($orderDto, 'Website.SaveOfflineOrder') + ->sendRequest(); +} catch (MindboxClientException $e) { + // Оставить запись в очереди HL для следующего прогона агента через 15 минут; залогировать. +} +``` + +--- + +- См. [OrderHelper в общих примерах SDK](../examples/order_helper.md), [исключения SDK](../examples/exceptions.md). +