Bitrix-D7 22.6
 
Загрузка...
Поиск...
Не найдено
orderbasket.php
1<?php
2
4
17
18Loc::loadMessages(__FILE__);
19
20require_once __DIR__.'/../../../../general/admin_tool.php';
21
23{
24 protected static $jsInited = false;
25 protected static $arSkuProps = array();
26 protected static $offersCatalog = array();
27 protected static $iblockPropsParams = array();
28 protected static $iblockPropsParamsOrder = array();
29 protected static $productsOffersSkuParams = array();
30
31 public $settingsDialog = null;
32
34 protected $order = null;
35 protected $data = null;
36 protected $dataLight = null;
37 protected $jsObjName = "";
38 protected $idPrefix = "";
39 protected $visibleColumns = array();
40 protected $createProductBasement = true;
41 protected $mode;
42 protected $weightUnit;
43 protected $weightKoef;
44 protected $isShowXmlId;
45
46 protected static $iblockIncluded = null;
47 protected static $catalogIncluded = null;
48 protected static $highloadIncluded = null;
49
50 const VIEW_MODE = 0;
51 const EDIT_MODE = 1;
52
53 public function __construct(Order $order, $jsObjName = "", $idPrefix = "", $createProductBasement = true, $mode = self::EDIT_MODE)
54 {
55 $this->order = $order;
56 $this->idPrefix = $idPrefix;
57 if (!$this->visibleColumns)
58 $this->visibleColumns = $this->getVisibleColumns($idPrefix);
59 $this->createProductBasement = $createProductBasement;
60 $this->mode = $mode;
61 $this->weightUnit = htmlspecialcharsbx(Option::get('sale', 'weight_unit', "", $this->order->getSiteId()));
62 $this->weightKoef = floatval(Option::get('sale', 'weight_koef', 1, $this->order->getSiteId()));
63
64 if($this->weightKoef <= 0)
65 $this->weightKoef = 1;
66
67 $this->isShowXmlId = Option::get("sale", "show_order_product_xml_id", "N") == "Y";
68
69 if($jsObjName <> '' && $idPrefix <> '')
70 {
71 $this->jsObjName = $jsObjName;
72
73 $this->settingsDialog = new OrderBasketSettings(array(
74 "ID_PREFIX" => $this->idPrefix,
75 "SETTINGS_DLG_OBJECT_NAME" => $jsObjName.".settingsDialog",
76 "ALL_COLUMNS" => array_merge(
77 static::getDefaultVisibleColumns(),
78 getAdditionalColumns(),
79 array('NUMBER' => Loc::getMessage('SALE_ORDER_BASKET_SETTINGS_COL_NUMBER'))
80 ),
81 "VISIBLE_COLUMNS" => $this->visibleColumns
82 ));
83 }
84 }
85
86 public function setSettingsShowPropsVisible(bool $isVisible): void
87 {
88 $this->settingsDialog->setShowPropsVisible($isVisible);
89 }
90
97 public function getEdit($defTails = false)
98 {
99 $productAddBool = Option::get('sale', 'SALE_ADMIN_NEW_PRODUCT', 'N');
100 $siteId = htmlspecialcharsbx(
101 \CUtil::JSEscape(
102 $this->order->getSiteId()
103 ));
104
105 $result = '
106 <div class="adm-s-gray-title" style="padding-right: 2px;">
107 '.Loc::getMessage("SALE_ORDER_BASKET_COMPOSITION").'
108 <div class="adm-s-gray-title-btn-container">
109 <span
110 class="adm-btn adm-btn-green adm-btn-add"
111 onClick="'.$this->jsObjName.'.addProductSearch({lang: \''.LANGUAGE_ID.'\', siteId: \''.$siteId.'\', orderId: '.intval($this->order->getId()).'});"
112 >'.
113 Loc::getMessage("SALE_ORDER_BASKET_PRODUCT_ADD").
114 '</span>
115 </div>
116 <div class="clb"></div>
117 </div>';
118
119 $result .= '
120 <div class="adm-s-order-table-ddi">
121 <table class="adm-s-order-table-ddi-table" style="width: 100%;" id="'.$this->idPrefix.'sale_order_edit_product_table">
122 <thead style="text-align: left;">
123 <tr>
124 <td class="adm-s-order-table-context-menu-column">
125 <span class="adm-s-order-table-title-icon"
126 title="'.Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_BUTTON_TITLE").'"
127 onclick="'.$this->jsObjName.'.onHeadMenu(this);"
128 >
129 </span>
130 </td> ';
131
132 foreach($this->visibleColumns as $name)
133 $result .= "<td>".htmlspecialcharsbx($name)."</td>";
134
135 $result .= '</tr>
136 </thead>';
137
138 if($defTails)
139 {
140 $result .='
141 <tbody style="border: 1px solid rgb(221, 221, 221);" id="'.$this->idPrefix.'sale-adm-order-basket-loading-row">
142 <tr>
143 <td colspan="'.(count($this->visibleColumns)+1).'" style="padding: 20px;">
144 <img src="/bitrix/images/sale/admin-loader.gif"/>
145 </td>
146 </tr>
147 </tbody>';
148 }
149
150 $result .='
151 <tbody style="border: 1px solid rgb(221, 221, 221);'.($defTails ? ' display:none;' : '').'" id="'.$this->idPrefix.'sale-adm-order-edit-basket-empty-row">
152 <tr>
153 <td colspan="'.(count($this->visibleColumns)+1).'" style="padding: 20px;">
154 '.Loc::getMessage("SALE_ORDER_BASKET_EMPTY_ROW").'.
155 </td>
156 </tr>
157 </tbody>';
158
159 $result .= '
160 </table>
161 </div>
162 <div class="adm-s-gray-title" style="padding-right: 2px;">
163 <div class="adm-s-gray-title-btn-container">
164 <!--<span
165 class="adm-btn adm-btn-green"
166 onClick="BX.Sale.Admin.OrderAjaxer.sendRequest(BX.Sale.Admin.OrderEditPage.ajaxRequests.refreshOrderData({operation: \'DATA_ACTUALIZE\'}));"
167 >'.Loc::getMessage('SALE_ORDER_BASKET_ACTUALIZE_DATA').'</span>&nbsp;-->';
168
169 if($productAddBool == "Y")
170 {
171 $result .= '<span
172 class="adm-btn adm-btn-green adm-btn-add"
173 onClick="'.$this->jsObjName.'.productEditDialog.show();"
174 >'.
175 Loc::getMessage("SALE_ORDER_BASKET_PRODUCT_NEW").
176 '</span>&nbsp;';
177 }
178
179 $result .= '<span
180 class="adm-btn adm-btn-green adm-btn-add"
181 onClick="'.$this->jsObjName.'.addProductSearch({lang: \''.LANGUAGE_ID.'\', siteId: \''.$siteId.'\', index: 1, orderId: '.intval($this->order->getId()).'});"
182 >'.
183 Loc::getMessage("SALE_ORDER_BASKET_PRODUCT_ADD").
184 '</span>
185 </div>
186 <div class="clb"></div>
187 </div>
188 <input type="hidden" name="BASKET[ID_PREFIX]" value="'.$this->idPrefix.'">
189 <div class="adm-s-result-container">';
190
191 $result .= $this->getCouponsHtml(self::EDIT_MODE, false);
192 $result .= $this->getTotalHtml(false);
193 $result .= '
194 </div>
195 <div class="clb"></div>';
196 return $result;
197 }
198
199 public static function getBasePrice(Order $order)
200 {
201 return $order->getPrice() - $order->getTaxValue() - $order->getDiscountPrice() - $order->getDeliveryPrice();
202 }
203
204 public function getTotalHtml($needRecalculate = true)
205 {
206 $currency = $this->order->getCurrency();
207 $basket = $this->order->getBasket();
208 $totalPrices = OrderEdit::getTotalPrices($this->order, $this, $needRecalculate);
209
210 $orderDiscount = '';
211 if ((float)$totalPrices['ORDER_DISCOUNT_VALUE'] > 0)
212 {
213 $orderDiscount = '<tr>
214 <td>'.Loc::getMessage("SALE_ORDER_DEPRECATED_DISCOUNT_VALUE").'</td>
215 <td id="'.$this->idPrefix.'sale_order_edit_basket_order_discount">'.
216 \CCurrencyLang::currencyFormat(floatval($totalPrices["ORDER_DISCOUNT_VALUE"]), $currency, true).
217 '</td>
218 </tr>';
219 }
220
221 if($basket)
222 $weight = $basket->getWeight();
223 else
224 $weight = 0;
225
226 return '
227 <div class="adm-s-result-container-itog">
228 <table class="adm-s-result-container-itog-table">
229 <tr>
230 <td>'.Loc::getMessage("SALE_ORDER_BASKET_PRICE").'</td>
231 <td id="'.$this->idPrefix.'sale_order_edit_basket_price_basket">'.
232 \CCurrencyLang::currencyFormat(floatval($totalPrices["PRICE_BASKET"]), $currency, true).
233 '</td>
234 </tr>
235 <tr>
236 <td>'.Loc::getMessage("SALE_ORDER_BASKET_PRICE_DISCOUNT").'</td>
237 <td id="'.$this->idPrefix.'sale_order_edit_basket_price_discount">'.
238 \CCurrencyLang::currencyFormat(floatval($totalPrices["PRICE_BASKET_DISCOUNTED"]), $currency, true).
239 '</td>
240 </tr>
241 <tr>
242 <td>'.Loc::getMessage("SALE_ORDER_BASKET_PRICE_DELIVERY").'</td>
243 <td id="'.$this->idPrefix.'sale_order_edit_basket_price_delivery">'.
244 \CCurrencyLang::currencyFormat(floatval($totalPrices["PRICE_DELIVERY"]), $currency, true).
245 '</td>
246 </tr>
247 <tr>
248 <td>'.Loc::getMessage("SALE_ORDER_BASKET_PRICE_DELIVERY_DISCOUNT").'</td>
249 <td id="'.$this->idPrefix.'sale_order_edit_basket_price_delivery_discount">'.
250 \CCurrencyLang::currencyFormat(floatval($totalPrices["PRICE_DELIVERY_DISCOUNTED"]), $currency, true).
251 '</td>
252 </tr>'.
253 $orderDiscount.'
254 <tr>
255 <td>'.Loc::getMessage("SALE_ORDER_BASKET_TAX").'</td>
256 <td id="'.$this->idPrefix.'sale_order_edit_basket_tax">'.
257 \CCurrencyLang::currencyFormat(floatval($totalPrices["TAX_VALUE"]), $currency, true).
258 '</td>
259 </tr>
260 <tr>
261 <td>'.Loc::getMessage("SALE_ORDER_BASKET_WEIGHT").'</td>
262 <td id="'.$this->idPrefix.'sale_order_edit_basket_weight">'.
263 roundEx(floatval($weight/$this->weightKoef), SALE_WEIGHT_PRECISION)." ".$this->weightUnit.
264 '</td>
265 </tr>
266 <tr>
267 <td>'.Loc::getMessage("SALE_ORDER_BASKET_PAID").'</td>
268 <td id="'.$this->idPrefix.'sale_order_edit_summ_paid">'.
269 \CCurrencyLang::currencyFormat(
270 floatval($totalPrices["SUM_PAID"]),
271 $currency,
272 true
273 ).
274 '</td>
275 </tr>
276 <tr class="adm-s-result-container-itog-table-result">
277 <td>'.Loc::getMessage("SALE_ORDER_BASKET_PRICE_TOTAL").'</td>
278 <td id="'.$this->idPrefix.'sale_order_edit_basket_price_total">'.
279 \CCurrencyLang::currencyFormat(
280 floatval($totalPrices["SUM_UNPAID"]),
281 $currency,
282 true
283 ).
284 '</td>
285 </tr>
286 </table>
287 </div>
288 ';
289
290 }
291
292 public function getCouponsHtml($mode, $needRecalculate = true)
293 {
294 $showBlock = true;
295
296 if($mode == self::VIEW_MODE)
297 {
298 $discounts = OrderEdit::getDiscountsApplyResult($this->order, $needRecalculate);
299 $showBlock = !empty($discounts["COUPON_LIST"]);
300 }
301
302 if($showBlock)
303 {
304 $couponMessage = '';
305 if ($this->order->getId() > 0 && !($this->order instanceof Sale\Archive\Order))
306 $couponMessage = '<br><div class="bx-adm-pc-section" style="font-size: smaller;">'.Loc::getMessage('SALE_ORDER_BASKET_COUPONS_NOTE').'</div>';
307
308 $result = '
309 <div class="adm-s-result-container-promo">
310 <div class="bx-adm-promocode-container">
311 <div class="bx-adm-pc-section">
312 <div class="bx-adm-pc-title">'.Loc::getMessage("SALE_ORDER_BASKET_PROMO").'</div>'.
313 ($mode == self::EDIT_MODE ?
314 '<div class="bx-adm-pc-inputs-container">
315 <input type="text" class="bx-adm-pc-inout-text" id="sale-admin-order-coupons">
316 <input type="submit" class="bx-adm-pc-input-submit" value='.Loc::getMessage("SALE_ORDER_BASKET_ADD").' onclick="BX.Sale.Admin.OrderBasketCoupons.onAddCoupons(); return false;">
317 </div>'.$couponMessage : '').
318 '</div>
319 <div class="bx-adm-pc-section">
320 <ul class="bx-adm-pc-sale-list" id="sale-admin-order-coupons-container">
321 </ul>
322 </div>
323 </div>
324 </div>';
325 unset($couponMessage);
326 }
327 else
328 {
329 $result = '';
330 }
331
332 return $result;
333 }
334
339 public function getView($index = 0)
340 {
341 $result = '
342 <div class="adm-s-order-table-ddi">
343 <table class="adm-s-order-table-ddi-table" style="width: 100%;" id="'.$this->idPrefix.'sale_order_view_product_table">
344 <thead style="text-align: left;">
345 <tr>';
346
347 foreach($this->visibleColumns as $colId => $name)
348 {
349 $result .= "<td>".htmlspecialcharsbx($name)."</td>";
350 }
351
352 $result .= '</tr>
353 </thead>
354 <tbody style="border: 1px solid rgb(221, 221, 221);" id="'.$this->idPrefix.'sale-adm-order-basket-loading-row">
355 <tr>
356 <td colspan="'.(count($this->visibleColumns)+1).'" style="padding: 20px;">
357 <img src="/bitrix/images/sale/admin-loader.gif"/>
358 </td>
359 </tr>
360 </tbody>
361 <tbody style="border: 1px solid rgb(221, 221, 221); display:none;" id="'.$this->idPrefix.'sale-adm-order-edit-basket-empty-row">
362 <tr>
363 <td colspan="'.(count($this->visibleColumns)+1).'" style="padding: 20px;">
364 '.Loc::getMessage("SALE_ORDER_BASKET_EMPTY_ROW").'.
365 </td>
366 </tr>
367 </tbody>
368 </table>
369 </div>
370 <div class="adm-s-result-container">';
371
372 $result .= $this->getCouponsHtml(self::VIEW_MODE, false);
373 $result .= $this->getTotalHtml(false);
374 $result .= '
375 </div>
376 <div class="clb"></div>';
377
378 return $result;
379 }
380
387 public function getScripts($defTails = false)
388 {
389 if(!static::$jsInited)
390 {
391 \Bitrix\Main\Page\Asset::getInstance()->addJs("/bitrix/js/sale/admin/order_basket.js");
392 static::$jsInited = true;
393 }
394
395 $langPhrases = array("SALE_ORDER_BASKET_TURN", "SALE_ORDER_BASKET_EXPAND", "SALE_ORDER_BASKET_UP_RATIO",
396 "SALE_ORDER_BASKET_PROD_EDIT", "SALE_ORDER_BASKET_DOWN_RATIO", "SALE_ORDER_BASKET_PROD_COUNT",
397 "SALE_ORDER_BASKET_NO_PICTURE", "SALE_ORDER_BASKET_PROD_CREATE", "SALE_ORDER_BASKET_ROW_SETTINGS",
398 "SALE_ORDER_BASKET_PROD_MENU_EDIT", "SALE_ORDER_BASKET_PROD_MENU_DELETE", "SALE_ORDER_BASKET_BASE_CATALOG_PRICE",
399 "SALE_ORDER_BASKET_PROD_EDIT_ITEM_SAVE", "SALE_ORDER_BASKET_KG", "SALE_ORDER_BASKET_COUPON",
400 "SALE_ORDER_BASKET_COUPON_STATUS", "SALE_ORDER_BASKET_COUPON_APPLY", "SALE_ORDER_BASKET_COUPON_DELETE",
401 "SALE_ORDER_BASKET_POSITION_EXISTS", "SALE_ORDER_BASKET_ADD_COUPON_ERROR", "SALE_ORDER_BASKET_NO_NAME",
402 "SALE_ORDER_BASKET_PRODUCT_UNAVAILABLE"
403 );
404 $result = '<script type="text/javascript">';
405
406 foreach($langPhrases as $phrase)
407 $result .= ' BX.message({'.$phrase.': "'.\CUtil::jsEscape(Loc::getMessage($phrase)).'"});';
408
409 if(!$defTails)
410 $data = static::prepareData();
411
412 $totalPrices = OrderEdit::getTotalPrices($this->order, $this, false);
413 $weight = $this->order->getBasket() ? $this->order->getBasket()->getWeight() : 0;
414
415 if($this->mode == self::EDIT_MODE)
416 {
417
418 $result .= '
419 BX.ready(function(){
420 var obParams = {
421 tableId: "'.$this->idPrefix.'sale_order_edit_product_table",
422 idPrefix: "'.$this->idPrefix.'",
423 visibleColumns: '.\CUtil::phpToJSObject($this->visibleColumns).',
424 objName: "'.$this->jsObjName.'",
425 createProductBasement: '.($this->createProductBasement ? 'true' : 'false').',
426 columnsCount: '.count($this->visibleColumns).',
427 createBasketBottom: true,
428 isShowXmlId: '.($this->isShowXmlId ? 'true' : 'false').',
429 discounts: '.\CUtil::phpToJSObject(OrderEdit::getOrderedDiscounts($this->order, false)).',
430 mode: "edit",
431 unRemovableFields: ["PRICE", "QUANTITY"],
432 formatQuantity: "'.Option::get('sale', 'format_quantity', 'AUTO').'",
433 weightUnit: "'.$this->weightUnit.'",
434 '.$this->getTotalBlockFieldsJs($totalPrices, array("WEIGHT" => $weight)).'
435 };';
436
437 if(!$defTails)
438 {
439 $result .= '
440 obParams.productsOrder = '.\CUtil::phpToJSObject($data["ITEMS_ORDER"] ?? []).';
441 obParams.products = '.\CUtil::phpToJSObject($data["ITEMS"] ?? []).';
442 obParams.iblocksSkuParams = '.\CUtil::phpToJSObject($data["IBLOCKS_SKU_PARAMS"] ?? []).';
443 obParams.iblocksSkuParamsOrder = '.\CUtil::phpToJSObject($data["IBLOCKS_SKU_PARAMS_ORDER"] ?? []).';';
444 }
445
446 $result .=
447 $this->jsObjName.'= new BX.Sale.Admin.OrderBasketEdit(obParams);
448 BX.Sale.Admin.OrderEditPage.registerFieldsUpdaters( '.$this->jsObjName.'.getFieldsUpdaters() );
449 BX.Sale.Admin.OrderBasketCoupons.statusCouponApplyed = '.DiscountCouponsManager::STATUS_APPLYED.';
450 BX.Sale.Admin.OrderBasketCoupons.mode = BX.Sale.Admin.OrderBasketCoupons.MODES_LIST.'.($this->order->getId() > 0 ? 'EDIT' : 'CREATE').';
451 BX.Sale.Admin.OrderBasketCoupons.setCoupons('.
452 \CUtil::phpToJSObject(
453 OrderEdit::getCouponList($this->order, false)
454 ).
455 ');
456 });';
457
458 $result .= $this->settingsDialog->getScripts();
459 }
460 else
461 {
462 $showProps = OrderBasketSettings::loadIsShowPropsVisible();
463
464 $result .= '
465 BX.ready(function(){
466 var obParams = {
467 tableId: "'.$this->idPrefix.'sale_order_view_product_table",
468 idPrefix: "'.$this->idPrefix.'",
469 visibleColumns: '.\CUtil::phpToJSObject($this->visibleColumns).',
470 objName: "'.$this->jsObjName.'",
471 createProductBasement: '.($this->createProductBasement ? 'true' : 'false').',
472 columnsCount: '.count($this->visibleColumns).',
473 isShowXmlId: '.($this->isShowXmlId ? 'true' : 'false').',
474 discounts: '.\CUtil::phpToJSObject(OrderEdit::getOrderedDiscounts($this->order, false)).',
475 createBasketBottom: true,
476 mode: "view",
477 showProps: '.($showProps ? 'true' : 'false').',
478 formatQuantity: "'.Option::get('sale', 'format_quantity', 'AUTO').'",
479 weightUnit: "'.$this->weightUnit.'",
480 '.$this->getTotalBlockFieldsJs($totalPrices, array("WEIGHT" => $weight)).'
481 };';
482
483 if(!$defTails)
484 {
485 $result .= '
486 obParams.productsOrder = '.\CUtil::phpToJSObject($data["ITEMS_ORDER"]).';
487 obParams.products = '.\CUtil::phpToJSObject($data["ITEMS"]).';
488 obParams.iblocksSkuParams = '.\CUtil::phpToJSObject($data["IBLOCKS_SKU_PARAMS"]).';
489 obParams.iblocksSkuParamsOrder = '.\CUtil::phpToJSObject($data["IBLOCKS_SKU_PARAMS_ORDER"]).';';
490 }
491
492 $result .=
493 $this->jsObjName.'= new BX.Sale.Admin.OrderBasket(obParams);
494 BX.Sale.Admin.OrderEditPage.registerFieldsUpdaters( '.$this->jsObjName.'.getFieldsUpdaters() );
495 BX.Sale.Admin.OrderBasketCoupons.mode = BX.Sale.Admin.OrderBasketCoupons.MODES_LIST.VIEW;
496 BX.Sale.Admin.OrderBasketCoupons.setCoupons('.
497 \CUtil::phpToJSObject(
498 OrderEdit::getCouponList($this->order, false)
499 ).
500 ');
501 });';
502
503 $result .= $this->settingsDialog->getScripts();
504 }
505
506 $result .= '</script>';
507 return $result;
508 }
509
510 protected function getTotalBlockFieldsJs($totalPrices, $data)
511 {
512 return '
513 totalBlockFields: {
514 PRICE_BASKET: {
515 id: "'.$this->idPrefix.'sale_order_edit_basket_price_basket",
516 value: "'.Sale\PriceMaths::roundByFormatCurrency($totalPrices["PRICE_BASKET"], $this->order->getCurrency()).'",
517 type: "currency"
518 },
519 PRICE_BASKET_DISCOUNTED: {
520 id: "'.$this->idPrefix.'sale_order_edit_basket_price_discount",
521 value: "'.Sale\PriceMaths::roundByFormatCurrency($totalPrices["PRICE_BASKET_DISCOUNTED"], $this->order->getCurrency()).'",
522 type: "currency"
523 },
524 PRICE_DELIVERY: {
525 id: "'.$this->idPrefix.'sale_order_edit_basket_price_delivery",
526 value: "'.Sale\PriceMaths::roundByFormatCurrency($totalPrices["PRICE_DELIVERY"], $this->order->getCurrency()).'",
527 type: "currency"
528 },
529 PRICE_DELIVERY_DISCOUNTED: {
530 id: "'.$this->idPrefix.'sale_order_edit_basket_price_delivery_discount",
531 value: "'.Sale\PriceMaths::roundByFormatCurrency($totalPrices["PRICE_DELIVERY_DISCOUNTED"], $this->order->getCurrency()).'",
532 type: "currency"
533 },
534 TAX_VALUE: {
535 id: "'.$this->idPrefix.'sale_order_edit_basket_tax",
536 value: "'.Sale\PriceMaths::roundByFormatCurrency($totalPrices["TAX_VALUE"], $this->order->getCurrency()).'",
537 type: "currency"
538 },
539 WEIGHT: {
540 id: "'.$this->idPrefix.'sale_order_edit_basket_weight",
541 value: "'.roundEx(floatval($data["WEIGHT"]), SALE_WEIGHT_PRECISION).'",
542 type: "weight"
543 },
544 SUM_PAID: {
545 id: "'.$this->idPrefix.'sale_order_edit_summ_paid",
546 value: "'.Sale\PriceMaths::roundByFormatCurrency($totalPrices["SUM_PAID"], $this->order->getCurrency()).'",
547 //edit: true,
548 type: "currency"
549 },
550 SUM_UNPAID: {
551 id: "'.$this->idPrefix.'sale_order_edit_basket_price_total",
552 value: "'.Sale\PriceMaths::roundByFormatCurrency($totalPrices["SUM_UNPAID"], $this->order->getCurrency()).'",
553 type: "currency"
554 }
555 }';
556 }
557
563 protected function getOffersIds($productId, array $products)
564 {
565 $result = array();
566
567 foreach($products as $product)
568 {
569 if($product['PRODUCT_ID'] == $productId && intval($product['OFFER_ID']) > 0)
570 {
571 $result[] = $product['OFFER_ID'];
572 }
573 }
574
575 return $result;
576 }
577
578 public function getOffersSkuParams(array $productsParams, array $visibleColumns = array())
579 {
580 return static::getOffersSkuParamsMode($productsParams, $visibleColumns, $this->mode);
581 }
582
590 public static function getOffersSkuParamsMode(array $productsParams, array $visibleColumns = array(), $mode = 0)
591 {
592 if(!empty($productsParams["ITEMS"]) && is_array($productsParams["ITEMS"]))
593 {
594 if (self::$catalogIncluded === null)
595 self::$catalogIncluded = Main\Loader::includeModule('catalog');
596 if (!self::$catalogIncluded)
597 return $productsParams;
598
599 $iblockPropsUsed = array();
600 $productIds = array();
601 $existOffers = array();
602 $skuFilter = array('ID' => array());
603 $propFilter = array('ID' => array());
604 $ibs = array();
605
606 foreach($productsParams["ITEMS"] as $params)
607 {
608 if($params['MODULE'] != 'catalog')
609 continue;
610
611 $productIds[] = $params['PRODUCT_ID'];
612
613 if ($mode == self::VIEW_MODE)
614 {
615 if ((int)$params['OFFER_ID'] > 0)
616 {
617 $skuFilter['ID'][] = $params['OFFER_ID'];
618 }
619 }
620
621 if (!isset($ibs[$params["IBLOCK_ID"]]))
622 {
623 $props = static::getSkuProps(true, $params["IBLOCK_ID"]);
624 if (!empty($props))
625 {
626 foreach($props as $prop)
627 {
628 $propFilter['ID'][] = $prop['ID'];
629 }
630 }
631
632 $ibs[$params["IBLOCK_ID"]] = true;
633 }
634
635 if($params["PRODUCT_ID"] != $params["OFFER_ID"])
636 $existOffers[] = $params["OFFER_ID"];
637 }
638
639 $skuFilter['ID'] = array_unique($skuFilter['ID']);
640 $productIds = array_unique($productIds);
641 $propFilter['ID'] = array_unique($propFilter['ID']);
642
643 $allOffers = \CCatalogSKU::getOffersList(
644 $productIds,
645 0,
646 $skuFilter,
647 array('NAME', "ACTIVE", 'CATALOG_QUANTITY'),
648 $propFilter
649 );
650
651 $tmpPropsOff = array();
652
653 if(!empty($allOffers))
654 $tmpPropsOff = static::getPropsFromOffers2($allOffers, $existOffers);
655
656 unset($skuFilter, $propFilter, $existOffers, $productIds);
657
658 foreach($productsParams["ITEMS"] as &$params)
659 {
660 if($params['MODULE'] != 'catalog')
661 continue;
662
663 if(!isset(self::$productsOffersSkuParams[$params["PRODUCT_ID"]]) || !isset(self::$productsOffersSkuParams[$params["PRODUCT_ID"]]))
664 {
665 if(isset($tmpPropsOff[$params["PRODUCT_ID"]]))
666 {
667 self::$productsOffersSkuParams[$params["PRODUCT_ID"]] = $tmpPropsOff[$params["PRODUCT_ID"]];
668
669 foreach($tmpPropsOff[$params["PRODUCT_ID"]] as $offerId => $propsList)
670 {
671 foreach($propsList as $propId => $propValue)
672 {
673 if(!isset($iblockPropsUsed[$propId]))
674 $iblockPropsUsed[$propId] = array();
675
676 if(is_array($propValue))
677 {
678 $iblockPropsUsed[$propId] = array_merge(
679 $iblockPropsUsed[$propId],
680 array_diff(
681 $propValue,
682 $iblockPropsUsed[$propId]
683 )
684 );
685 }
686 else
687 {
688 if(!in_array($propValue, $iblockPropsUsed[$propId]))
689 $iblockPropsUsed[$propId][] = $propValue;
690 }
691 }
692 }
693 }
694 else
695 {
696 $res = \CIBlockElement::GetPropertyValues($params["IBLOCK_ID"], array('ID' => $params['PRODUCT_ID']));
697 $tmpProps = $res->Fetch();
698
699 if(is_array($tmpProps))
700 {
701 foreach($tmpProps as $id => $val)
702 {
703 if(!empty($val))
704 {
705 if(!isset($iblockPropsUsed[$id]))
706 $iblockPropsUsed[$id] = array();
707
708 if(is_array($val))
709 {
710 $iblockPropsUsed[$id] = array_merge(
711 $iblockPropsUsed[$id],
712 array_diff(
713 $val,
714 $iblockPropsUsed[$id]
715 )
716 );
717 }
718 else
719 {
720 if(!in_array($val, $iblockPropsUsed[$id]))
721 $iblockPropsUsed[$id][] = $val;
722 }
723 }
724 }
725 }
726 }
727 }
728 }
729
730 unset($allOffers, $tmpPropsOff);
731 $possibleSkuParams = array();
732
733 foreach($productsParams["ITEMS"] as &$params)
734 {
735 if($params['MODULE'] != 'catalog')
736 continue;
737
738 $possibleSku = array();
739
740 if(intval($params["OFFERS_IBLOCK_ID"]) > 0 && !isset(self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]]))
741 {
742 self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]] = static::getPropsParams(
743 $params["OFFERS_IBLOCK_ID"],
744 array(),
745 $iblockPropsUsed
746 );
747 }
748
749 if(intval($params["IBLOCK_ID"]) > 0 && !isset(self::$iblockPropsParams[$params["IBLOCK_ID"]]))
750 {
751 self::$iblockPropsParams[$params["IBLOCK_ID"]] = static::getPropsParams(
752 $params["IBLOCK_ID"],
753 $visibleColumns,
754 $iblockPropsUsed
755 );
756 }
757
758 if (!empty(self::$productsOffersSkuParams[$params["PRODUCT_ID"]][$params["OFFER_ID"]]))
759 {
760 $params["SKU_PROPS"] = self::$productsOffersSkuParams[$params["PRODUCT_ID"]][$params["OFFER_ID"]];
761 }
762
763 if (
764 isset($params["SKU_PROPS"])
765 && is_array($params["SKU_PROPS"])
766 )
767 {
768 foreach ($params["SKU_PROPS"] as $id => $skuProps)
769 {
770 if(is_array($skuProps))
771 {
772 unset($params["SKU_PROPS"][$id]);
773 continue;
774 }
775
776 $params["SKU_PROPS"][$id] = array(
777 'ID' => $skuProps,
778 'NAME' => self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]][$id]['NAME'],
779 'VALUE' => self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]][$id]['VALUES'][$skuProps],
780 'CODE' => self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]][$id]['CODE'],
781 'SORT' => self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]][$id]['SORT']
782 );
783
784 $possibleSku[$id] = self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]][$id]['VALUES'][$skuProps]['ID'];
785 }
786 }
787
788 if($mode == self::EDIT_MODE && $params['PRODUCT_ID'] != $params['OFFER_ID'])
789 {
790 if(is_array(self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]]))
791 $skuOrder = array_keys(self::$iblockPropsParams[$params["OFFERS_IBLOCK_ID"]]);
792 else
793 $skuOrder = array_keys($possibleSku);
794
795 $possibleSkuParams[$params['OFFER_ID']] = array(
796 'PRODUCT_ID' => $params['PRODUCT_ID'],
797 'OFFER_ID' => $params['OFFER_ID'],
798 'SKU_PROPS' => $possibleSku,
799 'SKU_ORDER' => $skuOrder
800 );
801 }
802 }
803
804 unset($params, $iblockPropsUsed);
805
806 if($mode == self::EDIT_MODE && !empty($possibleSkuParams))
807 {
808 $possibleSkuProps = Sale\Helpers\Admin\SkuProps::getPossibleSkuPropsValues($possibleSkuParams);
809
810 if(!empty($possibleSkuProps))
811 {
812 foreach($productsParams["ITEMS"] as $key => $params)
813 {
814 if($params['MODULE'] != 'catalog')
815 continue;
816
817 $productsParams["ITEMS"][$key]["SKU_PROPS_POSSIBLE_VALUES"] = $possibleSkuProps[$params['OFFER_ID']] ?? [];
818 }
819
820 unset($possibleSkuParams);
821 }
822 }
823
824 $productsParams["IBLOCKS_SKU_PARAMS"] = self::$iblockPropsParams;
825
826 foreach(self::$iblockPropsParams as $iBlockId => $props)
827 self::$iblockPropsParamsOrder[$iBlockId] = array_keys($props);
828 }
829
830 $productsParams["IBLOCKS_SKU_PARAMS_ORDER"] = self::$iblockPropsParamsOrder;
831 return $productsParams;
832 }
833
845 public static function getProductDetails($productId, $quantity, $userId, $siteId, array $columns = array())
846 {
847 $stored = true;
848 $result = OrderEdit::getProductDetails($productId, $userId, $siteId);
849
850 if($result === false)
851 $stored = false;
852
853 if($result === false)
854 {
855 if (self::$catalogIncluded === null)
856 self::$catalogIncluded = Main\Loader::includeModule('catalog');
857 if (!self::$catalogIncluded)
858 return array();
859
860 $result = self::getProductDataToFillBasket($productId, $quantity, $userId, $siteId, implode(",",array_keys($columns)));
861
862 static $proxyProductData = array();
863
864 if (!empty($proxyProductData[$productId]) && is_array($proxyProductData[$productId]))
865 {
866 $productInfo = $proxyProductData[$productId];
867 }
868 else
869 {
870 $productInfo = \CCatalogSku::getProductInfo($productId);
871 $proxyProductData[$productId] = $productInfo;
872 }
873
874 if($productInfo != false)
875 {
876 $result["OFFERS_IBLOCK_ID"] = $productInfo["OFFER_IBLOCK_ID"];
877 $result["IBLOCK_ID"] = $productInfo["IBLOCK_ID"];
878 $result["PRODUCT_ID"] = $productInfo["ID"];
879 }
880 else
881 {
882 $result["OFFERS_IBLOCK_ID"] = 0;
883 $result["IBLOCK_ID"] = $result["PRODUCT_PROPS_VALUES"]["IBLOCK_ID"];
884 $result["PRODUCT_ID"] = $result["PRODUCT_PROPS_VALUES"]["ID"];
885 }
886 }
887
888 if(!$stored)
889 OrderEdit::setProductDetails($productId, $userId, $siteId, $result);
890
891 return $result;
892 }
893
902 public static function getProductsData(array $productsIds, $siteId, array $fields = array(), $userId = 0)
903 {
904 if(empty($productsIds))
905 return array();
906
907 $result = array();
908
909 foreach($productsIds as $id)
910 {
911 $details = OrderEdit::getProductDetails($id, $userId, $siteId);
912
913 if($details !== false)
914 $result[$id] = $details;
915 }
916
917 $noCachedProductIds = array_diff($productsIds, array_keys($result));
918
919 if(!empty($noCachedProductIds))
920 {
921 $noCachedData = \Bitrix\Sale\Helpers\Admin\Product::getData($noCachedProductIds, $siteId, array_keys($fields));
922
923 foreach($noCachedData as $productId => $productData)
924 {
925 $result[$productId] = $productData;
926 OrderEdit::setProductDetails($productId, $userId, $siteId, $result[$productId]);
927 }
928
929 $emptyData = array_diff($productsIds, array_keys($result));
930
931 foreach($emptyData as $productId)
932 $result[$productId] = array();
933 }
934
935 return $result;
936 }
937
938 protected static function getPropsParams($iblockId, array $visibleColumns = array(), array $iblockPropsUsed = array())
939 {
940 $arRes = array();
941 $bUseHLIblock = \Bitrix\Main\Loader::includeModule('highloadblock');
942 $filter = array(
943 '=IBLOCK_ID' => intval($iblockId),
944 '=ACTIVE' => 'Y'
945 );
946
947 if(!empty($iblockPropsUsed))
948 {
949 $filter['ID'] = array_keys($iblockPropsUsed);
950 }
951
952 if(!empty($visibleColumns))
953 {
954 $iBlockProps = array();
955 $iBlockPropsInt = array();
956
957 foreach ($visibleColumns as $id => $name)
958 {
959 if (mb_substr($id, 0, 9) == "PROPERTY_")
960 {
961 $iblockPropCode = mb_substr($id, 9);
962
963 if($iblockPropCode <> '')
964 {
965 $iBlockProps[] = $iblockPropCode;
966
967 if(intval($iblockPropCode) > 0)
968 $iBlockPropsInt[] = intval($iblockPropCode);
969 }
970 }
971 }
972
973 if(!empty($iBlockProps) || !empty($iBlockPropsInt))
974 {
975 $codes = array('LOGIC' => 'OR');
976
977 if(!empty($iBlockProps))
978 $codes['=CODE'] = $iBlockProps;
979
980 if(!empty($iBlockPropsInt))
981 $codes['=ID'] = $iBlockPropsInt;
982
983 $filter[] = $codes;
984 }
985 }
986
987 $rsProps = \Bitrix\Iblock\PropertyTable::getList(array(
988 'filter' => $filter,
989 'order' => array('SORT' => 'ASC', 'ID' => 'ASC'),
990 ));
991
992 while ($arProp = $rsProps->fetch())
993 {
994 if(!empty($iblockPropsUsed) && !array_key_exists($arProp['ID'], $iblockPropsUsed))
995 continue;
996
997 if (
998 $arProp['PROPERTY_TYPE'] == 'L'
999 || $arProp['PROPERTY_TYPE'] == 'E'
1000 || ($arProp['PROPERTY_TYPE'] == 'S' && $arProp['USER_TYPE'] == 'directory')
1001 )
1002 {
1003 if ($arProp['XML_ID'] == 'CML2_LINK')
1004 continue;
1005
1006 $arValues = array();
1007
1008 if ($arProp['PROPERTY_TYPE'] == 'L')
1009 {
1010 $arValues = array();
1011 $rsPropEnums = \CIBlockProperty::getPropertyEnum($arProp['ID']);
1012 while ($arEnum = $rsPropEnums->fetch())
1013 {
1014 $arValues[$arEnum['VALUE']] = array(
1015 'ID' => $arEnum['ID'],
1016 'NAME' => $arEnum['VALUE'],
1017 'PICT' => false
1018 );
1019 }
1020 }
1021 elseif ($arProp['PROPERTY_TYPE'] == 'E')
1022 {
1023 $eFilter = array('IBLOCK_ID' => $arProp['LINK_IBLOCK_ID'], 'ACTIVE' => 'Y');
1024
1025 if(!empty($iblockPropsUsed[$arProp['ID']]))
1026 $eFilter['ID'] = $iblockPropsUsed[$arProp['ID']];
1027 else
1028 continue;
1029
1030 $rsPropEnums = \CIBlockElement::getList(
1031 array('SORT' => 'ASC'),
1032 $eFilter,
1033 false,
1034 false,
1035 array('ID', 'NAME', 'PREVIEW_PICTURE', 'SORT')
1036 );
1037
1038 while ($arEnum = $rsPropEnums->Fetch())
1039 {
1040 $arEnum['PREVIEW_PICTURE'] = \CFile::getFileArray($arEnum['PREVIEW_PICTURE']);
1041
1042 if (!is_array($arEnum['PREVIEW_PICTURE']))
1043 {
1044 $arEnum['PREVIEW_PICTURE'] = false;
1045 }
1046
1047 if ($arEnum['PREVIEW_PICTURE'] !== false)
1048 {
1049 $productImg = \CFile::resizeImageGet($arEnum['PREVIEW_PICTURE'], array('width'=>80, 'height'=>80), BX_RESIZE_IMAGE_PROPORTIONAL, false, false);
1050 $arEnum['PREVIEW_PICTURE'] = $productImg['src'];
1051 }
1052
1053 $arValues[$arEnum['ID']] = array(
1054 'ID' => $arEnum['ID'],
1055 'NAME' => $arEnum['NAME'],
1056 'SORT' => $arEnum['SORT'],
1057 'PICT' => $arEnum['PREVIEW_PICTURE']
1058 );
1059 }
1060 }
1061 elseif ($arProp['PROPERTY_TYPE'] == 'S' && $arProp['USER_TYPE'] == 'directory')
1062 {
1063 if ($bUseHLIblock)
1064 {
1065 if(!is_array($arProp["USER_TYPE_SETTINGS"]))
1066 $arProp["USER_TYPE_SETTINGS"] = unserialize($arProp["USER_TYPE_SETTINGS"], ['allowed_classes' => false]);
1067
1068 $hlblock = HL\HighloadBlockTable::getList(array("filter" => array("TABLE_NAME" => $arProp["USER_TYPE_SETTINGS"]["TABLE_NAME"])))->fetch();
1069 if ($hlblock)
1070 {
1071 $entity = HL\HighloadBlockTable::compileEntity($hlblock);
1072 $entityDataClass = $entity->getDataClass();
1073 $rsData = $entityDataClass::getList();
1074
1075 while ($arData = $rsData->fetch())
1076 {
1077 $arValues[$arData['UF_XML_ID']] = array(
1078 'ID' => $arData['UF_XML_ID'],
1079 'NAME' => $arData['UF_NAME'],
1080 'SORT' => $arData['UF_SORT'],
1081 'FILE' => $arData['UF_FILE'],
1082 'PICT' => '',
1083 'XML_ID' => $arData['UF_XML_ID']
1084 );
1085 }
1086
1087 }
1088 }
1089 }
1090
1091 if (
1092 isset($iblockPropsUsed[$arProp['ID']])
1093 && is_array($iblockPropsUsed[$arProp['ID']])
1094 && !empty($arValues)
1095 && is_array($arValues)
1096 )
1097 {
1098 //if property value deleted or inactive
1099 $notFound = array_diff($iblockPropsUsed[$arProp['ID']], array_keys($arValues));
1100
1101 //if Empty values exist
1102 if((is_array($iblockPropsUsed[$arProp['ID']]) && in_array("-", $iblockPropsUsed[$arProp['ID']])) || (is_array($notFound) && !empty($notFound)))
1103 {
1104 $arValues["-"] = array(
1105 "ID" => "-",
1106 "NAME" => "-"
1107 );
1108 }
1109
1110 $arRes[$arProp['ID']] = array(
1111 'ID' => $arProp['ID'],
1112 'CODE' => $arProp['CODE'],
1113 'NAME' => $arProp['NAME'],
1114 'TYPE' => $arProp['PROPERTY_TYPE'],
1115 'ORDER' => array_keys($arValues),
1116 'VALUES' => $arValues,
1117 'SORT' => $arProp['SORT']
1118 );
1119 }
1120 }
1121
1122 if (
1123 $arProp['PROPERTY_TYPE'] == "S"
1124 && $arProp['USER_TYPE'] == 'directory'
1125 && isset($arRes[$arProp['ID']]['VALUES'])
1126 && is_array($arRes[$arProp['ID']]['VALUES'])
1127 )
1128 {
1129 foreach($arRes[$arProp['ID']]['VALUES'] as $id => $value)
1130 {
1131 if (isset($value["FILE"]))
1132 {
1133 $arTmpFile = \CFile::getFileArray($value["FILE"]);
1134 $tmpImg = \CFile::resizeImageGet(
1135 $arTmpFile,
1136 [
1137 'width' => 20,
1138 'height' => 20,
1139 ],
1140 BX_RESIZE_IMAGE_PROPORTIONAL,
1141 false,
1142 false
1143 );
1144 $arRes[$arProp['ID']]['VALUES'][$id]['PICT'] = $tmpImg['src'];
1145 }
1146 }
1147 }
1148 }
1149
1150 return $arRes;
1151 }
1152
1153 protected static function getPropsFromOffers2(array $items, array $existOffers)
1154 {
1155 $props = array();
1156 $notEmptyProps = array();
1157 $allProps = array();
1158
1159 foreach($items as $id => $item)
1160 {
1161 if(!isset($props[$id]))
1162 $props[$id] = array();
1163
1164 foreach($item as $offerId => $offer)
1165 {
1166 if(!isset($offer["PROPERTIES"]))
1167 continue;
1168
1169 if(!in_array($offerId, $existOffers) && $offer["ACTIVE"] != "Y")
1170 continue;
1171
1172 if(!isset($props[$id][$offerId]))
1173 $props[$id][$offerId] = array();
1174
1175 foreach($offer["PROPERTIES"] as $propCode => $propParams)
1176 {
1177 if($propParams["MULTIPLE"] == "Y")
1178 continue;
1179
1180 if($propParams["ACTIVE"] != "Y") //!$propParams["~VALUE"] ||
1181 continue;
1182
1183 if($propParams['PROPERTY_TYPE'] == 'L'
1184 || $propParams['PROPERTY_TYPE'] == 'E'
1185 || (
1186 $propParams['PROPERTY_TYPE'] == 'S'
1187 && $propParams['USER_TYPE'] == 'directory'
1188 )
1189 )
1190 {
1191 if(!in_array($propParams["ID"], $allProps))
1192 $allProps[] = $propParams["ID"];
1193
1194 if($propParams["~VALUE"] <> '')
1195 {
1196 $props[$id][$offerId][$propParams["ID"]] = $propParams["~VALUE"];
1197
1198 if(!in_array($propParams["ID"], $notEmptyProps))
1199 $notEmptyProps[] = $propParams["ID"];
1200 }
1201 else
1202 {
1203 $props[$id][$offerId][$propParams["ID"]] = "-";
1204 }
1205 }
1206 }
1207 }
1208 }
1209
1210 $emptyProps = array_diff($allProps, $notEmptyProps);
1211
1212 if(!empty($emptyProps))
1213 {
1214 foreach($emptyProps as $propId)
1215 {
1216 foreach($props as $prodId => $offers)
1217 {
1218 foreach($offers as $offerId => $offerProps)
1219 {
1220 unset($props[$prodId][$offerId][$propId]);
1221 }
1222 }
1223 }
1224 }
1225
1226 return $props;
1227 }
1228
1229 protected static function getSkuProps($flagAll, $iblockId)
1230 {
1231 if (!isset(static::$arSkuProps[$iblockId]))
1232 {
1233 $arCatalog = static::getOffersCatalog($iblockId);
1234 static::$arSkuProps[$iblockId] = $arCatalog? static::getPropsList($arCatalog["IBLOCK_ID"], $arCatalog['SKU_PROPERTY_ID']) : array();
1235 }
1236 return $flagAll? static::$arSkuProps[$iblockId] : static::filterProps(static::$arSkuProps[$iblockId]);
1237 }
1238
1239 protected static function getOffersCatalog($iblockId)
1240 {
1241 if (self::$catalogIncluded === null)
1242 self::$catalogIncluded = Main\Loader::includeModule('catalog');
1243 if (!self::$catalogIncluded)
1244 return array();
1245
1246 if (!isset(static::$offersCatalog[$iblockId]))
1247 static::$offersCatalog[$iblockId] = \CCatalogSKU::getInfoByProductIBlock($iblockId);
1248
1249 return static::$offersCatalog[$iblockId];
1250 }
1251
1252 protected static function getPropsList($iblockId, $skuPropertyId = 0)
1253 {
1254 if (self::$catalogIncluded === null)
1255 self::$catalogIncluded = Main\Loader::includeModule('catalog');
1256 if (!self::$catalogIncluded)
1257 return [];
1258
1259 $propertyIds = Catalog\Product\PropertyCatalogFeature::getOfferTreePropertyCodes($iblockId);
1260 if ($propertyIds === null)
1261 return [];
1262 $arResult = [];
1263 $filter = array(
1264 '@ID' => $propertyIds,
1265 '=IBLOCK_ID' => $iblockId,
1266 );
1267 if ($skuPropertyId > 0)
1268 $filter['!=ID'] = $skuPropertyId;
1269 $iterator = Iblock\PropertyTable::getList(array(
1270 'select' => array('*'),
1271 'filter' => $filter,
1272 'order' => array(
1273 'SORT' => 'ASC',
1274 'NAME' => 'ASC'
1275 )
1276 ));
1277 while ($row = $iterator->fetch())
1278 {
1279 $row['USER_TYPE'] = (string)$row['USER_TYPE'];
1280 $row['~NAME'] = $row['NAME'];
1281 $row['NAME'] = htmlspecialcharsEx($row['NAME']);
1282 $row['PROPERTY_USER_TYPE'] = ($row['USER_TYPE'] != '' ? \CIBlockProperty::getUserType($row['USER_TYPE']) : array());
1283 $arResult[] = $row;
1284 }
1285 unset($row, $iterator);
1286
1287 return $arResult;
1288 }
1289
1290 protected static function filterProps(&$props)
1291 {
1292 $result = array();
1293 if ($props)
1294 {
1295 foreach ($props AS $prop)
1296 {
1297 if ($prop['FILTRABLE'] == 'Y' && $prop['PROPERTY_TYPE'] != 'F')
1298 $result[] = $prop;
1299 }
1300 }
1301 return $result;
1302 }
1303
1304 public function getSettingsDialogContent()
1305 {
1306 return $this->settingsDialog->getHtml();
1307 }
1308
1309 public static function loadVisibleColumns($idPrefix)
1310 {
1311 return \CUserOptions::GetOption($idPrefix."order_basket_table", "table_columns");
1312 }
1313
1314 protected static function getDefaultVisibleColumns()
1315 {
1316 return array(
1317 "IMAGE" => Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_IMAGE"),
1318 "NAME" => Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_NAME"),
1319 "QUANTITY" => Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_QUANTITY"),
1320 "AVAILABLE" => Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_AVAILABLE"),
1321 "PROPS" => Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_PROPS"),
1322 "PRICE" => Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_PRICE"),
1323 "SUM" => Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_SUM")
1324 );
1325 }
1326
1327 protected function getVisibleColumns($idPrefix)
1328 {
1329 if (self::$iblockIncluded === null)
1330 self::$iblockIncluded = Main\Loader::includeModule('iblock');
1331 if (!self::$iblockIncluded)
1332 return array();
1333
1334 $result = array();
1335 $arTmpColumns = array();
1336 $arColumnsOptions = static::loadVisibleColumns($idPrefix);
1337
1338 if (is_array($arColumnsOptions) && isset($arColumnsOptions["columns"]) && $arColumnsOptions["columns"] <> '')
1339 $arTmpColumns = explode(",", $arColumnsOptions["columns"]);
1340
1341 if(is_array($arTmpColumns) && !empty($arTmpColumns))
1342 {
1343 $iBlockProps = array();
1344 $iBlockPropsInt = array();
1345
1346 foreach ($arTmpColumns as $id => $columnCode)
1347 {
1348 if (mb_substr($columnCode, 0, 9) == "PROPERTY_")
1349 {
1350 $iblockPropCode = mb_substr($columnCode, 9);
1351
1352 if($iblockPropCode <> '')
1353 {
1354 $iBlockProps[] = $iblockPropCode;
1355
1356 if(intval($iblockPropCode) > 0)
1357 $iBlockPropsInt[] = intval($iblockPropCode);
1358
1359 $result[$columnCode] = "";
1360 }
1361 }
1362 else
1363 {
1364 $result[$columnCode] = Loc::getMessage("SALE_ORDER_BASKET_SETTINGS_COL_".$columnCode);
1365 }
1366 }
1367
1368 if(!empty($iBlockProps))
1369 {
1370 $dbRes = \Bitrix\Iblock\PropertyTable::getList(array(
1371 'filter' => array(
1372 'LOGIC' => 'OR',
1373 '=CODE' => $iBlockProps,
1374 '=ID' => $iBlockPropsInt
1375 ),
1376 'select' => array('ID', 'NAME', 'CODE')
1377 ));
1378
1379 while($arPropData = $dbRes->fetch())
1380 {
1381 if($arPropData['CODE'] <> '')
1382 $result["PROPERTY_".$arPropData['CODE']] = $arPropData["NAME"];
1383 else
1384 $result["PROPERTY_".$arPropData['ID']] = $arPropData["NAME"];
1385 }
1386 }
1387 }
1388 else
1389 {
1390 $result = static::getDefaultVisibleColumns();
1391 }
1392
1393 return $result;
1394 }
1395
1396 public static function getProductEditDialogHtml($currency, $objName)
1397 {
1398 return '
1399 <input id="FORM_BASKET_PRODUCT_ID" name="BASKET_PRODUCT_ID" value="" type="hidden">
1400 <input id="FORM_PROD_BASKET_CUSTOM_PRICE" name="BASKET_CUSTOM_PRICE" value="Y" type="hidden">
1401 <input id="FORM_PROD_BASKET_BASKET_CODE" name="FORM_PROD_BASKET_BASKET_CODE" value="" type="hidden">
1402 <table class="edit-table">
1403 <tr>
1404 <td width="40%">&nbsp;</td>
1405 <td align="left" width="60%">
1406 <div id="basketError" style="display:none;">
1407 <table class="message message-error" border="0" cellpadding="0" cellspacing="0" style="border:2px solid #FF0000;color:#FF0000">
1408 <tr>
1409 <td>
1410 <table class="content" border="0" cellpadding="0" cellspacing="0" style="margin:4px;">
1411 <tr>
1412 <td valign="top"><div class="icon-error"></div></td>
1413 <td>
1414 <span class="message-title" style="font-weight:bold;">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ERROR").'</span><br>
1415 <div class="empty" style="height: 5px;"></div><div id="basketErrorText"></div>
1416 </td>
1417 </tr>
1418 </table>
1419 </td>
1420 </tr>
1421 </table>
1422 </div></td>
1423 </tr>
1424 <tr id="FORM_NEWPROD_CODE">
1425 <td class="adm-detail-content-cell-l" width="30%">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_ID").':</td>
1426 <td width="70%"><input size="10" id="FORM_PROD_BASKET_OFFER_ID" name="FORM_PROD_BASKET_OFFER_ID" type="text" value="" tabindex="1"></td>
1427 </tr>
1428 <tr class="adm-detail-required-field">
1429 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_NAME").':</td>
1430 <td><input size="40" id="FORM_PROD_BASKET_NAME" name="FORM_PROD_BASKET_NAME" type="text" value="" tabindex="2" onkeyup="'.$objName.'.productEditDialog.disableButton();"></td>
1431 </tr>
1432 <tr>
1433 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_PATH").':</td>
1434 <td><input id="FORM_PROD_BASKET_DETAIL_PAGE_URL" name="FORM_PROD_BASKET_DETAIL_PAGE_URL" value="" size="40" type="text" tabindex="3"></td>
1435 </tr>
1436 <tr>
1437 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_CATALOG_XML").':</td>
1438 <td><input id="FORM_PROD_BASKET_CATALOG_XML_ID" name="FORM_PROD_BASKET_CATALOG_XML_ID" value="" size="40" type="text" tabindex="4"></td>
1439 </tr>
1440 <tr>
1441 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_PRODUCT_XML").':</td>
1442 <td><input id="FORM_PROD_BASKET_PRODUCT_XML_ID" name="FORM_PROD_BASKET_PRODUCT_XML_ID" value="" size="40" type="text" tabindex="5"></td>
1443 </tr>
1444 <tr>
1445 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_NOTES").':</td>
1446 <td><input name="FORM_PROD_BASKET_NOTES" id="FORM_PROD_BASKET_NOTES" size="40" maxlength="250" value="" type="text" tabindex="6"></td>
1447 </tr>
1448 <tr>
1449 <td class="adm-detail-content-cell-l" valign="top" width="40%">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_PROPS").':</td>
1450 <td width="60%">
1451 <table id="BASKET_PROP_TABLE" class="internal" border="0" cellpadding="3" cellspacing="1" style="width: 521px; margin-top: 20px;">
1452 <tr class="heading" style="border-collapse:collapse;background-color:#E7EAF5;color:#525355;">
1453 <td align="center">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_IP_NAME").'</td>
1454 <td align="center">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_IP_VALUE").'</td>
1455 <td align="center">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_IP_CODE").'</td>
1456 <td align="center">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_IP_SORT").'</td>
1457 </tr>
1458 <tr id="FORM_PROD_BASKET_EMPTY_PROP_ROW">
1459 <td colspan="4" style="text-align: center;">
1460 '.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_EMPTY_PROP_ROW").'
1461 </td>
1462 </tr>
1463 </table>
1464 <div width="100%" style="text-align: right;">
1465 <input value="'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_PROPERTY_MORE").'" onclick="'.$objName.'.productEditDialog.addPropRow();" type="button" style="margin-top: 10px;">
1466 </div>
1467 </td>
1468 </tr>
1469 <tr class="adm-detail-required-field">
1470 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_QUANTITY").':</td>
1471 <td>
1472 <input name="FORM_PROD_BASKET_QUANTITY" id="FORM_PROD_BASKET_QUANTITY" size="10" maxlength="20" value="" type="text" tabindex="7" onkeyup="'.$objName.'.productEditDialog.disableButton();">&nbsp;
1473 '.OrderEdit::makeSelectHtml(
1474 'FORM_PROD_BASKET_MEASURE_CODE',
1475 self::getCatalogMeasures(),
1476 '',
1477 true,
1478 array(
1479 'id' => 'FORM_PROD_BASKET_MEASURE_CODE',
1480 'onchange' => $objName.'.productEditDialog.setMeasureText();'
1481 )
1482 ).'
1483 <input name="FORM_PROD_BASKET_MEASURE_TEXT" id="FORM_PROD_BASKET_MEASURE_TEXT" type="hidden" value="">
1484 </td>
1485 </tr>
1486 <tr class="adm-detail-required-field">
1487 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_PRICE").':</td>
1488 <td><input name="FORM_PROD_BASKET_PRICE" id="FORM_PROD_BASKET_PRICE" size="10" maxlength="20" value="" type="text" tabindex="8" onkeyup="'.$objName.'.productEditDialog.disableButton();"> ('.\CUtil::JSEscape($currency).')</td>
1489 </tr>
1490 <tr>
1491 <td class="adm-detail-content-cell-l">'.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_WEIGHT").':</td>
1492 <td><input name="FORM_PROD_BASKET_WEIGHT" id="FORM_PROD_BASKET_WEIGHT" size="10" maxlength="20" value="" type="text" tabindex="9"> ('.Loc::getMessage("SALE_ORDER_BASKET_PROD_EDIT_ITEM_GRAMM").')</td>
1493 </tr>
1494 </table>';
1495 }
1496
1497 public static function getCatalogMeasures()
1498 {
1499 return \Bitrix\Sale\Helpers\Order\Builder\BasketBuilder::getCatalogMeasures();
1500 }
1501
1502 public static function getDefaultMeasures()
1503 {
1504 return \CCatalogMeasure::getDefaultMeasure(true, true);
1505 }
1506
1518 public static function getProductDataToFillBasket($productId, $quantity, $userId, $LID, $userColumns, $tmpId = "")
1519 {
1520 $isSetItem = $tmpId != "";
1521
1522 if (self::$catalogIncluded === null)
1523 self::$catalogIncluded = Main\Loader::includeModule('catalog');
1524 if (!self::$catalogIncluded)
1525 return array();
1526
1527 $arParams = array();
1528
1529 static $proxyIblockElement = array();
1530 static $proxyCatalogMeasure = array();
1531 static $proxyParent = array();
1532 static $proxyIblockProperty = array();
1533 static $proxyProductData = array();
1534 static $proxyCatalogProduct = array();
1535 static $proxyCatalogMeasureRatio = array();
1536
1537 $productId = (int)$productId;
1538 if ($productId <= 0)
1539 {
1540 return $arParams;
1541 }
1542
1543 if (!empty($proxyIblockElement[$productId]))
1544 {
1545 $iblockId = $proxyIblockElement[$productId];
1546 }
1547 else
1548 {
1549 $iblockId = (int)\CIBlockElement::getIBlockByID($productId);
1550
1551 if ($iblockId > 0)
1552 $proxyIblockElement[$productId] = $iblockId;
1553 }
1554
1555 if ($iblockId <= 0)
1556 {
1557 return $arParams;
1558 }
1559
1560 $arSku2Parent = array();
1561 $arElementId = array();
1562
1563 $arElementId[] = $productId;
1564
1565 $proxyParentKey = $productId."|".$iblockId;
1566
1567 if (!empty($proxyParent[$proxyParentKey]) && is_array($proxyParent[$proxyParentKey]))
1568 {
1569 $arParent = $proxyParent[$proxyParentKey];
1570 }
1571 else
1572 {
1573 $arParent = \CCatalogSku::getProductInfo($productId, $iblockId);
1574 $proxyParent[$proxyParentKey] = $arParent;
1575 }
1576
1577
1578 if ($arParent)
1579 {
1580 $arElementId[] = $arParent["ID"];
1581 $arSku2Parent[$productId] = $arParent["ID"];
1582 }
1583
1584 $arPropertyInfo = array();
1585 $userColumns = (string)$userColumns;
1586 $arUserColumns = ($userColumns != '') ? explode(",", $userColumns) : array();
1587 foreach ($arUserColumns as $key => $column)
1588 {
1589 $column = mb_strtoupper($column);
1590 if (strncmp($column, 'PROPERTY_', 9) != 0)
1591 {
1592 unset($arUserColumns[$key]);
1593 }
1594 else
1595 {
1596 $propertyCode = mb_substr($column, 9);
1597 if ($propertyCode == '')
1598 {
1599 unset($arUserColumns[$key]);
1600 continue;
1601 }
1602
1603 if (!empty($proxyIblockProperty[$propertyCode]) && is_array($proxyIblockProperty[$propertyCode]))
1604 {
1605 $arPropertyInfo[$column] = $proxyIblockProperty[$propertyCode];
1606 }
1607 else
1608 {
1609 $dbres = \CIBlockProperty::getList(array(), array("CODE" => $propertyCode));
1610 if ($arPropData = $dbres->getNext())
1611 {
1612 $arPropertyInfo[$column] = $arPropData;
1613 $proxyIblockProperty[$propertyCode] = $arPropData;
1614 }
1615 }
1616
1617 }
1618 }
1619
1620 $arSelect = array_merge(
1621 [
1622 "ID",
1623 "NAME",
1624 "IBLOCK_ID",
1625 "IBLOCK_SECTION_ID",
1626 "DETAIL_PICTURE",
1627 "PREVIEW_PICTURE",
1628 "XML_ID",
1629 "IBLOCK_EXTERNAL_ID",
1630 "DETAIL_PAGE_URL",
1631 ],
1632 $arUserColumns
1633 );
1634
1635 $proxyProductDataKey = md5(join('|', $arElementId)."_".join('|', $arSelect));
1636 if (!empty($proxyProductData[$proxyProductDataKey]) && is_array($proxyProductData[$proxyProductDataKey]))
1637 {
1638 $arProductData = $proxyProductData[$proxyProductDataKey];
1639 }
1640 else
1641 {
1642 $arProductData = getProductProps($arElementId, $arSelect);
1643 $proxyProductData[$proxyProductDataKey] = $arProductData;
1644 }
1645
1646 $defaultMeasure = \CCatalogMeasure::getDefaultMeasure(true, true);
1647
1648 if (!empty($arProductData))
1649 {
1650 $arElementInfo = array();
1651 foreach ($arProductData as $elemId => &$arElement)
1652 {
1653 foreach ($arElement as $key => $value)
1654 {
1655 if (strncmp($key, 'PROPERTY_', 9) == 0 && mb_substr($key, -6) == "_VALUE")
1656 {
1657 $columnCode = str_replace("_VALUE", "", $key);
1658 if (!isset($arPropertyInfo[$columnCode]))
1659 continue;
1660 $keyResult = 'PROPERTY_'.$arPropertyInfo[$columnCode]['CODE'].'_VALUE';
1661 $arElement[$key] = getIblockPropInfo($value, $arPropertyInfo[$columnCode], array("WIDTH" => 90, "HEIGHT" => 90));
1662 if ($keyResult != $key)
1663 $arElement[$keyResult] = $arElement[$key];
1664 unset($keyResult);
1665 }
1666 }
1667 }
1668 unset($arElement);
1669
1670 if (isset($arProductData[$productId]))
1671 $arElementInfo = $arProductData[$productId];
1672
1673 if (isset( $arSku2Parent[$productId]))
1674 $arParent = $arProductData[$arSku2Parent[$productId]];
1675
1676 if (!empty($arSku2Parent)) // if sku element doesn't have value of some property - we'll show parent element value instead
1677 {
1678 foreach ($arUserColumns as $field)
1679 {
1680 $fieldVal = $field."_VALUE";
1681 $parentId = $arSku2Parent[$productId];
1682
1683 if ((!isset($arElementInfo[$fieldVal]) || (isset($arElementInfo[$fieldVal]) && $arElementInfo[$fieldVal] == ''))
1684 && (isset($arProductData[$parentId][$fieldVal]) && !empty($arProductData[$parentId][$fieldVal]))) // can be array or string
1685 {
1686 $arElementInfo[$fieldVal] = $arProductData[$parentId][$fieldVal];
1687 }
1688 }
1689 if (mb_strpos($arElementInfo["~XML_ID"], '#') === false)
1690 {
1691 $arElementInfo["~XML_ID"] = $arParent['~XML_ID'].'#'.$arElementInfo["~XML_ID"];
1692 }
1693 }
1694
1695 $arElementInfo["MODULE"] = "catalog";
1696 $arElementInfo["PRODUCT_PROVIDER_CLASS"] = "CCatalogProductProvider";
1697
1698 $arElementInfo["PRODUCT_ID"] = $arElementInfo["ID"];
1699 if ($arElementInfo["IBLOCK_ID"] > 0)
1700 {
1701 $arElementInfo["EDIT_PAGE_URL"] = \CIBlock::GetAdminElementEditLink($arElementInfo["IBLOCK_ID"], $arElementInfo["PRODUCT_ID"], array(
1702 "find_section_section" => $arElementInfo["IBLOCK_SECTION_ID"],
1703 'WF' => 'Y',
1704 ));
1705 }
1706
1707 static $buyersGroups = array();
1708
1709 if(empty($buyersGroups[$userId]))
1710 $buyersGroups[$userId] = \CUser::getUserGroup($userId);
1711
1712 $arBuyerGroups = $buyersGroups[$userId];
1713
1714 // price
1715 Catalog\Product\Price\Calculation::pushConfig();
1716 Catalog\Product\Price\Calculation::setConfig(array(
1717 'CURRENCY' => Sale\Internals\SiteCurrencyTable::getSiteCurrency($LID),
1718 'PRECISION' => (int)Main\Config\Option::get('sale', 'value_precision'),
1719 'USE_DISCOUNTS' => !$isSetItem,
1720 'RESULT_WITH_VAT' => true
1721 ));
1722 $arPrice = \CCatalogProduct::getOptimalPrice($arElementInfo["ID"], 1, $arBuyerGroups, "N", array(), $LID);
1723 Catalog\Product\Price\Calculation::popConfig();
1724 $priceType = GetCatalogGroup($arPrice["PRICE"]["CATALOG_GROUP_ID"]);
1725
1726 $currentPrice = $arPrice['RESULT_PRICE']['DISCOUNT_PRICE'];
1727 $arElementInfo['PRICE'] = $currentPrice;
1728 $arElementInfo['CURRENCY'] = $arPrice['RESULT_PRICE']['CURRENCY'];
1729 $currentTotalPrice = $arPrice['RESULT_PRICE']['BASE_PRICE'];
1730
1731 if (!empty($proxyCatalogProduct[$productId]) && is_array($proxyCatalogProduct[$productId]))
1732 {
1733 $arProduct = $proxyCatalogProduct[$productId];
1734 }
1735 else
1736 {
1737 $rsProducts = Catalog\ProductTable::getList([
1738 'select' => ['ID', 'QUANTITY', 'WEIGHT', 'MEASURE', 'TYPE', 'BARCODE_MULTI', 'WIDTH', 'LENGTH', 'HEIGHT'],
1739 'filter' => ['=ID' => $productId]
1740 ]);
1741 if ($arProduct = $rsProducts->fetch())
1742 {
1743 $proxyCatalogProduct[$productId] = $arProduct;
1744 }
1745 unset($rsProducts);
1746 }
1747
1748 if (empty($arProduct) || !is_array($arProduct))
1749 {
1750 return array();
1751 }
1752
1753 $balance = floatval($arProduct["QUANTITY"]);
1754
1755 // sku props
1756 $arSkuData = array();
1757
1758 static $proxySkuProperty = array();
1759
1760 if (!empty($proxySkuProperty[$productId]) && is_array($proxySkuProperty[$productId]))
1761 {
1762 $arSkuProperty = $proxySkuProperty[$productId];
1763 }
1764 else
1765 {
1766 $arSkuProperty = \CSaleProduct::GetProductSkuProps($productId, '', true);
1767 $proxySkuProperty[$productId] = $arSkuProperty;
1768 }
1769
1770 if (!empty($arSkuProperty))
1771 {
1772 foreach ($arSkuProperty as &$val)
1773 {
1774 $arSkuData[] = array(
1775 'NAME' => htmlspecialcharsback($val['NAME']),
1776 'VALUE' => htmlspecialcharsback($val['VALUE']),
1777 'CODE' => htmlspecialcharsback($val['CODE'])
1778 );
1779 }
1780 unset($val);
1781 }
1782
1783 if($arElementInfo["~IBLOCK_EXTERNAL_ID"] <> '')
1784 {
1785 $arSkuData[] = array(
1786 "NAME" => "Catalog XML_ID",
1787 "CODE" => "CATALOG.XML_ID",
1788 "VALUE" => $arElementInfo['~IBLOCK_EXTERNAL_ID']
1789 );
1790 }
1791
1792 if($arElementInfo["~XML_ID"] <> '')
1793 {
1794 $arSkuData[] = array(
1795 "NAME" => "Product XML_ID",
1796 "CODE" => "PRODUCT.XML_ID",
1797 "VALUE" => $arElementInfo["~XML_ID"]
1798 );
1799 }
1800
1801 $arElementInfo["WEIGHT"] = $arProduct["WEIGHT"];
1802 $arElementInfo["WIDTH"] = $arProduct["WIDTH"];
1803 $arElementInfo["LENGTH"] = $arProduct["LENGTH"];
1804 $arElementInfo["HEIGHT"] = $arProduct["HEIGHT"];
1805
1806 // measure
1807 $arElementInfo["MEASURE_TEXT"] = "";
1808 $arElementInfo["MEASURE_CODE"] = 0;
1809
1810 if ((int)$arProduct["MEASURE"] > 0)
1811 {
1812
1813 if (!empty($proxyCatalogMeasure[$arProduct["MEASURE"]]) && is_array($proxyCatalogMeasure[$arProduct["MEASURE"]]))
1814 {
1815 $arMeasure = $proxyCatalogMeasure[$arProduct["MEASURE"]];
1816 }
1817 else
1818 {
1819 $dbMeasure = \CCatalogMeasure::GetList(array(), array("ID" => intval($arProduct["MEASURE"])), false, false, array("ID", "SYMBOL_RUS", "SYMBOL_INTL"));
1820 if ($arMeasure = $dbMeasure->Fetch())
1821 {
1822 $proxyCatalogMeasure[$arProduct["MEASURE"]] = $arMeasure;
1823 }
1824 }
1825
1826 if (!empty($arMeasure) && is_array($arMeasure))
1827 {
1828 $arElementInfo["MEASURE_TEXT"] = ($arMeasure["SYMBOL_RUS"] != '' ? $arMeasure["SYMBOL_RUS"] : $arMeasure["SYMBOL_INTL"]);
1829 $arElementInfo["MEASURE_CODE"] = $arMeasure["CODE"];
1830 }
1831 }
1832 if ($arElementInfo["MEASURE_TEXT"] == '')
1833 {
1834 $arElementInfo["MEASURE_TEXT"] = ($defaultMeasure["SYMBOL_RUS"] != '' ? $defaultMeasure["SYMBOL_RUS"] : $defaultMeasure["SYMBOL_INTL"]);
1835 }
1836
1837
1838 // ratio
1839 $arElementInfo["RATIO"] = 1;
1840
1841 if (!empty($proxyCatalogMeasureRatio[$productId]) && is_array($proxyCatalogMeasureRatio[$productId]))
1842 {
1843 $arRatio = $proxyCatalogMeasureRatio[$productId];
1844 }
1845 else
1846 {
1847 $dbratio = Catalog\MeasureRatioTable::getList(array(
1848 'select' => array('*'),
1849 'filter' => array('=PRODUCT_ID' => $productId, '=IS_DEFAULT' => 'Y')
1850 ));
1851 if ($arRatio = $dbratio->fetch())
1852 {
1853 $proxyCatalogMeasureRatio[$productId] = $arRatio;
1854 }
1855
1856 }
1857
1858 if (!empty($arRatio) && is_array($arRatio))
1859 $arElementInfo["RATIO"] = $arRatio["RATIO"];
1860
1861 // image
1862 $imgCode = '';
1863 $imgUrl = '';
1864 if ($arElementInfo["PREVIEW_PICTURE"] > 0)
1865 $imgCode = $arElementInfo["PREVIEW_PICTURE"];
1866 elseif ($arElementInfo["DETAIL_PICTURE"] > 0)
1867 $imgCode = $arElementInfo["DETAIL_PICTURE"];
1868
1869 if ($imgCode == "" && !empty($arParent) && is_array($arParent))
1870 {
1871 if ($arParent["PREVIEW_PICTURE"] > 0)
1872 $imgCode = $arParent["PREVIEW_PICTURE"];
1873 elseif ($arParent["DETAIL_PICTURE"] > 0)
1874 $imgCode = $arParent["DETAIL_PICTURE"];
1875 }
1876
1877 if ($imgCode > 0)
1878 {
1879 $arFile = \CFile::GetFileArray($imgCode);
1880 $arImgProduct = \CFile::ResizeImageGet($arFile, array('width'=>80, 'height'=>80), BX_RESIZE_IMAGE_PROPORTIONAL, false, false);
1881 if (is_array($arImgProduct))
1882 $imgUrl = $arImgProduct["src"];
1883 }
1884
1885 $arSetInfo = array();
1886 $arStores = array();
1887
1889 if ($productProvider = \CSaleBasket::GetProductProvider(array("MODULE" => $arElementInfo["MODULE"], "PRODUCT_PROVIDER_CLASS" => $arElementInfo["PRODUCT_PROVIDER_CLASS"])))
1890 {
1891 // get set items if it is set
1892 if ($arProduct["TYPE"] == \CCatalogProduct::TYPE_SET)
1893 {
1894 if (method_exists($productProvider, "GetSetItems"))
1895 {
1896 $arSets = $productProvider::GetSetItems($productId, \CSaleBasket::TYPE_SET);
1897
1898 if ($tmpId == "")
1899 $tmpId = randString(7);
1900
1901 if (!empty($arSets))
1902 {
1903 foreach ($arSets as $arSetData)
1904 {
1905 foreach ($arSetData["ITEMS"] as $setItem)
1906 {
1907 $arSetItemParams = self::getProductDataToFillBasket($setItem["PRODUCT_ID"], $setItem["QUANTITY"], $userId, $LID, $userColumns, $tmpId); // recursive call
1908
1909 // re-define some fields with set data values
1910 $arSetItemParams["PARENT_OFFER_ID"] = $productId;
1911 $arSetItemParams["OFFER_ID"] = $setItem["PRODUCT_ID"];
1912 $arSetItemParams["NAME"] = $setItem["NAME"];
1913 $arSetItemParams["MODULE"] = $setItem["MODULE"];
1914 $arSetItemParams["PRODUCT_PROVIDER_CLASS"] = $setItem["PRODUCT_PROVIDER_CLASS"];
1915 $arSetItemParams["QUANTITY"] = $setItem["QUANTITY"] * $quantity;
1916 $arSetItemParams["BARCODE_MULTI"] = $setItem["BARCODE_MULTI"];
1917 $arSetItemParams["PRODUCT_TYPE"] = $setItem["TYPE"];
1918 $arSetItemParams["WEIGHT"] = $setItem["WEIGHT"];
1919 $arSetItemParams["VAT_RATE"] = $setItem["VAT_RATE"];
1920 $arSetItemParams["SET_ITEMS"] = "";
1921 $arSetItemParams["OLD_PARENT_ID"] = $productId."_tmp".$tmpId;
1922 $arSetItemParams["IS_SET_ITEM"] = "Y";
1923 $arSetItemParams["IS_SET_PARENT"] = "N";
1924 $arSetItemParams["PROVIDER_DATA"] = serialize($setItem);
1925 $arSetInfo[] = $arSetItemParams;
1926 }
1927 }
1928 }
1929 }
1930 }
1931
1932 // get stores
1933 $storeCount = $productProvider::GetStoresCount(array("SITE_ID" => $LID)); // with exact SITE_ID or SITE_ID = NULL
1934
1935 if ($storeCount > 0)
1936 {
1937 if ($arProductStore = $productProvider::GetProductStores(array("PRODUCT_ID" => $productId, "SITE_ID" => $LID)))
1938 $arStores = $arProductStore;
1939 }
1940 }
1941
1942 $currentTotalPrice = (float)$currentTotalPrice;
1943 // params array
1944 $arParams["OFFER_ID"] = $productId;
1945 $arParams["NAME"] = $arElementInfo["~NAME"]; //'
1946 $arParams["EDIT_PAGE_URL"] = $arElementInfo["EDIT_PAGE_URL"];
1947 $arParams["DETAIL_PAGE_URL"] = htmlspecialcharsex($arElementInfo["~DETAIL_PAGE_URL"]);
1948 $arParams["PICTURE_URL"] = $imgUrl;
1949 $arParams["PRICE"] = floatval($arElementInfo["PRICE"]);
1950 $arParams["PRICE_BASE"] = $currentTotalPrice;
1951 $arParams["DIMENSIONS"] = serialize(array("WIDTH" => $arElementInfo["WIDTH"], "HEIGHT" => $arElementInfo["HEIGHT"], "LENGTH" => $arElementInfo["LENGTH"]));
1952 $arParams["QUANTITY"] = $quantity;
1953 $arParams["MODULE"] = $arElementInfo["MODULE"];
1954 $arParams["CURRENCY"] = $arElementInfo["CURRENCY"];
1955 $arParams["WEIGHT"] = $arElementInfo["WEIGHT"];
1956 $arParams["VAT_RATE"] = $arPrice["PRICE"]["VAT_RATE"];
1957 $arParams["PRICE_TYPE"] = $priceType["NAME_LANG"];
1958 $arParams["AVAILABLE"] = $balance;
1959 $arParams["NOTES"] = (!empty($priceType["NAME_LANG"]) ? $priceType["NAME_LANG"] : "");
1960 $arParams["CATALOG_XML_ID"] = $arElementInfo["~IBLOCK_EXTERNAL_ID"];
1961 $arParams["PRODUCT_XML_ID"] = $arElementInfo["~XML_ID"];
1962 $arParams["PRODUCT_PROVIDER_CLASS"] = $arElementInfo["PRODUCT_PROVIDER_CLASS"];
1963 $arParams["PROPS"] = $arSkuData;
1964 $arParams["MEASURE_TEXT"] = $arElementInfo["MEASURE_TEXT"];
1965 $arParams["MEASURE_CODE"] = $arElementInfo["MEASURE_CODE"];
1966 $arParams["MEASURE_RATIO"] = $arElementInfo["RATIO"];
1967 $arParams["BARCODE_MULTI"] = $arProduct["BARCODE_MULTI"];
1968
1969 $arParams["PRODUCT_TYPE"] = empty($arSetInfo) ? "" : \CSaleBasket::TYPE_SET;
1970 $arParams["OLD_PARENT_ID"] = empty($arSetInfo) ? "" : $productId."_tmp".$tmpId;
1971
1972 $arParams["SET_ITEMS"] = $arSetInfo;
1973 $arParams["IS_SET_ITEM"] = "N";
1974 $arParams["IS_SET_PARENT"] = empty($arSetInfo) ? "N" : "Y";
1975
1976 $arParams["STORES"] = empty($arSetInfo) ? $arStores : array();
1977 $arParams["PRODUCT_PROPS_VALUES"] = $arElementInfo; // along with other information also contains values of properties with correct keys (after getProductProps)
1978 }
1979
1980 return $arParams;
1981 }
1982
1983
1989 public function prepareData(array $inParams = array())
1990 {
1991 if($this->data === null)
1992 {
1993 $inParams['ADDED_PRODUCTS'] ??= null;
1994 $isArrayAddedProducts = is_array($inParams['ADDED_PRODUCTS']);
1995
1996 $result = array(
1997 "ITEMS" => array(),
1998 "WEIGHT" => 0
1999 );
2000
2001 $basket = $this->order->getBasket();
2002 $discounts = !empty($inParams["DISCOUNTS"]) ? $inParams["DISCOUNTS"] : OrderEdit::getDiscountsApplyResult($this->order, true);
2003
2004 if(!$basket)
2005 {
2006 $result["WEIGHT_FOR_HUMAN"] = roundEx(floatval(0), SALE_WEIGHT_PRECISION);
2007 $this->data = $result;
2008 return $result;
2009 }
2010
2011 $result["WEIGHT"] = $basket->getWeight();
2012 $result["WEIGHT_FOR_HUMAN"] = roundEx(floatval($result["WEIGHT"]/$this->weightKoef), SALE_WEIGHT_PRECISION);
2013 $items = $basket->getBasketItems();
2014
2015 if (self::$catalogIncluded === null)
2016 self::$catalogIncluded = Main\Loader::includeModule('catalog');
2017
2018 if(!empty($inParams["ADDED_PRODUCTS"]))
2019 $result["ADDED_PRODUCTS"] = array();
2020
2021 $catalogProductIds = array();
2022
2024 foreach($items as $item)
2025 if($item->getField('MODULE') == 'catalog')
2026 $catalogProductIds[] = $item->getProductId();
2027
2028 $catalogPreparedData = static::getProductsData($catalogProductIds, $this->order->getSiteId(), $this->visibleColumns, $this->order->getUserId());
2029 $providerData = Provider::getProductData($basket, array("PRICE"));
2030
2032 foreach($items as $item)
2033 {
2034 $params = array();
2035 $productId = $item->getProductId();
2036
2037 $params["BASKET_CODE"] = $basketCode = $item->getBasketCode();
2038 $params["QUANTITY"] = Sale\BasketItem::formatQuantity($item->getField('QUANTITY'));
2039 $params["NOTES"] = $item->getField("NOTES");
2040 $params["MODULE"] = $item->getField("MODULE");
2041 $params['TYPE'] = (int)$item->getField('TYPE');
2042
2043 if($params["MODULE"] == 'catalog')
2044 {
2045 if(!empty($catalogPreparedData[$productId]['OFFERS_IBLOCK_ID']))
2046 $params["OFFERS_IBLOCK_ID"] = $catalogPreparedData[$productId]['OFFERS_IBLOCK_ID'];
2047
2048 if(!empty($catalogPreparedData[$productId]['IBLOCK_ID']))
2049 $params["IBLOCK_ID"] = $catalogPreparedData[$productId]['IBLOCK_ID'];
2050
2051 if(!empty($catalogPreparedData[$productId]['PRODUCT_ID']))
2052 $params["PRODUCT_ID"] = $catalogPreparedData[$productId]['PRODUCT_ID'];
2053 }
2054
2055 if(!isset($params["OFFER_ID"]))
2056 $params["OFFER_ID"] = $productId;
2057
2058 if(isset($discounts["RESULT"]["BASKET"][$basketCode]) && is_array($discounts["RESULT"]["BASKET"][$basketCode]))
2059 foreach($discounts["RESULT"]["BASKET"][$basketCode] as $discount)
2060 $params["DISCOUNTS"][$discount["DISCOUNT_ID"]] = $discount;
2061
2062 if(isset($discounts["PRICES"]["BASKET"][$basketCode]))
2063 $params["PRICE"] = $discounts["PRICES"]["BASKET"][$basketCode]["PRICE"];
2064 else
2065 $params["PRICE"] = $item->getPrice();
2066
2067 //alias for backward compatibility.
2068 $params["PRICE_BASE"] = $params["BASE_PRICE"] = $item->getField("BASE_PRICE");
2069 $params["CUSTOM_PRICE"] = $item->isCustomPrice() ? "Y" : "N";
2070
2071 if (
2072 !$isArrayAddedProducts
2073 ||
2074 (
2075 !empty($inParams["ADDED_PRODUCTS"])
2076 && in_array($productId, $inParams["ADDED_PRODUCTS"])
2077 )
2078 )
2079 {
2080 $params = $params + self::getPropsForBasketItem($item, $catalogPreparedData);
2081
2082 if ($isArrayAddedProducts && in_array($productId, $inParams["ADDED_PRODUCTS"]))
2083 {
2084 $result["ADDED_PRODUCTS"][] = $basketCode;
2085 }
2086 }
2087
2088 //Let's cache provider product data into form field
2089 if(!Provider::isExistsTrustData($this->order->getSiteId(), 'sale', $item->getProductId()))
2090 {
2091 $basketItem = $basket->getItemByBasketCode($basketCode);
2092 if($basketItem)
2093 {
2094 if (!empty($providerData[$basketCode]))
2095 {
2096 \Bitrix\Sale\Helpers\Admin\OrderEdit::setProviderTrustData($item, $this->order, $providerData[$basketCode]);
2097 $params["PROVIDER_DATA"] = serialize($providerData[$basketCode]);
2098 }
2099 }
2100 }
2101 else
2102 {
2103 $providerData = Provider::getTrustData($this->order->getSiteId(), 'sale', $item->getProductId());
2104
2105 if(is_array($providerData) && !empty($providerData))
2106 {
2107 $params["PROVIDER_DATA"] = serialize($providerData);
2108 }
2109 }
2110
2111 if (!empty($params["SET_ITEMS"]) && is_array($params["SET_ITEMS"]))
2112 {
2113 $offerToIdx = array();
2114
2115 foreach($params["SET_ITEMS"] as $idx => $childFields)
2116 $offerToIdx[$childFields["OFFER_ID"]] = $idx;
2117
2118 $setItems = [];
2119
2120 if($children = $item->getBundleCollection())
2121 {
2123 foreach($children->getBasketItems() as $idx => $child)
2124 {
2125 $fields = $child->getFieldValues();
2126
2127 if(isset($offerToIdx[$fields['PRODUCT_ID']]))
2128 {
2129 $fields = $fields + $params["SET_ITEMS"][$offerToIdx[$fields['PRODUCT_ID']]];
2130 }
2131 else
2132 {
2133 $fields["OFFER_ID"] = $fields["PRODUCT_ID"];
2134 }
2135
2136 $fields["IS_ENABLED"] = ($fields['CAN_BUY'] === 'N') ? 'N' : 'Y';
2137
2138 $setItems[$idx] = $fields;
2139 }
2140
2141 $params["SET_ITEMS"] = $setItems;
2142 }
2143
2144 $params["SET_ITEMS_DATA"] = serialize($params["SET_ITEMS"]);
2145 }
2146 elseif($item->isBundleParent())
2147 {
2148 $params["SET_ITEMS"] = array();
2149
2150 if($children = $item->getBundleCollection())
2151 {
2153 foreach($children->getBasketItems() as $child)
2154 {
2155 $childFields = $child->getFieldValues();
2156 $childFields["OFFER_ID"] = $child->getProductId();
2157 $childFields["IS_SET_ITEM"] = "Y";
2158 $childFields["IS_SET_PARENT"] = "N";
2159 $childFields["IS_ENABLED"] = ($childFields['CAN_BUY'] === 'N') ? 'N' : 'Y';
2160 $params["SET_ITEMS"][] = $childFields;
2161 }
2162 }
2163
2164 if(!empty($params["SET_ITEMS"]))
2165 {
2166 $params["IS_SET_PARENT"] = "Y";
2167 }
2168 }
2169
2170 $params["IS_ENABLED"] = (($params['CAN_BUY'] ?? null) === 'N') ? 'N' : 'Y';
2171
2172 $result["ITEMS"][$basketCode] = $params;
2173 }
2174
2175 $result = array_merge(
2176 $result, $this->getPrices($discounts)
2177 );
2178
2179 $result["ITEMS_ORDER"] = array_keys($result["ITEMS"]);
2180
2181 if (empty($inParams["SKIP_SKU_INFO"]))
2182 {
2183 $result = $this->getOffersSkuParams($result, $this->visibleColumns);
2184 }
2185
2186 $this->data = $result;
2187 }
2188
2189 return $this->data;
2190 }
2191
2192 public function getPrices($discounts = null)
2193 {
2194 static $result = null;
2195
2196 if($result === null)
2197 {
2198 $basketPrice = 0;
2199 $basketPriceBase = 0;
2200 $basket = $this->order->getBasket();
2201
2202 if($basket)
2203 {
2204 if (!$discounts)
2205 $discounts = OrderEdit::getDiscountsApplyResult($this->order, true);
2206
2207 $basketPriceBase = $basket->getBasePrice();
2208 $basketPrice = $basket->getPrice();
2209 }
2210
2211 $result = array(
2212 "BASKET_PRICE_BASE" => $basketPriceBase,
2213 "BASKET_PRICE" => $basketPrice,
2214 );
2215
2216 $result["DISCOUNT_VALUE"] = $result["BASKET_PRICE_BASE"] - $result["BASKET_PRICE"];
2217 }
2218
2219 return $result;
2220 }
2221
2222 protected function getPropsForBasketItem($item, array $preparedData = array())
2223 {
2224 $params = array();
2225
2227 if (self::$catalogIncluded === null)
2228 self::$catalogIncluded = Main\Loader::includeModule('catalog');
2229
2230 $productId = $item->getProductId();
2231
2232 if($item->getField("MODULE") == "catalog")
2233 {
2234 if(!empty($preparedData[$item->getProductId()]))
2235 {
2236 $params = $preparedData[$item->getProductId()];
2237 }
2238 else
2239 {
2240 $res = static::getProductsData(array($productId), $this->order->getSiteId(), $this->visibleColumns, $this->order->getUserId());
2241 $params = $res[$productId];
2242 }
2243 }
2244
2245 if(intval($item->getField("MEASURE_CODE")) > 0)
2246 $params["MEASURE_CODE"] = intval($item->getField("MEASURE_CODE"));
2247 elseif(!isset($params["MEASURE_CODE"]))
2248 $params["MEASURE_CODE"] = 0;
2249
2250 if($item->getField("MEASURE_NAME") <> '')
2251 $params["MEASURE_TEXT"] = $item->getField("MEASURE_NAME");
2252 elseif(!isset($params["MEASURE_TEXT"]))
2253 $params["MEASURE_TEXT"] = "";
2254
2255 if(!isset($params["OFFER_ID"]))
2256 $params["OFFER_ID"] = $productId;
2257
2258 $params["PRODUCT_PROVIDER_CLASS"] = $item->getProvider();
2259 $id = $params["PRODUCT_ID"] ?? 0;
2260 $params = array_merge($params, $item->getFieldValues(), array("PRODUCT_ID" => $id));
2261
2262 //If product became bundle, but in saved order it is a simple product.
2263 if($item->getBasketCode() == intval($item->getBasketCode()) && !$item->isBundleParent() && !empty($params['SET_ITEMS']))
2264 {
2265 unset($params['SET_ITEMS'], $params['OLD_PARENT_ID']);
2266 $params['IS_SET_PARENT'] = 'N';
2267 }
2268
2269 $params["PROPS"] = array();
2270
2272 foreach($item->getPropertyCollection() as $property)
2273 {
2274 $propKey = 'PROPERTY_'.$property->getField("CODE").'_VALUE';
2275
2276 if(isset($params['PRODUCT_PROPS_VALUES'][$propKey]))
2277 {
2278 $params['PRODUCT_PROPS_VALUES'][$propKey] = $property->getField("VALUE");
2279 }
2280
2281 $params["PROPS"][] = array(
2282 "VALUE" => $property->getField("VALUE"),
2283 "NAME" => $property->getField("NAME"),
2284 "CODE" => $property->getField("CODE"),
2285 "SORT" => $property->getField("SORT"),
2286 "ID" => $property->getField("ID")
2287 );
2288 }
2289
2290 //Let's cache provider product data into form field
2291 if(Provider::isExistsTrustData($this->order->getSiteId(), 'sale', $item->getProductId()))
2292 {
2293 $providerData = Provider::getTrustData($this->order->getSiteId(), 'sale', $item->getProductId());
2294
2295 if(is_array($providerData) && !empty($providerData))
2296 $params["PROVIDER_DATA"] = serialize($providerData);
2297 }
2298
2299 if (!empty($params["SET_ITEMS"]) && is_array($params["SET_ITEMS"]))
2300 {
2301 $offerToIdx = array();
2302 $items = [];
2303
2304 foreach($params["SET_ITEMS"] as $idx => $childFields)
2305 $offerToIdx[$childFields["OFFER_ID"]] = $idx;
2306
2307 if($children = $item->getBundleCollection())
2308 {
2310 foreach($children->getBasketItems() as $idx => $child)
2311 {
2312 $fields = $child->getFieldValues();
2313
2314 if(isset($offerToIdx[$fields['PRODUCT_ID']]))
2315 {
2316 $items[$idx] = $fields + $params["SET_ITEMS"][$offerToIdx[$fields['PRODUCT_ID']]];
2317 }
2318 else //Child have been deleted from bundle after order been created
2319 {
2320 $res = static::getProductsData(array($fields["PRODUCT_ID"]), $this->order->getSiteId(), $this->visibleColumns, $this->order->getUserId());
2321
2322 if(!empty($res[$fields["PRODUCT_ID"]]))
2323 {
2324 $fields = array_merge($res[$fields["PRODUCT_ID"]], $fields);
2325 }
2326
2327 $fields["OFFER_ID"] = $fields["PRODUCT_ID"];
2328 $fields["IS_SET_ITEM"] = "Y";
2329 $fields["IS_SET_PARENT"] = "N";
2330 $fields["OLD_PARENT_ID"] = $params["OLD_PARENT_ID"];
2331 $items[$idx] = $fields;
2332 }
2333 }
2334
2335 sortByColumn($items, array("SORT" => SORT_DESC), '');
2336 $params["SET_ITEMS"] = $items;
2337 }
2338
2339 $params["SET_ITEMS_DATA"] = serialize($params["SET_ITEMS"]);
2340 }
2341
2342 return $params;
2343 }
2344}
static loadMessages($file)
Definition: loc.php:64
static getMessage($code, $replace=null, $language=null)
Definition: loc.php:29
__construct(Order $order, $jsObjName="", $idPrefix="", $createProductBasement=true, $mode=self::EDIT_MODE)
Definition: orderbasket.php:53