Михаил Базаров Разработка на 1С-Битрикс Михаил Базаров

Вывести дату окончания скидки в карточке товара

Просмотров: 7248 Вывести информацию о скидке в карточке товара, методом CCatalogDiscount::GetList. Данный метод позволяет получить любую информацию о скидке. Заметка написана в 2019 году. В 2026 дописал способ через D7 \Bitrix\Catalog\DiscountTable

Получаем информацию о скидке. Старый способ

Для начала, создаем скидку с интевалом в модуле маркетинга и выводим всю информацию о ней, в карточке товара:

$PRODUCT_ID = $arResult['ID'];
$dbProductDiscounts = CCatalogDiscount::GetList(
    array("SORT" => "ASC"),
    array(
            "+PRODUCT_ID" => $PRODUCT_ID,
            "ACTIVE" => "Y",
        ),
    false,
    false,
    array(
            "ID", 
            "SITE_ID", 
            "ACTIVE", 
            "ACTIVE_FROM", 
            "ACTIVE_TO", 
            "RENEWAL", 
            "NAME", 
            "SORT", 
            "MAX_DISCOUNT", 
            "VALUE_TYPE", 
            "VALUE", 
            "CURRENCY"
        )
    );
while ($arProductDiscounts = $dbProductDiscounts->Fetch())
{
   print_r($arProductDiscounts)
}

В массиве arProductDiscounts - распечатается вся доступная информация о скидке. Но нам нужна только дата завершения- ACTIVE_TO. Эту дату сразу загоняем в переменную $saleDateTo. Обратите внимание, что если скидка уже осталась в прошлом- дата выведется в любом случае. Что бы этого не происходило, в фильтре оставляем отбор по активности "ACTIVE" => "Y" (флаг активности у прошедших скидок,снимается автоматически).


$dbProductDiscounts = CCatalogDiscount::GetList(
    array("SORT" => "ASC"),
    array(
        "+PRODUCT_ID" => $arResult['ID'],
        "ACTIVE" => "Y"
    ),
    false,
    false,
    array(
        "ACTIVE_TO"
    )
);
while ($arProductDiscounts = $dbProductDiscounts->Fetch()) {
        $saleDateTo = $arProductDiscounts['ACTIVE_TO'];
}

Собственно, если нужно просто вывести дату. Выводим переменную $saleDateTo в нужном месте шаблона. Более актуально, вывести количество дней до конца скидки. При этом, если осталось меньше одного дня, выводит "закончится сегодня".

Просто высчитываем разницу между текущей датой и датой завершения активности скидки. Подсказки в комментариях:


$diffSaleToDate = strtotime($saleDateTo) - strtotime(date("d.m.Y h:m:s"));
$saleEndDiff = floor($diffSaleToDate / 86000);
if ($saleEndDiff > 1) {
    $daysToEndSale = 'Закончится через ' . $saleEndDiff . ' дн.';
} elseif ($saleEndDiff = 1) {
    $daysToEndSale = 'Закончится сегодня';
} else {
    unset($saleEndDiff);
}

Работа со скидками через D7 \Bitrix\Catalog\DiscountTable

Если нужно вывести информацию о скидке в карточке товара, раньше для этого использовали метод CCatalogDiscount::GetList, но сейчас правильнее работать через D7 - \Bitrix\Catalog\DiscountTable. Он даёт тот же результат, но работает через ORM, поддерживает кеширование и не помечен как устаревший.

Самое актуальное - вывести дату окончания скидки или количество дней до её завершения. Чтобы покупатель видел: "Успевай, скидка скоро сгорит".

Получаем информацию о скидке

Создаём скидку с интервалом в модуле "Маркетинг" и выводим информацию о ней в карточке товара через D7:

<?
use Bitrix\Catalog\DiscountTable;
use Bitrix\Main\Loader;

$PRODUCT_ID = $arResult['ID'];

if (!Loader::includeModule('catalog')) {
    return;
}

