Возникла задача организации интернет-магазина с множеством торговых предложений (деление по цвету изделия, типам и пр.). За основу выбрали шаблон компонента Каталог по умолчанию. Инфолоки настроили, товары с торговыми предложениям создали - компонент работает. Но тут возникло требование - реализовать зависимость цены на товарную позицию от количества добавленного товара в корзину (расширенный режим управления ценами) и оказалось, что шаблон компонента данный фукнционал ещё не поддерживает.
Для начала в файле result_modifier организуем получение "ценовой матрицы" для товарной позиции. За работу с простым типом товаров и товаров с торговыми предложениями отвечают два простых условия:
if ($arResult['CATALOG'] && isset($arResult['OFFERS']) && !empty($arResult['OFFERS'])) {
...
foreach ($arResult['OFFERS'] as &$arOffer) {
...
$arResultPrices = CIBlockPriceTools::GetCatalogPrices($arParams['IBLOCK_ID'], $arParams['PRICE_CODE']);
foreach ($arResultPrices as $value) {
// if (!$value['CAN_VIEW'] && !$value['CAN_BUY'])
// continue;
$arPriceTypeID[] = $value['ID'];
}
if (isset($value))
unset($value);
$arOffer['PRICE_MATRIX'] = CatalogGetPriceTableEx($arOffer['ID'], 0, $arPriceTypeID, 'Y');
if (is_array($arOffer['PRICE_MATRIX'])) {
$boolSKUDisplayProps = true;
if (isset($arOffer['PRICE_MATRIX']['COLS']) && is_array($arOffer['PRICE_MATRIX']['COLS'])) {
foreach ($arOffer['PRICE_MATRIX']['COLS'] as $keyColumn => $arColumn)
$arOffer['PRICE_MATRIX']['COLS'][$keyColumn]['NAME_LANG'] = htmlspecialcharsbx($arColumn['NAME_LANG']);
}
}
}
...
}
if ($arResult['CATALOG_TYPE'] == CCatalogProduct::TYPE_PRODUCT || $arResult['CATALOG_TYPE'] == CCatalogProduct::TYPE_SET) {
...
$arResultPrices = CIBlockPriceTools::GetCatalogPrices($arParams['IBLOCK_ID'], $arParams['PRICE_CODE']);
foreach ($arResultPrices as &$value) {
// if (!$value['CAN_VIEW'] && !$value['CAN_BUY'])
// continue;
$arPriceTypeID[] = $value['ID'];
}
if (isset($value))
unset($value);
$arResult['PRICE_MATRIX'] = CatalogGetPriceTableEx($arResult['ID'], 0, $arPriceTypeID, 'Y');
if (isset($arResult['PRICE_MATRIX']['COLS']) && is_array($arResult['PRICE_MATRIX']['COLS'])) {
foreach ($arResult['PRICE_MATRIX']['COLS'] as $keyColumn => $arColumn)
$arResult['PRICE_MATRIX']['COLS'][$keyColumn]['NAME_LANG'] = htmlspecialcharsbx($arColumn['NAME_LANG']);
}
...
}
Далее в шаблоне для простого типа товаров просто выводим таблицу в отдельном блоке:
Для товаров с торговыми предложениями вывод интервалов цен несколько сложнее, т. к. у разных торговых предложений цены могут различаться. Вывод таблицы строится аналогично выводу свойств торговых предложений. Сначала выводится пустой блок с заданным идентификатором для доступа посредством JS. Затем формируется вывод таблицы для каждого торгового предложения в виде строки и добавляется в массив параметров для вызова JS.
Далее в файле script.js остаётся выбрать значение цены для указанного количества и подставить это значение в момент обновления цены на странице шаблона компонента. За выбор значения цены отвечает отдельный метод, который с помощью простых итераций формирует объект calcPrice. Обновление цены выполняется в методах QuantityUp, QuantityDown и QuantityChange.
Для поиска по каталогу товаров на сайте используем компонент «Поиск по каталогу» (bitrix:catalog.search). Компонент выводит результаты поиска по элементам каталога с указанным набором свойств, цен и т.д., является стандартным. В качестве параметров компоненту указываются тип инфо-блоков и ID инфобока, по которому будет производится поиск. http://dev.1c-bitrix.ru/user_help/con...search.php
Но выяснилась одна очень важная деталь, при поиске по свойствам/описанию торговых предложений, компонент их не выводит. Рассмотрев детально код (основной код компонента сосредоточен в шаблоне), выяснили, что компонент выполняет поиск по заданному инфоблоку поисковой фразы с помощью bitrix:search.page, а затем выводит элементы инфоблока с помощью bitrix:catalog.section.
Немного подправив код, можно указать компоненту bitrix:search.page, что искать нужно не только в инфоблоке основного каталога товаров, но и в инфоблоке торговых предложений. Т. к. для вывода товарных позиций в bitrix:catalog.section необходимо указывать ID элемента торгового каталога, то для торговых предложений необходимо выполнить дополнительно подзапрос к инфоблоку торговых предложений.
Для этого сначала в файле result_modifier.php с помощью метода CCatalogSKU::GetInfoByProductIBlock() определяем наличие инфоблока торговых предложений и его параметры. Определяем тип этого инфоблока и по идентификатору свойства-связки символьный код этого свойства.
<?php if (!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED !== true) die();?>
<?php
$arSKU = CCatalogSKU::GetInfoByProductIBlock($arParams["IBLOCK_ID"]);
if (is_array($arSKU)) {
$arResult["ORLND"]["SKU_IBLOCK_ID"] = $arSKU["IBLOCK_ID"];
$rsIBlock = CIBlock::GetByID($arSKU["IBLOCK_ID"]);
if ($arIBlock = $rsIBlock->GetNext())
$arResult["ORLND"]["SKU_IBLOCK_TYPE"] = $arIBlock["IBLOCK_TYPE_ID"];
$rsProperty = CIBlockProperty::GetByID($arSKU["SKU_PROPERTY_ID"], $arSKU["IBLOCK_ID"]);
if ($arProperty = $rsProperty->GetNext())
$arResult["ORLND"]["SKU_PROPERTY_SID"] = $arProperty["CODE"];
}
Получается, что массив arResult пополняется новыми полями:
Теперь модифицируем template.php. В случае, если типы инфоблоков торгового каталога и торговых предложений совпадают, формируется массив из идентификаторов этих инфоблоков.
Таким образом, мы с помощью подзапроса CIBlockElement::SubQuery() получаем элементы основного каталога товаров, торговые предложения которых были найдены.
Мне нужен поиск только по Названию или артикулу. Я подумал, что проще, в момент создания или редактирования товара, просто записать артикулы в свойство товара с ТП. Создать например ['SKU_ARTNUMBERS'] и туда записывать артикулы через пробел, и индексировать для поиска.
Тогда: 1. Меньше запросов при рендере шаблонов. 2. Не будет проблем с пагинацией, т.к. способ описанный в статье мне кажется сулит проблемами с пагинацией.
В одном из проектов постоянно возникали жалобы со стороны клиентов по поводу страницы оформления заказа.
не получается оформить заказ, ввела все данные синенькие квадратики по доставке почта России и наложенный платеж внизу нажимаю оформить заказ, но ничего не происходит
зарегистрировался, набрал заказ,заполнил в заказе все поля со звездочкой, нажимаю оформить заказ и не чего не происходит.
вроде все заполнил, а после нажатия Оформить заказ ничего не меняется
В соответствующем разделе используется стандартный компонент bitrix:sale.order.ajax со стандартным шаблоном. С помощью Я.Метрики выясняем ОС клиента, тип используемого браузера и его версию. Тестируем сайт в аналогичной ситуации - всё работает. При указании местоположений в заказе - всё срабатывает. Выбор способов оплаты/доставки также выполняется без ошибок.
В итоге долгое время «списывали» подобные проблемы на совесть клиента, т. к. большинство действительно без опыта работы в сети Интернет. Самым распространённым советом было «сменить браузер».
Это продолжалось до тех пор, пока один из менеджеров не заметил, что заказ не удаётся оформить при активном диалоге online-консультанта JivoSite. Online-консультант установлен на сайте вручную без использования дополнительных модулей. На сайте поддержки нашлась интересная тема для обсуждения.
Многие клиенты жаловались что не работает кнопка "оформить заказ" в самом конце оформления заказа. У меня сайт на битриксе, страница оформления на аяксе. При проверке такой проблемы не возникало, но вчера пообщавшись с оператором, и решив сделать заказ тоже столкнулся с этой проблемой. Проблема возникает только если клиент общался с оператором...
Практически в конце темы совет:
Проблема скорее всего в конфликте iframe и ajax модуля на вашем сайте. Не обрабатывался запрос изначально. В личном кабинете admin.jivosite.com разделе Сайты/Настройки/Опции - отключите iframe технологию чата, на которой он работает по-умолчанию...
Проверили - действительно, когда клиент ведёт активный диалог в online-консультанте, переходит на страницу оформления заказа, заполняет поля и нажимает кнопку «Купить» происходит перезагрузка страницы и ВСЁ. Компонент оформления заказа (bitrix:sale.order.ajax) не сработал и клиент опять вернулся на страницу оформления заказа. После включения одной из опций (на данный момент она называется «Перезагружать окно чата при навигации») описанная проблема пропадает.
Спасибо за сгруппированную и предоставленную информацию в разделе Разработчикам Bitrix. Конфликт ajax модулей и нашего сервиса действительно есть ( структура работы ajax без активного обновления страницы и работы нашего сервиса с использованием iframe технологии приводит к текущей ситуации).
Удалось обнаружить данный конфликт более года назад, после чего мы сразу же приняли решение доработать наш сервис с возможностью отключать данный режим работы с использованием iframe в настройках личного кабинета Jivosite
Как вы правильно заметили, данную информацию можно найти на форуме, а также уточнить у любого из сотрудников поддержки на нашем сайте.
Мы обязательно добавим данную тему, а также более подробное описание про заданную функцию и часть конфликтов, которые могут возникать при ее работе и их решения в нашу Базу знаний и постараемся подробнее рассказать о всех возможностях настройки нашего сервиса, настроек в личном кабинете, в также самой программы.
Если возникнут вопросы или потребуется поддержка в настройке и использовании сервиса Jivosite вы можете обращаться к нам напрямую в чат на сайте, на наш адрес технической поддержки info@jivosite.com , а также на наш форум.
В очередной раз, используя на одном из проектов компонент bitrix:catalog наткнулись на интересное поведение. При включении ЧПУ в данном компоненте и включённой опции "INCLUDE_SUBSECTIONS" ссылки на товары из вложенных разделов начинают выводится исходя из текущего раздела. Т. е. ссылки получаются дублирующими и доступными для всех клиентов, включая "роботов".
Если перейти во вложенный раздел, то ссылки соответственно поменяют "#SECTION_ID#" в URL.
Однако позже выяснилось, что при включении параметра "SHOW_ALL_WO_SECTION" ситуация меняется. Ссылки начинают формироваться в соответствии с ID группы, заданной для элемента в таблице `b_iblock_element`. В коде шаблона компонента bitrix:catalog в файле section.php при включении компонента bitrix:catalog.section этот параметр отсутствует, а по умолчанию для компонента он имеет значение "N", поэтому добавляем в section.php одну строку и смотрим на результат.
Но сейчас делаю сайт и там включил опцию SHOW_ALL_WO_SECTION, не зная что она действует на URL после добавления вышеуказанного кода ссылки не изменились, я особого этому значения не предал и просто удалил код.
Хочу поделиться интересным наблюдением поведения простых компонент bitrix:catalog.*. В одном из проектов решили использовать стандартные шаблоны компонентов каталога, хотя и знали о некоторой недоработке их шаблонов.
Одной из задач была возможность управления правами на различные типы цен, в частности "РОЗНИЦА", "ОПТ1" и "ОПТ2". Права выставляются следующие: РОЗНИЦА - права на просмотр/покупку ВСЕМ пользователям, ОПТ1 - права на просмотр ВСЕМ пользователям и покупку группе "Пользователи ОПТ1", ОПТ2 - права на просмотр ВСЕМ пользователям и покупку группе "Пользователи ОПТ2". В такой схеме возникает проблема с минимальной ценой за товарную позицию, а заключается она в том, что компонент выводит минимальную цену без учёта возможности использования её для покупки.
В качестве примера рассмотрим компонент bitrix:catalog.section и стандартный шаблон .default. При наличии у товара значений всех типов цен, компонент выводит в качестве минимального ОПТ2. Значение MIN_PRICE формируется в component.php, а затем используется и выводится в шаблоне.
Собственно в методе CIBlockPriceTools::GetItemPrices присутствует условие CAN_VIEW для типа цен, а вот CAN_BUY отсутствует. Возможно так и было задумано, но нас такое значение не устаивает, поэтому для обновления значения будем использовать result_modifier шаблона и два метода: CIBlockPriceTools::GetCatalogPrices для получения переченя типов цен с параметрами типа и с указанием, возможен ли просмотр и покупка этого типа цен для групп текущего пользователя, а также вышеупомянутый CIBlockPriceTools::GetItemPrices для получения рассчитанных с учетом скидок цен для элемента.
Остаётся лишь в цикле перебрать возвращаемые CIBlockPriceTools::GetCatalogPrices типы цен и выбрать из подходящие под условие задачи, а затем передать оставшиеся в качестве одного из параметров CIBlockPriceTools::GetItemPrices.
Дмитрий, я о другом. Да, компоненты каталога выбирают типы цен, доступные для показа и/или доступные к покупке. Но в корзину попадет цена только из типов цен, доступных к покупке (если Вы не реализовали иную логику). Из Вашего поста следует, что и показывать Вы хотите только цены с возможностью покупки. Для этого в result_modifier идет практически полный пересчет. Я потому и спрашиваю - чем не устроил вариант снять права на просмотр вместо такой тяжелой (по ресурсам сервера) кастомизации?
Понадобилось выгрузить список email адресов покупателей из соответствующего административного раздела. /bitrix/admin/sale_buyers.php
Но вот незадача, полноценной выгрузки единым файлом в системе не предусмотрено. Есть конечно, постраничная выгрузка для "формы отчёта" (списка элементов), но это порядка 20 страниц по 200 строк, т. е. 20 файлов. Но, как оказалось, есть вариант ускорить работу. В частности, смотрим код файла sale_buyers.php и находим вызов метода CSaleUser::GetBuyersList(). Документации по нему найти пока не удалось, возможно она ещё не готова, но суть метода (как я понял) заключается в получении списка покупателей с заданной сортировкой, по заданному фильтру и с возможностью группировки.
Пилецкий Антон, кстати, да. Мы использовали скрипт в "Командной PHP-строке" Битрикса, а там, видимо, требуемые модули подключены. Если кто-то планирует использовать этот код в отдельном файле, то, думаю, достаточно будет и модуля SALE:
В одном из проектов изредка возникают жалобы менеджеров по поводу неполных комментариев к заказам. Некоторые пользователи ограничиваются указанием просьбы перезвонить в комментариях к заказу, а некоторые оставляют большое описание желаемого алгоритма покупки. В частности покупатели указывают желаемое время получения заказа, альтернативные контактные данные и различные вопросы.
Рассмотрев поле "Комментарии покупателя" повнимательнее, выяснили, что в базе данных под это поле отведён тип VARCHAR(250), поэтому весь текст, который превышает этот лимит попросту игнорируется СУБД.
После создания заказа вызывается событие OnOrderAdd, в обработчик которого передаются параметры $ID и $arFields. Оценив эти параметры, выяснили, что в $arFields по ключу "USER_DESCRIPTION" содержится полный текст пользовательского комментария к заказу, соотвественно можно использовать это событие для реализации задуманного.
Начали искать способ хранения пользовательских комментариев "вне заказа". Оказалось, что свойства заказа также имеют ограничения на уровне СУБД.
Следующим вариантом хранения был выбран модуль Веб-формы. Для этого создаётся веб-форма с двумя полями: `order` (Integer) и `comments` (text). Так как модуль веб-форм работает в расширенном режиме, пришлось создать ещё статус "По умолчанию".
Теперь остаётся используя обработчик события OnOrderAdd, при каждом заказе (при заполненных комментариях к этому заказу) сохранять результат в веб-форму.
В результате получаем сохранённые в веб-формах ID заказа и комментарии покупателей. Условие можно усложнить, добавить ограничение и пр. В дальнейшем, в том числе и программно, по ID заказа мы можем получить полный комментарий покупателя.
В частности, если кастомизировать файл с пользовательской формой просмотра заказа и найдя по ID заказа один из результатов веб-форм, можно вывести полный комментарий прямо в эту форму.
Метод CCustomSaleHandlers::getAdditionalOrderFields() сначала ищет соотвествующий заказу результат веб-формы (CFormResult::GetList), а затем получает значения полей этого результата.
p.s. можно не делать модуль, а использовать hl блоки... Но мне, к примеру, они не понравились - неудобно, на одном из проектов использовал для записи цен продавцов - кода и ручных настроек с ними в разы больше.
Sirotin Dmitry, ну не совсем, автоматом не создается там выше закоментирован запрос в бд на создание табла... Но разобраться с созданием модуля и структурой всеже нужно, пригодиться (и приморов уже полно в блогах и инете)... Полное решение я не писал... просто пример сущности и вызовов привел...
Заинтересовал функционал создания кастомных элементов управления в параметрах компонента, а именно тип параметров CUSTOM. В документации данный тип описан очень кратко:
Для типа элемента управления TYPE есть значения:
LIST - ... .
STRING - ... .
CHECKBOX - ... .
CUSTOM - позволяет создавать кастомные элементы управления.
Поиск навёл на интересную статью: произвольный тип параметров компонента в bitrix. Статья содержит описание основных опций данного типа параметров в файле .parameters.php и в качестве примера разбирает компонент map.google.view.
Решили использовать данный тип параметров для механизма комментариев в каталоге (bitrix:catalog.element). Комментарии реализованы с помощью модуля Форум. Идея состоит в том, чтобы указать идентификатор форума не для товара по отдельности, а для целого раздела, а затем в соответствии с разделом элемента каталога, подставлять нужный идентификатор форума в result_modifier.
Задача поставлена, приступаем к реализации. Создаём в файле .parameters.php запись о новом параметре.
Из указанной выше статьи получаем описание опций данного типа параметров.
JS_FILE - файл с JS кодом ответственным за отображение кастомной опции JS_EVENT - callback функция которая будет вызвана после загрузки JS_FILE JS_DATA - будет передана в JS_EVENT
вообще говоря в JS_EVENT будет передано не JS_DATA, а объект
{
data:JS_DATA, //как не трудно догадаться тут будет JS_DATA из .parameters.php
oCont: td, /* контейнер, в котором предлагается размещать кастомный контрол управления параметром */
oInput: input,//input в котором и будет предаваться значение параметра на сервер при сохранении
popertyID:"MAP_DATA",//название параметра
propertyParams: { /*...*/ },//Объект содержащий всё тоже, что и массив параметра в .parameters.php
fChange:function(){ /*...*/ },//callback для вызова, при изменении параметра
getElements:function(){ /*...*/ }//возвращает объект со всеми параметрами компонента
}
Естественно не забываем про обновление языкового файла.
<?php
...
$MESS["F_CUSTOM_FORUMS_LIST"] = "Список форумов для отзывов";
$MESS["F_CUSTOM_FORUMS_LIST_PATH"] = "Путь к файлу списка форумов";
$MESS["F_CUSTOM_FORUMS_LIST_PARAM_EDIT"] = "Изменить";
...
?>
Далее создаём в папке шаблона директорию /settings/. В этой директории создаём скрипт вызова диалогового окна (settings.js) и файл вывода формы редактирования значения параметра (settings.php).
Файл settings.js содержит создание объекта window.jsForumsListEditor, конструктор которого создаёт кнопку вызова диалога и делегирует на неё обработчик (JForumsListEditor.prototype.btnClick). В данном обработчике на основе параметров, переданных в опции JS_DATA, формируется URL и данные POST запроса к файлу-обработчику settings.php.
Также данный файл содержит подключение скрипта settings_load.js и файла-стилей settings.css. Скрипт settings_load.js содержит методы для формирования массива значений параметра (arItems), "ликвидации" повторяющихся значений (tmpArray) и сериализации этих значений в строку (jsFLEditor.__serialize).
Файл settings.css содержит стили кнопки удаления строки (системные стили в диалоговом окне оказались не доступны).
Таким образом механизм обработки параметров данного типа получается следующим: 1. Скрипт-обработчик параметров компонента встречает запись о параметре типа CUSTOM, загружает файл, указанный в опции JS_FILE и вызывает callback-функцию, указанную в опции JS_EVENT. При вызове в функцию передаётся объект с данными, указанными в опции JS_DATA. 2. Callback-функция создаёт объект window.jsForumsListEditor, конструктор которого размещает на основной форме настройки параметров компонента кнопку "Изменить" для редактирования значения параметра.
3. По нажатию на кнопку создаётся и отображается на экране экземпляр окна диалога new BX.CDialog({}). В этом окне, в соответствии с параметрами вызова диалога, подгружается форма редактирования значений (settings.php). 4. После заполнения формы и нажатия на кнопку "Сохранить", выполняется запись значения в сериализованном виде (jsFLEditor.__saveChanges) и закрытие диалогового окна.
Пилецкий Антон, буду рад помочь, если будут вопросы. Хотя за качество кода JS ответить не смогу. Очень сильно "избаловало" использование jQuery, вплоть до того, что минимальный код на "нативном" JS уже вызывает ступор.
В одном из проектов используем для вывода однотипных публикаций один компонент bitrix:news. Меню формируется на основе разделов инфоблока. При выводе цепочки навигации возникает один лишний пункт с названием раздела, в котором расположен компонент вывода.
Соответственно получается, что раздел этот используется только для хранения файла с вызовом компонента и ссылок на него быть не должно.
В качестве решения установили условие на значение параметра START_FROM компонента в зависимости от текущего раздела.
Пункт "Главная" в цепочке навигации располагается в шаблоне компонента и выводится вне зависимости от содержимого массива пунктов. Теперь получается, что для раздела "Публикации" номер пункта, начиная с которого будет построена навигационная цепочка, на единицу больше, а навигационная цепочка принимает требуемый вид.
В справочном руководстве описывается вариант решения в виде:
Примечание: Для того чтобы ссылка на какой-либо раздел не выводилась в навигационной цепочке сайта, нужно удалить название раздела из поля Заголовок и сохранить внесенные изменения.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».