Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/cvetdv.ru/bitrix/modules/sale/lib/delivery/services/ |
Upload File : |
<?php namespace Bitrix\Sale\Delivery\Services; use Bitrix\Main\Config\Option; use Bitrix\Main\Error; use Bitrix\Main\Event; use Bitrix\Main\Loader; use Bitrix\Main\ORM\Data\AddResult; use Bitrix\Sale\Internals\Pool; use Bitrix\Sale\Result; use Bitrix\Main\IO\File; use Bitrix\Sale\Shipment; use Bitrix\Main\IO\Directory; use Bitrix\Main\SystemException; use Bitrix\Main\Localization\Loc; use Bitrix\Main\Entity\EventResult; use Bitrix\Main\ArgumentNullException; use Bitrix\Sale\Delivery\Restrictions; use Bitrix\Sale\Delivery\ExtraServices; use Bitrix\Sale\Internals\ShipmentTable; use Bitrix\Sale\Delivery\CalculationResult; use Bitrix\Sale\Internals\ServiceRestrictionTable; use Bitrix\Sale\Delivery\Services\Base; Loc::loadMessages(__FILE__); /** * Class Manager * Helps to manage delivery services. * @package Bitrix\Sale\Delivery\Services */ class Manager { const SKIP_PROFILE_PARENT_CHECK = 0; const SKIP_CHILDREN_PARENT_CHECK = 1; protected static $handlers = null; protected static $restHandlers = []; protected static $cachedFields = array(); /* Directories where we can found handlers */ protected static $handlersDirectories = array(); /** @var null|Pool */ protected static $objectsPool = null; /** * Returns service field, caches results during hit. * @param int $deliveryId * @return array Service fields * @throws SystemException */ public static function getById($deliveryId) { $id = intval($deliveryId); if($id <= 0) throw new SystemException("deliveryId"); if(!isset(self::$cachedFields[$deliveryId]) || !is_array(self::$cachedFields[$deliveryId])) { self::$cachedFields[$deliveryId] = array(); $resSrvParams = Table::getList(array( 'filter' => array("=ID" => $deliveryId) )); if($srvParams = $resSrvParams->fetch()) self::$cachedFields[$srvParams["ID"]] = $srvParams; } return self::$cachedFields[$deliveryId]; } /** * @param array $params * @return \Bitrix\Main\ORM\Query\Result * @throws SystemException * @throws \Bitrix\Main\ArgumentException * @throws \Bitrix\Main\ObjectPropertyException */ public static function getList(array $params = array()): \Bitrix\Main\ORM\Query\Result { return Table::getList($params); } /** * @param Shipment $shipment. * @param int $restrictionMode MODE_CLIENT or MODE_MANAGER from Restrictions\Manager. * @return Base[] delivery services objects */ public static function getRestrictedObjectsList(Shipment $shipment, $restrictionMode = Restrictions\Manager::MODE_CLIENT) { $result = array(); $services = self::getRestrictedList($shipment, $restrictionMode); foreach($services as $srvParams) { if($srvParams["CLASS_NAME"]::canHasProfiles()) continue; if(is_callable($srvParams["CLASS_NAME"]."::canHasChildren") && $srvParams["CLASS_NAME"]::canHasChildren()) continue; $service = self::getPooledObject($srvParams); if(!$service) continue; if(!$service->isCompatible($shipment)) continue; if($shipment->getCurrency() != $service->getCurrency()) { $service->getExtraServices()->setOperationCurrency( $shipment->getCurrency() ); } $result[$srvParams["ID"]] = $service; } return $result; } /** * @param $deliveryId * @return bool is service exists or not * @throws SystemException */ public static function isServiceExist($deliveryId) { if(intval($deliveryId) <= 0) return false; $srv = self::getById($deliveryId); return !empty($srv); } /** * Prepares and caches data during the hit * @param bool $calculatingOnly If we need absolutely all, or calculating items only. * @param array $restrictedIds If we have list of services ids, successful checked restrictions. * @return array Array of active delivery services fields. * @throws \Bitrix\Main\ArgumentException */ public static function getActiveList($calculatingOnly = false, $restrictedIds = null) { //If we alredy got all active services static $isDataPrepared = false; static $activeIds = array(); static $canHasProfiles = array(); static $canHasChildren = array(); static $DontHaveRestrictionsIds = array(); if(is_array($restrictedIds)) { $unPreparedRestrictedIds = array_diff_key( array_flip( $restrictedIds ), self::$cachedFields ); $unPreparedRestrictedIds = array_keys($unPreparedRestrictedIds); } else { $unPreparedRestrictedIds = array(); } if(!$isDataPrepared || !empty($unPreparedRestrictedIds)) { $result = array(); self::initHandlers(); $filter = array( '=ACTIVE' => 'Y' ); $params = array( 'order' => array('SORT' =>'ASC', 'NAME' => 'ASC'), 'filter' => $filter ); $params['runtime'] = array( new \Bitrix\Main\Entity\ExpressionField( 'RESTRICTIONS_EXIST', 'CASE WHEN EXISTS('. 'SELECT 1 FROM b_sale_service_rstr SSR WHERE SSR.SERVICE_ID = %s AND SSR.SERVICE_TYPE = '.Restrictions\Manager::SERVICE_TYPE_SHIPMENT.') THEN 1 ELSE 0 END', 'ID' ) ); $params['select'] = array('*', 'RESTRICTIONS_EXIST'); if(!empty($unPreparedRestrictedIds)) { if($isDataPrepared) { $params['filter']['ID'] = $unPreparedRestrictedIds; } else { $params['filter'][] = array( "LOGIC" => "OR", "ID" => $unPreparedRestrictedIds, 'RESTRICTIONS_EXIST' => 0 ); } } $dbRes = Table::getList($params); $profilesParentsIds = array(); while($service = $dbRes->fetch()) { if(!is_subclass_of($service["CLASS_NAME"], 'Bitrix\Sale\Delivery\Services\Base')) continue; if(!$service['RESTRICTIONS_EXIST']) $DontHaveRestrictionsIds[] = $service['ID']; if($service["CLASS_NAME"]::canHasChildren()) $canHasChildren[$service["ID"]] = true; if ($service['CLASS_NAME']::canHasProfiles()) $canHasProfiles[$service["ID"]] = true; if($service["PARENT_ID"] != 0) $profilesParentsIds[$service["PARENT_ID"]] = $service['ID']; $result[$service["ID"]] = $service; if($service['ACTIVE'] == 'Y') $activeIds[$service["ID"]] = $service["ID"]; } foreach(array_diff_key($canHasProfiles, $profilesParentsIds) as $id => $tmp) unset($result[$id]); self::$cachedFields = self::$cachedFields + $result; Restrictions\Manager::prepareData(array_keys($result)); ExtraServices\Manager::prepareData(array_keys($result)); //selected all active if(!$isDataPrepared && empty($unPreparedRestrictedIds)) $isDataPrepared = true; } if(is_array($restrictedIds) && !empty($restrictedIds)) $storedIds = array_diff($restrictedIds, $unPreparedRestrictedIds); else $storedIds = array(); if(!empty($storedIds) && is_array($storedIds)) { foreach($storedIds as $storedId) { if(empty(self::$cachedFields[$storedId])) continue; $service = self::$cachedFields[$storedId]; if(!class_exists($service["CLASS_NAME"])) continue; if($service["CLASS_NAME"]::canHasChildren()) $canHasChildren[$storedId] = true; if ($service['CLASS_NAME']::canHasProfiles()) $canHasProfiles[$storedId] = true; if($service['ACTIVE'] == 'Y') $activeIds[$storedId] = $storedId; } } $active = array_intersect_key(self::$cachedFields, array_flip($activeIds)); if(is_array($restrictedIds)) { $result = array_intersect_key($active, array_flip($DontHaveRestrictionsIds)); if(!empty($restrictedIds)) $result = $result + array_intersect_key($active, array_flip($restrictedIds)); } else { $result = $active; } /* * Clean children if parent is not present in result. * We mean that it doesn't pass restrictions checks. * Or it is not active. */ foreach($result as $id => $fields) { if(intval($fields['PARENT_ID']) <= 0) continue; if(empty($result[$fields['PARENT_ID']])) unset($result[$id]); } if($calculatingOnly) $result = array_diff_key($result, $canHasChildren, $canHasProfiles); if(!empty($result)) sortByColumn($result, array("SORT" => SORT_ASC, "NAME" => SORT_ASC), '', null, true); return $result; } /** * @param Shipment $shipment * @param int $restrictionMode MODE_CLIENT or MODE_MANAGER from Restrictions\Manager. * @param array $skipChecks self::SKIP_CHILDREN_PARENT_CHECK || self::SKIP_PROFILE_PARENT_CHECK * @return array Array of active delivery services fields filtered by restrictions. */ public static function getRestrictedList(Shipment $shipment = null, $restrictionMode, array $skipChecks = array()) { $result = array(); if(empty($skipChecks)) { $skipChecks = array( self::SKIP_CHILDREN_PARENT_CHECK, self::SKIP_PROFILE_PARENT_CHECK ); } //Have restrictions and this restrictions successfully checked $restrictedSrvIds = Restrictions\Manager::getRestrictedIds($shipment, $restrictionMode); //Don't have any restrictions + successfully checked $services = self::getActiveList(false, array_keys($restrictedSrvIds)); foreach($services as $srvParams) { $srvParams["RESTRICTED"] = false; if(!in_array(self::SKIP_PROFILE_PARENT_CHECK, $skipChecks)) if($srvParams["CLASS_NAME"]::canHasProfiles()) continue; if(!in_array(self::SKIP_CHILDREN_PARENT_CHECK, $skipChecks)) if(is_callable($srvParams["CLASS_NAME"]."::canHasChildren") && $srvParams["CLASS_NAME"]::canHasChildren()) continue; if(isset($restrictedSrvIds[$srvParams["ID"]]) && $restrictedSrvIds[$srvParams["ID"]] == Restrictions\Manager::SEVERITY_SOFT) $srvParams["RESTRICTED"] = true; $result[$srvParams["ID"]] = $srvParams; } return $result; } /** * @param array $srvParams Delivery service fields from DataBase to construct service object. * @return Base|null Delivery service object * All errors it writes to system log. * It's better to use \Bitrix\Sale\Delivery\Services\Manager::getPooledObject for performance purposes */ public static function createObject(array $srvParams) { self::initHandlers(); $errorMsg = ''; $service = null; if(!isset($srvParams['PARENT_ID'])) { $srvParams['PARENT_ID'] = 0; } if(class_exists($srvParams['CLASS_NAME'])) { if(is_subclass_of($srvParams['CLASS_NAME'], Base::class)) { try { $service = new $srvParams['CLASS_NAME']($srvParams); } catch (SystemException $err) { $errorMsg = $err->getMessage(); } } else { $errorMsg = 'Class "' . $srvParams['CLASS_NAME'] . '" is not subclass of of Bitrix\Sale\Delivery\Services\Base'; } } else { $errorMsg = 'Can\'t create delivery object. Class "'.$srvParams['CLASS_NAME']. '" does not exist.'; } if($errorMsg !== '') { static::log( [ 'SEVERITY' => \CEventLog::SEVERITY_ERROR, 'AUDIT_TYPE_ID' => 'SALE_DELIVERY_CREATE_OBJECT_ERROR', 'MODULE_ID' => 'sale', 'ITEM_ID' => 'createObject()', 'DESCRIPTION' => $errorMsg.' Fields: '.serialize($srvParams), ] ); return null; } return $service; } protected static function log(array $params): void { \CEventLog::Add($params); } public static function getPooledObject(array $fields) { if(self::$objectsPool === null) self::$objectsPool = new ObjectPool(); return self::$objectsPool->getObject($fields); } /** * @param int $deliveryId Delivery service id * @return Base Delivery service object * @throws ArgumentNullException * @throws SystemException */ public static function getObjectById($deliveryId) { if(intval($deliveryId) <= 0 ) throw new ArgumentNullException("deliveryId"); $srvParams = self::getById($deliveryId); if(empty($srvParams)) return null; return self::getPooledObject($srvParams); } /** * @param string $serviceCode Delivery service code * @return Base Delivery service object. * @throws ArgumentNullException * @throws SystemException * @throws \Bitrix\Main\ArgumentException */ public static function getObjectByCode($serviceCode) { if($serviceCode == '' ) throw new ArgumentNullException("serviceCode"); $srvParams = array(); foreach(self::$cachedFields as $id => $srv) { if($srv['CODE'] == $serviceCode) { $srvParams = $srv; } } if(empty($srvParams)) { $resSrvParams = Table::getList(array( 'filter' => array('=CODE' => $serviceCode) )); if(!($srvParams = $resSrvParams->fetch())) throw new SystemException("Can't get delivery service data with code: \"".$serviceCode."\""); self::$cachedFields[$srvParams['ID']] = $srvParams; } return self::getPooledObject($srvParams); } /** * Gets info about existing delivery services handlers * Stores this information during the hit * @return bool * @throws SystemException * @throws \Bitrix\Main\LoaderException */ protected static function initHandlers() { if(self::$handlers !== null) return true; self::$handlersDirectories = array( 'LOCAL' => '/local/php_interface/include/sale_delivery/', 'CUSTOM' => Option::get('sale', 'delivery_handles_custom_path', BX_PERSONAL_ROOT.'/php_interface/include/sale_delivery/'), 'SYSTEM' => '/bitrix/modules/sale/handlers/delivery/' ); $result = array( '\Bitrix\Sale\Delivery\Services\Group' => 'lib/delivery/services/group.php', '\Bitrix\Sale\Delivery\Services\Automatic' => 'lib/delivery/services/automatic.php', '\Bitrix\Sale\Delivery\Services\Configurable' => 'lib/delivery/services/configurable.php', '\Bitrix\Sale\Delivery\Services\AutomaticProfile' => 'lib/delivery/services/automatic_profile.php', '\Bitrix\Sale\Delivery\Services\EmptyDeliveryService' => 'lib/delivery/services/emptydeliveryservice.php', ); \Bitrix\Main\Loader::registerAutoLoadClasses('sale', $result); /* * To add you own handler you must wrote smth. like this in for example init.php: * * function addCustomDeliveryServices() * { * return new \Bitrix\Main\EventResult( * \Bitrix\Main\EventResult::SUCCESS, * array( * '\Sale\Handlers\Delivery\SimpleHandler' => '/bitrix/modules/sale/handlers/delivery/simple/handler.php' * ), * 'sale' * ); * } * * $eventManager->addEventHandler('sale', 'onSaleDeliveryHandlersClassNamesBuildList', 'addCustomDeliveryServices'); */ $event = new Event('sale', 'onSaleDeliveryHandlersClassNamesBuildList'); $event->send(); $resultList = $event->getResults(); if (is_array($resultList) && !empty($resultList)) { $customClasses = array(); foreach ($resultList as $eventResult) { /** @var \Bitrix\Main\EventResult $eventResult*/ if ($eventResult->getType() != EventResult::SUCCESS) continue; $params = $eventResult->getParameters(); if(!empty($params) && is_array($params)) $customClasses = array_merge($customClasses, $params); } if(!empty($customClasses)) { \Bitrix\Main\Loader::registerAutoLoadClasses(null, $customClasses); $result = array_merge($result, $customClasses); } } $handlers = self::getHandlersClasses(); if(!empty($handlers)) { \Bitrix\Main\Loader::registerAutoLoadClasses(null, $handlers); $result = array_merge($result, self::getHandlersClasses()); } self::$handlers = array_keys($result); for($idx = count(self::$handlers) - 1; $idx >= 0; $idx--) { /** @var \Bitrix\Sale\Delivery\Services\Base $handler */ $handler = self::$handlers[$idx]; if(!$handler::isHandlerCompatible()) { unset(self::$handlers[$idx]); continue; } $profiles = $handler::getChildrenClassNames(); if(!empty($profiles)) { self::$handlers = array_merge(self::$handlers, $profiles); } } return true; } /** * @return array Handler Classes * @throws \Bitrix\Main\IO\FileNotFoundException */ protected static function getHandlersClasses() { $result = array(); foreach(self::$handlersDirectories as $handlersDirectory) { $dirPath = $_SERVER['DOCUMENT_ROOT'].$handlersDirectory; if(!Directory::isDirectoryExists($dirPath)) continue; $dir = new Directory($_SERVER['DOCUMENT_ROOT'].$handlersDirectory); foreach ($dir->getChildren() as $handler) { if (!$handler->isDirectory()) continue; /** @var Directory $handler */ $handlerDir = $handler->getPath(); $handlerPath = $handlerDir.'/handler.php'; if(!File::isFileExists($handlerPath)) continue; $handlerClassName = ucfirst($handler->getName().'Handler'); $fullClassName = '\Sale\Handlers\Delivery\\'.$handlerClassName; $result[$fullClassName] = $handlersDirectory.$handler->getName().'/handler.php'; require_once($handlerPath); } } return $result; } /** * @return array Known delivery services handlers * @throws SystemException */ public static function getHandlersList() { if(self::$handlers === null) self::initHandlers(); return self::$handlers; } /** * @return array|null * @throws SystemException * @throws \Bitrix\Main\ArgumentException * @throws \Bitrix\Main\ObjectPropertyException */ public static function getRestHandlerList(): ?array { static $init = false; if (!$init) { $init = true; $restHandlerList = \Bitrix\Sale\Delivery\Rest\Internals\DeliveryRestHandlerTable::getList([ 'select' => ['ID', 'NAME', 'CODE', 'SORT', 'DESCRIPTION', 'SETTINGS', 'PROFILES'], ])->fetchAll(); foreach ($restHandlerList as $restHandler) { self::$restHandlers[$restHandler['CODE']] = $restHandler; } } return self::$restHandlers; } /** * Calculates the price of the shipment * @param Shipment $shipment * @param int $deliveryId optional * @param array $extraServices optional * @return \Bitrix\Sale\Delivery\CalculationResult * @throws ArgumentNullException */ public static function calculateDeliveryPrice(Shipment $shipment, $deliveryId = 0, $extraServices = array()) { if($deliveryId <=0) $deliveryId = $shipment->getDeliveryId(); $delivery = self::getObjectById($deliveryId); if($delivery) { $result = $delivery->calculate($shipment, $extraServices); } else { $result = new CalculationResult(); $result->addError(new Error("Can't create delivery service object with id: \"".$deliveryId."\"")); } return $result; } /** * Returns id of delivery service group. * Creates if such group does not exist. * @param string $name Group name * @return int Group id * @throws SystemException * @throws \Exception */ public static function getGroupId(string $name): int { $group = Table::getRow([ 'select' => ['ID'], 'filter' => [ '=NAME' => $name, '=CLASS_NAME' => '\Bitrix\Sale\Delivery\Services\Group', ] ]); if ($group) { $result = $group["ID"]; } else { $res = self::add([ 'NAME' => $name, 'CLASS_NAME' => '\Bitrix\Sale\Delivery\Services\Group', 'ACTIVE' => 'Y', 'CURRENCY' => Option::get('sale', 'default_currency'), ]); if($res->isSuccess()) $result = (int)$res->getId(); else throw new SystemException(implode("<br>\n",$res->getErrorMessages())); } return $result; } /** * @param int $parentId Delivery service parent id * @return array Delivery service fields * @throws \Bitrix\Main\ArgumentException */ public static function getByParentId($parentId) { $result = array(); $srvList = self::getActiveList(); foreach($srvList as $id => $srv) { if($srv['PARENT_ID'] == $parentId) { $result[$srv['ID']] = $srv; } } return $result; } /** * Returns entity link name for connection with Locations * @return string */ public static function getLocationConnectorEntityName() { return 'Bitrix\Sale\Delivery\DeliveryLocation'; } /** * Adds delivery service * @param array $fields * @return AddResult * @throws SystemException * @throws \Exception */ public static function add(array $fields) { self::initHandlers(); if(!empty($fields["CLASS_NAME"])) { /** @var \Bitrix\Main\Result $onBeforeAddResult */ $onBeforeAddResult = $fields["CLASS_NAME"]::onBeforeAdd($fields); if (!$onBeforeAddResult->isSuccess()) { return (new AddResult())->addErrors($onBeforeAddResult->getErrors()); } } $res = \Bitrix\Sale\Delivery\Services\Table::add($fields); if($res->isSuccess()) { if(!empty($fields["CLASS_NAME"])) $fields["CLASS_NAME"]::onAfterAdd($res->getId(), $fields); if(!empty($fields['CODE'])) self::setIdCodeCached($res->getId(), $fields['CODE']); } return $res; } /** * @return string */ public static function generateXmlId() { return uniqid('bx_'); } /** * Updates delivery service * @param int $id * @param array $fields * @return \Bitrix\Main\Entity\UpdateResult * @throws SystemException * @throws \Exception */ public static function update($id, array $fields) { self::initHandlers(); if (!empty($fields["CLASS_NAME"]) && class_exists($fields["CLASS_NAME"])) { $fields["CLASS_NAME"]::onBeforeUpdate($id, $fields); } $res = \Bitrix\Sale\Delivery\Services\Table::update($id, $fields); if ($res->isSuccess()) { if (!empty($fields["CLASS_NAME"]) && class_exists($fields["CLASS_NAME"])) { $fields["CLASS_NAME"]::onAfterUpdate($res->getId(), $fields); } if (isset($fields['CODE'])) { self::cleanIdCodeCached($id); } if (Loader::includeModule('pull')) { \CPullWatch::AddToStack( 'SALE_DELIVERY_SERVICE', [ 'module_id' => 'sale', 'command' => 'onDeliveryServiceSave', 'params' => [ 'ID' => $id, ] ] ); } } return $res; } /** * Deletes delivery service * @param int $id * @param bool $checkServiceUsage * @return \Bitrix\Main\Result * @throws ArgumentNullException * @throws SystemException * @throws \Bitrix\Main\ArgumentException * @throws \Exception */ public static function delete($id, bool $checkServiceUsage = true) { if ((int)$id <= 0) { throw new ArgumentNullException('id'); } if ($checkServiceUsage) { $res = self::checkServiceUsage($id); if (!$res->isSuccess()) { return $res; } } self::initHandlers(); $res = Table::getList(array( 'filter' => array( 'ID' => $id ), 'select' => array('ID', 'CLASS_NAME', 'LOGOTIP') )); $className = ''; $logotip = 0; if ($service = $res->fetch()) { $className = $service['CLASS_NAME']; $logotip = intval($service['LOGOTIP']); } $res = \Bitrix\Sale\Delivery\Services\Table::delete($id); if ($res->isSuccess()) { if (!empty($className) && class_exists($className)) { $className::onAfterDelete($id); } self::deleteRelatedEntities($id, $checkServiceUsage); if ($logotip > 0) { \CFile::Delete($logotip); } } return $res; } /** * @return array * registerEventHandler( * 'sale', 'OnGetBusinessValueConsumers', 'sale', * '\Bitrix\Sale\Delivery\Services\Manager', * 'onGetBusinessValueConsumers'); */ public static function onGetBusinessValueConsumers() { static $result = null; if($result !== null) return $result; $result = array(); $handlers = self::getHandlersList(); $consumers = array(); /** @var Base $handlerClassName */ foreach($handlers as $handlerClassName) { $tmpCons = $handlerClassName::onGetBusinessValueConsumers(); /** @var string $handlerClassName*/ if(!empty($tmpCons)) $consumers[$handlerClassName] = $tmpCons; } $res = Table::getList(array( 'filter' => array( '=CLASS_NAME' => array_keys($consumers), '=ACTIVE' => 'Y' ), 'select' => array('ID', 'CLASS_NAME', 'NAME') )); while($dlv = $res->fetch()) { $result['DELIVERY_'.$dlv['ID']] = $consumers[$dlv['CLASS_NAME']]; $result['DELIVERY_'.$dlv['ID']]['NAME'] = $dlv['NAME']; } return $result; } public static function onGetBusinessValueGroups() { $result = array( 'DELIVERY' => array('NAME' => Loc::getMessage('SALE_DLVR_MNGR_DLV_SRVS'), 'SORT' => 100), ); $handlers = self::getHandlersList(); /** @var Base $handlerClassName */ foreach($handlers as $handlerClassName) $result = array_merge($result, $handlerClassName::onGetBusinessValueGroups()); return $result; } /** * Sets fields values to all children * @param int $id * @param array $fields * @return int count modified children * @throws \Bitrix\Main\ArgumentException */ public static function setChildrenFieldsValues($id, array $fields) { if(empty($fields)) return 0; $counter = 0; $res = Table::getList(array( 'filter' => array('PARENT_ID' => $id), 'select' => array('ID') )); while($child = $res->fetch()) { $ures = self::update($child['ID'], $fields); if($ures->isSuccess()) $counter++; $counter += self::setChildrenFieldsValues($child['ID'], $fields); } return $counter; } /** * @param string $code * @return int Service id */ public static function getIdByCode($code) { $result = self::getIdCodeCached($code, "code"); if($result !== false) return $result; foreach(self::$cachedFields as $id => $srv) { if($srv['CODE'] == $code) { $result = $id; } } if(intval($result) <= 0) { $res = Table::getList(array( 'filter' => array( '=CODE' => $code ) )); if($handler = $res->fetch()) { $result = $handler["ID"]; self::$cachedFields[$handler["ID"]] = $handler; } } $result = intval($result); self::setIdCodeCached($result, $code); return $result; } /** * @param int $id * @return string Delivery service code * @throws \Bitrix\Main\ArgumentException */ public static function getCodeById($id) { $result = self::getIdCodeCached($id, "id"); if($result !== false) return $result; $srv = self::getById($id); $result = $srv['CODE']; self::setIdCodeCached($id, $result); return $result; } /** * * @param $value * @param $type * @return int|string Id or Code of delivery service */ protected static function getIdCodeCached($value, $type) { $result = false; $ttl = 315360000; $cacheId = "SALE_DELIVERY_ID_CODE_MAP_".($type == "id" ? "I" : "C")."_".$value; $cacheManager = \Bitrix\Main\Application::getInstance()->getManagedCache(); if($cacheManager->read($ttl, $cacheId)) $result = $cacheManager->get($cacheId); return $result; } /** * Saves relation between Id an code of delivery service * @param int $id * @param string $code */ protected static function setIdCodeCached($id, $code) { $cacheManager = \Bitrix\Main\Application::getInstance()->getManagedCache(); $cacheManager->set("SALE_DELIVERY_ID_CODE_MAP_I_".$id, $code); $cacheManager->set("SALE_DELIVERY_ID_CODE_MAP_C_".$code, $id); } /** * Cleans cache of delivery service id-code relation * @param int $id */ protected static function cleanIdCodeCached($id) { $cacheManager = \Bitrix\Main\Application::getInstance()->getManagedCache(); $code = self::getIdCodeCached($id, "id"); $cacheManager->clean("SALE_DELIVERY_ID_CODE_MAP_I_".$id); if($code <> '') $cacheManager->clean("SALE_DELIVERY_ID_CODE_MAP_C_".$code); } /** * Returns is delivery service is already used in shipments * @param $deliveryId * @return bool */ protected static function isDeliveryInShipments($deliveryId) { $res = ShipmentTable::getList(array( 'filter' => array( "=DELIVERY_ID" => $deliveryId, "=SYSTEM" => "N" ), 'select' => array("ID") )); if($res->fetch()) $result = true; else $result = false; return $result; } /** * Returns if delivery service and it's children are used in shipments * @param $deliveryId * @return Result * @throws \Bitrix\Main\ArgumentException */ public static function checkServiceUsage($deliveryId) { $result = new Result(); if(self::isDeliveryInShipments($deliveryId)) { $result->addError(new Error(Loc::getMessage('SALE_DLVR_MNGR_ERR_DEL_IN_SHPMNTS_EXIST'))); } else { $dbRes = Table::getList(array( 'filter' => array( "PARENT_ID" => $deliveryId ), 'select' => array("ID") )); while($child = $dbRes->fetch()) { if(self::isDeliveryInShipments($child["ID"])) { $result->addError(new Error(Loc::getMessage('SALE_DLVR_MNGR_ERR_DEL_IN_SHPMNTS_EXIST_CHLD'))); break; } } } return $result; } /** * Deletes related entities * @param int $deliveryId * @param bool $checkServiceUsage * @return bool * @throws ArgumentNullException * @throws \Bitrix\Main\ArgumentException * todo: restrictions, extra_services - can require some actions after deletion */ protected static function deleteRelatedEntities($deliveryId, bool $checkServiceUsage = true) { $con = \Bitrix\Main\Application::getConnection(); $deliveryId = (int)$deliveryId; $con->queryExecute(" DELETE FROM b_sale_service_rstr WHERE SERVICE_ID = " . $deliveryId . " AND SERVICE_TYPE = " . (int)Restrictions\Manager::SERVICE_TYPE_SHIPMENT . " "); $con->queryExecute("DELETE FROM b_sale_delivery2location WHERE DELIVERY_ID=".$deliveryId); $con->queryExecute("DELETE FROM b_sale_delivery2paysystem WHERE DELIVERY_ID=".$deliveryId); $con->queryExecute("DELETE FROM b_sale_delivery_es WHERE DELIVERY_ID=".$deliveryId); $dbRes = Table::getList(array( 'filter' => array( "PARENT_ID" => $deliveryId ), 'select' => array("ID") )); while ($child = $dbRes->fetch()) { self::delete($child["ID"], $checkServiceUsage); } self::cleanIdCodeCached($deliveryId); return true; } /** * @return int Empty delivery service id * @throws SystemException */ public static function getEmptyDeliveryServiceId() { self::initHandlers(); return \Bitrix\Sale\Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId(); } /** * @internal * @param int|int[] $deliveryId * @param mixed $checkParams * @param string $restrictionClassName * @return bool|int[] * @throws ArgumentNullException * @throws SystemException * @throws \Bitrix\Main\ArgumentException * @throws \Bitrix\Main\NotImplementedException */ public static function checkServiceRestriction($deliveryId, $checkParams, $restrictionClassName) { if(empty($deliveryId)) throw new ArgumentNullException("deliveryId"); if(!is_array($deliveryId)) $deliveryId = array($deliveryId); $dbRstrRes = ServiceRestrictionTable::getList(array( 'filter' => array( '=SERVICE_ID' => $deliveryId, '=SERVICE_TYPE' => Restrictions\Manager::SERVICE_TYPE_SHIPMENT, '=CLASS_NAME' => $restrictionClassName ) )); $tmp = array(); /** @var Restrictions\Base $restriction */ $restriction = static::getRestrictionObject($restrictionClassName); while($rstFields = $dbRstrRes->fetch()) { $rstParams = is_array($rstFields["PARAMS"]) ? $rstFields["PARAMS"] : array(); $tmp[$rstFields['SERVICE_ID']] = $restriction->check($checkParams, $rstParams, $rstFields['SERVICE_ID']); } if(count($deliveryId) == 1) return current($tmp); $result = array(); foreach($deliveryId as $id) if(!isset($tmp[$id]) || (isset($tmp[$id]) && $tmp[$id] == true)) $result[] = $id; return $result; } /** * Check if given class is valid delivery service class * inheritance of Bitrix\Sale\Delivery\Services\Base. * @param string $class Checking class. * @return bool */ public static function isDeliveryServiceClassValid($class) { if($class == '') return false; self::initHandlers(); if(!class_exists($class)) return false; if(!is_subclass_of($class, 'Bitrix\Sale\Delivery\Services\Base')) return false; return true; } /* * Deprecated methods. Will be removed in future versions. */ /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::calculateDeliveryPrice() */ public static function calculate(Shipment $shipment) { $delivery = self::getObjectById($shipment->getDeliveryId()); return $delivery->calculate($shipment); } /** * @deprecated will be remove in next versions */ public static function getRestrictionObject($className) { if(!class_exists($className)) throw new SystemException("Can't find class: ".$className); static $cache = array(); if(isset($cache[$className])) return $cache[$className]; $restriction = new $className; if(!is_subclass_of($className, 'Bitrix\Sale\Services\Base\Restriction')) throw new SystemException('Object must be the instance of Bitrix\Sale\Services\Base\Restriction'); $cache[$className] = $restriction; return $restriction; } /** * @deprecated use Restrictions\Manager::checkService() */ public static function checkServiceRestrictions($deliveryId, Shipment $shipment, $restrictionsClassesToSkip = array()) { return Restrictions\Manager::checkService($deliveryId, $shipment) == Restrictions\Manager::SEVERITY_NONE; } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::getRestrictedObjectsList() */ public static function getServicesForShipment(Shipment $shipment) { return self::getRestrictedObjectsList($shipment); } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::isServiceExist() */ public static function isExistService($deliveryId) { return self::isServiceExist($deliveryId); } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::getActiveList() */ public static function getActive() { return self::getActiveList(); } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::getRestrictedList() */ public static function getServicesBriefsForShipment(Shipment $shipment = null, array $skipChecks = array(), $getAll = false) { return self::getRestrictedList($shipment, Restrictions\Manager::MODE_CLIENT, $skipChecks); } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::createObject() */ public static function createServiceObject(array $srvParams) { return self::createObject($srvParams); } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::getObjectById() */ public static function getService($deliveryId) { return self::getObjectById($deliveryId); } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::getServiceByCode() */ public static function getServiceByCode($serviceCode) { return self::getObjectByCode($serviceCode); } /** * @deprecated use \Bitrix\Sale\Delivery\Services\Manager::getHandlersList() */ public static function getHandlersClassNames() { return self::getHandlersList(); } /** * @deprecated use Restrictions\Manager::getClassesList() */ public static function getRestrictionClassNames() { return Restrictions\Manager::getClassesList(); } /** * @deprecated use Restrictions\Manager::getRestrictionsList() */ public static function getRestrictionsByDeliveryId($deliveryId) { return Restrictions\Manager::getRestrictionsList($deliveryId); } }