How Bitrix to assign the cost of delivery when you sync?

Faced the following problem: when syncing a site on Bitriks gets a JSON file with the customer's order. You want to refresh data in the existing order.
When an order is updated (here is the code snippet using Bitrix D7): if the shipment contains paid shipping, then the amount of "I priiplyusovali" to the amount of delivery originally specified in the order.
For example, initially the user has placed the order with a delivery fee 500₽ later after order processing accounting program — was created by the sale of the products with "delivery" value of the same 500₽, so, as a result of the import of the order on the website "shipping Costs" was equal to 1000₽. That is, like, shipping, what was in the shipment of "add on" to the existing order, albeit in the import file, the shipping cost for the order is equal to 500 a long way, as for shipment.
<?
$importJson = file_get_contents('php://input');
$orderBx = Sale\Order::loadByAccountNumber($importJson['Info']['Id']);

// ...

// create shipment
$shipmentCollection = $orderBx->getShipmentCollection();

// shipments may be several
foreach (importJson['Shipments'] as $importOrderShipment)
{
 $shipment = $shipmentCollection->createItem();
$shipment->setAccountNumber($orderBx->getId());
 $shipmentItemCollection = $shipment->getShipmentItemCollection();

 foreach ($importOrderShipment['Items'] as $item)
{
 // add the items in the recycle bin from the import file
}

 $shipment->setStoreId($importOrderShipment['StoreId']); // id of the warehouse
 $service = \Bitrix\Sale\Delivery\Services\Manager::getById($importOrderShipment['DeliveryId']); // id of the shipping method

$shipment->setFields([
 'STATUS_ID' => 'DF',
 'DEDUCTED' => 'Y',
 'COMPANY_ID' => 1,
 'DATE_DEDUCTED' => \Bitrix\Main\Type\DateTime::createFromTimestamp($importOrderShipment['Date']),
 'DELIVERY_ID' => $service['ID'],
 'DELIVERY_NAME' => $service['NAME'],
 'DELIVERY_DOC_NUM' => $importOrderShipment['Document'],
 'DELIVERY_DOC_DATE' => \Bitrix\Main\Type\DateTime::createFromTimestamp($importOrderShipment['Date']),
 'COMMENTS' => $importOrderShipment['Comments'],
 'CURRENCY' => $orderBx->getCurrency(),
 'PRICE_DELIVERY' => $importOrderShipment['DeliveryPrice'], // in this case, only one delivery from $importOrderShipment['DeliveryPrice'] = 500;
 'BASE_PRICE_DELIVERY' => $importOrderShipment['DeliveryPrice'],
 'UPDATED_1C' => 'Y'
]);

$shipment->allowDelivery();
}

// Set the value of "delivery charge" from the import file
// $importJson['DeliveryPrice'] = 500;
$orderBx->setFieldNoDemand('PRICE_DELIVERY', $importJson['DeliveryPrice']);

$orderBx->save();
?>
April 4th 20 at 00:57
3 answers
April 4th 20 at 00:59
Solution
Let us explain a little more your code and let's imagine a hypothetical situation: you have a site created on the 1st shipment, and after an exchange from your system arrives 2 new shipments, instead of 1 existed.

Let's start with the fact that:
// create shipment
$shipmentCollection = $orderBx->getShipmentCollection();


You get a collection of shipments. Collection of shipments is a set consisting of system shipment + system-generated or user.
When processing an existing order with one shipment you will return a collection (an object) with the contents in 2 shipments: system + yours.

Next, you are iterating over came shipments
foreach (importJson['Shipments'] as $importOrderShipment)

Ie it turns out you have received 2 shipments and therefore you 2 times you log in to your cycle.

Snippet:
$shipment = $shipmentCollection->createItem();
Create another shipment. In other words, after executing the fragment in the collection of shipments you will have 4 shipping: system, source (which was online), as well as two new shipment that you created when iterating imported shipments.

In this case, you have a few scenarios:
1) You can clear the collection of shipments and create a new one. Events to change the order, you will be a large number, but nevertheless it will give you more transparency in your process (not to mention ease of implementation).

2) Add the token and use it to update existing shipment to change the price type, etc.
It will be harder, but purer from the point of view of events in the system.

P. S. And as I recall, the price of shipping PRICE_DELIVERY of order it's kind of like the amount PRICE_DELIVERY (?CUSTOM_PRICE_DELIVERY) of all non-system shipments, so ask him useless.
Thank you very much, Andrew! Thanks to Your detailed response understand the mechanism of formation of the cost of delivery in the order. - laury commented on April 4th 20 at 01:02
April 4th 20 at 01:01
You create a delivery without checking for existence. It does not fit in with the "to update data in an existing order". Moreover, in order always present sisenna shipment even if the shipment one, in the collection of their fakticheski two.
Validation of shipments to the existence of a — I display only a code snippet.
And about the system shipment: I understand that she and "the system", so I generally never touch. - laury commented on April 4th 20 at 01:04
Validation of shipments to the existence of a — I display only a code snippet.


Why don't you give the full code snippet then? Check for the existence of shipments cardinally change your code. - Clinton.Miller commented on April 4th 20 at 01:07
April 4th 20 at 01:03
The change in the cost of delivery of the order with the created shipments:
$shipmentCollection = $orderBx->getShipmentCollection();
$shipment = $shipmentCollection->createItem();

or
$shipmentCollection = $orderBx->getShipmentCollection();
$shipment = $shipmentCollection->createItem(
 Delivery\Services\Manager::getObjectById($deliveryID) // ID of the shipping service
);

Setting of shipping cost
$price = 123;
$shipment->setBasePriceDelivery($price);

Find more questions by tags 1C-Bitrix