- Проблема бизнеса
- Почему стандартные средства OpenCart не подходят
- Наше решение: архитектура и преимущества
- Реализация: от backend к frontend
- Изменения в модели (работа со скидками)
- Логика определения праздничной цены
- Интеграция с корзиной и заказом (безопасность)
- Динамическое обновление на фронтенде (AJAX, Pickadate)
- Особые случаи: составные товары и автоматизация опций
- Результат и выгоды для бизнеса
- Заключение
- Вопросы и ответы (FAQ)
Проблема бизнеса
К нам обратился владелец крупного цветочного магазина с очень распространённой, но при этом крайне болезненной бизнес-проблемой. Каждый год, к ключевым праздникам — 14 февраля, 8 марта, 1 сентября — цены на цветы резко вырастают из-за сезонного спроса и высокой закупочной стоимости.
Однако покупатели начинают оформлять заказы заранее, иногда за 3–7 дней до праздника, когда действуют ещё обычные «непраздничные» цены. В итоге менеджерам приходилось лично связываться с клиентами и объяснять, что:
- Цена заказа увеличится и потребуется доплата;
- Букеты по указанной цене недоступны для праздничной даты;
- Некоторые цветы отсутствуют в праздничные дни и будут заменены.
Это вызывало конфликты, недовольство клиентов, потери и репутационные риски. Магазин искал способ автоматизировать процесс и избежать ручных корректировок.
Цена должна зависеть не от текущего дня, а от даты доставки, выбранной самим покупателем.
На первый взгляд решение кажется очевидным, однако движок OpenCart не поддерживает динамическую смену цены по выбранной дате — только по текущей. Из-за этого стандартные скидки OpenCart совершенно не подходят для праздничных сценариев.
Почему стандартные средства OpenCart не подходят
OpenCart применяет скидки по очень простой логике:
[code lang=php] if ($discount['date_start'] <= date('Y-m-d') && $discount['date_end'] >= date('Y-m-d')) { $price = $discount['price']; } [/code]Скидка рассчитывается всегда исходя из текущей даты, а не из даты, которую выбирает покупатель.
В реальном кейсе это выглядело так:
- 10 февраля покупатель оформляет заказ
- Выбирает доставку на 14 февраля
- Цена должна быть праздничной (дороже)
- Но система применяет цену 10 февраля
Если доставка выпадает на праздничный период — цена должна пересчитаться автоматически.
Наше решение: архитектура и преимущества
Не изобретать свой механизм цен, а раскрыть потенциал стандартного OpenCart, добавив недостающий слой логики.
Мы использовали существующие сущности OpenCart и дополнили их «умным» поведением:
- Вкладка «Скидки» — стала хранилищем праздничных цен, т.к. уже поддерживает диапазон дат (date_start / date_end) и разные группы покупателей.
- Опция типа «Дата» — стала источником даты доставки, которую выбирает клиент.
- AJAX-пересчет цены — срабатывает, когда клиент выбирает дату, и возвращает корректную цену.
- Пересчёт цены в корзине и заказе — обязательный backend-контроль, чтобы никто не обошёл праздничную цену.
- Автоматическое управление опцией «Дата» — если у товара появились скидки с датами, опция Дата включается автоматически.
- Поддержка составных товаров (композитов) — праздничная цена рассчитывается из цен компонентов.


