Добавление в корзину с определенным типом цены

Модуль расширенного управления меню для битрикс

Сентябрь 22, 2018

Теги: Магазин, Как это сделать?

Добавление в корзину с заданным типом цены (а не с минимальной ценой как по умолчанию).

Чтобы добавить в корзину товар с заранее заданным типом цены, а не с минимальной ценой из возможных типов, к которым пользователь имеет доступ, необходимо при добавлении в корзину указать класс провайдера "PRODUCT_PROVIDER_CLASS", который будет использоваться системой для расчета цены. В данном примере наследуется стандартный класс провайдера "\Bitrix\Catalog\Product\CatalogProvider", в котором переопределяются функции "getProductData" и "getCatalogData", в которых перед запуском тех же функций в родительском классе добавляется обработчик события "OnGetOptimalPrice", который влияет на выбор типа цены при расчете. XML_ID типа цены заранее сохраняется в свойствах элемента корзины, а в функциях "getProductData" и "getCatalogData" массив цены товара сохраняется в статическую переменную класса, откуда впоследствии забирается в обработчике "OnGetOptimalPrice". Возвращая этот массив, обработчик "OnGetOptimalPrice" указывает функции "CCatalogProduct::GetOptimalPrice" использовать именно этот тип цены.


<?php

    
namespace Partner;

\Bitrix\Main\Loader::includeModule("catalog");

class 
Basket
{
    const 
defaultCatalogGroupXmlId "base_price";
    
    public static function 
add($productId,$quantity=1,$catalogGroupXmlId)
    {
        
// функция добавления в корзину, сохраняем тип цены в свойствах элемента корзины
        // параметр $catalogGroupXmlId содержит XML_ID нужного типа цены
        
if($catalogGroupXmlId)
        {
            
$rsGroup \Bitrix\Catalog\GroupTable::getList(array('filter'=>array('XML_ID'=>$catalogGroupXmlId)));
            if(!
$rsGroup->fetch())
                
$catalogGroupXmlId self::defaultCatalogGroupXmlId;
        }
        else
            
$catalogGroupXmlId self::defaultCatalogGroupXmlId;

        
$arRewriteFields = array(
            
'PRODUCT_PROVIDER_CLASS' => '\Partner\CatalogProvider',
        );
        
$arProps = array( // required for $arRewriteFields, can be an empty array
            
array(
                
"NAME" => "Тип цены",
                
"CODE" => "CATALOG_GROUP_XML_ID",
                
"VALUE" => $catalogGroupXmlId,
                
"SORT" => "100",
            ),
        );
        
$basketId \Add2BasketByProductID(
            
$productId,
            
$quantity,
            
$arRewriteFields,
            
$arProps
        
);

        
$basket \Bitrix\Sale\Basket::loadItemsForFUser(\Bitrix\Sale\Fuser::getId(), \Bitrix\Main\Context::getCurrent()->getSite());
        
$refreshStrategy \Bitrix\Sale\Basket\RefreshFactory::create(\Bitrix\Sale\Basket\RefreshFactory::TYPE_FULL);
        
$result $basket->refresh($refreshStrategy);
        
$basket->save();
        
        return 
$basketId;
    }
}

class 
CatalogProvider extends \Bitrix\Catalog\Product\CatalogProvider
{
    private static 
$PartnerPrice false;
    
    
/**
     * @param array $products
     *
     * @return Sale\Result
     */
    
public function getProductData(array $products)
    {
        return 
self::customGetData($products,__FUNCTION__);
    }

    
/**
     * @param array $products
     *
     * @return Sale\Result
     */
    
public function getCatalogData(array $products)
    {
        return 
self::customGetData($products,__FUNCTION__);
    }

    private function 
customGetData(array $products,$methodName)
    {
        
self::$PartnerPrice false;

        foreach(
$products as $product)
        {
            
$basketPropRes \Bitrix\Sale\Internals\BasketPropertyTable::getList(array(
                
'filter' => array('BASKET_ID' => $product['BASKET_ID'],'CODE'=>'CATALOG_GROUP_XML_ID'),
            ));
            
            if (
                !(
$property $basketPropRes->fetch())
                || !(
$catalogGroupXmlId=$property['VALUE'])
            ) 
                continue;
            
            
$rsPrice \Bitrix\Catalog\PriceTable::getList(array(
                
'filter' => array('PRODUCT_ID'=>$product['PRODUCT_ID'],'CATALOG_GROUP.XML_ID'=>$catalogGroupXmlId),
                
'limit' => 1,
            ));
            if(
$arPrice=$rsPrice->fetch())
            {
                if(!
is_array(self::$PartnerPrice))
                    
self::$PartnerPrice=array();
                
self::$PartnerPrice[intval($product['PRODUCT_ID'])] = $arPrice;
            }
        }

        
$eventManager \Bitrix\Main\EventManager::getInstance();
                
        
// Добавляем обработчик OnGetOptimalPrice
        
$eventManager->addEventHandler('catalog''OnGetOptimalPrice''\\'.static::class.'::onGetOptimalPriceHandler');

        
$arResult parent::$methodName($products);

        
self::$PartnerPrice false;
        
        
// Убираем обработчик OnGetOptimalPrice
        
$eventManager->removeEventHandler('catalog''OnGetOptimalPrice''\\'.static::class.'::onGetOptimalPriceHandler');        
        
        return 
$arResult;        
    }

    public function 
onGetOptimalPriceHandler(
        
$intProductID,
        
$quantity 1,
        
$arUserGroups = array(),
        
$renewal "N",
        
$arPrices = array(),
        
$siteID false,
        
$arDiscountCoupons false        
    
) {
        
/*
        В результате работы обработчика могут быть возвращены следующие значения:
        
        true - обработчик ничего не сделал, будет выполнена работа метода CCatalogProduct::GetOptimalPrice;
        false - возникла ошибка, работа метода прерывается;
        массив, описывающий наименьшую цену для товара.        
        */
        
if(
            !
is_array(self::$PartnerPrice)
            || !
is_array($arPrice=self::$PartnerPrice[$intProductID])
        )
            return 
true;

        return array(
'PRICE'=>$arPrice); // также можно вернуть описания скидок
    
}    
}

См. также:

← Переход к списку