PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/sale/handlers/delivery/additional/ruspost/reliability/service.php

https://gitlab.com/alexprowars/bitrix
PHP | 514 lines | 329 code | 80 blank | 105 comment | 52 complexity | cc9caa593ff6c0c6bd4cf746c60b1210 MD5 | raw file
  1. <?php
  2. namespace Sale\Handlers\Delivery\Additional\RusPost\Reliability;
  3. use Bitrix\Main\ArgumentNullException;
  4. use Bitrix\Main\Event;
  5. use Bitrix\Main\Loader;
  6. use Bitrix\Main\Localization\Loc;
  7. use Bitrix\Main\Web\HttpClient;
  8. use Bitrix\Sale\Delivery;
  9. use Bitrix\Sale\Internals\ReliabilityTable;
  10. use Bitrix\Sale\Order;
  11. use Bitrix\Sale\PropertyValueCollectionBase;
  12. use Bitrix\Sale\Shipment;
  13. Loader::registerAutoLoadClasses(
  14. 'sale',
  15. array(
  16. __NAMESPACE__.'\Reliability' => 'handlers/delivery/additional/ruspost/reliability/reliability.php',
  17. __NAMESPACE__.'\ReliabilityCollection' => 'handlers/delivery/additional/ruspost/reliability/reliabilitycollection.php',
  18. __NAMESPACE__.'\Requester' => 'handlers/delivery/additional/ruspost/reliability/requester.php'
  19. )
  20. );
  21. /**
  22. * Class Service
  23. * @package Sale\Handlers\Delivery\Additional\RusPost\Reliability
  24. */
  25. class Service
  26. {
  27. const UNKNOWN = 0;
  28. const RELIABLE = 10;
  29. const FRAUD = 20;
  30. /**
  31. * @param int $deliveryId
  32. * @param ReliabilityCollection $collection
  33. * @return ReliabilityCollection
  34. * @throws ArgumentNullException
  35. * @throws \Bitrix\Main\ArgumentException
  36. * @throws \Bitrix\Main\SystemException
  37. */
  38. public static function getReliabilityCollection(int $deliveryId, ReliabilityCollection $collection)
  39. {
  40. if($deliveryId <= 0)
  41. {
  42. throw new ArgumentNullException('deliveryId');
  43. }
  44. if($collection->count() <= 0)
  45. {
  46. return $collection;
  47. }
  48. $notFoundInDb = $collection->getHashList();
  49. /** @var ReliabilityCollection $stored */
  50. $stored = self::getTableClass()::query()
  51. ->addFilter('HASH', $collection->getHashList())
  52. ->whereNotNull("RELIABILITY")
  53. ->addSelect('*')
  54. ->fetchCollection();
  55. if($stored)
  56. {
  57. $notFoundInDb = array_diff($collection->getHashList(), $stored->getHashList());
  58. if (empty($notFoundInDb))
  59. {
  60. return $stored;
  61. }
  62. }
  63. $requested = self::requestReliability(
  64. $deliveryId,
  65. $collection->filterByHashes($notFoundInDb)
  66. );
  67. $result = new ReliabilityCollection();
  68. $result->setItems($collection->getAll());
  69. if($stored)
  70. {
  71. $result->setItems($stored->getAll());
  72. }
  73. if($requested)
  74. {
  75. $result->setItems($requested->getAll());
  76. }
  77. $result->saveItems();
  78. return $result;
  79. }
  80. /**
  81. * @param int $deliveryId
  82. * @param string $fullName
  83. * @param string $address
  84. * @param string $phone
  85. * @return int
  86. * @throws ArgumentNullException
  87. * @throws \Bitrix\Main\ArgumentException
  88. * @throws \Bitrix\Main\SystemException
  89. */
  90. public static function getReliabilityValue(int $deliveryId, string $fullName, string $address, string $phone)
  91. {
  92. $collection = new ReliabilityCollection();
  93. $collection->add(Reliability::create($fullName, $address, $phone));
  94. $hash = self::createHash($fullName, $address, $phone);
  95. $resultCollection = self::getReliabilityCollection(
  96. $deliveryId,
  97. $collection
  98. );
  99. if($reliability = $resultCollection->getByPrimary($hash))
  100. {
  101. return $reliability->getReliability();
  102. }
  103. return self::UNKNOWN;
  104. }
  105. /**
  106. * @param int $deliveryId
  107. * @return string
  108. * @throws \Bitrix\Main\ArgumentException
  109. * @throws \Bitrix\Main\SystemException
  110. */
  111. public static function prepareData(int $deliveryId, int $attempt = 0)
  112. {
  113. if($deliveryId <= 0)
  114. {
  115. return '';
  116. }
  117. /** @var ReliabilityCollection $collection */
  118. $collection = self::getTableClass()::query()
  119. ->whereNull('RELIABILITY')
  120. ->addSelect('*')
  121. ->fetchCollection();
  122. if($collection->count() <= 0)
  123. {
  124. return '';
  125. }
  126. /** @var ReliabilityCollection $requestedCollection */
  127. if($requestedCollection = self::requestReliability($deliveryId, $collection))
  128. {
  129. $requestedCollection->saveItems();
  130. return '';
  131. }
  132. if($attempt > 0)
  133. {
  134. return self::createAgentName($deliveryId, --$attempt);
  135. }
  136. return '';
  137. }
  138. /**
  139. * @param Shipment $shipment
  140. * @return PropertyValueCollectionBase|null
  141. * @throws \Bitrix\Main\ArgumentException
  142. * @throws \Bitrix\Main\NotImplementedException
  143. */
  144. private static function extractProperties(Shipment $shipment)
  145. {
  146. if (!($order = $shipment->getOrder()))
  147. {
  148. return null;
  149. }
  150. if (!($userId = (int)$order->getUserId()) || $userId === (int)\CSaleUser::GetAnonymousUserID())
  151. {
  152. return null;
  153. }
  154. if(!$props = $order->getPropertyCollection())
  155. {
  156. return null;
  157. }
  158. return $props;
  159. }
  160. /**
  161. * @param PropertyValueCollectionBase $props
  162. * @return array|null
  163. * @throws \Bitrix\Main\ArgumentOutOfRangeException
  164. */
  165. private static function extractDataFromProps(PropertyValueCollectionBase $props)
  166. {
  167. $addressValue = '';
  168. $fullNameValue = '';
  169. $phoneValue = '';
  170. if($address = $props->getAddress())
  171. {
  172. if($address->getValue() <> '')
  173. {
  174. $addressValue = (string)$address->getValue();
  175. }
  176. }
  177. if($payerName = $props->getPayerName())
  178. {
  179. if($payerName->getValue() <> '' )
  180. {
  181. $fullNameValue = (string)$payerName->getValue();
  182. }
  183. }
  184. if($phone = $props->getPhone())
  185. {
  186. if($phone->getValue() <> '' )
  187. {
  188. $phoneValue = (string)$phone->getValue();
  189. }
  190. }
  191. if($addressValue == '' && $fullNameValue == '' && $phoneValue == '')
  192. {
  193. return null;
  194. }
  195. return[$fullNameValue, $addressValue, $phoneValue];
  196. }
  197. /**
  198. * @param $expectedDeliveryId
  199. * @param Event $event
  200. * @throws ArgumentNullException
  201. * @throws \Bitrix\Main\ArgumentException
  202. * @throws \Bitrix\Main\ArgumentOutOfRangeException
  203. * @throws \Bitrix\Main\NotImplementedException
  204. * @throws \Bitrix\Main\ObjectPropertyException
  205. * @throws \Bitrix\Main\SystemException
  206. */
  207. public static function onShipmentSave($expectedDeliveryId, Event $event)
  208. {
  209. /** @var Shipment $shipment */
  210. if (!($shipment = $event->getParameter('ENTITY')))
  211. {
  212. return;
  213. }
  214. /** @var Delivery\Services\Base */
  215. if (!($delivery = $shipment->getDelivery()))
  216. {
  217. return;
  218. }
  219. if(!self::isDeliverySuitable($delivery, $expectedDeliveryId))
  220. {
  221. return;
  222. }
  223. if(!$props = self::extractProperties($shipment))
  224. {
  225. return;
  226. }
  227. if(!($data = self::extractDataFromProps($props)))
  228. {
  229. return;
  230. }
  231. list($fullName, $address, $phone) = $data;
  232. $hash = self::createHash($fullName, $address, $phone);
  233. if(!($reliability = self::getTableClass()::getByPrimary($hash)->fetchObject()))
  234. {
  235. $reliability = Reliability::create($fullName, $address, $phone);
  236. $reliability->save();
  237. }
  238. self::addAgent($delivery->getId(), 3);
  239. }
  240. /**
  241. * @param $expectedDeliveryId
  242. * @param Event $event
  243. * @return \Bitrix\Main\EventResult
  244. * @throws ArgumentNullException
  245. * @throws \Bitrix\Main\ArgumentException
  246. * @throws \Bitrix\Main\ArgumentOutOfRangeException
  247. * @throws \Bitrix\Main\NotImplementedException
  248. * @throws \Bitrix\Main\SystemException
  249. */
  250. public static function onSaleAdminOrderInfoBlockShow($expectedDeliveryId, Event $event)
  251. {
  252. /** @var Order $order */
  253. $order = $event->getParameter("ORDER");
  254. $findSuitable = false;
  255. /** @var Shipment $shipment */
  256. foreach ($order->getShipmentCollection() as $shipment)
  257. {
  258. if($shipment->isSystem())
  259. {
  260. continue;
  261. }
  262. if(!($delivery = $shipment->getDelivery()))
  263. {
  264. continue;
  265. }
  266. if (self::isDeliverySuitable($delivery, $expectedDeliveryId))
  267. {
  268. $findSuitable = true;
  269. break;
  270. }
  271. }
  272. $result = new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS);
  273. if(!$findSuitable)
  274. {
  275. return $result;
  276. }
  277. if(!($props = $order->getPropertyCollection()))
  278. {
  279. return $result;
  280. }
  281. if(!($data = self::extractDataFromProps($props)))
  282. {
  283. return $result;
  284. }
  285. list($fullName, $address, $phone) = $data;
  286. $reliability = self::getReliabilityValue($delivery->getId(), $fullName, $address, $phone);
  287. global $APPLICATION;
  288. ob_start();
  289. $APPLICATION->IncludeComponent(
  290. 'bitrix:sale.delivery.ruspost.reliability',
  291. '.default',
  292. ['RELIABILITY' => $reliability]
  293. );
  294. $value = ob_get_contents();
  295. ob_end_clean();
  296. return new \Bitrix\Main\EventResult(
  297. \Bitrix\Main\EventResult::SUCCESS,
  298. [
  299. [
  300. 'TITLE' => Loc::getMessage('SALE_DLVRS_RELIABILITY_TITLE'),
  301. 'VALUE' => $value
  302. ]
  303. ],
  304. 'sale'
  305. );
  306. }
  307. /**
  308. * @param int $deliveryId
  309. * @param ReliabilityCollection $collection
  310. * @return bool|ReliabilityCollection
  311. * @throws ArgumentNullException
  312. * @throws \Bitrix\Main\SystemException
  313. */
  314. private static function requestReliability(int $deliveryId, ReliabilityCollection $collection)
  315. {
  316. if($deliveryId <= 0)
  317. {
  318. return $collection;
  319. }
  320. if($collection->count() <= 0)
  321. {
  322. return $collection;
  323. }
  324. $delivery = Delivery\Services\Manager::getObjectById($deliveryId);
  325. if(!$delivery || !self::isDeliverySuitable($delivery))
  326. {
  327. return $collection;
  328. }
  329. /** @var \Sale\Handlers\Delivery\Additional\DeliveryRequests\RusPost\Handler $deliveryRequest */
  330. if(!($deliveryRequest = $delivery->getDeliveryRequestHandler()))
  331. {
  332. return $collection;
  333. }
  334. $deliveryRequest->setHttpClient(self::createHttpClient());
  335. return (new Requester($deliveryRequest))
  336. ->request($collection);
  337. }
  338. /**
  339. * @param Delivery\Services\Base $delivery
  340. * @return bool
  341. */
  342. private static function isDeliverySuitable(Delivery\Services\Base $delivery, $expectedDeliveryId = 0)
  343. {
  344. if (get_class($delivery) !== 'Sale\Handlers\Delivery\AdditionalProfile' || $delivery->getId() <= 0)
  345. {
  346. return false;
  347. }
  348. /** @var \Sale\Handlers\Delivery\AdditionalProfile $delivery */
  349. if ($delivery->getParentService()->getServiceType() !== 'RUSPOST')
  350. {
  351. return false;
  352. }
  353. if($expectedDeliveryId > 0)
  354. {
  355. if(!($deliveryRequest = $delivery->getDeliveryRequestHandler()))
  356. {
  357. return false;
  358. }
  359. if($deliveryRequest->getHandlingDeliveryServiceId() != $expectedDeliveryId)
  360. {
  361. return false;
  362. }
  363. }
  364. return true;
  365. }
  366. /**
  367. * @param string $address
  368. * @param string $fullName
  369. * @param string $phone
  370. * @return string
  371. */
  372. public static function createHash(string $fullName, string $address, string $phone)
  373. {
  374. return md5(trim($fullName).trim($address).trim($phone));
  375. }
  376. /**
  377. * @param int $deliveryId
  378. */
  379. public static function install(int $deliveryId)
  380. {
  381. $eventManager = \Bitrix\Main\EventManager::getInstance();
  382. $eventManager->registerEventHandler('sale', 'OnSaleShipmentEntitySaved' , 'sale', '\Sale\Handlers\Delivery\Additional\RusPost\Reliability\Service', 'onShipmentSave', 100, "", [$deliveryId]);
  383. $eventManager->registerEventHandler('sale', 'onSaleAdminOrderInfoBlockShow' , 'sale', '\Sale\Handlers\Delivery\Additional\RusPost\Reliability\Service', 'onSaleAdminOrderInfoBlockShow', 100, "", [$deliveryId]);
  384. }
  385. /**
  386. * @param int $deliveryId
  387. */
  388. public static function unInstall(int $deliveryId)
  389. {
  390. $eventManager = \Bitrix\Main\EventManager::getInstance();
  391. $eventManager->unRegisterEventHandler('sale', 'OnSaleShipmentEntitySaved' , 'sale', '\Sale\Handlers\Delivery\Additional\RusPost\Reliability\Service', 'onShipmentSave', "", [$deliveryId]);
  392. $eventManager->unRegisterEventHandler('sale', 'onSaleAdminOrderInfoBlockShow' , 'sale', '\Sale\Handlers\Delivery\Additional\RusPost\Reliability\Service', 'onSaleAdminOrderInfoBlockShow', "", [$deliveryId]);
  393. }
  394. /**
  395. * @return HttpClient
  396. */
  397. private static function createHttpClient()
  398. {
  399. return new HttpClient(array(
  400. "version" => "1.1",
  401. "socketTimeout" => 5,
  402. "streamTimeout" => 5,
  403. "redirect" => true,
  404. "redirectMax" => 3,
  405. ));
  406. }
  407. /**
  408. * @param int $deliveryId
  409. */
  410. private static function addAgent(int $deliveryId, int $attempts)
  411. {
  412. if($attempts <= 0)
  413. {
  414. return;
  415. }
  416. \CAgent::AddAgent(self::createAgentName($deliveryId, $attempts), "sale", "N", 60, "", "Y");
  417. }
  418. /**
  419. * @param int $deliveryId
  420. * @param int $attempts
  421. * @return string
  422. */
  423. private static function createAgentName(int $deliveryId, int $attempts)
  424. {
  425. return '\Sale\Handlers\Delivery\Additional\RusPost\Reliability\Service::prepareData('.$deliveryId.', '.$attempts.');';
  426. }
  427. /**
  428. * @return ReliabilityTable
  429. */
  430. private static function getTableClass()
  431. {
  432. return ReliabilityTable::class;
  433. }
  434. }