Почему такое решение оказалось идеальным
Работа полностью через OCMOD, без переписи системных классов.
Работает с любыми версиями шаблона UniTheme / UniStore, любыми модулями корзины и SEO-расширениями.
Можно добавлять сколько угодно праздничных периодов и групп клиентов.
Менеджер работает в стандартной админке OpenCart и не учится новому интерфейсу.
Как это выглядит с точки зрения данных
Менеджер создаёт скидку:
- Цена — праздничная цена
- Количество = 1
- Дата начала / дата конца — период праздника
Покупатель выбирает:
- Доставить 14.02.2026
AJAX отправляет эту дату → PHP получает её → ищет скидку именно для этого дня → возвращает корректную цену.
Даже если покупатель подменит AJAX-запрос, cart.php пересчитает цену заново.
Реализация: от backend к frontend
Изменения в модели (работа со скидками)
По умолчанию OpenCart отдаёт только активные на текущий день скидки. Для праздничной логики это неприемлемо — нам нужно видеть все будущие периоды скидок.
Поэтому мы добавили отдельный метод:
[code lang=php] public function getProductDiscountsWithDates($product_id) { $query = $this->db->query(" SELECT product_discount_id, product_id, customer_group_id, quantity, priority, price, date_start, date_end FROM " . DB_PREFIX . "product_discount WHERE product_id = '" . (int)$product_id . "' AND customer_group_id = '" . (int)$this->config->get('config_customer_group_id') . "' ORDER BY quantity ASC, priority ASC, price ASC "); return $query->rows; } [/code]Логика определения праздничной цены
Сначала нужно обработать дату от фронтенда. Фронтенд отдаёт дату в формате:
dd/mm/yyyy
Например:
14/02/2026
Backend должен перевести это в формат MySQL:
yyyy-mm-dd
Например: 2026-02-14
[code lang=php] if (preg_match('/^\d{2}/\d{2}/\d{4}$/', $posted_date)) { $parts = explode('/', $posted_date); if (checkdate($parts[1], $parts[0], $parts[2])) { $selected_date = $parts[2] . '-' . $parts[1] . '-' . $parts[0]; } } [/code]
Теперь, когда дата доставки обработана, мы ищем подходящий период:
[code lang=php] foreach ($discounts as $discount) { if (!empty($discount['date_start']) && !empty($discount['date_end'])) { if ($selected_date >= $discount['date_start'] && $selected_date <= $discount['date_end']) { $holiday_price = $discount['price']; $discount_period_info = sprintf( "Период праздничных цен: %s - %s", date('d.m.Y', strtotime($discount['date_start'])), date('d.m.Y', strtotime($discount['date_end'])) ); break; } } } [/code]Сохранение даты в сессию
Чтобы покупатель при переходе по товарам не выбирал дату заново — она сохраняется:
[code lang=php] $this->session->data['delivery_date'] = $selected_date; [/code]Это позволяет:
- ✔ подтягивать дату в календарь автоматически
- ✔ использовать её в корзине
- ✔ использовать в checkout
- ✔ пересчитывать цены постоянно в одном контексте
Интеграция с корзиной и заказом (безопасность)
Даже если пользователь отключит JavaScript, все цены обязательно будут пересчитаны на сервере.
В system/library/cart/cart.php:
[code lang=php] if ($holiday_price !== null) { // применяем праздничную цену $price = $holiday_price; } else { // fallback: обычная цена или скидка по количеству } [/code]Даже если злоумышленник попытается подменить JS или отправить запрос вручную — сервер всегда проставит правильную цену.
Backend защищает от:
- подмены фронтенда
- попыток оплатить товар по неактуальной цене
- некорректных сумм в письмах
- ошибок в заказах в админке
Динамическое обновление на фронтенде (AJAX, Pickadate)
Когда покупатель выбирает дату доставки — нужно мгновенно пересчитать цену, не перезагружая страницу. Для этого мы реализовали несколько логичных и аккуратных шагов.
1. Отправка опций и даты на сервер
При каждом изменении в карточке товара (в том числе выборе даты) вызывается AJAX-функция:
[code lang=js] function updateProductPrice() { let formData = $('#product input[type="text"], \ #product input[type="hidden"]:not("#uni_purchase_byoneclick_form_product input"), \ #product input[type="radio"]:checked, \ #product input[type="checkbox"]:checked, \ #product select, \ #product .uni-datepicker input[type="text"]').serialize(); $.ajax({ type: 'post', url: 'index.php?route=unitemplate/main/uni_functions/updatePrices', data: formData, dataType: 'json', cache: false, success: function(json) { // Обновление цены $('#product .sc-module-price').html(json['price']); if (json['special']) { $('#product .sc-module-price-old').html(json['price']); $('#product .sc-module-price').html(json['special']); } // Отображение информации о праздничном периоде $('.sc-holiday-price-info').remove(); if (json['discount_period']) { $('.datepicker-tooltip-info').append( '<div class="sc-holiday-price-info d-flex align-items-center mt-2 mb-2">' + '<i class="fa fa-gift text-danger me-2"></i>' + '<span class="fsz-12 fw-500 dark-text">' + json['discount_period'] + '</span>' + '</div>' ); } // Автозаполнение календаря, если пришла дата из сессии if (json['delivery_date']) { const [y, m, d] = json['delivery_date'].split('-'); const $dateInput = $('#product .uni-datepicker input[type="text"]'); if ($dateInput.length) { let picker = $dateInput.pickadate('picker'); if (picker && picker.get('select') === null) { picker.set('select', [parseInt(y), parseInt(m)-1, parseInt(d)]); } } } } }); } [/code]При каждом изменении опций товар общается с сервером и получает актуальную цену по выбранной дате.
2. Инициализация календаря Pickadate
Мы подключаем кастомный календарь:
[code lang=js] productDatePicker = $dateInput.pickadate({ format: 'dd/mm/yyyy', formatSubmit: 'dd/mm/yyyy', firstDay: 1, max: 90, min: true, monthsFull: ['Январь','Февраль','Март','Апрель','Май','Июнь', 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], weekdaysShort: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], today: 'Сегодня', clear: 'Очистить', close: 'Закрыть', hiddenName: true, onSet: function(ctx) { if (ctx.select || ctx.hasOwnProperty('clear')) { setTimeout(updateProductPrice, 50); } } }).pickadate('picker'); [/code]3. Автоматический запуск при загрузке страницы
Если на товаре есть обязательная дата доставки — нужно рассчитать цену сразу.
[code lang=js] $(document).ready(function() { const $dateInput = $('#product .uni-datepicker input[type="text"]'); if ($dateInput.length > 0 && !$dateInput.val()) { updateProductPrice(); // первый расчет } }); [/code]Это удобно, когда:
- • клиент вернулся из корзины
- • дата уже лежит в сессии
- • нужно сразу показать праздничную цену
Особые случаи: составные товары и автоматизация опций
Автоматическая работа с составными товарами
- Все комплекты получают праздничные цены автоматически
- Администратору не нужно ничего менять вручную
- Логика полностью встроена в OpenCart
Автоматическое управление опцией "Дата"
[code lang=php] if ($has_holiday_discount && !$has_date_option) { INSERT INTO product_option ... } elseif (!$has_holiday_discount && $has_date_option) { DELETE FROM product_option ... } [/code]Интеграция с быстрой покупкой и checkout
[code lang=php] $custom_field[10] = $formatted_date; // Дата доставки $custom_field[4] = $formatted_date; // Дата самовывоза [/code]- Покупатель выбирает дату один раз
- Все формы на сайте автоматически заполняются
Результат и выгоды для бизнеса
Менеджеры больше не тратят время на объяснение изменений цен и не вызывают недовольство клиентов. Все процессы автоматизированы.
Цена ясна сразу при выборе даты доставки. Никаких скрытых доплат и сюрпризов при оформлении заказа.
Система автоматически масштабируется на любые праздники и сезонные периоды. Просто добавляйте новые скидки в админке.
- Полностью решена проблема праздничных цен
- Работает через штатные механизмы OpenCart
- Не ломает ядро и совместима с другими модулями
- Поддерживает составные товары и автоматизацию
- Запоминает дату доставки на всех этапах заказа
- Обновляет цены в реальном времени без перезагрузки
- Корректно рассчитывает цену на всех этапах заказа
Покупатель теперь всегда видит правильную цену для своей даты.
Менеджеры больше не перезванивают клиентам.
Бизнес получил автоматизацию и точность.
Заключение
Готовы автоматизировать сезонное ценообразование в вашем магазине?
Если вы сталкиваетесь с похожими проблемами в вашем интернет-магазине на OpenCart, команда Uni Opencart готова помочь вам создать эффективное решение.
Что мы предлагаем:
- Индивидуальные доработки под ваш бизнес
- Оптимизацию существующих решений
- Техническую поддержку 24/7
- Гарантию на все работы
Наши преимущества:
- Более 10 лет опыта работы с OpenCart
- Специализация на технических доработках
- Минимальное вмешательство в ядро
- Совместимость с популярными шаблонами