1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
claimbuilder.php
См. документацию.
1<?php
2
3namespace Sale\Handlers\Delivery\YandexTaxi\ClaimBuilder;
4
5use Bitrix\Location\Entity\Address\FieldCollection;
6use Bitrix\Location\Entity\Location;
7use Bitrix\Location\Entity;
8use Bitrix\Main\Error;
9use Bitrix\Main\Loader;
10use Bitrix\Main\Localization\Loc;
11use Bitrix\Main\Result;
12use Bitrix\Sale\Delivery\ExtraServices\Manager;
13use Bitrix\Sale\Delivery\Services\RecipientDataProvider;
14use Bitrix\Sale\Shipment;
15use Bitrix\Sale\ShipmentItem;
16use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\Address;
17use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\Claim;
18use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\ClientRequirements;
19use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\Contact;
20use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\RoutePoint;
21use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\ShippingItem;
22use Sale\Handlers\Delivery\YandexTaxi\Api\RequestEntity\TransportClassification;
23use Sale\Handlers\Delivery\YandexTaxi\Api\Tariffs\Repository;
24use Sale\Handlers\Delivery\YandexTaxi\Common\OrderEntitiesCodeDictionary;
25use Sale\Handlers\Delivery\YandexTaxi\Common\ReferralSourceBuilder;
26use Bitrix\Main\PhoneNumber;
27use Sale\Handlers\Delivery\YandexTaxi;
28use Bitrix\Location\Entity\Address\Field;
29use Sale\Handlers\Delivery\YandexTaxi\ServiceContainer;
30
36final class ClaimBuilder
37{
38 public const SOURCE_ROUTE_POINT_ID = 1;
39 private const SOURCE_ROUTE_POINT_VISIT_ORDER = 1;
40 private const SOURCE_ROUTE_POINT_TYPE = 'source';
41
42 public const DESTINATION_ROUTE_POINT_ID = 2;
43 private const DESTINATION_ROUTE_POINT_VISIT_ORDER = 2;
44 private const DESTINATION_ROUTE_POINT_TYPE = 'destination';
45
47 protected $tariffsRepository;
48
50 protected $referralSourceBuilder;
51
53 protected $result;
54
60 public function __construct(
61 Repository $tariffsRepository,
62 ReferralSourceBuilder $referralSourceBuilder
63 )
64 {
65 $this->tariffsRepository = $tariffsRepository;
66 $this->referralSourceBuilder = $referralSourceBuilder;
67 }
68
73 public function build(Shipment $shipment): Result
74 {
75 $this->result = new Result();
76
77 $claim = new Claim();
78
82 $contactFrom = $this->buildContactFrom($shipment);
83 if (is_null($contactFrom))
84 {
85 return $this->result;
86 }
87
88 $contactTo = $this->buildContactTo($shipment);
89 if (is_null($contactTo))
90 {
91 return $this->result;
92 }
93
97 $addressFromResult = $this->buildAddressFrom($shipment);
98 if (!$addressFromResult->isSuccess())
99 {
100 return $this->result->addErrors($addressFromResult->getErrors());
101 }
103 $addressFrom = $addressFromResult->getData()['ADDRESS'];
104 $addressFrom->setId(self::SOURCE_ROUTE_POINT_ID);
105
106 $addressToResult = $this->buildAddressTo($shipment);
107 if (!$addressToResult->isSuccess())
108 {
109 return $this->result->addErrors($addressToResult->getErrors());
110 }
112 $addressTo = $addressToResult->getData()['ADDRESS'];
113 $addressTo->setId(self::DESTINATION_ROUTE_POINT_ID);
114
118 $commentForDriver = $this->getPropertyValue(
119 $shipment,
120 OrderEntitiesCodeDictionary::COMMENT_FOR_DRIVER_PROPERTY_CODE
121 );
122 if ($commentForDriver)
123 {
124 $claim->setComment($commentForDriver);
125 }
126
127 $buildClientReqResult = $this->buildTransportClassification($shipment);
128 if (!$buildClientReqResult->isSuccess())
129 {
130 return $this->result->addErrors($buildClientReqResult->getErrors());
131 }
132 $clientRequirements = $buildClientReqResult->getData()['REQUIREMENTS'];
133
137 if (!$this->isDoorDeliveryRequired($shipment))
138 {
139 $claim->setSkipDoorToDoor(true);
140 }
141
142 $claim
143 ->setEmergencyContact($contactFrom)
144 ->setClientRequirements($clientRequirements)
145 ->setRoutePoints([
146 (new RoutePoint())
147 ->setPointId(self::SOURCE_ROUTE_POINT_ID)
148 ->setVisitOrder(self::SOURCE_ROUTE_POINT_VISIT_ORDER)
149 ->setType(self::SOURCE_ROUTE_POINT_TYPE)
150 ->setContact($contactFrom)
151 ->setAddress($addressFrom)
152 ->setSkipConfirmation(true),
153 (new RoutePoint())
154 ->setPointId(self::DESTINATION_ROUTE_POINT_ID)
155 ->setVisitOrder(self::DESTINATION_ROUTE_POINT_VISIT_ORDER)
156 ->setType(self::DESTINATION_ROUTE_POINT_TYPE)
157 ->setContact($contactTo)
158 ->setAddress($addressTo)
159 ->setSkipConfirmation(true)
160 ])
161 ->setReferralSource(
162 $this->referralSourceBuilder->getReferralSourceValue()
163 );
164
165 $shippingItemCollection = $this->getShippingItemCollection($shipment);
166 $validationResult = $shippingItemCollection->isValid();
167 if (!$validationResult->isSuccess())
168 {
169 return $this->result->addErrors($validationResult->getErrors());
170 }
171
172 foreach ($shippingItemCollection as $shippingItem)
173 {
174 $claim->addItem($shippingItem);
175 }
176
177 return $this->result->setData(['RESULT' => $claim]);
178 }
179
184 public function getShippingItemCollection(Shipment $shipment): ShippingItemCollection
185 {
186 $result = new ShippingItemCollection();
187
189 foreach($shipment->getShipmentItemCollection()->getShippableItems() as $shipmentItem)
190 {
191 $basketItem = $shipmentItem->getBasketItem();
192 if(!$basketItem)
193 {
194 continue;
195 }
196
197 $result->addItem(
198 (new ShippingItem())
199 ->setTitle((string)$basketItem->getField('NAME'))
200 ->setCostValue((string)((float)$basketItem->getPriceWithVat() * $shipmentItem->getQuantity()))
201 ->setCostCurrency((string)$basketItem->getCurrency())
202 ->setQuantity((int)ceil($shipmentItem->getQuantity()))
203 ->setPickupPoint(self::SOURCE_ROUTE_POINT_ID)
204 ->setDropoffPoint(self::DESTINATION_ROUTE_POINT_ID)
205 );
206 }
207
208 return $result;
209 }
210
215 private function getExtraServiceValues(Shipment $shipment): array
216 {
217 $result = [];
218
219 $extraServicesValues = is_array($shipment->getExtraServices()) ? $shipment->getExtraServices() : [];
220
221 $services = Manager::getExtraServicesList($shipment->getDeliveryId());
222 foreach ($services as $serviceId => $serviceItem)
223 {
224 $initValue = isset($serviceItem['INIT_VALUE']) ? $serviceItem['INIT_VALUE'] : null;
225
226 $value = isset($extraServicesValues[$serviceId]) ? $extraServicesValues[$serviceId] : $initValue;
227
228 $result[$serviceItem['CODE']] = [
229 'VALUE' => $value,
230 'SERVICE' => $serviceItem,
231 ];
232 }
233
234 return $result;
235 }
236
241 public function isDoorDeliveryRequired(Shipment $shipment)
242 {
243 $extraServiceValues = $this->getExtraServiceValues($shipment);
244
245 foreach ($extraServiceValues as $code => $item)
246 {
247 if ($code != OrderEntitiesCodeDictionary::DOOR_DELIVERY_EXTRA_SERVICE_CODE)
248 {
249 continue;
250 }
251
252 return ($item['VALUE'] === 'Y');
253 }
254
255 return false;
256 }
257
262 public static function isOffersCalculateMethod(string $taxiClass): bool
263 {
264 return (
265 in_array($taxiClass, ['express', 'cargo'])
266 && ServiceContainer::getRegionFinder()->getCurrentRegion() === 'ru'
267 );
268 }
269
274 public function buildClientRequirements(Shipment $shipment): Result
275 {
276 $requirements = new ClientRequirements();
277
278 $result = $this->getTaxiClass($shipment);
279
280 if (!$result->isSuccess())
281 {
282 return $result;
283 }
284
285 $tariff = $result->getData()['tariff'];
286
287 $requirements->setTaxiClasses([$tariff['name']]);
288 $requirements->setSkipDoorToDoor(!$this->isDoorDeliveryRequired($shipment));
289
290 $options = $this->makeOptions($shipment, $tariff);
291 $requirements->setOptions($options);
292
293 $result->setData(['REQUIREMENTS' => $requirements]);
294
295 return $result;
296 }
297
302 public function buildTransportClassification(Shipment $shipment): Result
303 {
304 $requirements = new TransportClassification();
305
306 $result = $this->getTaxiClass($shipment);
307
308 if (!$result->isSuccess())
309 {
310 return $result;
311 }
312
313 $tariff = $result->getData()['tariff'];
314
315 $requirements->setTaxiClass($tariff['name']);
316
317 $options = $this->makeOptions($shipment, $tariff);
318 $requirements->setOptions($options);
319
320 $result->setData(['REQUIREMENTS' => $requirements]);
321
322 return $result;
323 }
324
329 protected function buildContactFrom(Shipment $shipment): ?Contact
330 {
331 $responsibleUser = $this->getResponsibleUser($shipment);
332
333 if (!$responsibleUser)
334 {
335 $this->result->addError(new Error(Loc::getMessage('SALE_YANDEX_TAXI_RESPONSIBLE_NOT_SPECIFIED')));
336 return null;
337 }
338
339 $responsibleUserName = $this->getResponsibleUserName($responsibleUser);
340 $responsibleUserEmail = $this->getResponsibleUserEmail($responsibleUser);
341 $responsibleUserPhone = $this->getResponsibleUserPhone($responsibleUser);
342
346 if (!$responsibleUserName)
347 {
348 $this->result->addError(new Error(Loc::getMessage('SALE_YANDEX_TAXI_RESPONSIBLE_FULL_NAME_NOT_SPECIFIED')));
349 return null;
350 }
351 if (!$responsibleUserPhone)
352 {
353 $this->result->addError(new Error(Loc::getMessage('SALE_YANDEX_TAXI_RESPONSIBLE_PHONE_NOT_SPECIFIED')));
354 return null;
355 }
356
357 $oResponsibleUserPhone = PhoneNumber\Parser::getInstance()->parse($responsibleUserPhone);
358 if (!$oResponsibleUserPhone->isValid())
359 {
360 $this->result->addError(
361 new Error(
362 sprintf(
363 '%s: %s',
364 Loc::getMessage('SALE_YANDEX_TAXI_RESPONSIBLE_PHONE_NOT_VALID'),
365 (string)$oResponsibleUserPhone->format()
366 )
367 )
368 );
369 return null;
370 }
371
372 if (!$responsibleUserEmail)
373 {
374 $this->result->addError(new Error(Loc::getMessage('SALE_YANDEX_TAXI_RESPONSIBLE_EMAIL_NOT_SPECIFIED')));
375 return null;
376 }
377
378 return (new Contact())
379 ->setName($responsibleUserName)
380 ->setPhone(
381 PhoneNumber\Formatter::format($oResponsibleUserPhone, PhoneNumber\Format::E164)
382 )
383 ->setEmail($responsibleUserEmail);
384 }
385
390 protected function buildContactTo(Shipment $shipment): ?Contact
391 {
392 $recipientContact = RecipientDataProvider::getContact($shipment);
393
394 if (is_null($recipientContact))
395 {
396 $this->result->addError(
397 new Error(
398 Loc::getMessage('SALE_YANDEX_TAXI_CLIENT_CLIENT_CONTACT_NOT_FOUND')
399 )
400 );
401 return null;
402 }
403
404 if (!$recipientContact->getName())
405 {
406 $this->result->addError(
407 new Error(
408 Loc::getMessage('SALE_YANDEX_TAXI_CLIENT_FULL_NAME_NOT_SPECIFIED')
409 )
410 );
411 return null;
412 }
413
414 $recipientContactPhones = $recipientContact->getPhones();
415 if (empty($recipientContactPhones))
416 {
417 $this->result->addError(
418 new Error(
419 Loc::getMessage('SALE_YANDEX_TAXI_CLIENT_PHONE_NOT_SPECIFIED')
420 )
421 );
422 return null;
423 }
424 else
425 {
426 $oPhone = PhoneNumber\Parser::getInstance()->parse($recipientContactPhones[0]->getValue());
427 if (!$oPhone->isValid())
428 {
429 $this->result->addError(
430 new Error(
431 sprintf(
432 '%s: %s',
433 Loc::getMessage('SALE_YANDEX_TAXI_CLIENT_PHONE_NOT_VALID'),
434 (string)$oPhone->format()
435 )
436 )
437 );
438 return null;
439 }
440 }
441
442 return (new Contact())
443 ->setName($recipientContact->getName())
444 ->setPhone(PhoneNumber\Formatter::format($oPhone, PhoneNumber\Format::E164));
445 }
446
451 private function getResponsibleUserName(array $responsibleUser)
452 {
453 return trim(sprintf('%s %s', $responsibleUser['NAME'], $responsibleUser['LAST_NAME']));
454 }
455
460 private function getResponsibleUserEmail(array $responsibleUser)
461 {
462 return isset($responsibleUser['EMAIL']) ? (string)$responsibleUser['EMAIL'] : null;
463 }
464
469 private function getResponsibleUserPhone(array $responsibleUser)
470 {
471 if (isset($responsibleUser['WORK_PHONE']) && !empty($responsibleUser['WORK_PHONE']))
472 {
473 return (string)$responsibleUser['WORK_PHONE'];
474 }
475 elseif (isset($responsibleUser['PERSONAL_MOBILE']) && !empty($responsibleUser['PERSONAL_MOBILE']))
476 {
477 return (string)$responsibleUser['PERSONAL_MOBILE'];
478 }
479 elseif (isset($responsibleUser['PERSONAL_PHONE']) && !empty($responsibleUser['PERSONAL_PHONE']))
480 {
481 return (string)$responsibleUser['PERSONAL_PHONE'];
482 }
483
484 return null;
485 }
486
491 public function buildAddressFrom(Shipment $shipment): Result
492 {
493 return $this->buildAddress($shipment, 'IS_ADDRESS_FROM');
494 }
495
500 public function buildAddressTo(Shipment $shipment): Result
501 {
502 return $this->buildAddress($shipment, 'IS_ADDRESS_TO');
503 }
504
509 public function getTaxiClass(Shipment $shipment): Result
510 {
511 $result = new Result();
512
513 $deliveryService = $shipment->getDelivery();
514 if (!$deliveryService)
515 {
516 return $result->addError(
517 new Error(Loc::getMessage('SALE_YANDEX_TAXI_DELIVERY_SERVICE_NOT_FOUND'))
518 );
519 }
520
521 $deliveryServiceConfig = $deliveryService->getConfig();
522 if (!isset($deliveryServiceConfig['MAIN']['ITEMS']['PROFILE_TYPE']['VALUE']))
523 {
524 return $result->addError(
525 new Error(Loc::getMessage('SALE_YANDEX_TAXI_TARIFF_IS_NOT_SPECIFIED'))
526 );
527 }
528 $tariffCode = $deliveryServiceConfig['MAIN']['ITEMS']['PROFILE_TYPE']['VALUE'];
529
530 $tariff = null;
531 $availableTariffs = $this->tariffsRepository->getTariffs();
532 foreach ($availableTariffs as $availableTariff)
533 {
534 if ($availableTariff['name'] === $tariffCode)
535 {
536 $tariff = $availableTariff;
537 break;
538 }
539 }
540
541 if (is_null($tariff))
542 {
543 return $result->addError(
544 new Error(Loc::getMessage('SALE_YANDEX_TAXI_TARIFF_HAS_NOT_BEEN_FOUND'))
545 );
546 }
547
548 $result->setData(['tariff' => $tariff]);
549
550 return $result;
551 }
552
558 private function makeOptions(Shipment $shipment, array $tariff): array
559 {
560 $extraServiceValues = $this->getExtraServiceValues($shipment);
561 $options = [];
562
563 foreach ($tariff['supported_requirements'] as $supportedRequirement)
564 {
565 if ($supportedRequirement['type'] === 'multi_select')
566 {
567 foreach ($supportedRequirement['options'] as $srOption)
568 {
569 if (isset($extraServiceValues[$srOption['value']])
570 && $extraServiceValues[$srOption['value']]['VALUE'] === 'Y'
571 )
572 {
573 if (!is_array($options[$supportedRequirement['name']]))
574 {
575 $options[$supportedRequirement['name']] = [];
576 }
577 $options[$supportedRequirement['name']][] = $srOption['value'];
578 }
579 }
580 }
581 elseif ($supportedRequirement['type'] === 'select')
582 {
583 if (isset($extraServiceValues[$supportedRequirement['name']])
584 && !empty($extraServiceValues[$supportedRequirement['name']]['VALUE'])
585 )
586 {
587 foreach ($supportedRequirement['options'] as $srOption)
588 {
592 if ($srOption['value'] == $extraServiceValues[$supportedRequirement['name']]['VALUE'])
593 {
594 $options[$supportedRequirement['name']] = $srOption['value'];
595 break;
596 }
597 }
598 }
599 }
600 }
601
602 return $options;
603 }
604
610 private function buildAddress(Shipment $shipment, string $attribute)
611 {
612 $result = new Result();
613
614 if (!Loader::includeModule('location'))
615 {
616 return $result->addError(
617 new Error(Loc::getMessage('SALE_YANDEX_TAXI_LOCATION_MODULE_REQUIRED'))
618 );
619 }
620
621 $property = $shipment->getPropertyCollection()->getAttribute($attribute);
622 $addressArray = $property ? $property->getValue() : null;
623 if (!is_array($addressArray) || empty($addressArray))
624 {
625 return $result->addError(
626 new Error(
627 Loc::getMessage(
628 'SALE_YANDEX_TAXI_FIELD_VALUE_NOT_SPECIFIED',
629 [
630 '#FIELD_NAME#' => $property ? $property->getName() : ''
631 ]
632 )
633 )
634 );
635 }
636
637 $address = Entity\Address::fromArray($addressArray);
638 $addressFieldCollection = $address->getFieldCollection();
639
641 $countryField = $addressFieldCollection->getItemByType(Location\Type::COUNTRY);
642
644 $cityField = $addressFieldCollection->getItemByType(Location\Type::LOCALITY);
645
647 $streetField = $addressFieldCollection->getItemByType(Location\Type::STREET);
648
650 $buildingField = $addressFieldCollection->getItemByType(Location\Type::BUILDING);
651
652 return $result->setData(
653 [
654 'ADDRESS' => (new YandexTaxi\Api\RequestEntity\Address())
655 ->setCountry($countryField ? $countryField->getValue() : '')
656 ->setCity($cityField ? $cityField->getValue() : '')
657 ->setStreet($streetField ? $streetField->getValue() : '')
658 ->setBuilding($buildingField ? $buildingField->getValue() : '')
659 ->setComment(
660 $this->getAddressFieldValues(
661 $addressFieldCollection,
662 function (Field $field)
663 {
664 return (
665 $field->getType() > Location\Type::ADDRESS_LINE_1
666 );
667 }
668 )
669 )
670 ->setFullName(
671 $this->getAddressFieldValues(
672 $addressFieldCollection,
673 function (Field $field)
674 {
675 return (
676 $field->getType() >= Location\Type::COUNTRY
677 && $field->getType() <= Location\Type::ADDRESS_LINE_1
678 );
679 }
680 )
681 )
682 ->setCoordinates([(float)$address->getLongitude(), (float)$address->getLatitude()])
683 ]
684 );
685 }
686
692 private function getAddressFieldValues(FieldCollection $addressFieldCollection, \Closure $fieldsFilter): string
693 {
694 return implode(
695 ', ',
696 array_map(
697 static function (Field $field)
698 {
699 return $field->getValue();
700 },
701 array_filter(
702 $addressFieldCollection->getSortedItems(),
703 $fieldsFilter
704 )
705 )
706 );
707 }
708
714 private function getPropertyValue(Shipment $shipment, string $propertyCode)
715 {
716 $propertyValueObject = $this->getPropertyValueObject($shipment, $propertyCode);
717 if (!$propertyValueObject)
718 {
719 return null;
720 }
721
722 return $propertyValueObject->getValue();
723 }
724
730 private function getPropertyValueObject(Shipment $shipment, string $propertyCode)
731 {
732 $propertyValueCollection = $shipment->getPropertyCollection();
733
735 foreach ($propertyValueCollection as $propertyValue)
736 {
738 $property = $propertyValue->getPropertyObject();
739
740 if ($property->getField('CODE') !== $propertyCode)
741 {
742 continue;
743 }
744
745 return $propertyValue;
746 }
747
748 return null;
749 }
750
755 private function getResponsibleUser(Shipment $shipment): ?array
756 {
757 $result = null;
758
759 $userId = (int)$shipment->getField('RESPONSIBLE_ID');
760 if (!$userId && is_object($GLOBALS['USER']))
761 {
762 $userId = (int)$GLOBALS['USER']->getId();
763 }
764
765 $result = \CUser::GetList(
766 'id',
767 'asc',
768 ['ID' => $userId]
769 )->fetch();
770
771 return $result ?? null;
772 }
773}
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
Определения check_mail.php:18
const E164
Определения format.php:7
static format(PhoneNumber $number, $formatType, $forceNationalPrefix=false)
Определения formatter.php:7
static getContact(Shipment $shipment)
Определения recipientdataprovider.php:22
$options
Определения commerceml2.php:49
</td ></tr ></table ></td ></tr ><?endif?><? $propertyIndex=0;foreach( $arGlobalProperties as $propertyCode=> $propertyValue
Определения file_new.php:729
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$result
Определения get_property_values.php:14
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
Определения options.php:195
$value
Определения Param.php:39
getValue()
Определения Param.php:141
setType(string $type)
Определения Param.php:121
setTitle(?string $title)
Определения columnfields.php:178
$GLOBALS['____1690880296']
Определения license.php:1
trait Error
Определения error.php:11
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393