$discountIterator = DiscountTable::getList([
    'filter' => [
        '=ACTIVE' => 'Y',
        '=%SITE_ID' => SITE_ID,
        [
            'LOGIC' => 'OR',
            ['=PRODUCT_ID' => $PRODUCT_ID],
            ['=PRODUCT_ID' => false], // скидка на всю корзину
        ],
    ],
    'select' => [
        'ID', 'NAME', 'ACTIVE_FROM', 'ACTIVE_TO',
        'VALUE_TYPE', 'VALUE', 'CURRENCY', 'MAX_DISCOUNT',
    ],
    'order' => ['SORT' => 'ASC'],
]);

while ($discount = $discountIterator->fetch()) {
    print_r($discount);
}
?>

В массиве $discount - вся информация о скидке. Нам нужна только дата завершения - ACTIVE_TO. Загоняем её в переменную $saleDateTo.

Обратите внимание: в D7 дата приходит уже объектом Bitrix\Main\Type\DateTime, а не строкой, как в старом API. Это удобнее - можно сразу сравнивать, форматировать и конвертировать без костылей.

Если скидка уже прошла - флаг ACTIVE снимается автоматически, поэтому в выдачу она не попадёт. Дополнительно можно отфильтровать по сайту.

<?
$discountIterator = DiscountTable::getList([
    'filter' => [
        '=ACTIVE' => 'Y',
        '=%SITE_ID' => SITE_ID,
        ['=PRODUCT_ID' => $arResult['ID']],
    ],
    'select' => ['ACTIVE_TO'],
    'order' => ['SORT' => 'ASC'],
    'limit' => 1,
]);

if ($discount = $discountIterator->fetch()) {
    $saleDateTo = $discount['ACTIVE_TO']; // объект Bitrix\Main\Type\DateTime
}
?>

Дальше выводим $saleDateTo в нужном месте шаблона. Можно отформатировать через format():

<?=$saleDateTo->format('d.m.Y')?>

Выводим количество дней до конца скидки

Ещё актуальнее - показать не просто дату, а сколько дней осталось. Если осталось меньше одного дня - пишем "закончится сегодня".

Используем D7-шный DateTime, чтобы нормально посчитать разницу:

<?
use Bitrix\Main\Type\DateTime;

$now = new DateTime();

if ($saleDateTo instanceof DateTime) {
    $diff = $now->getDiff($saleDateTo);
    $daysLeft = (int)$diff->days;

    if ($daysLeft > 1) {
        $daysToEndSale = 'Закончится через ' . $daysLeft . ' дн.';
    } elseif ($daysLeft == 1) {
        $daysToEndSale = 'Закончится завтра';
    } elseif ($daysLeft == 0) {
        $daysToEndSale = 'Закончится сегодня';
    } else {
        $daysToEndSale = '';
    }
}
?>

Здесь getDiff() возвращает объект DateInterval, у которого есть свойство days - количество полных дней между датами. Надёжнее, чем делить секунды на 86400, потому что учитывает перевод часов и летнее время.

В переменной $daysToEndSale - готовый текст. Выводим и оформляем где нужно:

<?if ($daysToEndSale):?>
    <div class="discount-timer">
        <?=$daysToEndSale?>
    </div>
<?endif;?>

Кеширование (чтобы не дёргать базу на каждом хите)

Запрос к DiscountTable на каждом показе товара - лишняя нагрузка. Битрикс умеет кешировать через CacheManager:

<?
use Bitrix\Main\Data\Cache;
use Bitrix\Catalog\DiscountTable;

$cache = Cache::createInstance();
$cacheKey = 'discount_date_' . $PRODUCT_ID;
$cacheDir = '/discounts';

if ($cache->initCache(3600, $cacheKey, $cacheDir)) {
    $saleDateTo = $cache->getVars()['saleDateTo'];
} elseif ($cache->startDataCache()) {
    $discountIterator = DiscountTable::getList([
        'filter' => [
            '=ACTIVE' => 'Y',
            '=%SITE_ID' => SITE_ID,
            ['=PRODUCT_ID' => $PRODUCT_ID],
        ],
        'select' => ['ACTIVE_TO'],
        'order' => ['SORT' => 'ASC'],
        'limit' => 1,
    ]);

    $saleDateTo = null;
    if ($discount = $discountIterator->fetch()) {
        $saleDateTo = $discount['ACTIVE_TO'];
    }

    $cache->endDataCache(['saleDateTo' => $saleDateTo]);
}
?>

Если скидка привязана не к товару, а к цене

