PageRenderTime 26ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/sale/lib/shipmentitemstore.php

https://gitlab.com/alexprowars/bitrix
PHP | 794 lines | 511 code | 117 blank | 166 comment | 60 complexity | 23cea3d2e0e0ee82381d783f5d9a5e2e MD5 | raw file
  1. <?php
  2. namespace Bitrix\Sale;
  3. use Bitrix\Main\Localization\Loc;
  4. use Bitrix\Main;
  5. use Bitrix\Sale;
  6. Loc::loadMessages(__FILE__);
  7. /**
  8. * @method ShipmentItemStoreCollection getCollection()
  9. */
  10. class ShipmentItemStore
  11. extends Internals\CollectableEntity
  12. implements \IEntityMarker
  13. {
  14. /**
  15. * @return array
  16. */
  17. public static function getAvailableFields()
  18. {
  19. return [
  20. 'ORDER_DELIVERY_BASKET_ID', 'STORE_ID', 'QUANTITY',
  21. 'BARCODE', 'BASKET_ID', 'MARKING_CODE'
  22. ];
  23. }
  24. /**
  25. * @return array
  26. */
  27. protected static function getMeaningfulFields()
  28. {
  29. return [];
  30. }
  31. /**
  32. * @param array $itemData
  33. * @return mixed
  34. * @throws Main\ArgumentException
  35. */
  36. private static function createShipmentItemStoreObject(array $itemData = array())
  37. {
  38. $registry = Registry::getInstance(static::getRegistryType());
  39. $shipmentItemStoreClassName = $registry->getShipmentItemStoreClassName();
  40. return new $shipmentItemStoreClassName($itemData);
  41. }
  42. /**
  43. * @return string
  44. */
  45. public static function getRegistryType()
  46. {
  47. return Registry::REGISTRY_TYPE_ORDER;
  48. }
  49. /**
  50. * @return string
  51. */
  52. public static function getRegistryEntity()
  53. {
  54. return Registry::ENTITY_SHIPMENT_ITEM_STORE;
  55. }
  56. /**
  57. * @param ShipmentItemStoreCollection $collection
  58. * @param BasketItem $basketItem
  59. * @return mixed
  60. * @throws Main\ArgumentException
  61. * @throws Main\ArgumentNullException
  62. */
  63. public static function create(ShipmentItemStoreCollection $collection, BasketItem $basketItem)
  64. {
  65. $shipmentItemStore = static::createShipmentItemStoreObject();
  66. $shipmentItemStore->setCollection($collection);
  67. $shipmentItem = $collection->getShipmentItem();
  68. if ($shipmentItem)
  69. {
  70. $fields = array(
  71. 'ORDER_DELIVERY_BASKET_ID' => $collection->getShipmentItem()->getId(),
  72. 'BASKET_ID' => $shipmentItem->getBasketItem()->getId(),
  73. );
  74. $shipmentItemStore->setFieldsNoDemand($fields);
  75. }
  76. return $shipmentItemStore;
  77. }
  78. /**
  79. * @param string $name
  80. * @param mixed $oldValue
  81. * @param mixed $value
  82. * @return Result
  83. * @throws Main\ArgumentOutOfRangeException
  84. * @throws Main\ObjectException
  85. */
  86. protected function onFieldModify($name, $oldValue, $value)
  87. {
  88. global $USER;
  89. if (is_object($USER) && $USER->isAuthorized())
  90. {
  91. $this->setFieldNoDemand('MODIFIED_BY', $USER->GetID());
  92. }
  93. $this->setFieldNoDemand('DATE_MODIFY', new Main\Type\DateTime());
  94. $result = parent::onFieldModify($name, $oldValue, $value);
  95. if (!$result->isSuccess())
  96. {
  97. return $result;
  98. }
  99. if (
  100. $name === 'STORE_ID'
  101. && $this->needMoveReserve()
  102. )
  103. {
  104. $shipmentItem = $this->getCollection()->getShipmentItem();
  105. if (
  106. $shipmentItem->getReservedQuantity() > 0
  107. && $this->getQuantity() > 0
  108. )
  109. {
  110. $storeIdFrom = (int)$oldValue ?: Configuration::getDefaultStoreId();
  111. $storeIdTo = (int)$value;
  112. if ($storeIdFrom === $storeIdTo)
  113. {
  114. return $result;
  115. }
  116. $basketItem = $shipmentItem->getBasketItem();
  117. $reserveTo = $reserveFrom = null;
  118. /** @var ReserveQuantity $reserve */
  119. foreach ($basketItem->getReserveQuantityCollection() as $reserve)
  120. {
  121. if ($reserve->getStoreId() === $storeIdFrom)
  122. {
  123. $reserveFrom = $reserve;
  124. }
  125. elseif ($reserve->getStoreId() === $storeIdTo)
  126. {
  127. $reserveTo = $reserve;
  128. }
  129. if ($reserveTo && $reserveFrom)
  130. {
  131. break;
  132. }
  133. }
  134. if ($reserveFrom)
  135. {
  136. $settableQuantity = $reserveFrom->getQuantity() - $this->getQuantity();
  137. if ($settableQuantity > 0)
  138. {
  139. $reserveFrom->setField('QUANTITY', $settableQuantity);
  140. }
  141. else
  142. {
  143. $reserveFrom->delete();
  144. }
  145. }
  146. if (!$reserveTo)
  147. {
  148. $reserveTo = $basketItem->getReserveQuantityCollection()->create();
  149. $reserveTo->setStoreId($storeIdTo);
  150. }
  151. $reserveTo->setQuantity($reserveTo->getQuantity() + $this->getQuantity());
  152. }
  153. }
  154. elseif (
  155. $name === 'QUANTITY'
  156. && $this->needMoveReserve()
  157. )
  158. {
  159. $shipmentItem = $this->getCollection()->getShipmentItem();
  160. if ($shipmentItem->getReservedQuantity() > 0)
  161. {
  162. if ($value > $oldValue)
  163. {
  164. $storeIdFrom = Configuration::getDefaultStoreId();
  165. $storeIdTo = $this->getStoreId();
  166. }
  167. else
  168. {
  169. $storeIdTo = Configuration::getDefaultStoreId();
  170. $storeIdFrom = $this->getStoreId();
  171. }
  172. if ($storeIdFrom === $storeIdTo)
  173. {
  174. return $result;
  175. }
  176. $basketItem = $shipmentItem->getBasketItem();
  177. $reserveTo = $reserveFrom = null;
  178. /** @var ReserveQuantity $reserve */
  179. foreach ($basketItem->getReserveQuantityCollection() as $reserve)
  180. {
  181. if ($reserve->getStoreId() === $storeIdFrom)
  182. {
  183. $reserveFrom = $reserve;
  184. }
  185. elseif ($reserve->getStoreId() === $storeIdTo)
  186. {
  187. $reserveTo = $reserve;
  188. }
  189. if ($reserveTo && $reserveFrom)
  190. {
  191. break;
  192. }
  193. }
  194. $delta = abs($oldValue - $value);
  195. if ($reserveFrom)
  196. {
  197. $settableQuantity = $reserveFrom->getQuantity() - $delta;
  198. if ($settableQuantity > 0)
  199. {
  200. $reserveFrom->setField('QUANTITY', $settableQuantity);
  201. }
  202. else
  203. {
  204. $reserveFrom->delete();
  205. }
  206. }
  207. if (!$reserveTo)
  208. {
  209. $reserveTo = $basketItem->getReserveQuantityCollection()->create();
  210. $reserveTo->setStoreId($storeIdTo);
  211. }
  212. $reserveTo->setQuantity($reserveTo->getQuantity() + $delta);
  213. }
  214. }
  215. return $result;
  216. }
  217. protected function needMoveReserve() : bool
  218. {
  219. return true;
  220. }
  221. /**
  222. * Deletes shipment item
  223. *
  224. * @throws Main\ArgumentOutOfRangeException
  225. * @throws \Exception
  226. */
  227. public function delete()
  228. {
  229. $result = new Result();
  230. $oldEntityValues = $this->fields->getOriginalValues();
  231. $event = new Main\Event('sale', "OnBeforeSaleShipmentItemStoreEntityDeleted", [
  232. 'ENTITY' => $this,
  233. 'VALUES' => $oldEntityValues,
  234. ]);
  235. $event->send();
  236. foreach ($event->getResults() as $eventResult)
  237. {
  238. if ($eventResult->getType() == Main\EventResult::ERROR)
  239. {
  240. $eventResultData = $eventResult->getParameters();
  241. if ($eventResultData instanceof ResultError)
  242. {
  243. return $result->addError($eventResultData);
  244. }
  245. }
  246. }
  247. $r = parent::delete();
  248. if (!$r->isSuccess())
  249. {
  250. return $result->addErrors($r->getErrors());
  251. }
  252. $shipmentItem = $this->getCollection()->getShipmentItem();
  253. if ($shipmentItem->getReservedQuantity() > 0)
  254. {
  255. $storeIdTo = Configuration::getDefaultStoreId();
  256. $storeIdFrom = $this->getStoreId();
  257. if ($storeIdFrom === $storeIdTo)
  258. {
  259. return $result;
  260. }
  261. $basketItem = $shipmentItem->getBasketItem();
  262. $reserveTo = $reserveFrom = null;
  263. /** @var ReserveQuantity $reserve */
  264. foreach ($basketItem->getReserveQuantityCollection() as $reserve)
  265. {
  266. if ($reserve->getStoreId() === $storeIdFrom)
  267. {
  268. $reserveFrom = $reserve;
  269. }
  270. elseif ($reserve->getStoreId() === $storeIdTo)
  271. {
  272. $reserveTo = $reserve;
  273. }
  274. if ($reserveTo && $reserveFrom)
  275. {
  276. break;
  277. }
  278. }
  279. $delta = $this->getQuantity();
  280. if ($reserveFrom)
  281. {
  282. $settableQuantity = $reserveFrom->getQuantity() - $delta;
  283. if ($settableQuantity > 0)
  284. {
  285. $reserveFrom->setField('QUANTITY', $settableQuantity);
  286. }
  287. else
  288. {
  289. $reserveFrom->delete();
  290. }
  291. }
  292. if (!$reserveTo)
  293. {
  294. $reserveTo = $basketItem->getReserveQuantityCollection()->create();
  295. $reserveTo->setStoreId($storeIdTo);
  296. }
  297. $reserveTo->setQuantity($reserveTo->getQuantity() + $delta);
  298. }
  299. $event = new Main\Event('sale', "OnSaleShipmentItemStoreEntityDeleted", array(
  300. 'ENTITY' => $this,
  301. 'VALUES' => $this->fields->getOriginalValues(),
  302. ));
  303. $event->send();
  304. foreach ($event->getResults() as $eventResult)
  305. {
  306. if ($eventResult->getType() == Main\EventResult::ERROR)
  307. {
  308. $eventResultData = $eventResult->getParameters();
  309. if ($eventResultData instanceof ResultError)
  310. {
  311. $result->addError($eventResultData);
  312. }
  313. }
  314. }
  315. return $result;
  316. }
  317. /**
  318. * @return int
  319. */
  320. public function getBasketId() : int
  321. {
  322. return (int)$this->getField('BASKET_ID');
  323. }
  324. /**
  325. * @return float
  326. */
  327. public function getQuantity() : float
  328. {
  329. return (float)$this->getField('QUANTITY');
  330. }
  331. /**
  332. * @return int
  333. */
  334. public function getStoreId() : int
  335. {
  336. return (int)$this->getField('STORE_ID');
  337. }
  338. /**
  339. * @return string
  340. */
  341. public function getBarcode() : string
  342. {
  343. return (string)$this->getField('BARCODE');
  344. }
  345. /**
  346. * @return string
  347. */
  348. public function getMarkingCode() : string
  349. {
  350. return (string)$this->getField('MARKING_CODE');
  351. }
  352. /**
  353. * @param $id
  354. * @return array
  355. * @throws Main\ArgumentException
  356. * @throws Main\ArgumentNullException
  357. * @throws Main\ObjectPropertyException
  358. * @throws Main\SystemException
  359. */
  360. public static function loadForShipmentItem($id)
  361. {
  362. if ((int)$id <= 0)
  363. {
  364. throw new Main\ArgumentNullException("id");
  365. }
  366. $items = [];
  367. $itemDataList = static::getList([
  368. 'filter' => ['=ORDER_DELIVERY_BASKET_ID' => $id],
  369. 'order' => ['DATE_CREATE' => 'ASC', 'ID' => 'ASC']
  370. ]);
  371. while ($itemData = $itemDataList->fetch())
  372. {
  373. $items[] = static::createShipmentItemStoreObject($itemData);
  374. }
  375. return $items;
  376. }
  377. /**
  378. * @return Result
  379. * @throws Main\ArgumentNullException
  380. * @throws Main\ArgumentOutOfRangeException
  381. */
  382. public function verify()
  383. {
  384. $result = new Result();
  385. if ($this->getBarcode() === "")
  386. {
  387. /** @var ShipmentItemStoreCollection $itemStoreCollection */
  388. $itemStoreCollection = $this->getCollection();
  389. /** @var BasketItem $itemCollection */
  390. $basketItem = $itemStoreCollection->getShipmentItem()->getBasketItem();
  391. /** @var Shipment $shipent */
  392. $shipment = $itemStoreCollection->getShipmentItem()->getCollection()->getShipment();
  393. if ($basketItem->isBarcodeMulti() && $shipment->isShipped())
  394. {
  395. $result->addError(
  396. new ResultError(
  397. Loc::getMessage(
  398. 'SHIPMENT_ITEM_STORE_BARCODE_MULTI_EMPTY',
  399. [
  400. '#PRODUCT_NAME#' => $basketItem->getField('NAME'),
  401. '#STORE_ID#' => $this->getStoreId(),
  402. ]
  403. ),
  404. 'SHIPMENT_ITEM_STORE_BARCODE_MULTI_EMPTY'
  405. )
  406. );
  407. }
  408. }
  409. return $result;
  410. }
  411. /**
  412. * @return void
  413. */
  414. protected function checkCallingContext()
  415. {
  416. /** @var ShipmentItemStoreCollection $itemStoreCollection */
  417. $itemStoreCollection = $this->getCollection();
  418. /** @var ShipmentItemCollection $itemCollection */
  419. $itemCollection = $itemStoreCollection->getShipmentItem()->getCollection();
  420. /** @var ShipmentCollection $shipmentCollection */
  421. $shipmentCollection = $itemCollection->getShipment()->getCollection();
  422. if (!$shipmentCollection->getOrder()->isSaveRunning())
  423. {
  424. trigger_error("Incorrect call to the save process. Use method save() on \Bitrix\Sale\Order entity", E_USER_WARNING);
  425. }
  426. }
  427. /**
  428. * @return Result
  429. * @throws Main\ArgumentException
  430. * @throws Main\ArgumentNullException
  431. * @throws Main\ArgumentOutOfRangeException
  432. * @throws Main\ObjectException
  433. * @throws Main\ObjectNotFoundException
  434. */
  435. public function save()
  436. {
  437. $result = new Result();
  438. $this->checkCallingContext();
  439. if (!$this->isChanged() || $this->getQuantity() === 0)
  440. {
  441. return $result;
  442. }
  443. $this->callEventOnBeforeItemStoreEntitySaved();
  444. $id = $this->getId();
  445. if ($id > 0)
  446. {
  447. $r = $this->updateInternal($id, $this->getFields()->getChangedValues());
  448. }
  449. else
  450. {
  451. /** @var ShipmentItemStoreCollection $itemStoreCollection */
  452. $itemStoreCollection = $this->getCollection();
  453. if (!$this->getField("ORDER_DELIVERY_BASKET_ID"))
  454. {
  455. $this->setFieldNoDemand('ORDER_DELIVERY_BASKET_ID', $itemStoreCollection->getShipmentItem()->getId());
  456. }
  457. if (!$this->getField("BASKET_ID"))
  458. {
  459. $this->setFieldNoDemand('BASKET_ID', $itemStoreCollection->getShipmentItem()->getBasketItem()->getId());
  460. }
  461. $this->setFieldNoDemand('DATE_CREATE', new Main\Type\DateTime());
  462. $r = $this->addInternal($this->getFields()->getValues());
  463. if ($r->isSuccess())
  464. {
  465. $id = $r->getId();
  466. $this->setFieldNoDemand('ID', $id);
  467. }
  468. }
  469. if (!$r->isSuccess())
  470. {
  471. $this->addErrorMessagesToHistory($r->getErrorMessages());
  472. $result->addErrors($r->getErrors());
  473. return $result;
  474. }
  475. if ($id > 0)
  476. {
  477. $result->setId($id);
  478. }
  479. $this->callEventOnItemStoreEntitySaved();
  480. return $result;
  481. }
  482. /**
  483. * @return void
  484. */
  485. protected function callEventOnBeforeItemStoreEntitySaved()
  486. {
  487. /** @var Main\Entity\Event $event */
  488. $event = new Main\Event('sale', 'OnBeforeSaleShipmentItemStoreEntitySaved', [
  489. 'ENTITY' => $this,
  490. 'VALUES' => $this->fields->getOriginalValues()
  491. ]);
  492. $event->send();
  493. }
  494. /**
  495. * @return void
  496. */
  497. protected function callEventOnItemStoreEntitySaved()
  498. {
  499. /** @var Main\Event $event */
  500. $event = new Main\Event('sale', 'OnSaleShipmentItemStoreEntitySaved', [
  501. 'ENTITY' => $this,
  502. 'VALUES' => $this->fields->getOriginalValues(),
  503. ]);
  504. $event->send();
  505. }
  506. /**
  507. * @param $errors
  508. * @throws Main\ArgumentException
  509. * @throws Main\ArgumentNullException
  510. * @throws Main\ArgumentOutOfRangeException
  511. */
  512. protected function addErrorMessagesToHistory($errors)
  513. {
  514. $registry = Registry::getInstance(static::getRegistryType());
  515. /** @var ShipmentItemStoreCollection $shipmentItemStoreCollection */
  516. $shipmentItemStoreCollection = $this->getCollection();
  517. /** @var \Bitrix\Crm\Order\ShipmentItemCollection $shipmentItemCollection */
  518. $shipmentItemCollection = $shipmentItemStoreCollection->getShipmentItem()->getCollection();
  519. $order = $shipmentItemCollection->getShipment()->getOrder();
  520. /** @var OrderHistory $orderHistory */
  521. $orderHistory = $registry->getOrderHistoryClassName();
  522. $orderHistory::addAction(
  523. 'SHIPMENT',
  524. $order->getId(),
  525. ($this->getId() > 0) ? 'SHIPMENT_ITEM_STORE_UPDATE_ERROR' : 'SHIPMENT_ITEM_STORE_ADD_ERROR',
  526. ($this->getId() > 0) ? $this->getId() : null,
  527. $this,
  528. [
  529. "ERROR" => $errors
  530. ]
  531. );
  532. }
  533. /**
  534. * @param string $name
  535. * @param null $oldValue
  536. * @param null $value
  537. * @throws Main\ArgumentException
  538. * @throws Main\ArgumentNullException
  539. * @throws Main\ArgumentOutOfRangeException
  540. */
  541. protected function addChangesToHistory($name, $oldValue = null, $value = null)
  542. {
  543. if ($this->getId() <= 0)
  544. {
  545. return;
  546. }
  547. /** @var ShipmentItem $shipmentItem */
  548. $shipmentItem = $this->getCollection()->getShipmentItem();
  549. /** @var ShipmentItemCollection $shipmentItemCollection */
  550. $shipmentItemCollection = $shipmentItem->getCollection();
  551. $shipmentItemCollection->getShipment()->getOrder();
  552. $shipment = $shipmentItemCollection->getShipment();
  553. if ($shipment->isSystem())
  554. {
  555. return;
  556. }
  557. $basketItem = $shipmentItem->getBasketItem();
  558. $registry = Registry::getInstance(static::getRegistryType());
  559. /** @var OrderHistory $orderHistory */
  560. $orderHistory = $registry->getOrderHistoryClassName();
  561. $orderHistory::addField(
  562. 'SHIPMENT_ITEM_STORE',
  563. $shipment->getOrder()->getId(),
  564. $name,
  565. $oldValue,
  566. $value,
  567. $this->getId(),
  568. $this,
  569. [
  570. 'NAME' => $basketItem->getField('NAME'),
  571. 'PRODUCT_ID' => $basketItem->getField('PRODUCT_ID'),
  572. ]
  573. );
  574. }
  575. /**
  576. * @param array $parameters
  577. * @return Main\ORM\Query\Result|Internals\EO_ShipmentItemStore_Result
  578. * @throws Main\ArgumentException
  579. * @throws Main\ObjectPropertyException
  580. * @throws Main\SystemException
  581. */
  582. public static function getList(array $parameters = array())
  583. {
  584. return Sale\Internals\ShipmentItemStoreTable::getList($parameters);
  585. }
  586. /**
  587. * @param $value
  588. *
  589. * @return string
  590. */
  591. public function getErrorEntity($value)
  592. {
  593. static $className = null;
  594. $errorsList = static::getAutoFixErrorsList();
  595. if (is_array($errorsList) && in_array($value, $errorsList))
  596. {
  597. if ($className === null)
  598. {
  599. $className = static::getClassName();
  600. }
  601. }
  602. return $className;
  603. }
  604. /**
  605. * @param $value
  606. *
  607. * @return bool
  608. */
  609. public function canAutoFixError($value)
  610. {
  611. $errorsList = static::getAutoFixErrorsList();
  612. return (is_array($errorsList) && in_array($value, $errorsList));
  613. }
  614. /**
  615. * @return array
  616. */
  617. public function getAutoFixErrorsList()
  618. {
  619. return array();
  620. }
  621. /**
  622. * @param $code
  623. *
  624. * @return Result
  625. */
  626. public function tryFixError($code)
  627. {
  628. return new Result();
  629. }
  630. /**
  631. * @return bool
  632. */
  633. public function canMarked()
  634. {
  635. return false;
  636. }
  637. /**
  638. * @return string|null
  639. */
  640. public function getMarkField()
  641. {
  642. return null;
  643. }
  644. /**
  645. * @param array $data
  646. * @return Main\Entity\AddResult
  647. */
  648. protected function addInternal(array $data)
  649. {
  650. return Internals\ShipmentItemStoreTable::add($data);
  651. }
  652. /**
  653. * @param $primary
  654. * @param array $data
  655. * @return Main\Entity\UpdateResult
  656. */
  657. protected function updateInternal($primary, array $data)
  658. {
  659. return Internals\ShipmentItemStoreTable::update($primary, $data);
  660. }
  661. /**
  662. * @return array
  663. */
  664. protected static function getFieldsMap()
  665. {
  666. return Internals\ShipmentItemStoreTable::getMap();
  667. }
  668. /**
  669. * @return null|string
  670. * @internal
  671. *
  672. */
  673. public static function getEntityEventName()
  674. {
  675. return 'SaleShipmentItemStore';
  676. }
  677. }