B
B
boris tyrepharm2018-04-01 00:44:49
1C-Bitrix
boris tyrepharm, 2018-04-01 00:44:49

How to update order properties and change payer type in Bitrix?

Orders from Bitrix are uploaded to the accounting program, and then, after processing, they arrive back in the form of an unloading XML file.
Sometimes the counterparty changes in the accounting program: it is necessary that in the order of Bitrix it also changes in accordance with the data from XML.
The XML parser has already been written. And the function is successfully hung up on the "OnSaleOrderBeforeSaved" event. The only thing that does not work is to save the new data to the order, deleting the old ones.
Example: the counterparty was:

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

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

The above data is output as follows:
$propertyCollection = $OrderBX->getPropertyCollection();
foreach ($propertyCollection as $Prop)
{
  echo '['.$Prop->getPropertyId().'] '.$Prop->getName().': '.$Prop->getValue().'<br>';
}

The algorithm is as follows:
1. A new profile is formed from XML
2. All existing fields are deleted from the order
3. The payer type is changed
4. New fields are assigned according to the data from the profile
Code fragment:
//	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();

But as a result I catch an error in debugging:
[Error] 
Call to a member function setValue() on null (0)
/home/bitrix/www/bitrix/php_interface/init.php:1020

Who can help solve this problem?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dmitry, 2018-04-03
@borisevstratov

Try this

$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());
}

Please note that you do not need to save the entities yourself, they will be saved later in the save() method of the order. Premature saving can give unexpected results.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question