Перейти к содержимому

Свойства заказа - чтение, запись и фильтрация по значению

Читаем и пишем свойства заказа, выбираем заказы по значению и убираем поля, которых быть не должно.

Решение

Читаем все свойства заказа с их кодами:

$order = Bitrix\Sale\Order::load($orderId); // коллекция свойств живёт у заказа
// у нового заказа коллекция собирается по типу плательщика, а не из базы
foreach ($order->getPropertyCollection() as $property) {
printf("%-4d %-22s %-14s %s\n",
$property->getPropertyId(),
$property->getField('CODE'),
$property->getField('TYPE'),
(string)$property->getValue());
}

Коллекция собирается по типу плательщика заказа. У физлица и у организации это разные наборы, поэтому обходить её надо целиком, а не брать поля по номеру.

Пишем значение и сохраняем:

$props = $order->getPropertyCollection();
$props->getPhone()->setValue('+7 900 123-45-67');
$props->getItemByOrderPropertyId(15)->setValue('Москва, Тверская, 1');
$order->save();

Методы getPhone, getUserEmail и getPayerName возвращают не любое свойство с похожим названием, а то, у которого в настройках стоит признак назначения. Остальные берут по идентификатору.

Выбираем заказы по значению свойства:

$rows = Bitrix\Sale\Internals\OrderPropsValueTable::getList([
'select' => ['ORDER_ID', 'VALUE'],
'filter' => ['=ORDER_PROPS_ID' => 15, '%VALUE' => 'Тверская'],
'limit' => 50,
]);
foreach ($rows as $row) {
echo "{$row['ORDER_ID']}: {$row['VALUE']}\n";
}

Значения свойств лежат в отдельной таблице, поэтому фильтр по ним - это условие по ORDER_PROPS_ID, а не по имени поля заказа. Свойство типа «дата» хранится строкой, и сравнение по диапазону на нём не работает.

Убираем лишнее поле из формы заказа:

CSaleOrderProps::Update($propertyId, ['ACTIVE' => 'N']); // скрыть, но сохранить значения

Свойство отключают, а не удаляют: удаление уносит значения по всем прежним заказам. Скрытое свойство остаётся в истории и продолжает читаться кодом.

Считаем, у скольких заказов свойство заполнено:

$filled = Bitrix\Sale\Internals\OrderPropsValueTable::getCount([
'=ORDER_PROPS_ID' => $propertyId,
'!=VALUE' => '',
]);
echo "заполнено у {$filled} заказов\n";

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

Смотрим, каким типам плательщиков свойство привязано:

$links = CSaleOrderProps::GetList([], ['ID' => $propertyId], false, false,
['ID', 'CODE', 'PERSON_TYPE_ID', 'ACTIVE', 'REQUIRED']);
while ($row = $links->Fetch()) {
printf("%-18s тип плательщика %d, обязательное=%s\n",
$row['CODE'], $row['PERSON_TYPE_ID'], $row['REQUIRED']);
}

Одно свойство принадлежит одному типу плательщика. Одинаковый вопрос в двух формах - это две записи справочника, и правят их по отдельности. Забытая вторая запись и даёт классическую жалобу «у юрлиц поле осталось».

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

Типичные проблемы

Свойства заполнены, а в заказе пусто.

Значения записаны до создания отгрузки и платежа. Эти операции пересобирают коллекцию свойств, поэтому её заполняют последней, перед самым сохранением.

Код работает на физлице и падает на организации.

Свойство берётся по жёстко заданному идентификатору. У другого типа плательщика тот же вопрос покупателю - это другое свойство с другим номером.

В админке при добавлении товара появляются лишние свойства.

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

Фильтр по свойству типа «дата» ничего не находит.

Значение хранится строкой в формате сайта. Диапазон по нему не работает: либо сравнивают строки целиком, либо заводят отдельное свойство под нужный формат.

Частые вопросы

Как получить свойство заказа, не загружая весь заказ?

Прямой выборкой из OrderPropsValueTable по идентификатору заказа и свойства. Это дешевле полной загрузки, но объект заказа при этом не создаётся, и менять значение так нельзя.

Можно ли завести своё свойство только для одного сайта?

Да, свойства привязываются к типу плательщика, а типы плательщиков - к сайту. На мультисайте это штатный способ развести формы заказа.

Почему свойство не приходит в 1С?

В выгрузку попадают свойства с признаком обмена и заполненным внешним кодом. Свойство без кода на сайте живёт, а в файле обмена его нет.

Как сделать свойство обязательным только на одном шаге оформления?

Штатной настройки для этого нет: обязательность задаётся у свойства целиком. Условную проверку делают своим кодом на событии проверки заказа.

Смежное

Первоисточник