Создаём простую логистическую службу

Создаём простую логистическую службу

Есть два пути по добавлению своей логистики в AlterCPA — через хаки или стандартную службу доставки. Вариант хаков мощнее, серьёзнее, но требует понимания работы платформы. А вот через стандартную службу доставки можно привязать всё с помощью трёх ссылок и любой удобной реализации на любимом вами языке без вмешательства в код самой системы. Значит, такая штука доступна и в бесплатной AlterCPA Moe.

Общие принципы работы служб доставки мы уже разбирали в статье «Организация логистики в AlterCPA Pro и AlterCPA Moe«, рекомендую перечитать её и вспомнить, как и зачем мы играем в курьеров. Продвинутым технарям рекомендую изучить документацию службам доставки в хаках.

Как добавить стандартную службу доставки?

Логистика настраивается в разделе «Доставка» в управлении компанией. Вам нужно добавить новую службу с типом «Встроенная» или «Generic». Она располагает рядом полезных опций:

  • Службу доставки нужно активировать после настройки. Если поставить галочку «По умолчанию», то именно она будет присваиваться всем поступающим лидам.
  • При наличии URL трекинга, включите автоматический перенос заказов по статусам доставки. Так CRM сама перетащит лид в «Оплачен» или «Возврат», если логистика выдаст соответствующий статус.
  • Цена и себестоимость доставки задаются фиксировано, она не поддерживает динамическое определение ценников перед отправкой с помощью наценки. Процент за расчётно-кассовое обслуживание (РКО) в себестоимости считается от цены заказа для покупателя, а не от себестоимости.
  • С активным трекингом можно включить автоматическую отправку заказов в колл-центр обзвона доставки, если они зависают в каком-то из статусов на несколько дней.
  • При наличии ссылки отправки, можно также автоматически добавлять заказы в курьерскую службу. Это особенно удобно при работе с фулфилментом: просто укажите статус, откуда посылку забрать и куда переложить. Рекомендую добавить вложенный статус для ошибок отправки — перетаскивать их в возврат сомнительно.
  • Главная фишка встроенной службы доставки — возможность указать три ссылки интеграции, о которых и пойдёт речь в этой статье. Читаем и автоматизируем!

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

В чём удобство её применения?

Она задумывалась как заглушка для курьерской службы, которая обслуживается вручную. Главное её преимущество — это три волшебных ссылки для веб-хуков:

  1. URL трекинга позволяет реализовать отслеживание посылки на всех этапах пути. Он должен получить трек-код посылки и выдать историю её статусов.
  2. URL отправки позволяет создавать посылки на стороне логистической службы. На него отсылаются данные заказа, а в ответ ожидается трек-код.
  3. URL документов позволяет добавить печать этикеток на посылки. Он должен выдать ссылку на файлы с документами.

Наш путь прост: создаём файлы на стороннем хостинге, добавляем ссылки на них в службу доставки и получаем готовый автоматизированный интерфейс логистики!

Особенности работы ссылок

Все три ссылки поддерживают макросы. С помощью макроса в ссылки трекинга и документов нужно вписать трек-код посылки или идентификатор заказа. Доступные макросы:

  • {code} или {track} — трек-код посылки, полученный при отправке.
  • {order} — идентификатор заказа на стороне CRM.
  • {track:xxx} — трекинг-параметр с названием xxx, полученный при отправке.

Дополнительные параметры могут использоваться, например, для указания внутреннего ID в конкретной службе доставки или любых других действий. Они извлекаются из поля meta при отправке посылки.

Трекинг посылки

Опрос статусов посылок производится дважды в день автоматически. Оператор может проверить историю статусов вручную со страницы заказа. При получении определённых статусов, посылка автоматически переводится в статусы «Доставлено», «Оплачено» и «Возврат».

По указанному URL ваш логистический сервис должен выдать историю статусов в формате JSON в виде простого массива объектов, каждый из которых соответствует своему статусу. Соблюдение указанной ниже структуры является строго обязательным.

Объект статуса может содержать следующие поля:

  • status — обязательное поле с символьным статусом доставки, список ниже.
  • time — обязательное поле со временем возникновения статуса в формате UNIX timestamp.
  • country — символьный ISO-код страны.
  • zip — индекс или ZIP-код.
  • city — город или населённый пункт.
  • comment — произвольный комментарий к статусу.

