@borisevstratov

Как в Битриксе обновить свойства заказа и сменить тип плательщика?

Заказы из Битрикса выгружаются в учётную программу, а затем после обработки прилетают обратно в виде XML-файла выгрузки.
Иногда в учётной программе меняется контрагент: надо чтоб и в заказе Битрикса он менялся в соответствии с данными из XML.
Парсер XML уже написан. И функция успешно повешена на событие "OnSaleOrderBeforeSaved". Единственное, что не получается — сохранить новые данные в заказ, удалив старые.

Пример: контрагентом был:
[1] Ваше ФИО: Дмитрий
[21] Получатель: Дмитрий Иванов
[20] Паспортные данные: 0000 123456
[2] E-Mail: dima@ivanov.ru
[3] Телефон: +7 (000) 111-22-33
[4] Индекс: 190000
[7] Адрес доставки: Санкт-Петербург, Невский пр.

А новым контрагентом стал:
[8] Название компании: ООО "ОРГАНИЗАЦИЯ"
[10] ИНН: 7800000000
[11] КПП: 780000000
[25] ОГРН: 10000000000
[9] Юридический адрес: 190000 ГОРОД САНКТ-ПЕТЕРБУРГ, НЕВСКИЙ ПРОСПЕКТ,  ДОМ 1
[24] Физический адрес: 190000 ГОРОД САНКТ-ПЕТЕРБУРГ, НЕВСКИЙ ПРОСПЕКТ,  ДОМ 1
[26] Расчётный счёт: 40000000000000001
[29] Наименование банка: Филиал ПАО Банка «БАНК» г. Санкт-Петербург
[28] Корреспондентский счёт: 30000000000009
[27] БИК: 000000011
[12] Контактное лицо: Иван Петров
[13] E-Mail: ivan.petrov@mail.su
[14] Телефон: +7 (999) 999-99-99
[44] Получатель: Семен
[16] Индекс: 190000
[19] Адрес доставки: г Санкт-Петербург, Московское шоссе, д.1

Вышеприведённые данные выведены таким образом:
$propertyCollection = $OrderBX->getPropertyCollection();
foreach ($propertyCollection as $Prop)
{
	echo '['.$Prop->getPropertyId().'] '.$Prop->getName().': '.$Prop->getValue().'<br>';
}

Алгоритм таков:
1. Формируется новый профиль из XML
2. Удаляются все существующие поля из заказа
3. Изменяется тип плательщика
4. Назначаются новые поля по данным из профиля

Фрагмент кода:
//	1.  Формирование нового профиля
$arProfileFields = array(
    "NAME" => $NAME,
    "USER_ID" => $UID,
    "PERSON_TYPE_ID" => $PID
);
$PROPS = array ( ... );
$PROFILE_ID = CSaleOrderUserProps::Add($arProfileFields);
foreach ($PROPS as $prop)
{
    CSaleOrderUserPropsValue::Add($prop);
}
$newUserIDBX = $PROFILE_ID;

//	2.  Удалим все свойства заказа
$orderProperties = $OrderBX->getPropertyCollection();
foreach ($orderProperties as $orderProperty) {
    $Del = $orderProperty->getPropertyId();
    $orderProperty->delete($Del);
}
$orderProperties->save();

//	3.  Установим новый тип плательщика
$OrderBX->setPersonTypeId(intval($PID));

//	4.  Получим свойства профиля $newUserIDBX и назначим соответствующие им ORDER_PROPS
$profileProperties = Sale\OrderUserProperties::getProfileValues(intval($newUserIDBX));
$propertyCollection = $OrderBX->getPropertyCollection();
foreach ($profileProperties as $propId => $propVal) {
	$orderPropValue = $propertyCollection->getItemByOrderPropertyId($propId);
	$orderPropValue->setValue($propVal);
}

//	Сохраним
$propertyCollection->save();


Но в результате ловлю ошибку в отладке:
[Error] 
Call to a member function setValue() on null (0)
/home/bitrix/www/bitrix/php_interface/init.php:1020

Кто может помочь с решением данной проблемы?
  • Вопрос задан
  • 6028 просмотров
Решения вопроса 1
Попробуйте такое

$eventManager = \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler('sale', 'OnSaleOrderBeforeSaved', 'orderModify');

function orderModify(Bitrix\Main\Event $event)
{
    global $USER;

    /** @var \Bitrix\Sale\Order $order */
    $order = $event->getParameter('ENTITY');

    $personTypeId = 3;

    $profileId = CSaleOrderUserProps::DoSaveUserProfile($USER->GetID(), null, 'Профиль ' . random_int(0, 500), $personTypeId,
        // код свойства и его значение
        [
            20 => random_int(100, 900),
            21 => random_int(500, 599)
        ], $errors);

    // Получаем текущую коллекцию свойств заказа и удаляем все свойства
    /** @var \Bitrix\Sale\PropertyValueCollection $orderProperties */
    $orderProperties = $order->getPropertyCollection();
    /** @var \Bitrix\Sale\PropertyValue $orderProperty */
    foreach ($orderProperties as $orderProperty) {
        $orderProperty->delete();
    }

    // Меняем тип плательщика
    $order->setPersonTypeId($personTypeId);

    // Далее взято из \Bitrix\Sale\PropertyValueCollection::load()
    // Т.к. на объекте заказа уже была получена коллекция, то при вызове $order->getPropertyCollection(),
    // коллекция не будет заполнена свойствами под новый тип плательщика.
    // Поэтому нужно добавлять свойства вручную

    // Получаем список свойств нового плательщика
    $props = \Bitrix\Sale\PropertyValue::loadForOrder($order);

    // Добавляем свойства к коллекции
    /** @var \Bitrix\Sale\PropertyValue $prop */
    foreach ($props as $prop) {
        $prop->setCollection($orderProperties);
        $orderProperties->addItem($prop);

        // В своём коде напямую этого сделать не можем, т.к. метод и свойство имеют приватный доступ
        // Но можно сделать обходным путём
//        $orderProperties->setAttributes($prop);
//        $orderProperties->propertyGroupMap[$prop->getGroupId() > 0 && isset($groups[$personTypeId][$prop->getGroupId()]) ? $prop->getGroupId() : 0][] = $prop;
    }

    // Получаем значения профиля
    $profileProperties = \Bitrix\Sale\OrderUserProperties::getProfileValues($profileId);

    // Записываем к заказу
    $orderProperties->setValuesFromPost(array('PROPERTIES' => $profileProperties), array());
}


Обратите внимание, сохранять сущности самостоятельно не нужно, они сохранятся позже в методе save() заказа. Преждевременное сохранение может дать неожиданный результат.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы