Хочу поделиться способом как вывести информацию по доставке в карточке товара на основе служб доставки. Имеем несколько Служб доставки по группам местоположений: по Москве, по Санкт-Петербургу, и некоторых других регионов.
Настройки у всех похожи: Ограничения по конкретным местоположениям и ограничения по стоимости. Пример показан на рисунке:
Нам нужно в Карточке Товара вывести информацию по стоимости доставки в регион и описание из службы доставки. Основная трудность заключается в том, чтобы отфильтровать Службы доставки по регионам. Ограничения по регионам хранятся в таблице b_sale_delivery2location. Нам нужны входящие местоположения, т.е. с LOCATION_TYPE = "L". Был написан следующий метод, решающий нашу задачу:
На вход подаем $sLocationCode - Код местоположения из наших местоположений 2.0; $fPrice - стоимость товара; $obEntityLocation2Delivery - объект, с описанием таблицы b_sale_delivery2location
Объект $obEntityLocation2Delivery мы описываем в методе getLocationToDeliveryEntity():
Таким образом в карточке товара выводится стоимость доставки в регионе с учетом самой стоимости товара:
Срок доставки рассчитывается отдельно в зависимости от наличия и сроков производства. Если товар есть в наличии на складе, обслуживающим данный регион, то срок доставки в течении 5 дней, если нет - то берется срок производства + 5 дней на доставку. Города, которые обслуживает склад хранятся в пользовательском свойстве у склада UF_SERVICE_LOCATION (хранит код местоположения), срок производства зависит от типа товара и рассчитывается отдельно. Основная "фишка" метода: дополнительное ограничение выборки по конкретному товару из Таблицы наличия \Bitrix\Catalog\StoreProductTable. Получился такой метод:
Как видно из кода, фильтрация по товару и складу происходит за счет условий:
Надеюсь моя статья кому-то пригодится.
Настройки у всех похожи: Ограничения по конкретным местоположениям и ограничения по стоимости. Пример показан на рисунке:
Нам нужно в Карточке Товара вывести информацию по стоимости доставки в регион и описание из службы доставки. Основная трудность заключается в том, чтобы отфильтровать Службы доставки по регионам. Ограничения по регионам хранятся в таблице b_sale_delivery2location. Нам нужны входящие местоположения, т.е. с LOCATION_TYPE = "L". Был написан следующий метод, решающий нашу задачу:
/** * Получим массив с информацией о системе доставки по местоположению и ценовому диапазону * * @param string $sLocationCode - код местоположения 2.0 * @param float $fPrice - стоимость товара * @param $obEntityLocation2Delivery * @return array */ private function getHomeDeliveryByLocationAndPriceRestriction( string $sLocationCode, float $fPrice, $obEntityLocation2Delivery ): array { $arHomeDelivery = array(); try { $obDeliveries = \Bitrix\Sale\Delivery\Services\Table::getList([ "filter" => [ "=PARENT_ID" => AT_HOME_DELIVERY_GROUP_ID, "LOCATION2DELIVERY.LOCATION_CODE" => $sLocationCode, "LOCATION2DELIVERY.LOCATION_TYPE" => "L", // Входящие местоположения "=RESTRICTION.CLASS_NAME" => "\Bitrix\Sale\Delivery\Restrictions\ByPrice", "ACTIVE" => "Y", ], "select" => array( "LOCATION2DELIVERY.LOCATION_CODE", "RESTRICTION.PARAMS", "ID", "DESCRIPTION", "CONFIG" ), "runtime" => array( new ReferenceField( "LOCATION2DELIVERY", $obEntityLocation2Delivery, array( "=this.ID" => "ref.DELIVERY_ID" ), array( "join_type" => "LEFT" ) ), new ReferenceField( "RESTRICTION", "\Bitrix\Sale\Internals\ServiceRestrictionTable", array( "=this.ID" => "ref.SERVICE_ID" ), array( "join_type" => "LEFT" ) ), ), "cache" => array( "ttl" => self::CACHE_TIME, "cache_joins" => true, ) ]); while ($arDeliveries = $obDeliveries->fetch()) { if ($fPrice >= $arDeliveries["SALE_DELIVERY_SERVICES__RESTRICTION_PARAMS"]["MIN_PRICE"] && $fPrice <= $arDeliveries["SALE_DELIVERY_SERVICES__RESTRICTION_PARAMS"]["MAX_PRICE"]) { $arHomeDelivery = array( "DESCRIPTION" => $arDeliveries["DESCRIPTION"], "PRICE" => (string)$arDeliveries["CONFIG"]["MAIN"][0] ); } } } catch (ObjectPropertyException | ArgumentException | SystemException $obException) { AddMessage2Log($obException->getMessage(),"main"); } return $arHomeDelivery; } |
На вход подаем $sLocationCode - Код местоположения из наших местоположений 2.0; $fPrice - стоимость товара; $obEntityLocation2Delivery - объект, с описанием таблицы b_sale_delivery2location
Объект $obEntityLocation2Delivery мы описываем в методе getLocationToDeliveryEntity():
/** * Возвращаем объект описания таблицы b_sale_delivery2location * * @return Entity|bool */ private function getLocationToDeliveryEntity() { try { return \Bitrix\Main\Entity\Base::compileEntity( "LOCATION2DELIVERY", [ "DELIVERY_ID" => [ "data_type" => "integer" ], "LOCATION_CODE" => [ "data_type" => "string" ], "LOCATION_TYPE" => [ "data_type" => "string" ], ], [ "table_name" => "b_sale_delivery2location", ] ); } catch (\Bitrix\Main\ArgumentException | \Bitrix\Main\SystemException $obException) { return false; } } |
Таким образом в карточке товара выводится стоимость доставки в регионе с учетом самой стоимости товара:
Срок доставки рассчитывается отдельно в зависимости от наличия и сроков производства. Если товар есть в наличии на складе, обслуживающим данный регион, то срок доставки в течении 5 дней, если нет - то берется срок производства + 5 дней на доставку. Города, которые обслуживает склад хранятся в пользовательском свойстве у склада UF_SERVICE_LOCATION (хранит код местоположения), срок производства зависит от типа товара и рассчитывается отдельно. Основная "фишка" метода: дополнительное ограничение выборки по конкретному товару из Таблицы наличия \Bitrix\Catalog\StoreProductTable. Получился такой метод:
** * Получаем срок доставки товара в днях. Срок зависит от наличия: если на складе, обслуживающим этот город, нет в * наличии, то рассчитывается исходя из сроков производства + сроков поставки * * @param string $sLocationCode - код местоположения 2.0 * @param int $iSkuId - ID Торгового предложения (товара) * @param array $arHomeDelivery - Массив с информацией по доставке, который нужно дополнить сроками * @return array */ private function getHomeDeliveryPeriod(string $sLocationCode, int $iSkuId, array $arHomeDelivery): array { try { $obStore = \Bitrix\Catalog\StoreTable::getList(array( "filter" => array( "=UF_SERVICE_LOCATION" => $sLocationCode, ), "select" => array( "PRODUCT_STORE.AMOUNT", "ID", ), "limit" => 1, "runtime" => array( new ReferenceField( "PRODUCT_STORE", "\Bitrix\Catalog\StoreProductTable", array( "=this.ID" => "ref.STORE_ID", "ref.PRODUCT_ID" => new \Bitrix\Main\DB\SqlEx * pression("?i", $iSkuId) ), array( "join_type" => "LEFT" ) ), ), "cache" => array( "ttl" => self::CACHE_TIME, ) )); if ($arStore = $obStore->fetch()) { if (intval($arStore["CATALOG_STORE_PRODUCT_STORE_AMOUNT"]) <= 0) { if (intval($arStorePeriodByStore[$arProductType["UF_XML_ID"]]) > 0) { $arHomeDelivery["DELIVERY_DAYS"] = $this->iManufacturePeriod + self::HOME_DELIVERY_PERIOD; } } else { $arHomeDelivery["DELIVERY_DAYS"] = self::HOME_DELIVERY_PERIOD; } } } catch (\Bitrix\Main\ObjectPropertyException | \Bitrix\Main\ArgumentException | \Bitrix\Main\SystemException $obException) { AddMessage2Log($obException->getMessage(),"main"); } return $arHomeDelivery; } |
Как видно из кода, фильтрация по товару и складу происходит за счет условий:
"=this.ID" => "ref.STORE_ID", ref.PRODUCT_ID" => new \Bitrix\Main\DB\SqlEx * pression("?i", $iSkuId) |
Надеюсь моя статья кому-то пригодится.