##  [Как мы сделали интеграции Business.ru и Catapulto в Drupal понятными и управляемыми](/blog/kak-my-sdelali-integracii-businessru-i-catapulto-v-drupal-ponyatnymi-i-upravlyaemymi) 

/sites/default/files/2026-03/Mrgav.png

Эта статья о том, как в реальном проекте на Drupal собрать устойчивый рабочий процесс: данные по товарам и заказам синхронизируются с [Business.ru](https://www.business.ru/), отправки оформляются через [Catapulto](https://catapulto.ru/), а статусы и треки доходят до нужных систем без ручной рутины.

## 1. С чего начинали

Когда в проекте одновременно живут сайт, учетная система и внешний логистический сервис, самая частая проблема — не «нет интеграции», а «интеграция есть, но она неудобная и хрупкая». Часть действий приходится делать вручную, статусы запаздывают, а треки дописываются отдельными задачами.

Поэтому цель была очень практичной: выстроить нормальную последовательность этапов, в которой каждому участнику процесса понятно, что происходит дальше. Пользователь оформляет заказ, менеджер видит прозрачный путь отправки, а система сама поддерживает актуальные данные между Drupal, Business.ru и Catapulto.

**Ключевая идея: не «один большой скрипт», а несколько понятных шагов, где каждый закрывает свою задачу и аккуратно передает данные следующему этапу.**

## 2. Общая картина решения

Архитектуру разделили на три слоя. Сначала сделали стабильный API-слой Business.ru, затем разложили обменные процессы по отдельным сценариям, и только после этого встроили Catapulto как продолжение маршрута после оформления заказа.

![1-integration-scheme](/sites/default/files/inline-images/1-integration-scheme.png)*Схема 1. Как связаны Drupal, Business.ru, Catapulto и сервисы обогащения данных*Такой порядок оказался важным: сначала «фундамент», потом прикладные процессы, и только потом тонкая операционная логика с доставкой, треками и фоновыми проверками.

## 3. Этап 1: единый API-клиент для Business.ru

Первым шагом мы оперлись на единый класс `Business_ru_api_lib` (`core_api_connector.php`), чтобы все запросы работали по единым правилам: подпись параметров, проверка подписи ответа, единая обработка ошибок, обновление токена через `repair()`.

```php
public function request($action, $model, $params = array()) {
  $params['app_id'] = $this->app_id;
  ksort($params);
  $params_string = http_build_query($params);

  $params = array();
  $params['app_psw'] = md5($this->token . $this->secret . $params_string);
  $params_string .= '&' . http_build_query($params);

  $url = $this->address . "/api/rest/" . $model . ".json";
  // ... cURL вызов ...

  if ($status_code == 200) {
    $result = json_decode($result, true);
    $app_psw = $result['app_psw'];
    unset($result['app_psw']);

    if (md5($this->token . $this->secret . json_encode($result)) == $app_psw) {
      $this->token = $result['token'];
      return $result;
    }
  }
  return array("status" => "error");
}
```

Этот шаг может казаться «техническим», но именно он дал предсказуемость дальше: все сценарии обмена используют одну и ту же точку входа и одинаково себя ведут при сбоях.

## 4. Этап 2: обмен с Business.ru — разложили на понятные сценарии

Когда базовый слой стабилен, следующий логичный шаг — разделить обмен по задачам. В проекте это сделали через отдельные скрипты: клиенты/заказы, каталог/остатки и статусы/треки.

![2-exchange-scenarios](/sites/default/files/inline-images/2-exchange-scenarios.png)*Схема 2. Отдельные сценарии обмена с Business.ru*### 4.1 Сайт -&gt; Business.ru: клиенты и заказы

Скрипт `portal_out_sync.php` передает новых клиентов и заказы. На практике самым полезным решением стала защита от дублей контрагентов: сначала ищем по ID сайта, а если его нет — по email, телефону и ФИО.

```php
$search_fields = [
  'email' => strtolower($mail),
  'phone' => $phone,
  'name' => $name,
];

foreach ($search_fields as $search_field => $value) {
  $response = $api->request("get", "partners", [
    'extended' => 1,
    'with_additional_fields' => 1,
    $search_field => $value,
  ]);

  if (!empty($response['result'][0])) {
    $cid = $response['result'][0]['id'];
    break;
  }
}
```

Дополнительно смаппили локальные коды доставок и оплат в справочники Business.ru, чтобы в учетной системе и на сайте этапы заказа читались одинаково.

### 4.2 Business.ru -&gt; сайт: каталог, цены, остатки

Скрипт `portal_in_sync.php` постранично грузит товары, цены и остатки. Остатки считаются по складам с учетом резерва, а цена выбирается по нужному типу прайса.

```php
$response = $api->request("get", "goods", [
  'with_additional_fields' => 1,
  'with_barcodes' => 1,
  'with_remains' => 1,
  'with_prices' => 1,
  'limit' => 250,
  'page' => $page,
]);

foreach ($product['prices'] as $item) {
  if ($item['price_type']['id'] == $selling_retail_price_type_id) {
    $price = $item['price'];
    break;
  }
}
```

После того как обмен клиентами, заказами, каталогом и остатками стал стабильным, стало возможно перейти к следующему шагу: автоматизировать саму отправку, а не только хранение ее результата.

## 5. Этап 3: Catapulto как продолжение процесса после оформления заказа

![3-shipping-way-to-send](/sites/default/files/inline-images/3-shipping-way-to-send.png)*Схема 3. Путь от выбора доставки до создания отправления*### 5.1 Что видит пользователь

В форме оформления заказа подключается виджет Catapulto. Пользователь выбирает вариант доставки, а параметры выбора сохраняются в поле `field_catapulto` в JSON.

```php
$out .= '<span id="catapulto-widget-open" class="btn-green btn-small">Выбрать способ доставки</span>';
$out .= '<div id="for_catapultowidget" weight="' . $weight . '"></div>';
$out .= '<script type="module" crossorigin src="/sites/all/libraries/CatapultoWidget/release/catapulto-widget.js"></script>';
$out .= '<script type="text/javascript" src="/sites/all/modules/checkout_custom/js/shipping_widget.js"></script>';
```

В JS добавили практичную логику расчета грузомест по весовым диапазонам, чтобы оценка доставки была ближе к реальному отправлению.

```javascript
if (weight < 5) {
  cargo = [{ height: 200, length: 200, width: 300, quantity: 1, weight: weight * 1000 }];
} else if (weight >= 25 && weight < 36) {
  cargo = [
    { height: 600, length: 400, width: 400, quantity: 1, weight: (weight * 1000)/2 },
    { height: 600, length: 400, width: 400, quantity: 1, weight: (weight * 1000)/2 }
  ];
}
```

### 5.2 Что делает менеджер

На странице `/custom_catapulto` менеджер подтверждает параметры отправки и, при необходимости, корректирует их перед созданием shipment. Для этого используется отдельное поле `field_catapulto_custom`.

Важный момент: мы не перезаписываем пользовательский выбор, а сохраняем менеджерскую версию отдельно. Благодаря этому всегда понятно, что было выбрано изначально и что ушло в отправку.

## 6. Этап 4: создание отправления и фиксация результата

После подтверждения отправка создается в Catapulto API: сначала контакт, затем shipment. Возвращенные идентификаторы записываются в заказ Drupal и передаются в Business.ru по статусу.

```php
$response = _custom_catapulto_curl_post($apiUrl . "/contact", $receiver_contact, $token);

if ($response['code'] == 201) {
  $shipment['receiver_contact_id'] = $response['data']['id'];
  $response = _custom_catapulto_curl_post($apiUrl . "/shipment", $shipment, $token);
}

if ($response['code'] === 201) {
  $order->field_catapulto_track['und'][0]['value'] = $response['data']['key'];
  $order->field_catapulto_shipment_id['und'][0]['value'] = $response['data']['number'];
  node_save($order);
}
```

На этом шаге процесс не заканчивается: отправление создано, но его нужно сопровождать до завершения. Поэтому следующий этап — фоновые проверки и синхронизация.

![4-cron-support-streams-statuses](/sites/default/files/inline-images/4-cron-support-streams-statuses.png)*Схема 4. Как cron поддерживает синхронизацию треков и статусов*## 7. Этап 5: фоновые задачи и «дотягивание» данных

В `hook_cron()` заложены две задачи: обновление треков/статусов по активным отправкам и дозапись треков в Business.ru, если где-то они остались пустыми.

```php
function custom_catapulto_cron() {
  _custom_catapulto_update_status_task();
  _custom_catapulto_sync_tracking_to_business_ru_task();
}
```

Именно этот блок делает интеграцию «живой»: даже если в момент отправки произошла частичная ошибка, система позже корректно выравнивает состояние и возвращает процесс в норму.

## 8. Дополнительный шаг: качество адресов через DaData

Чтобы снизить адресные неточности, добавлен запрос к DaData по `fias_id`. Это улучшает отображение адреса и уменьшает спорные случаи на этапе отправки.

```php
$response = drupal_http_request(
  'https://suggestions.dadata.ru/suggestions/api/4_1/rs/findById/address',
  array(
    'method' => 'POST',
    'data' => json_encode(array('query' => $fias_id)),
    'headers' => array(
      'Content-Type' => 'application/json',
      'Authorization' => 'Token ' . $api_key,
    ),
  )
);
```

## 9. Что в итоге изменилось в работе

БылоСталоРазрозненные действия между системамиЕдиная последовательность этапов от оформления до финального статусаРучные корректировки статусов и трековАвтоматическая синхронизация + фоновые довороты данныхРиск дублей контрагентовПоиск и связывание по ID + email + телефон + ФИОНепрозрачная логика отправкиОтдельный интерфейс подтверждения менеджером

Главный практический результат: процесс стал предсказуемым и «человечным» не только для клиента, но и для команды. У каждого этапа есть понятный вход, понятный выход и понятная точка ответственности.

## 10. Что улучшать дальше

1. Добавить централизованный retry/backoff для внешних API: так мы уменьшаем количество «потерянных» операций при кратковременных сбоях сети или ограничениях провайдера.
2. Сделать отдельный журнал интеграционных событий с correlation id: это ускорит разбор инцидентов, потому что путь одного заказа можно будет проследить сквозь все системы по одному идентификатору.
3. Добавить smoke-тесты для критичных сценариев: это позволит ловить регрессии до релиза и снижать риск незаметной поломки обмена после изменений в модуле.

## 11. Как можно усилить процесс с помощью искусственного интеллекта

После стабилизации базовой интеграции следующий логичный шаг — добавить ИИ не «ради моды», а в те точки, где он снижает ручную нагрузку и сокращает количество ошибок.

![5-ai-enhanced-integration](/sites/default/files/inline-images/5-ai-enhanced-integration.png)*Схема 5. Где ИИ усиливает процесс интеграций*1. Умная проверка адресов перед отправкой: модель может анализировать адрес, индекс, город и выбранный способ доставки, находить противоречия (например, несоответствие индекса городу) и предлагать корректный вариант до создания shipment.
2. Автоматическая классификация интеграционных ошибок: ИИ-слой над логами может группировать сбои по типам (лимиты API, адресные ошибки, несогласованные статусы), показывать приоритет и сразу предлагать рекомендуемое действие для менеджера или разработчика.
3. Прогноз проблемных заказов: на основе истории отправок можно предсказывать риск задержки, возврата или ручной доработки и заранее поднимать такие заказы в очередь оператора.
4. Интеллектуальный контроль статусов: если заказ «завис» между этапами дольше нормы, ИИ может автоматически формировать задачу, комментарий или уведомление с контекстом по заказу и списком вероятных причин.
5. Помощник менеджера в интерфейсе: встроенный AI-ассистент может кратко объяснять, почему система предлагает тот или иной тариф/маршрут, и подсказывать оптимальный следующий шаг без перехода между несколькими системами.

Важно внедрять эти улучшения поэтапно: сначала как рекомендательный слой (подсказки), затем как полуавтоматические действия с подтверждением менеджера, и только после накопления точности — как полностью автоматизированные правила для узких сценариев.

### 11.1 Примеры LLM-моделей под задачи процесса

Ниже примеры того, как можно подобрать модели по роли, чтобы получить баланс качества, скорости и стоимости:

- Для AI-помощника менеджера (объяснение тарифа, формулировка комментария по заказу): GPT-4.1 или Claude 3.5 Sonnet.
- Для массовой классификации логов и инцидентов в фоне: GPT-4o mini или Llama 3.1 70B Instruct.
- Для on-prem/self-hosted контура с чувствительными данными: Llama 3.1 70B Instruct или Qwen2.5 72B Instruct.

Практичный путь внедрения: начать с одной модели в режиме «подсказок» для операторов, замерить качество и экономию времени, затем расширить на автоматическую приоритизацию ошибок и SLA-контроль.



[Drupal](/blog/drupal)

[кейсы](/blog/keysy)

[интеграции](/blog/integracii)

 

Ещё по теме

[Интеграция сайта Drupal 8 с CRM Битрикс24](/blog/integraciya-sayta-drupal-8-s-crm-bitriks24)

[Интеграция платёжной системы с сайтом на Drupal](/blog/integraciya-platyozhnoy-sistemy-s-saytom-na-drupal)

[Интеграция Sendpulse с сайтом на Drupal](/blog/integraciya-sendpulse-s-saytom-na-drupal)

[Простая интеграция Drupal с Telegram](/blog/prostaya-integraciya-drupal-s-telegram)

 

 

   

 [](https://drupal-coder.ru/rss.xml)