40 $this->getList($select, $filter, $order, $pageNavigation),
54 $this->addErrors($r->getErrors());
59 return [
'PRICE' => $this->
get($id)];
70 if (!is_array($fields[
'PRODUCT'][
'PRICES']))
72 $this->addError(
new Error(
'Product prices are empty'));
77 $r = $this->modifyValidate($fields[
'PRODUCT'][
'PRICES']);
84 $r = $this->
modify($fields);
90 $this->addErrors($r->getErrors());
95 $ids = $r->getData()[0];
100 $entityTable::getList(
101 [
'filter' => [
'=ID' => $ids]]
119 $r = \Bitrix\Catalog\Model\Price::delete($id);
123 if (!$r->isSuccess())
125 $this->addErrors($r->getErrors());
140 $price = $this->
get($id);
143 $this->addError(
new Error(
'Price is not exists'));
148 $fields = array_merge($price, $fields);
149 return $this->modifySingleProductPrice($fields);
158 unset($fields[
'ID']);
160 return $this->modifySingleProductPrice($fields);
164 private function modifySingleProductPrice(array $fields): ?array
167 if (!$resultGroupType)
169 $this->addError(
new Error(
'Validate price error. Catalog price group is wrong'));
174 $entityTable = $this->getEntityTable();
176 $entityTable::getList(
179 '=PRODUCT_ID' => $fields[
'PRODUCT_ID'],
180 '=CATALOG_GROUP_ID' => $fields[
'CATALOG_GROUP_ID'],
187 $prices = array_combine(array_column($prices,
'ID'), $prices);
188 $prices[$fields[
'ID']] = $fields;
190 $r = $this->modifyValidate($prices);
195 'ID' => $fields[
'PRODUCT_ID'],
196 'PRICES' => [$fields]
201 if (!$r->isSuccess())
203 $this->addErrors($r->getErrors());
207 $ids = $r->getData()[0];
210 'PRICE'=>$this->
get($ids[0])
217 $productId = $fields[
'PRODUCT'][
'ID'];
218 $prices = $fields[
'PRODUCT'][
'PRICES'];
220 $r = $this->checkPermissionIBlockElementPriceModify($productId);
223 foreach ($prices as $price)
225 if(isset($price[
'ID']))
227 self::normalizeFields($price);
229 $result = \Bitrix\Catalog\Model\Price::update($price[
'ID'], $price);
230 if($result->isSuccess())
232 $ids[] = $price[
'ID'];
237 $result = \Bitrix\Catalog\Model\Price::add([
238 'PRODUCT_ID' => $productId,
239 'CATALOG_GROUP_ID' => $price[
'CATALOG_GROUP_ID'],
240 'CURRENCY' => $price[
'CURRENCY'],
241 'PRICE' => $price[
'PRICE'],
242 'QUANTITY_FROM' => isset($price[
'QUANTITY_FROM']) ? $price[
'QUANTITY_FROM']:
null,
243 'QUANTITY_TO' => isset($price[
'QUANTITY_TO']) ? $price[
'QUANTITY_TO']:
null,
244 'EXTRA_ID' => isset($price[
'EXTRA_ID']) ? $price[
'EXTRA_ID']:
null,
247 if($result->isSuccess())
249 $ids[] = $result->getId();
253 if($result->isSuccess() ==
false)
255 $r->addErrors($result->getErrors());
268 $productId = $fields[
'PRODUCT'][
'ID'];
271 $prices = $fields[
'PRODUCT'][
'PRICES'];
272 foreach ($prices as $price)
279 $res = $entityTable::getList([
'filter'=>[
'PRODUCT_ID'=>$productId]]);
280 while ($item = $res->fetch())
282 if(in_array($item[
'ID'], $ids) ==
false)
284 $entityTable::delete($item[
'ID']);
291 private static function normalizeFields(array &$fields)
293 if (isset($fields[
'QUANTITY_FROM']))
295 if (is_string($fields[
'QUANTITY_FROM']) && $fields[
'QUANTITY_FROM'] ===
'')
296 $fields[
'QUANTITY_FROM'] =
null;
297 elseif ($fields[
'QUANTITY_FROM'] ===
false || $fields[
'QUANTITY_FROM'] === 0)
298 $fields['QUANTITY_FROM'] = null;
302 $fields[
'QUANTITY_FROM'] =
null;
305 if (isset($fields[
'QUANTITY_TO']))
307 if (is_string($fields[
'QUANTITY_TO']) && $fields[
'QUANTITY_TO'] ===
'')
308 $fields[
'QUANTITY_TO'] =
null;
309 elseif ($fields[
'QUANTITY_TO'] ===
false || $fields[
'QUANTITY_TO'] === 0)
310 $fields['QUANTITY_TO'] = null;
314 $fields[
'QUANTITY_TO'] =
null;
317 if (isset($fields[
'EXTRA_ID']))
319 if (is_string($fields[
'EXTRA_ID']) && $fields[
'EXTRA_ID'] ===
'')
320 $fields[
'EXTRA_ID'] =
null;
321 elseif ($fields[
'EXTRA_ID'] ===
false)
322 $fields['EXTRA_ID'] = null;
326 $fields[
'EXTRA_ID'] =
null;
330 private function modifyValidate(array $items): Result
333 $items = array_values($items);
335 $basePriceTypeId = $basePriceType[
'ID'];
338 $extendPrices =
false;
339 foreach ($items as $fields)
341 $groupId = (int)$fields[
'CATALOG_GROUP_ID'];
342 if (!isset($groupTypes[$groupId]))
344 $r->addError(
new Error(
'Validate price error. Catalog price group is wrong'));
351 $extendPrices = (isset($fields[
'QUANTITY_FROM']) || isset($fields[
'QUANTITY_TO']));
353 $sortedByType[$groupId][] = $fields;
356 $allowEmptyRange = Option::get(
'catalog',
'save_product_with_empty_price_range') ===
'Y';
357 $enableQuantityRanges = Feature::isPriceQuantityRangesEnabled();
361 if (count($items) > count($sortedByType))
363 $r->addError(
new Error(
'Validate price error. Catalog product is allowed has only single price without ranges in price group.'));
369 if ($enableQuantityRanges ===
false)
371 $r->addError(
new Error(
'Validate price error. Price quantity ranges disabled'));
376 $basePrices = $sortedByType[$basePriceTypeId];
379 $r->addError(
new Error(
'Validate price error. Ranges of base price are not equal to another price group range'));
384 $basePrices = $this->sortPriceRanges($basePrices);
386 foreach ($sortedByType as $typeId => $prices)
388 $count = count($prices);
389 $prices = $this->sortPriceRanges($prices);
391 foreach ($prices as $i => $item)
393 $quantityFrom = (float)$item[
'QUANTITY_FROM'];
394 $quantityTo = (float)$item[
'QUANTITY_TO'];
397 $typeId !== $basePriceTypeId
399 !isset($basePrices[$i])
400 || $quantityFrom !== (float)$basePrices[$i][
'QUANTITY_FROM']
401 || $quantityTo !== (
float)$basePrices[$i][
'QUANTITY_TO']
407 'Validate price error. Ranges of base price are not equal to another price group range'
415 ($i !== 0 && $quantityFrom <= 0)
416 || ($i === 0 && $quantityFrom < 0)
421 "Quantity bounds error: lower bound {$quantityFrom} must be above zero (for the first range)"
427 ($i !== $count-1 && $quantityTo <= 0)
428 || ($i === $count-1 && $quantityTo < 0)
433 "Quantity bounds error: higher bound {$quantityTo} must be above zero (for the last range)"
439 if ($quantityFrom > $quantityTo && ($i !== $count-1 || $quantityTo > 0))
443 "Quantity bounds error: range {$quantityFrom}-{$quantityTo} is incorrect"
448 $nextQuantityFrom = (float)$prices[$i + 1][
"QUANTITY_FROM"];
449 $nextQuantityTo = (float)$prices[$i + 1][
"QUANTITY_TO"];
450 if ($i < $count-1 && $quantityTo >= $nextQuantityFrom)
454 "Quantity bounds error: ranges {$quantityFrom}-{$quantityTo} and {$nextQuantityFrom}-{$nextQuantityTo} overlap"
461 && $nextQuantityFrom - $quantityTo > 1
465 $validRangeFrom = $quantityTo + 1;
466 $validRangeTo = $nextQuantityFrom - 1;
470 "Invalid quantity range entry: no price is specified for range {$validRangeFrom}-{$validRangeTo})"
475 if ($i >= $count-1 && $quantityTo > 0)
479 "Invalid quantity range entry: no price is specified for quantity over {$quantityTo}"
489 private function sortPriceRanges(array $prices): array
491 $count = count($prices);
493 for ($i = 0; $i < $count - 1; $i++)
495 for ($j = $i + 1; $j < $count; $j++)
497 if ($prices[$i][
"QUANTITY_FROM"] > $prices[$j][
"QUANTITY_FROM"])
500 $prices[$i] = $prices[$j];
517 if(isset($this->
get($id)[
'ID']) ==
false)
518 $r->addError(
new Error(
'Price is not exists'));
531 $name = mb_strtolower($name);
533 if($name ==
'modify')
539 $r = parent::checkPermissionEntity($name);
549 if (!$this->accessController->check(ActionDictionary::ACTION_PRICE_EDIT))
551 $r->addError(
new Error(
'Access Denied', 200040300020));
563 !$this->accessController->check(ActionDictionary::ACTION_CATALOG_READ)
564 && !$this->accessController->check(ActionDictionary::ACTION_PRICE_EDIT)
567 $r->addError(
new Error(
'Access Denied', 200040300010));
574 private function checkPermissionIBlockElementPriceModify($productId)
578 $iblockId = \CIBlockElement::GetIBlockByID($productId);
579 if(!\CIBlockElementRights::UserHasRightTo($iblockId, $productId, self::IBLOCK_ELEMENT_EDIT_PRICE))
581 $r->addError(
new Error(
'Access Denied', 200040300030));