...
...

Индивидуальные цены: Как мы это накодили.

Ready.KZ: Готовые сайты

Описание
Здравствуйте, друзья. Сегодня хотелось бы немного вам рассказать о том, как мы решаем проблемы не только наших клиентов в частности, но и Битрикса в целом. И речь пойдет о индивидуальных ценах.


Проблема.
Не так давно возникла необходимость решить одну задачу – как сделать так, чтобы в каталоге товаров для каждого пользователя (читай – контрагента) выводилась индивидуальная цена? Признаться, ответить на этот вопрос удалось не сразу. Клиенты все чаще стали спрашивать нас об этом, и мы пришли к выводу, что вопрос с индивидуальными ценами больше нельзя оставлять в стороне и пора бы его уже решить.
План действий.
Суть проблемы мы уловили довольно быстро. Но одно дело сформулировать суть, и совсем другое дело учесть при этом все возможные варианты, просчитать последствия, и понять, что будет в перспективе. Что же делать? Составить план:

1. Постановка задачи.
С задачей определились – нужно сделать так, чтобы в каталоге для каждого пользователя (читай – контрагента) можно было отображать индивидуальную цену на товар. Немного подумав, решили, что на цену будут влиять два фактора: некий идентификатор пользователя и идентификатор товара соответственно. В качестве идентификатора необходимо использовать некое поле, которое уникально для каждой сущности (товар, пользователь). Если поддаться порыву и долго не думать, то можно взять ID товара и ID пользователя.

Но мы быстро смекнули, что все данные будут выгружаться на сайт из 1С, а, значит, в качестве идентификатора уместнее взять XML_ID (внешний код) товара и пользователя. Ну а после уже добавить еще одну переменную, которая могла бы влиять на цену товара – внешний код склада.

Стоит отметить, что бывают такие магазины, у которых нет склада. И мы не можем их игнорировать. Но об этом моменте мы расскажем чуть позднее, когда пойдет речь о настройках модуля.

2. Почему нельзя сделать все на стандартах 1С-Битрикс?
Разработка любого решения под 1С-Битрикс начинается с вопроса: «А можно ли реализовать требуемый функционал, используя мощности самой платформы?». В нашем случае ответ прост и неутешителен: «Нельзя». Почему? На это есть минимум 2 причины.
Причина первая.
Стандартный каталог на Битрикс работает с типами цен и группами пользователей, для которых он и отображает те или иные цены. Но нам необходима индивидуальная цена для каждого пользователя. Что же делать?

Самое очевидное – создать для каждого пользователя свою группу и, соответственно, для каждой из них выставить отдельный тип цены. Звучит совсем несложно. Если только вы не разработчик. Потому что только они за этой парой предложений видят реальные масштабы и проблемы этого действа.  

Только представьте, что у вас на сайте 100 пользователей (смешная цифра для современного бизнеса, конечно, но тем наглядней будет пример). Берем и создаем для них 100 групп. Даже руками – это не так уж и сложно, конечно, и – дешевле, чем какой-то модуль в Маркетплейсе, само собой. Поскольку групп у нас 100 (по числу пользователей), это значит, что нужно назначить 100 типов цен.

На этом моменте некоторые из вас уже могут призадуматься – а стоит ли возиться, но большинство все же будут стоять на своем. И делать все руками. Итак, в нашей формуле не хватает еще одной переменной – количество товаров. Просто предположим, что у вас их 300.
Только вдумайтесь 30.000 полей необходимо заполнить вручную, да еще и обновлять периодически. Но и тут тоже есть несколько вариантов:
  • посвятить всю свою жизнь редактированию цен;
  • нанять специалиста, который захочет за скромную плату (вы же экономить собираетесь!) потратить свою жизнь на редактирование цен товаров вашего магазина;
  • нанять разработчика (фрилансера), что бы тот написал скриптов (обработчиков) под ваши нужды, которые будут все это делать за вас – добавлять и обновлять цены;
  • все-таки купить готовое решение.
Если углубиться в детали, то можно заметить, что данный список отсортирован по убыванию финансовых затрат. Выходит, что покупка готового модуля – это и есть самый выгодный вариант. Кто-то может резонно возразить, мол, модуль же делается под нужды большинства, а, значит, в нем может чего-то не хватать, или же наоборот – будет лишний функционал. На это мы можем ответить только одно – мы модуль разработали, значит, и адаптировать его сможем под любого заказчика.

По итогу мы пришли к следующему. Каталог работает только с группами пользователей, но никак не с самими пользователями, а тем более не с их профилями. А это идет в разрез с поставленной задачей. Кроме этого, стандартный каталог не может изменять цены в зависимости от выбранного склада, что нас тоже не устраивает.
Причина вторая.
Использование стандартных инструментов подразумевает отключение кеширования каталога (что неправильно, ведь это одно из ключевых преимуществ Битрикса), что, в свою очередь, неизбежно приведет к потере дискового пространства – даже не успеете оглянуться, как свободное место исчезнет (файлы кэша будут создаваться для каждого пользователя). Поэтому отключение кеширования – поступок не только неразумный, но и опасный. Можно, конечно, все время чистить кеш руками, но это опять же чревато потерей массы времени, которое, как все знают, деньги.

3. Какие варианты решения вообще могут быть.
Когда задача сформулирована и решение о разработке принято, наступает самая интересная и насыщенная часть работы – найти возможные пути реализации. Поскольку к этому моменту мы рассматривали технологию композитного сайта, то первой мыслью была возможность менять цены таким же образом.

