3namespace Sale\Handlers\Delivery\YandexTaxi\EventJournal;
5use Bitrix\Main\Localization\Loc;
6use Bitrix\Main\Type\DateTime;
7use Bitrix\Sale\Delivery\Requests\RequestTable;
8use Bitrix\Sale\Repository\ShipmentRepository;
9use Sale\Handlers\Delivery\YandexTaxi\Api\Api;
10use Sale\Handlers\Delivery\YandexTaxi\Api\ApiResult\Journal\Event;
11use Sale\Handlers\Delivery\YandexTaxi\Api\ApiResult\Journal\PriceChanged;
12use Sale\Handlers\Delivery\YandexTaxi\Api\ApiResult\Journal\StatusChanged;
13use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\Claim;
14use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\RoutePoint;
15use Sale\Handlers\Delivery\YandexTaxi\Api\StatusDictionary;
16use Sale\Handlers\Delivery\YandexTaxi\Internals\ClaimsTable;
17use Bitrix\Sale\Delivery\Services;
18use Bitrix\Sale\Delivery\Requests;
19use Bitrix\Sale\Delivery\Requests\Message;
20use Bitrix\Sale\Internals\Analytics\Storage;
21use Bitrix\Sale\Delivery\Internals\Analytics\Provider;
22use Bitrix\Main\Application;
29final class EventProcessor
31 private const DELIVERY_ANALYTICS_CODE =
'yandex_taxi';
46 public function __construct(Api $api)
55 public function process(
int $serviceId,
array $events)
57 $this->prepareClaims($events);
58 $this->prepareEvents($events);
60 $this->applyChanges($serviceId);
66 private function prepareClaims(
array $events)
70 foreach ($events as
$event)
72 $claimsIds[
$event->getClaimId()] =
true;
75 $claims = ClaimsTable::getList(
77 'filter' => [
'=EXTERNAL_ID' => array_keys($claimsIds)],
81 $eventTypes = $this->getKnownEventTypes();
82 foreach ($claims as $claim)
84 $this->claims[$claim[
'EXTERNAL_ID']] = [
85 'CURRENT_ITEM' => $claim,
86 'CHANGES' => array_combine($eventTypes, array_fill(0,
count($eventTypes),
null)),
94 private function prepareEvents(
array $events)
96 foreach ($events as
$event)
98 $claimId =
$event->getClaimId();
99 $eventCode =
$event->getCode();
101 if (!isset($this->events[$claimId]))
103 $this->events[$claimId] = [];
107 if (!isset($this->events[$claimId][$eventCode]))
109 $this->events[$claimId][$eventCode] = [];
111 $this->events[$claimId][$eventCode][] =
$event;
118 private function getKnownEventTypes()
121 PriceChanged::EVENT_CODE,
122 StatusChanged::EVENT_CODE,
129 private function findChanges()
131 $eventTypes = $this->getKnownEventTypes();
132 foreach ($this->claims as $claimId => $claimItem)
134 $claim = $claimItem[
'CURRENT_ITEM'];
136 if (!isset($this->events[$claimId]))
141 foreach ($eventTypes as $eventType)
143 if (!isset($this->events[$claimId][$eventType]))
149 $events = $this->events[$claimId][$eventType];
151 foreach ($events as
$event)
153 $eventUpdatedAt = $this->readDate(
$event->getUpdatedTs());
154 $currentUpdatedAt = $this->readDate($claim[
'EXTERNAL_UPDATED_TS']);
156 if ($currentUpdatedAt >= $eventUpdatedAt)
162 $latestEvent = $claimItem[
'CHANGES'][$eventType];
163 if (is_null($latestEvent) ||
164 $this->readDate($latestEvent->getUpdatedTs()) < $eventUpdatedAt
167 $this->claims[$claimId][
'CHANGES'][$eventType] =
$event;
177 private function applyChanges(
int $serviceId): void
179 foreach ($this->claims as $claimId => $claimItem)
181 $newUpdatedTs =
null;
184 foreach ($claimItem[
'CHANGES'] as $eventType =>
$event)
193 if (is_null($newUpdatedTs)
194 || $this->readDate(
$event->getUpdatedTs()) > $this->readDate($newUpdatedTs))
196 $newUpdatedTs =
$event->getUpdatedTs();
207 $claimItem[
'CURRENT_ITEM'][
'ID'],
220 private function updateClaim(
int $serviceId,
int $id,
string $newUpdatedTs,
array $fields)
225 'UPDATED_AT' =>
new DateTime(),
226 'EXTERNAL_UPDATED_TS' => $newUpdatedTs,
230 $updateResult = ClaimsTable::update($id,
$fields);
231 if ($updateResult->isSuccess())
233 $this->onClaimUpdated($serviceId, $id,
$fields);
242 private function onClaimUpdated(
int $serviceId,
int $id,
array $fields)
244 $claim = ClaimsTable::getById($id)->fetch();
250 $deliveryServiceIds = array_column(
253 'filter' => [
'PARENT_ID' => $serviceId]
257 $deliveryServiceIds[] = $serviceId;
261 '=DELIVERY_ID' => $deliveryServiceIds,
262 '=EXTERNAL_ID' => $claim[
'EXTERNAL_ID'],
270 $shipment = ShipmentRepository::getInstance()->getById($claim[
'SHIPMENT_ID']);
275 $deliveryName = !is_null($shipment->getDelivery()) ? $shipment->getDelivery()->getName() :
'';
277 switch (
$fields[
'EXTERNAL_STATUS'])
279 case StatusDictionary::READY_FOR_APPROVAL:
280 $remoteClaim = $this->requestClaim($claim[
'EXTERNAL_ID']);
283 && ($pricing = $remoteClaim->getPricing())
284 && ($offer = $pricing->getOffer())
287 $price = $offer->getPrice();
296 $result = $this->api->acceptClaim($claim[
'EXTERNAL_ID'], 1);
297 $message = (
new Message\Message())->setSubject(Loc::getMessage(
'SALE_YANDEX_TAXI_ACCEPTING_CLAIM'));
298 $deleteRequest =
false;
306 Loc::getMessage(
'SALE_YANDEX_TAXI_DELIVERY_CALCULATION_RECEIVED_SUCCESSFULLY_V2')
309 ->addMoneyValue(
'#PRICE#', $price)
314 $message->setBody(Loc::getMessage(
'SALE_YANDEX_TAXI_DELIVERY_CALCULATION_FAILED'));
316 Loc::getMessage(
'SALE_YANDEX_TAXI_ERROR_STATUS'),
319 $deleteRequest =
true;
325 ->setBody(Loc::getMessage(
'SALE_YANDEX_TAXI_DELIVERY_ACCEPT_CLAIM_ERROR'))
326 ->setStatus(
new Message\
Status(
327 Loc::getMessage(
'SALE_YANDEX_TAXI_ERROR_STATUS'),
330 $deleteRequest =
true;
333 Requests\Manager::sendMessage(
334 Requests\Manager::MESSAGE_MANAGER_ADDRESSEE,
341 Requests\Manager::deleteDeliveryRequest(
$request[
'ID']);
344 case StatusDictionary::PERFORMER_FOUND:
345 $remoteClaim = $this->requestClaim($claim[
'EXTERNAL_ID']);
351 $performerInfo = $remoteClaim->getPerformerInfo();
357 $externalProperties = [
359 'NAME' => Loc::getMessage(
'SALE_YANDEX_TAXI_PERFORMER'),
363 $performerInfo->getCourierName(),
367 $performerInfo->getCarModel(),
368 $performerInfo->getCarNumber(),
376 $getPhoneResult = $this->api->getPhone($claim[
'EXTERNAL_ID']);
377 if ($getPhoneResult->isSuccess())
379 $externalProperties[] = [
380 'NAME' => Loc::getMessage(
'SALE_YANDEX_TAXI_DRIVER_PHONE'),
381 'VALUE' => $getPhoneResult->getPhone(),
385 $externalProperties[] = [
386 'NAME' => Loc::getMessage(
'SALE_YANDEX_TAXI_DRIVER_PHONE_EXT'),
387 'VALUE' => $getPhoneResult->getExt(),
391 Requests\Manager::updateDeliveryRequest(
394 'EXTERNAL_STATUS' => Loc::getMessage(
'SALE_YANDEX_TAXI_DELIVERY_IN_PROCESS_V2'),
395 'EXTERNAL_STATUS_SEMANTIC' => Requests\Manager::EXTERNAL_STATUS_SEMANTIC_PROCESS,
396 'EXTERNAL_PROPERTIES' => $externalProperties,
400 $expectedOnSourceTimestamp = $this->getExpectedOnSourceTimestamp($remoteClaim->getRoutePoints());
401 if ($expectedOnSourceTimestamp)
403 Requests\Manager::sendMessage(
404 Requests\Manager::MESSAGE_MANAGER_ADDRESSEE,
405 (
new Message\Message())
407 Loc::getMessage(
'SALE_YANDEX_TAXI_PERFORMER_FOUND')
411 'SALE_YANDEX_TAXI_PICKUP_TIME',
413 '#PERSON_NAME#' => $performerInfo->getCourierName()
414 ?: Loc::getMessage(
'SALE_YANDEX_TAXI_PERFORMER')
416 '#DELIVERY_NAME#' => $deliveryName,
422 $expectedOnSourceTimestamp,
423 Application::getInstance()->getContext()->getCulture()->getShortTimeFormat()
432 case StatusDictionary::PICKUPED:
433 Requests\Manager::sendMessage(
434 Requests\Manager::MESSAGE_RECIPIENT_ADDRESSEE,
435 (
new Message\Message())
436 ->
setBody(Loc::getMessage(
'SALE_YANDEX_TAXI_YOUR_ORDER_IS_ON_ITS_WAY'))
437 ->
setType(Message\Message::TYPE_SHIPMENT_PICKUPED),
442 case StatusDictionary::PERFORMER_NOT_FOUND:
443 case StatusDictionary::FAILED:
444 case StatusDictionary::ESTIMATING_FAILED:
446 StatusDictionary::PERFORMER_NOT_FOUND => [
447 'SUBJECT' => Loc::getMessage(
'SALE_YANDEX_TAXI_PERFORMER_NOT_FOUND'),
448 'BODY' => Loc::getMessage(
449 'SALE_YANDEX_TAXI_PERFORMER_NOT_FOUND_DESCRIPTION'
452 StatusDictionary::FAILED => [
453 'SUBJECT' => Loc::getMessage(
'SALE_YANDEX_TAXI_ERROR_OCCURRED'),
454 'BODY' => Loc::getMessage(
455 'SALE_YANDEX_TAXI_ERROR_OCCURRED_DESCRIPTION'
458 StatusDictionary::ESTIMATING_FAILED => [
459 'SUBJECT' => Loc::getMessage(
'SALE_YANDEX_TAXI_ESTIMATING_FAILED'),
460 'BODY' => Loc::getMessage(
461 'SALE_YANDEX_TAXI_ESTIMATING_FAILED_DESCRIPTION'
466 Requests\Manager::sendMessage(
467 Requests\Manager::MESSAGE_MANAGER_ADDRESSEE,
468 (
new Message\Message())
469 ->setSubject($messagesMap[
$fields[
'EXTERNAL_STATUS']][
'SUBJECT'] ??
'')
473 Loc::getMessage(
'SALE_YANDEX_TAXI_ERROR_STATUS'),
480 Requests\Manager::deleteDeliveryRequest(
$request[
'ID']);
482 case StatusDictionary::CANCELLED_BY_TAXI:
483 Requests\Manager::sendMessage(
484 Requests\Manager::MESSAGE_MANAGER_ADDRESSEE,
485 (
new Message\Message())
486 ->setSubject(Loc::getMessage(
'SALE_YANDEX_TAXI_CANCELLED_BY_PERFORMER'))
487 ->
setBody(Loc::getMessage(
'SALE_YANDEX_TAXI_CANCELLED_BY_PERFORMER_DESCRIPTION'))
490 Loc::getMessage(
'SALE_YANDEX_TAXI_CANCELLATION'),
497 Requests\Manager::deleteDeliveryRequest(
$request[
'ID']);
499 case StatusDictionary::RETURNED_FINISH:
500 Requests\Manager::sendMessage(
501 Requests\Manager::MESSAGE_MANAGER_ADDRESSEE,
502 (
new Message\Message())
503 ->setSubject(Loc::getMessage(
'SALE_YANDEX_TAXI_PERFORMER_RETURNED_CARGO'))
504 ->
setBody(Loc::getMessage(
'SALE_YANDEX_TAXI_PERFORMER_RETURNED_CARGO_DESCRIPTION'))
507 Loc::getMessage(
'SALE_YANDEX_TAXI_RETURN'),
514 Requests\Manager::deleteDeliveryRequest(
$request[
'ID']);
516 case StatusDictionary::DELIVERED_FINISH:
517 Requests\Manager::updateDeliveryRequest(
520 'STATUS' => Requests\Manager::STATUS_PROCESSED,
521 'EXTERNAL_STATUS' => Loc::getMessage(
'SALE_YANDEX_TAXI_DELIVERY_FINISHED_V2'),
522 'EXTERNAL_STATUS_SEMANTIC' => Requests\Manager::EXTERNAL_STATUS_SEMANTIC_SUCCESS,
526 $message = (
new Message\Message())->setSubject(
527 Loc::getMessage(
'SALE_YANDEX_TAXI_PERFORMER_FINISHED_DELIVERY')
529 $price = isset($claim[
'EXTERNAL_FINAL_PRICE']) ? (float)$claim[
'EXTERNAL_FINAL_PRICE'] : null;
530 $currency = isset($claim[
'EXTERNAL_CURRENCY']) ? (string)$claim[
'EXTERNAL_CURRENCY'] : null;
531 if (!is_null($price) && !is_null(
$currency))
536 'SALE_YANDEX_TAXI_PRICE',
538 '#DELIVERY_NAME#' => $deliveryName,
542 ->addMoneyValue(
'#PRICE#', $price)
550 'SALE_YANDEX_TAXI_TARIFF',
552 '#DELIVERY_NAME#' => $deliveryName,
558 Requests\Manager::sendMessage(
559 Requests\Manager::MESSAGE_MANAGER_ADDRESSEE,
572 !is_null($claim[
'EXTERNAL_RESOLUTION'])
573 || $claim[
'EXTERNAL_STATUS'] === StatusDictionary::PERFORMER_NOT_FOUND)
575 ClaimsTable::update($claim[
'ID'], [
'FURTHER_CHANGES_EXPECTED' =>
'N']);
578 isset($claim[
'EXTERNAL_RESOLUTION'])
579 && $claim[
'EXTERNAL_RESOLUTION'] === ClaimsTable::EXTERNAL_STATUS_SUCCESS
582 $this->saveOrderForAnalytics($claim);
583 if ($shipment->setField(
'DEDUCTED',
'Y')->isSuccess())
585 $shipment->getOrder()->save();
594 private function saveOrderForAnalytics(
array $claim): void
597 'id' => $claim[
'EXTERNAL_ID'],
598 'is_successful' =>
'Y',
599 'status' => $claim[
'EXTERNAL_STATUS'],
600 'created_at' => $claim[
'CREATED_AT']->getTimestamp(),
603 if ($claim[
'EXTERNAL_FINAL_PRICE'] && $claim[
'EXTERNAL_CURRENCY'])
605 $order[
'amount'] = $claim[
'EXTERNAL_FINAL_PRICE'];
606 $order[
'currency'] = $claim[
'EXTERNAL_CURRENCY'];
609 (
new Storage(
new Provider(self::DELIVERY_ANALYTICS_CODE, [
$order])))->
save();
616 private function requestClaim(
string $externalId): ?Claim
618 $getClaimResult = $this->api->getClaim($externalId);
619 $remoteClaim = $getClaimResult->getClaim();
621 if ($getClaimResult->isSuccess() && !is_null($remoteClaim))
633 private function readDate(
string $dateTime)
635 return \DateTime::createFromFormat(
'Y-m-d\TH:i:s.uP', $dateTime);
642 private function getExpectedOnSourceTimestamp(
array $routePoints): ?int
644 $sourceRoutePoints = array_filter(
646 static function (RoutePoint $routePoint)
648 return $routePoint->getType() ===
'source';
652 if (empty($sourceRoutePoints))
657 $sourceRoutePoint = $sourceRoutePoints[0];
658 $visitedAt = $sourceRoutePoint->getVisitedAt();
664 $expectedTimeOnSourceRaw = $visitedAt->getExpected();
665 if (!$expectedTimeOnSourceRaw)
670 $expectedTimeOnSource = $this->readDate($expectedTimeOnSourceRaw);
671 if (!$expectedTimeOnSource)
676 return $expectedTimeOnSource->getTimestamp();
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
static getList(array $parameters=[])
static getErrorSemantic()
static getProcessSemantic()
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"