Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
shipmentrules.php
1<?php
2
4
7
13{
17 protected function __construct() {}
18
25 public static function createOrderRuleMap(Sale\Order $order, PoolQuantity $pool)
26 {
27 $resultList = array();
28
29 $productPool = ItemsPool::getPoolByCode($order->getInternalId());
30 if (empty($productPool))
31 {
32 return $resultList;
33 }
34
35 foreach ($productPool as $productId => $itemList)
36 {
37 foreach ($itemList as $item)
38 {
39 if ($item instanceof Sale\ShipmentItem)
40 {
41 $itemRule = static::createReserveRuleForShipmentItem($item, $pool);
42 if (!empty($itemRule) && is_array($itemRule))
43 {
44 $resultList[] = $itemRule;
45 }
46
47 $itemRule = static::createShipRule($item, $pool);
48 if (!empty($itemRule) && is_array($itemRule))
49 {
50 $resultList[] = $itemRule;
51 }
52 }
53 elseif ($item instanceof Sale\ReserveQuantity)
54 {
55 $itemRule = static::createReserveRule($item, $pool, $productId);
56 if (!empty($itemRule) && is_array($itemRule))
57 {
58 $resultList[] = $itemRule;
59 }
60 }
61 }
62 }
63
64 return $resultList;
65 }
66
74 private static function createShipRule(Sale\ShipmentItem $shipmentItem, PoolQuantity $pool)
75 {
76 $basketItem = $shipmentItem->getBasketItem();
77 if (!$basketItem->isReservableItem())
78 {
79 return false;
80 }
81
82 $poolQuantitiesList = $pool->getQuantitiesWithStore(PoolQuantity::POOL_QUANTITY_TYPE);
83 if (empty($poolQuantitiesList))
84 {
85 return false;
86 }
87
88 $shipment = $shipmentItem->getCollection()->getShipment();
89
90 $coefficient = 1;
91 if ($shipment->needShip() === Sale\Internals\Catalog\Provider::SALE_TRANSFER_PROVIDER_SHIPMENT_NEED_SHIP)
92 {
93 $coefficient = -1;
94 }
95
96 $needUseReserve = $coefficient < 1 || Sale\Configuration::isEnableAutomaticReservation();
97
98 $productId = $basketItem->getProductId();
99
100 $rule = array(
101 'SHIPMENT_ITEM' => $shipmentItem,
102 'BASKET_ITEM' => $basketItem,
103 'PRODUCT_ID' => $productId,
104 'PROVIDER_NAME' => $basketItem->getProvider(),
105 );
106
107 $storeData = Sale\Internals\Catalog\Provider::createMapShipmentItemStoreData($shipmentItem, $needUseReserve);
108 if (!empty($storeData))
109 {
110 $reservedQuantity = 0;
111 $needReserveByStore = [];
112 foreach ($storeData as $item)
113 {
114 $reservedQuantity += $item['RESERVED_QUANTITY'];
115
116 $needReserveByStore[$item['STORE_ID']] = $item['RESERVED_QUANTITY'] > 0;
117 }
118
119 $rule['STORE_DATA'] = [
120 $shipmentItem->getInternalIndex() => $storeData
121 ];
122
123 $rule['NEED_RESERVE'] = $reservedQuantity > 0;
124
125 $rule['NEED_RESERVE_BY_STORE'] = [
126 $shipmentItem->getInternalIndex() => $needReserveByStore
127 ];
128 }
129 else
130 {
131 $rule['NEED_RESERVE'] = $basketItem->getReservedQuantity() > 0;
132 $rule['NEED_RESERVE_BY_STORE'] = [
133 $shipmentItem->getInternalIndex() => [
134 Sale\Configuration::getDefaultStoreId() => $rule['NEED_RESERVE']
135 ]
136 ];
137
138 $reservedQuantity = 0;
139
141 $reserveQuantityCollection = $basketItem->getReserveQuantityCollection();
142 if ($reserveQuantityCollection)
143 {
144 $reservedQuantity = $reserveQuantityCollection->getQuantityByStoreId(
146 );
147 }
148
149 if ($shipmentItem->getQuantity() < $reservedQuantity)
150 {
151 $reservedQuantity = $shipmentItem->getQuantity();
152 }
153
154 $rule['RESERVED_QUANTITY'] = $reservedQuantity;
155 $rule['RESERVED_QUANTITY_BY_STORE'] = [
156 $shipmentItem->getInternalIndex() => [
157 Sale\Configuration::getDefaultStoreId() => $reservedQuantity
158 ]
159 ];
160 }
161
162 if (array_key_exists($productId, $poolQuantitiesList))
163 {
164 $quantityByStore = [];
165 foreach ($storeData as $item)
166 {
167 $storeId = $item['STORE_ID'];
168 $quantity = $coefficient * $item['QUANTITY'];
169
170 if (!isset($quantityByStore[$storeId]))
171 {
172 $quantityByStore[$storeId] = 0;
173 }
174
175 $quantityByStore[$storeId] += $quantity;
176
177 $poolQuantity = $poolQuantitiesList[$productId][$storeId] - $quantity;
178
179 $pool->setByStore(PoolQuantity::POOL_QUANTITY_TYPE, $productId, $storeId, $poolQuantity);
180 }
181
182 if ($quantityByStore)
183 {
184 $rule['ACTION'][PoolQuantity::POOL_QUANTITY_TYPE] = [
185 'QUANTITY_BY_STORE' => $quantityByStore,
186 'QUANTITY' => array_sum($quantityByStore)
187 ];
188 }
189 else
190 {
191 $storeId = Sale\Configuration::getDefaultStoreId();
192
193 $quantity = $coefficient * $shipmentItem->getQuantity();
194
195 $rule['ACTION'][PoolQuantity::POOL_QUANTITY_TYPE] = [
196 'QUANTITY' => $quantity,
197 'QUANTITY_BY_STORE' => [
198 $storeId => $quantity
199 ]
200 ];
201 }
202 }
203
204 return $rule;
205 }
206
214 private static function createReserveRuleForShipmentItem(Sale\ShipmentItem $shipmentItem, PoolQuantity $pool)
215 {
216 $basketItem = $shipmentItem->getBasketItem();
217 if (!$basketItem->isReservableItem())
218 {
219 return false;
220 }
221
222 $reserveCollection = $basketItem->getReserveQuantityCollection();
223 if (!$reserveCollection)
224 {
225 return false;
226 }
227
228 $poolReservationList = $pool->getQuantitiesWithStore(PoolQuantity::POOL_RESERVE_TYPE);
229 if (empty($poolReservationList))
230 {
231 return false;
232 }
233
234 $shipment = $shipmentItem->getCollection()->getShipment();
235 if ($shipment->needShip() === Sale\Internals\Catalog\Provider::SALE_TRANSFER_PROVIDER_SHIPMENT_NEED_NOT_SHIP)
236 {
237 return false;
238 }
239
240 $productId = $basketItem->getProductId();
241
242 $rule = [
243 'SHIPMENT_ITEM' => $shipmentItem,
244 'BASKET_ITEM' => $basketItem,
245 'PRODUCT_ID' => $productId,
246 'PROVIDER_NAME' => $basketItem->getProvider(),
247 'STORE' => []
248 ];
249
250 if (!isset($poolReservationList[$productId]))
251 {
252 return $rule;
253 }
254
255 $needReserveQuantity = $shipmentItem->getNeedReserveQuantity();
256 if ($needReserveQuantity == 0)
257 {
258 $needQuantityByStore = $poolReservationList[$productId];
259 $rule['ACTION'][PoolQuantity::POOL_RESERVE_TYPE] = [
260 'QUANTITY_BY_STORE' => $needQuantityByStore,
261 'QUANTITY' => array_sum($needQuantityByStore),
262 ];
263
264 $pool->delete(PoolQuantity::POOL_RESERVE_TYPE, $productId);
265
266 return $rule;
267 }
268
269 $needQuantityByStore = [];
270
272 $shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
273 if ($shipmentItemStoreCollection)
274 {
276 foreach ($shipmentItemStoreCollection as $itemStore)
277 {
278 if (
279 isset($poolReservationList[$productId][$itemStore->getStoreId()])
280 && $poolReservationList[$productId][$itemStore->getStoreId()] == 0
281 )
282 {
283 continue;
284 }
285
287 foreach ($reserveCollection as $reserve)
288 {
289 if (
290 $reserve->getStoreId() !== $itemStore->getStoreId()
291 || !$reserve->getFields()->isChanged('QUANTITY')
292 )
293 {
294 continue;
295 }
296
297 if (!isset($needQuantityByStore[$reserve->getStoreId()]))
298 {
299 $needQuantityByStore[$reserve->getStoreId()] = 0;
300 }
301
302 $needQuantity = $reserve->getQuantity() - $reserve->getFields()->getOriginalValues()['QUANTITY'];
303 if (abs($needQuantity) > abs($needReserveQuantity))
304 {
305 $needQuantityByStore[$reserve->getStoreId()] += $needReserveQuantity;
306 $needReserveQuantity = 0;
307 $poolReservationList[$productId][$reserve->getStoreId()] -= $needReserveQuantity;
308 }
309 else
310 {
311 $needQuantityByStore[$reserve->getStoreId()] += $needQuantity;
312 $needReserveQuantity -= $needQuantity;
313 $poolReservationList[$productId][$reserve->getStoreId()] -= $needQuantity;
314 }
315 }
316 }
317 }
318
319 if ($needReserveQuantity != 0)
320 {
321 $storeId = Sale\Configuration::getDefaultStoreId();
322 if (!isset($needQuantityByStore[$storeId]))
323 {
324 $needQuantityByStore[$storeId] = 0;
325 }
326
327 foreach ($reserveCollection as $reserve)
328 {
329 if (
330 !$reserve->getStoreId() === $storeId
331 || !$reserve->getFields()->isChanged('QUANTITY')
332 )
333 {
334 continue;
335 }
336
337 $needQuantity = $reserve->getQuantity() - $reserve->getFields()->getOriginalValues()['QUANTITY'];
338 if (abs($needQuantity) > abs($needReserveQuantity))
339 {
340 $needQuantityByStore[$reserve->getStoreId()] += $needReserveQuantity;
341 $needReserveQuantity = 0;
342 $poolReservationList[$productId][$reserve->getStoreId()] -= $needReserveQuantity;
343 }
344 else
345 {
346 $needQuantityByStore[$reserve->getStoreId()] += $needQuantity;
347 $needReserveQuantity -= $needQuantity;
348 $poolReservationList[$productId][$reserve->getStoreId()] -= $needQuantity;
349 }
350 }
351
352 if ($needReserveQuantity != 0)
353 {
354 foreach ($poolReservationList[$productId] as $storeId => $quantity)
355 {
356 if ($needReserveQuantity == 0)
357 {
358 break;
359 }
360
361 if ($quantity != 0)
362 {
363 if (!isset($needQuantityByStore[$storeId]))
364 {
365 $needQuantityByStore[$storeId] = 0;
366 }
367
368 if (abs($needReserveQuantity) > abs($quantity))
369 {
370 $needQuantityByStore[$storeId] += $quantity;
371 $needReserveQuantity -= $quantity;
372
373 $poolReservationList[$productId][$storeId] = 0;
374 }
375 else
376 {
377 $needQuantityByStore[$storeId] += $needReserveQuantity;
378 $needReserveQuantity = 0;
379
380
381 $poolReservationList[$productId][$storeId] -= $quantity;
382 }
383
384 }
385 }
386 }
387 }
388
389 foreach ($poolReservationList as $productId => $quantityByStore)
390 {
391 foreach ($quantityByStore as $storeId => $quantity)
392 {
393 $pool->setByStore(PoolQuantity::POOL_RESERVE_TYPE, $productId, $storeId, $quantity);
394 }
395 }
396
397 $rule['ACTION'][PoolQuantity::POOL_RESERVE_TYPE] = [
398 'QUANTITY_BY_STORE' => $needQuantityByStore,
399 'QUANTITY' => array_sum($needQuantityByStore),
400 ];
401
402 return $rule;
403 }
404
412 private static function createReserveRule(Sale\ReserveQuantity $reserve, PoolQuantity $pool, int $productId)
413 {
414 $basketItem = $reserve->getCollection()->getBasketItem();
415
416 $poolReservationList = $pool->getQuantitiesWithStore(PoolQuantity::POOL_RESERVE_TYPE);
417 if (
418 empty($poolReservationList)
419 || !isset($poolReservationList[$productId])
420 )
421 {
422 return false;
423 }
424
425 $rule = [
426 'PRODUCT_ID' => $productId,
427 'BASKET_ITEM' => $basketItem,
428 'PROVIDER_NAME' => $basketItem->getProvider(),
429 'RESERVE_ITEM' => $reserve,
430 'STORE' => []
431 ];
432
433 $quantityByStore = [];
434 if ($reserve->getQuantity() > 0)
435 {
436 $quantity = $reserve->getFields()->getOriginalValues()['QUANTITY'] ?? 0;
437 $quantityByStore = [
438 $reserve->getStoreId() => $reserve->getQuantity() - $quantity
439 ];
440 }
441 elseif ($reserve->getQuantity() == 0)
442 {
443 $quantity = $reserve->getFields()->getOriginalValues()['QUANTITY'];
444 $quantityByStore = [$reserve->getStoreId() => -$quantity];
445 }
446
447 if ($quantityByStore)
448 {
449 $rule['ACTION'][PoolQuantity::POOL_RESERVE_TYPE] = [
450 'QUANTITY_BY_STORE' => $quantityByStore,
451 'QUANTITY' => array_sum($quantityByStore),
452 ];
453 }
454
455 $pool->setByStore(PoolQuantity::POOL_RESERVE_TYPE, $productId, $reserve->getStoreId(), 0);
456
457 return $rule;
458 }
459
460
468 public static function saveRules(array $rules, array $context)
469 {
470 $result = new Sale\Result();
471 $shipProductsList = array();
472
473 foreach ($rules as $ruleData)
474 {
475 if (empty($ruleData['ACTION']))
476 {
477 continue;
478 }
479
480 foreach ($ruleData['ACTION'] as $action => $quantityItem)
481 {
482 if (is_array($quantityItem))
483 {
484 $quantity = $quantityItem['QUANTITY'];
485 $quantityByStore = $quantityItem['QUANTITY_BY_STORE'] ?? 0;
486 }
487 else
488 {
489 $quantity = $quantityItem;
490 $quantityByStore = [];
491 }
492
493 if ($quantity == 0)
494 {
495 continue;
496 }
497
498 $fields = $ruleData;
499 $fields['QUANTITY'] = $quantity;
500 $fields['QUANTITY_BY_STORE'] = $quantityByStore;
501 unset($fields['ACTION']);
502
503 if ($action === PoolQuantity::POOL_QUANTITY_TYPE)
504 {
505 $shipProductsList[] = $fields;
506 }
507 elseif ($action === PoolQuantity::POOL_RESERVE_TYPE)
508 {
509 $reserveProductsList[] = $fields;
510 }
511 }
512 }
513
514 if (!empty($reserveProductsList))
515 {
516 if (self::isHasDoubleBasketItems($reserveProductsList))
517 {
518 // each item is processed separately so that the number of identical basket items is not summed up.
519 foreach ($reserveProductsList as $reserveProductData)
520 {
521 $creator = Sale\Internals\ProviderCreator::create($context);
522 $creator->addProductData($reserveProductData);
523 $r = $creator->reserve();
524 if (!$r->isSuccess())
525 {
526 $result->addErrors($r->getErrors());
527 }
528 }
529 }
530 else
531 {
532 $creator = Sale\Internals\ProviderCreator::create($context);
533 foreach ($reserveProductsList as $reserveProductData)
534 {
535 $creator->addProductData($reserveProductData);
536 }
537
538 $r = $creator->reserve();
539 if (!$r->isSuccess())
540 {
541 $result->addErrors($r->getErrors());
542 }
543 }
544 }
545
546 if (!empty($shipProductsList))
547 {
548 $creator = Sale\Internals\ProviderCreator::create($context);
549 foreach ($shipProductsList as $shipProductData)
550 {
551 $creator->addProductData($shipProductData);
552 }
553
554 $r = $creator->ship();
555 if (!$r->isSuccess())
556 {
557 $result->addErrors($r->getErrors());
558 }
559
560 if ($r->hasWarnings())
561 {
562 $result->addWarnings($r->getWarnings());
563 }
564
565 $r = $creator->setItemsResultAfterShip($r);
566 if (!$r->isSuccess())
567 {
568 $result->addErrors($r->getErrors());
569 }
570 }
571
572
573 return $result;
574 }
575
583 private static function isHasDoubleBasketItems(array $reserveProductsList): bool
584 {
585 if (count($reserveProductsList) <= 1)
586 {
587 return false;
588 }
589
590 $map = [];
591 foreach ($reserveProductsList as $item)
592 {
593 $basketItem = $item['BASKET_ITEM'] ?? null;
594 if ($basketItem instanceof Sale\BasketItem)
595 {
596 $basketCode = $basketItem->getBasketCode();
597 if (isset($map[$basketCode]))
598 {
599 return true;
600 }
601
602 $map[$basketCode] = true;
603 }
604 }
605
606 return false;
607 }
608}
setByStore($type, $code, $storeId, $value)
static saveRules(array $rules, array $context)
static createOrderRuleMap(Sale\Order $order, PoolQuantity $pool)