04.10.2021, 9:38 Добрый день.
Спасибо за пояснения. Технически, в штатных компонентах Битрикса ссылка для отслеживания, видимо, завязана на получение информации от службы доставки через метод getTrackingUrl класса обработчика СД, ответственного за трекинг отправлений. У современных обработчиков служб доставок, как у Почты или Озона, можно "прикрутить" tracking class и в теории все должно заработать само собой.
Т.е. это не просто готовая ссылка, которая где-то хранится.
У Озона по ТЗ такой функционал не требовали, поэтому не было реализовано. Плюс у Битрикса традиционно очень "подробная" документация: все, что известно про создание своего tracking class:
"У служб доставок существует механизм автоматического отслеживания идентификаторов отправления (трэкинг-номеров)". Какая начинка должна быть по минимуму, что для чего - разбирайтесь сами, анализируя исходники Битрикса и обработчиков, где это работает.
Соответственно:
- Чтобы решить эту задачу для Озона, нужно прикрутить свой tracking class к нему (что потребует доработки модуля, т.к. в его обработчике оный класс со своими методами сейчас отсутствует)
- В общем случае каждой доставке нужно делать свой класс отслеживания. При этом нет уверенности, что для СД, использующих ныне устаревший вариант обработчика "автоматизированная служба доставки" (СДЭК, DPD, Boxberry и т.п.) это вообще реализуемо, по другим решениям таких примеров не видели, нужно смотреть исходники Битрикса.
- Можно пойти другим путем и кастомизировать сам компонент на странице
https://intercom-nn.ru/personal/orders/95888?access=a49aa812bd3cb48f488988d9b6ad2d79
.
Т.е. прямо в нем проверять "что за доставка" и генерировать ссылку на отслеживание, если по заказу есть номер отправления (а его практически все СД умеют ставить в отгрузку заказа). Но это несколько костыльно и будет ломаться, если СД поменяет у себя ссылку или принцип ее построения и т.п.
05.10.2021, 15:21
Спасибо, более-менее посмотрели что в движке и обработчике Почты России
, который Битрикс предлагает брать как пример вместо написания адекватной документации.
В общем, помимо формирования ссылки на отслеживание класс трекинга отвечает еще и за статусы трекинга, на примере заказа 95190 и его отгрузки в Почту - вот этот блок параметров
. Как видите, тут есть кнопка обновления статусов трекинга, которая делает запрос к серверу Почты, получает информацию об этом отправлении и , обработав, отдает движку CMS в формализованном виде, а тот "двигает" статус трекинга этой отгрузки, причем это НЕ то же самое, что статус отгрузки
Из плюсов - вроде не слишком времязатратно реализовать желаемое.
Из минусов - похоже, что колдунство с запросами статусов трекинга от ТК обязательно, т.е. даже если оно вам совсем не требуется, его придется реализовать в классе трекинга. Причем в движке Битрикса жестко прошиты статусы трекинга, которые вообще могут быть, их всего 8
, без влезания в ядро CMS добавить свои нельзя, поменять тексты нельзя и связать это чудо со статусами Отгрузок (например, по трекингу заказ перешел в определенный статус - и отгрузка тоже перешла в него, как сейчас обновление статусов заказов работает по статусам, получаемым от Озон) тоже нельзя.
По времени порядка 4 ч оценка, с учетом, что часть времени пошла на расковыривание движка CMS
Сделано 11.10.2021
/bitrix/modules/ipol.ozon/classes/lib/Bitrix/Handler/DeliveryHandlerProfile.php
и создан файл: /bitrix/modules/ipol.ozon/classes/lib/Bitrix/Handler/Tracking.php
<?
namespace Ipol\Ozon\Bitrix\Handler;
use \Bitrix\Main\Localization\Loc;
use \Bitrix\Main\Error;
use \Bitrix\Sale\Result;
use \Bitrix\Sale\Delivery\Tracking\StatusResult;
use \Bitrix\Sale\Delivery\Tracking\Statuses;
use \Ipol\Ozon\StatusHandler;
use \Ipol\Ozon\OrdersTable;
use \Ipol\Ozon\Bitrix\Tools;
use \Ipol\Ozon\Bitrix\Controller\Status;
Loc::loadMessages(__FILE__);
/**
* Class Tracking
* @package namespace Ipol\Ozon\Bitrix\Handler
*/
class Tracking extends \Bitrix\Sale\Delivery\Tracking\Base
{
/**
* @return string
*/
public function getClassTitle()
{
return Tools::getMessage('TRACKING_TITLE');
}
/**
* @return string
*/
public function getClassDescription()
{
return Tools::getMessage('TRACKING_DESCRIPTION');
}
/**
* Get Bitrix Tracking status by tracking number
* @param $trackingNumber
* @return \Bitrix\Sale\Delivery\Tracking\StatusResult
*/
public function getStatus($trackingNumber)
{
$statusResult = new StatusResult();
$trackingNumber = trim($trackingNumber);
/*if (preg_match('/^[A-Z]{2}?\d{9}?[A-Z]{2}$/i', $trackingNumber) !== 1)
$statusResult->addError(new Error(Tools::getMessage('TRACKING_ERROR_WRONG_FORMAT')));*/
if (!\Ipol\Ozon\AuthHandler::isAuthorized())
$statusResult->addError(new Error(Tools::getMessage('TRACKING_ERROR_NO_AUTH')));
$orders = OrdersTable::getList([
'select' => ['ID', 'BITRIX_ID', 'LOGISTIC_ORDER_NUMBER', 'POSTING_ID'],
'filter' => ['=LOGISTIC_ORDER_NUMBER' => $trackingNumber],
'order' => ['ID' => 'ASC'],
])->fetchAll();
if (count($orders) > 1) {
// What if some goat edited orders table manually and LOGISTIC_ORDER_NUMBER not unique?
$statusResult->addError(new Error(Tools::getMessage('TRACKING_ERROR_DUPLICATE_ORDERS').$trackingNumber));
} else if (empty($orders)) {
$statusResult->addError(new Error(Tools::getMessage('TRACKING_ERROR_NO_ORDERS').$trackingNumber));
} else {
$primaryId = $orders[0]['ID'];
$postingId = $orders[0]['POSTING_ID'];
if (empty($postingId))
$statusResult->addError(new Error(Tools::getMessage('TRACKING_ERROR_NO_POSTING_ID').$trackingNumber));
}
if ($statusResult->isSuccess())
{
$handler = new Status();
$answer = $handler->checkStatus($postingId);
if ($answer && $answer->isSuccess()) {
StatusHandler::settleStatuses($answer, $postingId);
// Get last inner module status from local table
$order = OrdersTable::getByOrderId($primaryId, ['STATUS']);
$statusResult->trackingNumber = $trackingNumber;
$statusResult->status = self::getMappedStatus($order['STATUS']);
$link = $this->getTrackingUrl($trackingNumber);
$statusResult->description = Tools::getMessage('TRACKING_STATUS_DESCR').'<a href="'.$link.'">'.$link.'</a>';
$events = $answer->getResponse()->getItems();
if ($events && $events->getLast()) {
$statusResult->lastChangeTimestamp = strtotime($events->getLast()->getMoment());
}
}
else
$statusResult->addError(new Error(Tools::getMessage('TRACKING_ERROR_REQUEST_FAIL').$trackingNumber));
}
return $statusResult;
}
/**
* Get Bitrix Tracking statuses by tracking numbers array
* @param array $trackingNumbers
* @return \Bitrix\Sale\Delivery\Tracking\StatusResult[]
*/
public function getStatuses(array $trackingNumbers)
{
$data = array();
foreach($trackingNumbers as $number)
$data[$number] = $this->getStatus($number);
return $data;
}
/**
* Map corresponded Bitrix Tracking status with module inner status
* @param string $moduleStatus
* @return string
*/
protected static function getMappedStatus($moduleStatus)
{
switch ($moduleStatus)
{
case 'NEW':
case 'OK':
$bitrixStatus = Statuses::NO_INFORMATION;
break;
case 'REGISTRED':
case 'SENDED':
case 'DATEWAITS':
case 'SENDEDTOCITY':
case 'ARRIVEDTOCITY':
$bitrixStatus = Statuses::ON_THE_WAY;
break;
case 'READYFORGIVE':
case 'COURIER':
$bitrixStatus = Statuses::ARRIVED;
break;
case 'GIVEN':
case 'GIVENPART':
$bitrixStatus = Statuses::HANDED;
break;
case 'PARTRETURN':
case 'RETURNPRECEED':
case 'RETURNREADY':
case 'RETURNDONE':
$bitrixStatus = Statuses::RETURNED;
break;
case 'REFUSE':
case 'REJECTED':
case 'ANNULED':
$bitrixStatus = Statuses::PROBLEM;
break;
default:
$bitrixStatus = Statuses::UNKNOWN;
break;
}
return $bitrixStatus;
}
/**
* @param string $trackingNumber
* @return string Url were we can see tracking information
*/
public function getTrackingUrl($trackingNumber = '')
{
return 'https://tracking.ozon-dostavka.ru/?SearchId='.$trackingNumber;
}
/**
* Returns params structure
* @return array
*/
public function getParamsStructure()
{
return [];
}
}