Поле status может содержать одно из следующих значений:

  1. wait — посылка ожидает отправки.
  2. transfer — посылка находится в пути, переводится в статус «Доставка».
  3. problem — при доставке посылки возникли проблемы, требуется реакция поставщика.
  4. delivered — посылка прибыла в пункт назначения, переводится в статус «Доставлено».
  5. paid — посылка успешно выкуплена, переводится в статус «Оплачено».
  6. return — посылка возвращена или утилизирована, переводится в статус «Возврат».
  7. comment — произвольный комментарий, не меняющий состояние посылки.

Пример ответа функции может выглядеть вот так:

[ 
   { 
      "status":"delivered",
      "time":1234567890,
      "zip":"AB1234",
      "city":"Neverland"
   },
   { 
      "status":"paid",
      "time":1234567891,
      "comment":"Awesome!"
   }
]

Ссылка на проверку истории статусов посылки может выглядеть так:

https://yourlogistics/track.php?code={track}

Файл обработчика на PHP можно реализовать так:

<?php

// Prepare the code and URL
$code = filter_var( $_GET['code'] );
$url = "https://someotherlogiscits/track/$code" 
$status = [];

// Status to status table
$s2s = [ 123 => 'delivered', 234 => 'return', 345 => 'paid', 456 => 'problem' ];
// Converts service status to CRM status

// Fetch the info from the service
$reply = file_get_contents( $url );
$result = json_decode( $reply, true );

// Walt through statuses in tracking array
foreach ( $result['tracking'] as $t ) {
  $stage‎ = [ 'status' => $s2s[$t['status']] ?: 'comment', 'time' => strtotime($t['time']) ];
  if ( $t['location'] ) $stage['city'] = $t['location'];
  if ( $t['geo'] ) $stage['country'] = $t['geo'];
  if ( $t['messages'] ) $stage['comment'] = implode( ' ', $t['messages'] );
  $status[] = $stage;
}

// Show the results
echo json_encode( $status );

В этом файле необходимо подготовить массив статусов в соответсвии со стандартом AlterCPA. Удобно использовать $s2s для сопоставления статуса на стороне службы доставки со статусом AlterCPA. Если статусов нет или произошла ошибка — просто выдаём пустой массив.

Отправка посылки

Отправка посылок может производиться автоматически по расписанию или вручную с карточки заказа. CRM отправляет на указанную ссылку POST-запрос в формате JSON с данными заказа, поэтому использовать какие-либо макросы в ссылке отправки не обязательно.

По указанному URL ваш логистический сервис должен получить заказ в JSON, создать посылку и ответить в JSON-формате со следующими полями:

  • status — статус отправки, может быть ok или error, обязательное поле.
  • error — код ошибки для статуса error, который осядет в логе отправки.
  • message — текстовое сообщение об ошибке, которое будет добавлено в изменения заказа.
  • track — трек-код для проверки посылки и распечатки документов, обязательное поле.
  • price — цена доставки посылки, которая будет записана в себестоимость доставки заказа.
  • meta — дополнительные поля, которые нужно добавить к заказу для дальнейшей проверки статусов, например ключ или дополнительный код. Указываются в виде ассоциативного массива поле-значение.

Заказ в виде ассоциативного массива с полями:

  • id — идентификатор заказа на стороне CRM.
  • name — имя покупателя.
  • phone — телефон покупателя в международном формате, только цифры.
  • email — почта покупателя.
  • country — ISO-код страны покупателя, две буквы, нижний регистр.
  • zip, region, city, street, address — элементы адреса покупателя: индекс, регион, город, улица, дом.
  • created, approved — время создания и подтверждения заказа в формате UNIX timestamp.
  • price — общая цена заказа, которая включает в себя цену товаров, доставки и наценки.
  • delivery — стоимость доставки заказа в составе цены.
  • markup — стоимость дополнительной наценки или скидки в составе цены.
  • currency — трёхбуквенный ISO-код валюты заказа.
  • meta — дополнительные поля заказа, зависят от настроек произвольных полей оффера.
  • param — внутренние параметры оффера.
  • items — товары в заказе.

Поле items представлено массивом, в котором собраны вложенные в заказ товары. Массив содержит как минимум один элемент с основным товаром. Каждый товар представлен полями:

  • id — внутренний идентификатор товарной позиции (оффера или товара)
  • name — название товара для покупателя.
  • sku — артикул товара или ID оффера.
  • price — цена за единицу товара.
  • count — количество товаров в заказе.
  • param — параметры товара из CRM, оптимально использовать их для передачи размеров и веса товара.

Пример запроса с полным составом заказа:

{
    "id": 1707,
    "name": "John Doe",
    "phone": "79876543210",
    "email": "john.doe@gmail.com",
    "country": "ru",
    "zip": "127000",
    "region": "Moscow City",
    "city": "Moscow",
    "street": "Bolshaya Lubyanka",
    "address": "house 1",
    "created": 1658581026,
    "approved": 1658678174,
    "price": 1550,
    "delivery": 500,
    "markup": 50,
    "currency": "rub",
    "meta": {
        "prepaid": 1,
        "prepay": 550
    },
    "param": {
        "crm-id": "4132",
        "ref-code": "10"
    },
    "items": [
        {
            "id": 1,
            "name": "Cube Cat",
            "article": "cube",
            "price": 600,
            "count": 1,
            "param": {
                "weight": 100,
                "width": 21,
                "height": 16,
                "depth": 20
            }
        },
        {
            "id": 2,
            "name": "Green Hat",
            "article": "hat",
            "price": 400,
            "count": 1,
            "param": []
        }
    ]
}

Ссылка на отправку посылок может выглядеть так, макросы не нужны:

https://yourlogistics/send.php?token=secret

Пример файла обработчика для отправки заказов:

<?php

// Get the lead data and make some magic
$data = json_decode( file_get_contents('php://input'), true );
$result = makesomemagic( $data );

// Process the result
if ( $result['success'] ) {
  $code = trim( $result['track'] );
  $info = [ 'status' => 'ok', 'track' => $code, 'meta' => [ 'mode' => 'fullfillment' ] ];
} else $info = [ 'status' => 'error', 'message' => $result['error'] ];

// Show the result info
echo json_encode( $info );

Как именно будет работать магия, которая связывает ваш файл с логистическим сервисом — решать только вам. Рекомендуется добавить какую-нибудь авторизацию в сам файл, например, использовать API-токен. Выдавать трек-код на выходе — обязательно.

Распечатка документов

Распечатка документов работает поштучно в карточке товара или массово в разделе «Заказы». При штучной обработке, оператор нажимает на кнопку «Документы» и открывает файл для распечатки. При массовой работе, сервис делает отдельный запрос по каждому заказу, скачивает файлы и формирует из них готовый архив.

По указанному URL ваш логистический сервис должен выдать ответ в формате JSON с двумя полями: status и url. Поле status должно содержать ok в случае успешного формирования пакета документов и error в случае ошибки. Поле url должно содержать ссылку на документ или пакет документов, которая будет предоставлена пользователю.

Пример успешного ответа функции может выглядеть вот так:

{
    "status": "ok",
    "url": "https://yourlogistics/docs/abcdef123456.zip"
}

В ответе нужно указывать именно ссылку на готовый файл документа. Ваш сервис должен по запросу подготовить сам документ, сложить его в виде готового компилированного файла в какую-нибудь папку и выдать ссылку на него.

Ссылка на распечатку документов может выглядеть так:

https://yourlogistics/docs.php?code={track}

Тогда файл обработчика на PHP может быть таким:

<?php

// Prepare the code and URL
$code = filter_var( $_GET['code'] );
$uid = md5( $code . 'secret' );
$url = "https://yourlogiscits/docs/$uid.pdf" 

if (!file_exists( "docs/$uid.pdf" )) {
  $data = somemagictoprint( $code );
  file_put_contents( "docs/$uid.pdf", $data );
}

// Show the results
echo json_encode([ 'status' => 'ok', 'url' => $url ]);

В этом файле функция somemagictoprint должна создавать сам контент документа. Она поместит его в файл с кодированным названием и будет выдавать на него ссылку. Конкретная реализация зависит от службы доставки.

Краткие итоги

Несколько финальных советов по созданию вашей собственной логистической службы:

  1. Самый простой вариант реализации — создать «обёртку» над функциями логистической службы. Обычно, у неё присутствуют именно функции отправки, проверки статуса и распечатки документов.
  2. Постарайтесь сохранять данные о посылках и запросах в каком-нибудь журнале. Оптимальнее всего вести отдельную базу посылок и их статусов, извлекая данные из базы, а не проксируя их в службу доставки.
  3. Не забывайте выдавать реальную цену доставки при добавлении заказа, чтобы точно оценивать расходы на вашу логистику.
  4. Обязательно организуйте все три функции — и отправку, и документы, и трекинг. Это закроет все потребности в логистике.
  5. Создание полноценной службы доставки через хаки всё равно лучше.

Удачи с подключением логистических сервисов!