Но свежи были еще воспоминания о написании модуля «Интеграция с CRM Битрикс24», где пришлось не раз столкнуться с любимым ответом облака «too many requests». Сюда же присовокупился опыт работы с сайтами, где эта фраза возникала с завидной периодичностью и без дополнительных запросов. Поэтому использование ajax для обновления цен было отвергнуто. Хотя позже мы узнали, что кто-то уже попытался реализовать подобную задачу, используя ajax.

Идея вторая – отложенные функции. Как вы понимаете, этот вариант нас тоже не устроил. И причина на это одна, но весомая. Суть в том, что отложенные функции не работают в кеше, а мы уже решили, что без кеша решение – не решение. Кеш должен работать, а шоу – продолжаться.

И вот мы вплотную подошли к тому варианту, на котором и остановились. В двух словах суть идеи следующая – ставим метку, а после собираем все метки и делаем всего один запрос к базе, чтобы заменить метки на цены. Но ведь нам неинтересно в двух словах, правда? Поэтому дальше будет более подробный рассказ.

4. Как мы все это делали.
Раздумывая над идеей с метками, мы пришли к нескольким ключевым моментам:
  • Для магазина с большим каталогом и большим количеством пользователей количество записей в таблице тоже будет немаленьким. Тогда как долго будет происходить выборка?
  • Как поставить метку?
  • Когда производить замену цен?
Разбив таким образом задачу на подпункты, мы принялись разбираться с ними. И вот что вышло.
Время выборки.
Поставленный вопрос требовал эксперимента, поэтому была создана и заполнена таблица в базе данных MYSQL. Для примера был взят условный магазин с товарной номенклатурой в 50 000 товаров и с 10 000 пользователей. Получили 500 млн. записей соответственно. Такое количество записей нам показалось не очень внушительным, и мы решили создать 2.5 млрд записей (создавать пришлось долго, но чего не сделаешь ради эксперимента).

В итоге выборка по ключевым полям производилась за 0,1 сек., но если в выборку добавлять неключевое поле, то окончания выборки дождаться не удавалось. По итогу мы пришли к более или менее разумному времени выборки – меньше 0,04 сек., что совсем не отражается на загрузке страницы, а для кеширования запросов использовали ядро D7.
Каким образом ставить метку?
Не мудрствуя лукаво, метку мы решили ставить следующим образом. Находим место, где в шаблоне стоит цена и заменяем ее кодом:

Первой строкой мы проверяем, подключен ли модуль. А второй строкой передаем в модуль идентификатор товара и его цену, модуль проставляет метку туда, где вызывается метод. При этом модуль запоминает цену товара для его идентификатора на случай, если она не будет найдена в таблице с индивидуальными ценами.
Когда производить замену меток?
Первое, что пришло в голову, это вызывать процедуру замены меток на цены после компонента «каталог». Но тогда непонятно, а как же быть с другими компонентами? Такими как «похожие товары» или «недавно просмотренные товары», например. После каждого из них тоже пришлось бы вызывать процедуру – а это еще как минимум по одному запросу. А необходимо сделать все красиво и уложиться в один запрос.

И мы подумали еще немного. И пришли к выводу, что нужно добавить обработку события «OnEndBufferContent» модуля «main». В данном событии у нас находится весь html страницы со всеми нашими метками, и уже не важно, из какого компонента они были поставлены.

Собрать все метки не составило особого труда и вот уже у нас готовый и красивый список идентификаторов товаров. Для запроса нам не хватает только идентификатора профиля пользователя. В одном из наших модулей sotbit.client была уже реализована возможность выборки профиля, после чего идентификатор профиля записывается в сессию. Получить его в модуле также не составляет труда.

Не забыли мы и про то, что в исходной задаче у нас что-то говорилось про необходимость учитывать склад. Его идентификатор мы берем также из сессии, куда он попадает при выборе местоположения.

Делаем запрос. Собираем массив типа array (<метка> => <цена> ) . Если в запросе заполнили не все метки, то дополняем их ценами из шаблона. Заменяем метки на цены и отдаем html на экран. Максимальное время выполнения всей это процедуры 0,04 сек. А если в ход идет кеширование запросов – то время измеряется в тысячных частях секунды и даже меньше!

А тем, кто не верит, вот вам вырезка из логов. Количество записей в таблице 7000+.
Кроме всего прочего, в модуле обрабатывается событие добавление в корзину. А все для того, чтобы индивидуальные цены учитывались при добавлении товара в эту самую корзину. Как? А вот как. На одном из проектов реализована выгрузка цен из 1С:
  • 1С выгружает цены в xml файлы на сервер;
  • В конце выгрузки 1С отправляет запрос на api, в котором сообщает нашему модулю «Парсер контента», что все готово;
  • И дальше наш «Парсер» обновляет цены в таблице. В настройках модуля вынесен выбор hl-блока, где хранятся цены с настройкой ключевых колонок. Если в складе поставить пустое значение (...), то склад в выборке участвовать не будет соответственно.

5. Заключение.
И так происходит почти каждый раз. В отдел разработки приходит задача, мы ее разбираем, ищем, пробуем, экспериментируем, танцуем вокруг Битрикса и находим, порой, весьма нетривиальные решения. Просто потому, что мы можем! А еще потому что мы команда и любим свою работу. На этом все, с вами был отдел разработки Сотбит! До скорых встреч!

Оригинал статьи вы можете найти на нашем сайте.

Получить консультацию можно любым удобным для вас способом:


с помощью соц. сетей, мессенджеров, либо онлайн-чата на нашем сайте


             
...
...
...