Бывает, что скидка висит на типе цены (например, "Оптовая цена - 20%") и не привязана к конкретному товару через PRODUCT_ID. В этом случае искать через DiscountTable бесполезно - нужно лезть в \Bitrix\Catalog\PriceTable и проверять PRICE против BASE_PRICE:

<?
use Bitrix\Catalog\PriceTable;
use Bitrix\Catalog\GroupTable;

$baseGroupId = GroupTable::getBasePriceGroup(); // ID базового типа цены
$priceIterator = PriceTable::getList([
    'filter' => [
        '=PRODUCT_ID' => $PRODUCT_ID,
        '!=CATALOG_GROUP_ID' => $baseGroupId,
    ],
    'select' => [
        'PRICE', 'CURRENCY',
        'CATALOG_GROUP_ID',
        'CATALOG_GROUP.NAME',
    ],
]);

while ($price = $priceIterator->fetch()) {
    // Тут уже другая история - проценты и наценки
    // Можно вывести: "Цена по акции: X руб."
}
?>

Красивый обратный отсчёт (опционально)

Если хочется не просто текст, а живой таймер - передаём Unix-штамп в JavaScript и крутим на клиенте:

<?if ($saleDateTo instanceof DateTime):?>
    <div class="discount-timer"
         data-until="<?=$saleDateTo->getTimestamp()?>"
         data-label="до конца скидки"></div>
<?endif;?>

А на JS навешиваете любой счётчик - это уже дело вкуса и фронта.

Итог

Старый CCatalogDiscount::GetList работает, но D7-версия удобнее:

  • даты сразу приходят объектами DateTime, не надо парсить строки
  • фильтры читаемые, а не магические массивы с плюсами
  • результат можно кешировать штатными средствами
  • не нужен strtotime и деление на 86400 - всё считает getDiff()

Услуги Стоимость разработки на 1С-Битрикс

Стоимость разработки сайта зависит от объёма и сложности проекта. Ниже приведены ориентировочные цены, как правило не выходят за обозначенные рамки. Срок разработки зависит от сложности проекта: как правило называю сроки с запасом.
Финальная стоимость и сроки разработки обговариваются на этапе обсуждения. Скачайте опросник на разработку, заполните как можно подробнее и вышлите удобным способом. После ознакомления смогу задать уточняющие вопросы и оценить проект.
Индивидуальная разработка магазина
от 300 000 руб. от 5-ти недель

Разработка магазина на 1С-Битрикс с нуля. Дизайн, сборка и оптимизация производительности под конкретный проект и требования. Реализация любого функционала без ограничений готовых решений.

Подробнее
Сайт на готовом решении 1С-Битрикс
от 70 000 руб. от 5-ти дней

Вариант для тех, кто не хочет тратить много средств на индивидуальный проект, и не имеет серьезных требований к сайту. Магазин, быстро запускается на базе одного из 200-та готовых решений.

Подробнее
Мобильное приложение
от 300 000 руб. от 4-х недель

Разработка кроссплатформенного мобильного приложения, которое не уступает нативным решениям как в производительности, так и пользовательском опыте. Публикуется в AppStore, GooglePlay и RuStore

Подробнее
Сайт компании
от 150 000 руб. от 2-х недель

Корпоративный сайт с информационными разделами, каталогом товаров или услуг. Включает формы обратной связи карточек каталога, любое количество статичных и динамичных разделов.

Подробнее
Инфоресурс
от 170 000 руб. от 3-х недель

Информационный ресурс любой сложности. Сайт для СМИ, городской портал или многопользовательская доска объявлений. Внутренние форумы, блоги- по необходимости.

Подробнее
Поддержка и доработки проектов
от 3 000 руб. от 1 часа

Выполнение доработок любой сложности. Поддержка, модернизация и расширение функционала существующих проектов. Решение задач: от мелких правок вёрстки до разработки новых модулей.

Подробнее

Включено в стоимость разработки:

  • Лицензия на 1С-Битрикс необходимой редакции, дополнительные модули, для реализации функционала и видео-инструкции по работе с готовым проектом
  • Оптимизация программной части проекта и конфигурации сервера под максимальную скорость работы. Базовая СЕО оптимизация и добавление сайта в поисковые системы.

Блог-note Заметки по 1С-Битрикс