Получить цены товара и выбрать актуальную
Получение всех цен товара через CPrice::GetList с фильтрацией по типу цены и выбором актуальной цены с учётом скидок.
Как использовать
- Все цены: getProductPrices($productId) или getProductPrices($productId, $priceTypeId) для одного типа.
- Актуальная цена со скидками: getActualProductPrice($productId, $quantity, $userId); для гостя передайте userId = 0.
- Модули catalog и для скидок sale должны быть подключены.
В каталоге 1С-Битрикс у товара может быть несколько записей цен (разные типы, пороги количества). Для отображения в карточке и корзине нужны либо все цены по типам, либо одна актуальная с учётом скидок и количества. Проблема: если брать только первую запись из CPrice без учёта скидок, пользователь видит цену без скидки; при нескольких типах цен без фильтра сложно показать «от» или цену нужного типа. Симптомы: завышенная цена, скидка не отображается, неверная валюта. Ниже — получение списка цен через CPrice::GetList (с опциональной фильтрацией по типу) и получение актуальной цены через GetOptimalPrice (скидки, количество, пользователь); проверка и типичные ошибки.
Решение
Получение цен товара из каталога с выбором актуальной цены. Используйте в компонентах каталога, корзины, детальных страницах.
use Bitrix\Main\Loader;
/**
* Получить все цены товара
* @param int $productId ID товара
* @param int $priceTypeId ID типа цены (опционально)
* @return array Массив цен
*/
function getProductPrices($productId, $priceTypeId = null) {
if (!Loader::includeModule('catalog')) {
return [];
}
$filter = ['PRODUCT_ID' => $productId];
if ($priceTypeId) {
$filter['CATALOG_GROUP_ID'] = $priceTypeId;
}
$res = CPrice::GetList(
['CATALOG_GROUP_ID' => 'ASC'],
$filter
);
$prices = [];
while ($price = $res->Fetch()) {
$prices[] = [
'ID' => $price['ID'],
'PRICE' => $price['PRICE'],
'CURRENCY' => $price['CURRENCY'],
'PRICE_TYPE_ID' => $price['CATALOG_GROUP_ID'],
'QUANTITY_FROM' => $price['QUANTITY_FROM'],
'QUANTITY_TO' => $price['QUANTITY_TO']
];
}
return $prices;
}
/**
* Получить актуальную цену товара с учётом скидок
* @param int $productId ID товара
* @param int $quantity Количество для расчёта (по умолчанию 1)
* @param int $userId ID пользователя (для персональных скидок)
* @return array|false ['PRICE', 'CURRENCY', 'DISCOUNT_PRICE', 'DISCOUNT_PERCENT', 'BASE_PRICE'] или false
*/
function getActualProductPrice($productId, $quantity = 1, $userId = 0) {
if (!Loader::includeModule('catalog') || !Loader::includeModule('sale')) {
return false;
}
$prices = getProductPrices($productId);
if (empty($prices)) {
return false;
}
$basePrice = $prices[0];
$currentUserId = $userId ?: ($GLOBALS['USER']->IsAuthorized() ? $GLOBALS['USER']->GetID() : 0);
$arPrice = CCatalogProduct::GetOptimalPrice(
$productId,
$quantity,
$currentUserId,
'N'
);
if ($arPrice && isset($arPrice['PRICE']['PRICE'])) {
return [
'PRICE' => (float)$arPrice['PRICE']['PRICE'],
'CURRENCY' => $arPrice['PRICE']['CURRENCY'],
'DISCOUNT_PRICE' => isset($arPrice['DISCOUNT']['PRICE']) ? (float)$arPrice['DISCOUNT']['PRICE'] : null,
'DISCOUNT_PERCENT' => isset($arPrice['DISCOUNT']['PERCENT']) ? (float)$arPrice['DISCOUNT']['PERCENT'] : null,
'BASE_PRICE' => (float)$basePrice['PRICE']
];
}
return [
'PRICE' => (float)$basePrice['PRICE'],
'CURRENCY' => $basePrice['CURRENCY'],
'DISCOUNT_PRICE' => null,
'BASE_PRICE' => (float)$basePrice['PRICE']
];
}
Пример использования:
$prices = getProductPrices(12345);
foreach ($prices as $price) {
echo $price['PRICE'] . ' ' . $price['CURRENCY'];
}
$actualPrice = getActualProductPrice(12345, 1, $USER->GetID());
if ($actualPrice) {
if ($actualPrice['DISCOUNT_PRICE']) {
echo 'Старая цена: ' . $actualPrice['BASE_PRICE'];
echo 'Цена со скидкой: ' . $actualPrice['PRICE'];
} else {
echo 'Цена: ' . $actualPrice['PRICE'];
}
}
GetOptimalPrice учитывает скидки, персональные цены и количество. Для скидок нужен модуль sale. Для неавторизованного передавайте userId = 0.
Проверка
-
Товар с одной ценой — getProductPrices($productId) должен вернуть массив с одним элементом; getActualProductPrice — массив с PRICE, CURRENCY, BASE_PRICE. Цена должна совпадать с карточкой товара в админке.
-
Товар со скидкой — настройте скидку на товар или корзину, вызовите getActualProductPrice. Ожидаем PRICE меньше BASE_PRICE, DISCOUNT_PRICE или DISCOUNT_PERCENT заполнены (если модуль скидок возвращает их).
-
Фильтр по типу цены — getProductPrices($productId, $priceTypeId) должен вернуть только записи с указанным CATALOG_GROUP_ID. Сверьте с типами цен в настройках каталога.
-
Товар без цен — для элемента без записей в b_catalog_price getProductPrices вернёт [], getActualProductPrice — false. Обрабатывайте в шаблоне (не показывать цену или «по запросу»).
Типичные ошибки
- Скидка не применяется — подключите модуль sale и передавайте актуальный userId в GetOptimalPrice. Для гостя передавайте 0; проверьте, что скидки активны и применимы к товару/корзине.
- Передан ID SKU вместо товара — GetOptimalPrice и CPrice работают с PRODUCT_ID: для торгового предложения это ID родительского товара в привязке каталога. Если в компоненте приходит ID SKU, сначала получите родителя (например по SKU) и передайте PRODUCT_ID в функции цен.
- Несколько типов цен — getProductPrices возвращает все типы; для «минимальной по всем типам» используйте отдельный сниппет с учётом групп пользователя.
Где применять
- Prod / dev: карточка товара, корзина, списки каталога, API цен, расчёт «старая цена / со скидкой».
- Компоненты: передавайте productId из элемента каталога (для SKU — ID родительского товара, если цены привязаны к товару).
Связанные сниппеты: Минимальная цена по типам цен, Родительский товар по SKU, Список элементов с пагинацией.