Last active
March 29, 2023 10:41
-
-
Save livevasiliy/936874d5b828246d9584b4c160404302 to your computer and use it in GitHub Desktop.
Персональные скидки Битрикс
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Для создания кастомизированного правила работы с корзиной на сайт необходимо: | |
1. Скопировать файл saleactiondiscountfromdirectory.php в папку сайта рядом с init.php (либо в /local/php_interface/init.php либо /bitrix/php_interface/init.php либо /bitrix/php_interface/ID сайта/init.php). | |
2. Подключить файл saleactiondiscountfromdirectory.php в init.php: | |
include "saleactiondiscountfromdirectory.php"; | |
3. Создать Highload блок. Импортировать файл discount_hlb.xml со структурой hl-блока на странице ваш-сайт/bitrix/admin/highloadblock_import.php | |
4. Создать записи в hl-блоке. | |
5. Создать правило работы с корзиной. | |
На странице ваш-сайт/bitrix/admin/sale_discount.php нажать на кнопку "добавить правило". | |
В настройках правила на вкладке "Общие параметры" указать Сайт, Название (например, "Персональная скидка") и Активность. | |
На вкладке "Действия и условия" добавить действие "Применить скидку из справочника" и выбрать в выпадающем списке созданный hl-блок со скидками. | |
Сохранить правило. | |
6. Создайте нового агента. | |
На странице ваш-сайт/bitrix/admin/agent_list.php нажать на кнопку "добавить агента". В настройках укажите в время для следующего запуска агента, в параметре функция агента укажите updateDiscountValueHlb(); в параметре "Периодичность выполнения" выберите: через заданный интервал. | |
И укажите нужный вам интервал обновления агента. В файле init.php расскоментировать вызов функции updateDiscountValueHlb. | |
ИЛИ | |
Подключение ajax. | |
Вставить и вызовите ajax-запрос. | |
Для этого сделайте в корне проекта/или где удобно папку для хранения ajax-обработчика. (Файл handlePersonalDiscount.php) | |
Затем подключите и вызовите файл ajax.js | |
7. Результат работы правила можно увидеть в корзине, положив в нее товары указанные в hl-блоке для текущегно пользователя. | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Можно заменить на аналог от jQuery. | |
BX.ready(function(){ | |
// Увеличиваем скидку каждую минуту, отправляя ajax запрос | |
let timeId = setInterval(function () { | |
BX.ajax({ | |
url: '/ajax/handlePersonalDiscount.php', // путь где лежит этот файл | |
method: 'POST', | |
timeout: 60, | |
async: true, | |
processData: true, | |
scriptsRunFirst: true, | |
emulateOnload: true, | |
start: true, | |
cache: false, | |
onsuccess: function(data){ | |
console.log(data); | |
}, | |
onfailure: function(){ | |
} | |
}) | |
}, 60000) | |
// Очищаем таймер после 5 минут | |
setTimeout(function () { | |
clearInterval(timeId) | |
}, 300000) | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<hiblock> | |
<hiblock> | |
<id>4</id> | |
<name>DISCOUNT</name> | |
<table_name>discount</table_name> | |
</hiblock> | |
<langs> | |
</langs> | |
<fields> | |
<field> | |
<id>38</id> | |
<entity_id>HLBLOCK_4</entity_id> | |
<field_name>UF_PRODUCT</field_name> | |
<user_type_id>string</user_type_id> | |
<xml_id /> | |
<sort>100</sort> | |
<multiple>N</multiple> | |
<mandatory>N</mandatory> | |
<show_filter>N</show_filter> | |
<show_in_list>Y</show_in_list> | |
<edit_in_list>Y</edit_in_list> | |
<is_searchable>N</is_searchable> | |
<settings> | |
<size>20</size> | |
<rows>1</rows> | |
<regexp /> | |
<min_length>0</min_length> | |
<max_length>0</max_length> | |
<default_value /> | |
</settings> | |
<edit_form_label> | |
<en /> | |
<ru>ID товара</ru> | |
</edit_form_label> | |
<list_column_label> | |
<en /> | |
<ru>ID товара</ru> | |
</list_column_label> | |
<list_filter_label> | |
<en /> | |
<ru /> | |
</list_filter_label> | |
<error_message> | |
<en /> | |
<ru /> | |
</error_message> | |
<help_message> | |
<en /> | |
<ru /> | |
</help_message> | |
<base_type>string</base_type> | |
</field> | |
<field> | |
<id>39</id> | |
<entity_id>HLBLOCK_4</entity_id> | |
<field_name>UF_DISCOUNT</field_name> | |
<user_type_id>string</user_type_id> | |
<xml_id /> | |
<sort>100</sort> | |
<multiple>N</multiple> | |
<mandatory>N</mandatory> | |
<show_filter>N</show_filter> | |
<show_in_list>Y</show_in_list> | |
<edit_in_list>Y</edit_in_list> | |
<is_searchable>N</is_searchable> | |
<settings> | |
<size>20</size> | |
<rows>1</rows> | |
<regexp /> | |
<min_length>0</min_length> | |
<max_length>0</max_length> | |
<default_value /> | |
</settings> | |
<edit_form_label> | |
<en>Discount (%)</en> | |
<ru>Размер скидки (%)</ru> | |
</edit_form_label> | |
<list_column_label> | |
<en>Discount (%)</en> | |
<ru>Размер скидки (%)</ru> | |
</list_column_label> | |
<list_filter_label> | |
<en /> | |
<ru /> | |
</list_filter_label> | |
<error_message> | |
<en /> | |
<ru /> | |
</error_message> | |
<help_message> | |
<en>Скидка на товар в процентах</en> | |
<ru>Скидка на товар в процентах</ru> | |
</help_message> | |
<base_type>string</base_type> | |
</field> | |
<field> | |
<id>40</id> | |
<entity_id>HLBLOCK_4</entity_id> | |
<field_name>UF_USER</field_name> | |
<user_type_id>string</user_type_id> | |
<xml_id /> | |
<sort>100</sort> | |
<multiple>N</multiple> | |
<mandatory>N</mandatory> | |
<show_filter>N</show_filter> | |
<show_in_list>Y</show_in_list> | |
<edit_in_list>Y</edit_in_list> | |
<is_searchable>N</is_searchable> | |
<settings> | |
<size>20</size> | |
<rows>1</rows> | |
<regexp /> | |
<min_length>0</min_length> | |
<max_length>0</max_length> | |
<default_value /> | |
</settings> | |
<edit_form_label> | |
<en>User id</en> | |
<ru>ID Пользователя</ru> | |
</edit_form_label> | |
<list_column_label> | |
<en>User id</en> | |
<ru>ID Пользователя</ru> | |
</list_column_label> | |
<list_filter_label> | |
<en>User id</en> | |
<ru>ID Пользователя</ru> | |
</list_filter_label> | |
<error_message> | |
<en /> | |
<ru /> | |
</error_message> | |
<help_message> | |
<en /> | |
<ru /> | |
</help_message> | |
<base_type>string</base_type> | |
</field> | |
<field> | |
<id>48</id> | |
<entity_id>HLBLOCK_4</entity_id> | |
<field_name>UF_UPDATED_AT</field_name> | |
<user_type_id>datetime</user_type_id> | |
<xml_id /> | |
<sort>100</sort> | |
<multiple>N</multiple> | |
<mandatory>N</mandatory> | |
<show_filter>N</show_filter> | |
<show_in_list>Y</show_in_list> | |
<edit_in_list>Y</edit_in_list> | |
<is_searchable>N</is_searchable> | |
<settings> | |
<default_value> | |
<type>NONE</type> | |
<value /> | |
</default_value> | |
<use_second>Y</use_second> | |
<use_timezone>N</use_timezone> | |
</settings> | |
<edit_form_label> | |
<en /> | |
<ru /> | |
</edit_form_label> | |
<list_column_label> | |
<en>Update date</en> | |
<ru>Дата обновления</ru> | |
</list_column_label> | |
<list_filter_label> | |
<en /> | |
<ru /> | |
</list_filter_label> | |
<error_message> | |
<en /> | |
<ru /> | |
</error_message> | |
<help_message> | |
<en /> | |
<ru /> | |
</help_message> | |
<base_type>datetime</base_type> | |
</field> | |
</fields> | |
</hiblock> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<? require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php'); | |
include "local/php_interface/update_discount_value_hlb.php"; | |
try | |
{ | |
updateDiscountValueHlb(); | |
echo 'success'; | |
} catch (Exception $e) | |
{ | |
\Bitrix\Main\Diag\Debug::writeToFile($e->getMessage()); | |
echo $e->getMessage(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Bitrix\Main\Loader; | |
use \Bitrix\Highloadblock\HighloadBlockTable as HLB; | |
/** | |
* Helper функция для работы с Highload блоками | |
* | |
* | |
* @param $HlBlockId | |
* @return \Bitrix\Main\ORM\Data\DataManager|bool | |
* @throws \Bitrix\Main\ArgumentException | |
* @throws \Bitrix\Main\LoaderException | |
* @throws \Bitrix\Main\ObjectPropertyException | |
* @throws \Bitrix\Main\SystemException | |
*/ | |
function GetEntityDataClass($HlBlockId) { | |
Loader::includeModule('highloadblock'); | |
if (empty($HlBlockId) || $HlBlockId < 1) | |
{ | |
return false; | |
} | |
$hlblock = HLB::getById($HlBlockId)->fetch(); | |
$entity = HLB::compileEntity($hlblock); | |
$entity_data_class = $entity->getDataClass(); | |
return $entity_data_class; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
include 'helpers.php'; | |
include "update_discount_value_hlb.php"; | |
include "saleactiondiscountfromdirectory.php"; | |
// updateDiscountValueHlb(); // Раскомментировать, если будет использоваться, через Агенты. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<? | |
use Bitrix\Main\ArgumentException; | |
use Bitrix\Main\EventManager; | |
use \Bitrix\Main\Loader, | |
\Bitrix\Highloadblock\HighloadBlockTable as HLB, | |
\Bitrix\Highloadblock\HighloadBlockLangTable; | |
use Bitrix\Main\LoaderException; | |
use Bitrix\Main\ObjectPropertyException; | |
use Bitrix\Main\ORM\Data\DataManager; | |
use Bitrix\Main\SystemException; | |
if (Loader::includeModule('sale')) | |
{ | |
$eventManager = EventManager::getInstance(); | |
$eventManager->addEventHandlerCompatible("sale", | |
"OnCondSaleActionsControlBuildList", | |
[ | |
"SaleActionDiscountFromDirectory", | |
"GetControlDescr" | |
]); | |
class SaleActionDiscountFromDirectory extends CSaleActionCtrlBasketGroup | |
{ | |
public static function GetClassName() | |
{ | |
return __CLASS__; | |
} | |
public static function GetControlID() | |
{ | |
return "DiscountFromDirectory"; | |
} | |
public static function GetControlDescr() | |
{ | |
return parent::GetControlDescr(); | |
} | |
public static function GetAtoms() | |
{ | |
return static::GetAtomsEx(false, false); | |
} | |
public static function GetControlShow($arParams) | |
{ | |
$arAtoms = static::GetAtomsEx(false, false); | |
$arResult = [ | |
"controlId" => static::GetControlID(), | |
"group" => false, | |
"label" => "Применить скидку из справочника", | |
"defaultText" => "", | |
"showIn" => static::GetShowIn($arParams["SHOW_IN_GROUPS"]), | |
"control" => [ | |
"Применить скидку из HighLoad блока", | |
$arAtoms["HLB"] | |
] | |
]; | |
return $arResult; | |
} | |
public static function GetAtomsEx($strControlID = false, $boolEx = false) | |
{ | |
$boolEx = (true === $boolEx ? true : false); | |
$hlbList = []; | |
if (Loader::includeModule('highloadblock')) | |
{ | |
$dbRes = HLB::GetList([]); | |
while ($el = $dbRes->fetch()) | |
{ | |
$hlbList[$el['ID']] = $el['NAME']; | |
} | |
$res = HighloadBlockLangTable::GetList(['filter' => ['=LID' => LANGUAGE_ID]]); | |
while ($el = $res->fetch()) | |
{ | |
if ($hlbList[$el['ID']]) | |
$hlbList[$el['ID']] = $el['NAME'] . " [" . $hlbList[$el['ID']] . "]"; | |
} | |
} | |
$arAtomList = [ | |
"HLB" => [ | |
"JS" => [ | |
"id" => "HLB", | |
"name" => "extra", | |
"type" => "select", | |
"values" => $hlbList, | |
"defaultText" => "...", | |
"defaultValue" => "", | |
"first_option" => "..." | |
], | |
"ATOM" => [ | |
"ID" => "HLB", | |
"FIELD_TYPE" => "string", | |
"FIELD_LENGTH" => 255, | |
"MULTIPLE" => "N", | |
"VALIDATE" => "list" | |
] | |
], | |
]; | |
if (!$boolEx) | |
{ | |
foreach ($arAtomList as &$arOneAtom) | |
{ | |
$arOneAtom = $arOneAtom["JS"]; | |
} | |
if (isset($arOneAtom)) | |
{ | |
unset($arOneAtom); | |
} | |
} | |
return $arAtomList; | |
} | |
public static function Generate($arOneCondition, $arParams, $arControl, $arSubs = false) | |
{ | |
$mxResult = __CLASS__ . "::applyProductDiscount(" . $arParams["ORDER"] . ", " . "\"" . $arOneCondition["HLB"] . "\"" . ");"; | |
return $mxResult; | |
} | |
/** | |
* Возвращает название класса Highload Block | |
* | |
* @param $HlBlockId | |
* @return DataManager|bool | |
* @throws ArgumentException | |
* @throws ObjectPropertyException | |
* @throws SystemException | |
*/ | |
private static function GetEntityDataClass($HlBlockId) | |
{ | |
if (empty($HlBlockId) || $HlBlockId < 1) | |
{ | |
return false; | |
} | |
$hlblock = HLB::getById($HlBlockId)->fetch(); | |
$entity = HLB::compileEntity($hlblock); | |
$entity_data_class = $entity->getDataClass(); | |
return $entity_data_class; | |
} | |
/** | |
* Применяет скидку из справочника к товарам из корзины | |
* @param $arOrder | |
* @param $hlb - Highload block | |
* @return void | |
* @throws ArgumentException | |
* @throws LoaderException | |
* @throws ObjectPropertyException | |
* @throws SystemException | |
* @throws Exception | |
*/ | |
public static function applyProductDiscount(&$arOrder, $hlb) | |
{ | |
$userId = $arOrder['USER_ID']; | |
if ($userId && Loader::includeModule('highloadblock')) | |
{ | |
$productIds = []; | |
foreach ($arOrder['BASKET_ITEMS'] as &$product) | |
{ | |
$productIds[] = $product['PRODUCT_ID']; | |
} | |
unset($product); | |
$hlblock = HLB::getById($hlb)->fetch(); | |
if (!$hlblock) | |
{ | |
return; | |
} | |
$entity = HLB::compileEntity($hlblock); | |
$entityClass = $entity->getDataClass(); | |
//Находим записи в справочнике с нужными параметрами - товар/пользователь | |
$dbRes = $entityClass::getList([ | |
'filter' => [ | |
'=UF_PRODUCT' => $productIds, | |
'=UF_USER' => $userId | |
], | |
'order' => [ | |
'ID' => 'DESC' | |
] | |
]); | |
$discounts = []; | |
while ($el = $dbRes->fetch()) | |
{ | |
if (!$discounts[$el['UF_PRODUCT']]) | |
{ | |
$discounts[$el['UF_PRODUCT']] = $el; | |
} | |
} | |
//Применяем скидку | |
foreach ($arOrder['BASKET_ITEMS'] as &$product) | |
{ | |
$productId = $product['PRODUCT_ID']; | |
if ($discounts[$productId]) | |
{ | |
$product['DISCOUNT_PRICE'] = $product['BASE_PRICE'] * $discounts[$productId]['UF_DISCOUNT'] / 100; | |
$product['PRICE'] = $product['BASE_PRICE'] - $product['DISCOUNT_PRICE']; | |
} | |
} | |
unset($product); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use Bitrix\Main\Context; | |
use Bitrix\Main\Loader; | |
use Bitrix\Sale\Basket; | |
const DISCOUNT_HLB = 4; // ID HighLoad Block с персональными скидками | |
const MAX_DISCOUNT_PERCENT = 5; // До скольки процентов будем расти скидку. | |
const STEP_INCREMENT_DISCOUNT_PERCENT = 1; // Значение шага увеличения скидки в указанным период в агенте | |
/** | |
* Обработчик для обновления значения скидки и даты обновления в | |
* Highload блоке с персональными скидками | |
* | |
* @throws Exception | |
*/ | |
function updateDiscountValueHlb() | |
{ | |
global $USER; | |
$USER = new CUser(); | |
$currentDateTimeOnSite = new \Bitrix\Main\Type\DateTime(); | |
Loader::includeModule('highloadblock'); | |
if ($USER->IsAuthorized()) | |
{ | |
$userId = $USER->GetID(); | |
$basket = Basket::loadItemsForFUser( | |
$userId, | |
Context::getCurrent()->getSite() | |
); | |
$basketItems = $basket->getBasketItems(); | |
$arProductIds = []; | |
/** @var \Bitrix\Sale\BasketItem $basketItem */ | |
foreach ($basketItems as $basketItem) | |
{ | |
$arProductIds[] = $basketItem->getProductId(); | |
} | |
$arFilter = [ | |
'filter' => [ | |
'=UF_USER' => $userId, | |
'=UF_PRODUCT' => $arProductIds | |
], | |
'order' => [ | |
'ID' => 'DESC' | |
] | |
]; | |
$entity_data_class = GetEntityDataClass(DISCOUNT_HLB); | |
$rsData = $entity_data_class::getList($arFilter); | |
$discounts = []; | |
$arProductIdsFromDiscounts = []; | |
$currentDiscountSize = 1; | |
while($el = $rsData->fetch()){ | |
{ | |
if (!$discounts[$el['UF_PRODUCT']]) | |
{ | |
$discounts[$el['UF_PRODUCT']] = $el; | |
$arProductIdsFromDiscounts[] = $el['UF_PRODUCT']; | |
$currentDiscountSize = $el['UF_DISCOUNT']; | |
} | |
} | |
} | |
$missingProductIds = array_diff($arProductIds, $arProductIdsFromDiscounts); | |
foreach ($missingProductIds as $missingProductId) | |
{ | |
$entity_data_class::add([ | |
'UF_PRODUCT' => $missingProductId, | |
'UF_USER' => $userId, | |
'UF_DISCOUNT' => $currentDiscountSize, | |
'UF_UPDATED_AT' => $currentDateTimeOnSite | |
]); | |
} | |
foreach($discounts as $discount) | |
{ | |
$sizeDiscount = $discount['UF_DISCOUNT']; | |
$lastDateTimeUpdate = new \Bitrix\Main\Type\DateTime($discount['UF_UPDATED_AT']); | |
if ($sizeDiscount < MAX_DISCOUNT_PERCENT && $currentDateTimeOnSite > $lastDateTimeUpdate) | |
{ | |
$sizeDiscount += STEP_INCREMENT_DISCOUNT_PERCENT; | |
$arFields = $discount; | |
$arFields['UF_DISCOUNT'] = $sizeDiscount; | |
$arFields['UF_UPDATED_AT'] = $currentDateTimeOnSite; | |
$entity_data_class::update($discount['ID'], $arFields); | |
} | |
} | |
} | |
return "updateDiscountValueHlb();"; // для вызова функции, через Битрикс.Агенты | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment