Хочу поделиться способом как вывести информацию по доставке в карточке товара на основе служб доставки. Имеем несколько Служб доставки по группам местоположений: по Москве, по Санкт-Петербургу, и некоторых других регионов.
Настройки у всех похожи: Ограничения по конкретным местоположениям и ограничения по стоимости. Пример показан на рисунке:
Нам нужно в Карточке Товара вывести информацию по стоимости доставки в регион и описание из службы доставки. Основная трудность заключается в том, чтобы отфильтровать Службы доставки по регионам. Ограничения по регионам хранятся в таблице 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) |
Надеюсь моя статья кому-то пригодится.