Разработка функционала «назови свою цену» на 1С-Битрикс
Механизм PWYW (Pay What You Want) позволяет покупателю самому ввести сумму за товар или услугу — с возможным нижним порогом. Битрикс не поддерживает это из коробки: цена в b_catalog_price фиксирована, и модуль sale не принимает произвольную сумму от клиента. Вся логика переопределяется на уровне корзины и формы оформления заказа.
Где хранить настройки
Для каждого товара, участвующего в механизме, нужно три дополнительных параметра:
-
PWYW_ENABLED— флаг активности (Y/N) -
PWYW_MIN_PRICE— минимальная сумма (может быть 0) -
PWYW_SUGGESTED_PRICE— рекомендуемая сумма (отображается по умолчанию)
Хранение — свойства инфоблока каталога. Для торговых предложений (SKU) добавляются через CIBlockProperty::Add() к IBLOCK_ID торговых предложений. Тип свойств — N (число) для цен, S для флага.
Альтернатива — HL-блок PwywSettings с полями UF_PRODUCT_ID, UF_MIN_PRICE, UF_SUGGESTED_PRICE, UF_ACTIVE. Подходит, когда нужно управлять настройками массово из административного интерфейса без редактирования каждого товара.
Перехват цены при добавлении в корзину
Стандартный $basket->addItem() берёт цену из каталога. Нужно перехватить момент до сохранения и подставить цену от клиента.
Клиентская часть: форма на странице товара содержит поле pwyw_price. При отправке — AJAX на кастомный endpoint.
Серверная обработка:
use Bitrix\Sale\Basket;
use Bitrix\Sale\BasketItem;
use Bitrix\Main\Context;
$request = Context::getCurrent()->getRequest();
$productId = (int)$request->getPost('product_id');
$userPrice = (float)$request->getPost('pwyw_price');
// Проверяем минимальный порог
$minPrice = getPwywMinPrice($productId); // читает свойство инфоблока
if ($userPrice < $minPrice) {
echo json_encode(['error' => 'Цена ниже минимальной']);
die();
}
$basket = Basket::loadItemsForFUser(
\CSaleBasket::GetBasketUserID(),
\Bitrix\Main\Context::getCurrent()->getSite()
);
$item = $basket->createItem('catalog', $productId);
$item->setFields([
'QUANTITY' => 1,
'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
'LID' => SITE_ID,
'PRODUCT_PROVIDER_CLASS' => 'CCatalogProductProvider',
'PRICE' => $userPrice,
'BASE_PRICE' => $userPrice,
'CUSTOM_PRICE' => 'Y', // запрет автоматического пересчёта
]);
// Сохраняем введённую цену в свойство корзины
$item->getPropertyCollection()->setProperty([
'NAME' => 'PWYW_PRICE',
'CODE' => 'PWYW_PRICE',
'VALUE' => $userPrice,
'SORT' => 100,
]);
$basket->save();
Поле CUSTOM_PRICE = 'Y' — ключевое. Без него Битрикс при пересчёте корзины заменит введённую цену каталожной через провайдер CCatalogProductProvider.
Защита от пересчёта
Даже с CUSTOM_PRICE = 'Y' некоторые обработчики могут сбросить цену. Подписываемся на событие OnSaleBasketItemRefreshData и восстанавливаем цену из свойства корзины:
AddEventHandler('sale', 'OnSaleBasketItemRefreshData', function(&$fields) {
$basketItem = $fields['BASKET_ITEM'];
$props = $basketItem->getPropertyCollection();
$pwywProp = $props->getItemByCode('PWYW_PRICE');
if ($pwywProp && $pwywProp->getValue() > 0) {
$fields['PRICE'] = (float)$pwywProp->getValue();
$fields['BASE_PRICE'] = (float)$pwywProp->getValue();
$fields['CUSTOM_PRICE'] = 'Y';
}
});
Минимальная цена и UI-валидация
Минимальный порог проверяется дважды: на клиенте (JavaScript) и на сервере (PHP). Клиентская проверка — для UX, серверная — обязательна.
На странице товара данные минимальной цены передаются через data-атрибуты или inline-JS:
<div class="pwyw-widget"
data-min-price="{{ $minPrice }}"
data-suggested="{{ $suggestedPrice }}">
<input type="number" name="pwyw_price"
min="{{ $minPrice }}"
value="{{ $suggestedPrice }}"
step="1">
<div class="pwyw-hint">Минимальная сумма: {{ $minPrice }} ₽</div>
</div>
Вместо шаблонизатора Битрикса — значения подставляются в компоненте через $arResult или $arParams.
Отображение в заказе и личном кабинете
В административном заказе (sale.admin.order.edit) и в письмах нужно показывать, что цена введена вручную. Переопределяем шаблон компонента bitrix:sale.order.ajax — добавляем вывод свойства PWYW_PRICE с пометкой «цена указана покупателем».
В почтовых шаблонах типа SALE_NEW_ORDER добавляем блок с выводом свойств корзины через #BASKET_ITEMS# — свойство PWYW_PRICE уже будет включено в стандартную подстановку.
Аналитика и минимальные суммы
Для анализа реального поведения покупателей — какие суммы вводят, сколько раз вводят ниже минимума — логируем все попытки в кастомную таблицу b_pwyw_log:
CREATE TABLE b_pwyw_log (
ID INT AUTO_INCREMENT PRIMARY KEY,
PRODUCT_ID INT,
USER_ID INT,
PRICE_ENTERED DECIMAL(10,2),
MIN_PRICE DECIMAL(10,2),
ACCEPTED TINYINT(1),
DATE_ADD DATETIME DEFAULT CURRENT_TIMESTAMP
);
Данные из этой таблицы помогают принять решение о корректировке минимального порога.
Сроки реализации
| Вариант | Описание | Срок |
|---|---|---|
| Базовый (одно поле, без ограничений) | Свойства инфоблока + AJAX + обработчик корзины | 3–5 дней |
| С минимальным порогом и логированием | + таблица логов, серверная валидация, UI-подсказки | 1 неделя |
| Полноценный (HL-блок настроек, аналитика, поддержка SKU) | Административный интерфейс + аналитический отчёт | 1.5–2 недели |







