diff --git a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php index da2ffcd1..6902d052 100644 --- a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php +++ b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php @@ -91,7 +91,9 @@ class RetailCrmEvent * @param $event * * @return bool - * @throws InvalidArgumentException + * @throws \Bitrix\Main\ObjectPropertyException + * @throws \Bitrix\Main\SystemException + * @throws \Bitrix\Main\ArgumentException */ function orderSave($event) { diff --git a/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php index 8eef60b7..4622d78f 100644 --- a/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php +++ b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php @@ -23,6 +23,7 @@ class RetailCrmHistory public static $CRM_ORDER_NUMBERS = 'order_numbers'; public static $CRM_CANSEL_ORDER = 'cansel_order'; public static $CRM_CURRENCY = 'currency'; + public static $CRM_DISCOUNT_ROUND = 'discount_round'; const CANCEL_PROPERTY_CODE = 'INTAROCRM_IS_CANCELED'; @@ -433,7 +434,7 @@ class RetailCrmHistory } } - if ($newOrder === null) { + if (!isset($newOrder) || $newOrder === null) { RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', 'Error order load number=' . $order['number']); continue; @@ -648,26 +649,68 @@ class RetailCrmHistory if (isset($order['items'])) { $itemUpdate = true; - $response = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']); + if (isset($response['order'])) { $orderTemp = $response['order']; - $ditems = []; + $duplicateItems = []; + foreach ($orderTemp['items'] as $item) { - $ditems[$item['offer']['externalId']]['quantity'] += $item['quantity']; - $ditems[$item['offer']['externalId']]['discountTotal'] += $item['quantity'] * $item['discountTotal']; - $ditems[$item['offer']['externalId']]['initialPrice'] = (float)$item['initialPrice']; - $ditems[$item['offer']['externalId']]['price_sum'] = $ditems[$item['offer']['externalId']]['initialPrice'] * $ditems[$item['offer']['externalId']]['quantity'] - $ditems[$item['offer']['externalId']]['discountTotal']; - $ditems[$item['offer']['externalId']]['price_item'] = $ditems[$item['offer']['externalId']]['price_sum'] / $ditems[$item['offer']['externalId']]['quantity']; + $duplicateItems[$item['id']]['externalId'] += $item['offer']['externalId']; + $duplicateItems[$item['id']]['quantity'] += $item['quantity']; + $duplicateItems[$item['id']]['discountTotal'] += + $item['quantity'] * $item['discountTotal']; + $duplicateItems[$item['id']]['initialPrice'] = (float) $item['initialPrice']; + $duplicateItems[$item['id']]['price_sum'] = ($item['quantity'] * $item['initialPrice']) + - ($item['quantity'] * $item['discountTotal']); } + unset($orderTemp); + } else { + continue; } - $log->write($ditems, 'duplicateItemsOrderHistory'); + $collectItems = []; + + foreach ($duplicateItems as $it) { + $collectItems[$it['externalId']]['quantity'] += $it['quantity']; + $collectItems[$it['externalId']]['price_sum'] += $it['price_sum']; + $collectItems[$it['externalId']]['discountTotal_sum'] += $it['discountTotal']; + + if (isset($collectItems[$it['externalId']]['initialPrice_max'])) { + if ($collectItems[$it['externalId']]['initialPrice_max'] < $it['initialPrice']) { + $collectItems[$it['externalId']]['initialPrice_max'] = $it['initialPrice']; + } + } else { + $collectItems[$it['externalId']]['initialPrice_max'] = $it['initialPrice']; + } + + $collectItems[$it['externalId']]['initialPricesList'][] = $it['initialPrice']; + } + + foreach ($collectItems as $key => $itemData) { + if (count($itemData['initialPricesList']) > 1) { + $discountDelta = 0; + + foreach ($itemData['initialPrices'] as $initialPriceItem) { + $delta = $itemData['initialPrice_max'] - (float) $initialPriceItem; + + if ($delta !== 0) { + $discountDelta += $delta; + } + } + + $collectItems[$key]['discountTotal_sum'] += $discountDelta; + } + } + + $log->write($duplicateItems, 'duplicateItemsOrderHistory'); + $log->write($collectItems, 'collectItemsOrderHistory'); + $optionDiscRound = COption::GetOptionString(self::$MODULE_ID, self::$CRM_DISCOUNT_ROUND, 0); foreach ($order['items'] as $product) { - if($ditems[$product['offer']['externalId']]['quantity']){ - $product['quantity'] = $ditems[$product['offer']['externalId']]['quantity']; + if ($collectItems[$product['offer']['externalId']]['quantity']) { + $product['quantity'] = $collectItems[$product['offer']['externalId']]['quantity']; } $item = self::getExistsItem($basket, 'catalog', $product['offer']['externalId']); @@ -682,10 +725,11 @@ class RetailCrmHistory if ($item instanceof \Bitrix\Sale\BasketItem) { $elem = self::getInfoElement($product['offer']['externalId']); + $item->setFields(array( 'CURRENCY' => $newOrder->getCurrency(), 'LID' => $site, - 'BASE_PRICE' => $product['initialPrice'], + 'BASE_PRICE' => $collectItems[$product['offer']['externalId']]['initialPrice_max'], 'NAME' => $product['offer']['name'] ? RCrmActions::fromJSON($product['offer']['name']) : $elem['NAME'], 'DETAIL_PAGE_URL' => $elem['URL'], 'PRODUCT_PROVIDER_CLASS' => 'CCatalogProductProvider', @@ -703,7 +747,7 @@ class RetailCrmHistory } if ($product['delete']) { - if ($ditems[$product['offer']['externalId']]['quantity'] <= 0) { + if ($collectItems[$product['offer']['externalId']]['quantity'] <= 0) { $item->delete(); continue; @@ -714,34 +758,29 @@ class RetailCrmHistory $item->setFieldNoDemand('QUANTITY', $product['quantity']); } - if (array_key_exists('discountTotal', $product)) { - $itemCost = $item->getField('PRICE'); + if (array_key_exists('initialPrice_max', $collectItems[$product['offer']['externalId']])) { + $item->setField( + 'BASE_PRICE', + $collectItems[$product['offer']['externalId']]['initialPrice_max'] + ); + } - if (empty($itemCost)) { - $itemCost = $item->getField('BASE_PRICE'); + if (array_key_exists('discountTotal_sum', $collectItems[$product['offer']['externalId']])) { + $item->setField('CUSTOM_PRICE', 'Y'); + $item->setField('DISCOUNT_NAME', ''); + $item->setField('DISCOUNT_VALUE', ''); + + // Полную цену позиции с учётом скидок делим на количество - получаем цену каждой единицы + // товара с учётом скидок. + $price = $collectItems[ + $product['offer']['externalId'] + ]['price_sum'] / $collectItems[$product['offer']['externalId']]['quantity']; + + if ('Y' == $optionDiscRound) { + $price = self::truncate($price, 2); } - $discount = (double) $item->getField('DISCOUNT_PRICE'); - - if (isset($itemCost) && $itemCost >= 0) { - if ($discount < 0) { - $resultDiscount = $product['discountTotal'] + $discount; - } else { - $resultDiscount = $product['discountTotal']; - } - - $item->setField('CUSTOM_PRICE', 'Y'); - $item->setField('DISCOUNT_NAME', ''); - $item->setField('DISCOUNT_VALUE', ''); - $item->setField('DISCOUNT_PRICE', $resultDiscount); - $item->setField('PRICE', $itemCost - $resultDiscount); - - //set price dublicate item - if ($ditems[$product['offer']['externalId']]['price_item']) { - $item->setField('PRICE', $ditems[$product['offer']['externalId']]['price_item']); - $item->setField('DISCOUNT_PRICE', ''); - } - } + $item->setField('PRICE', $price); } } } @@ -1378,6 +1417,25 @@ class RetailCrmHistory return false; } } + + /** + * Truncate a float number + * + * @param float $val + * @param int f Number of precision + * + * @return float + */ + public static function truncate($val, $precision = "0") + { + if(($p = strpos($val, '.')) !== false + || ($p = strpos($val, ',')) !== false + ) { + $val = floatval(substr($val, 0, $p + 1 + $precision)); + } + + return $val; + } } class RetailUser extends CUser diff --git a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php index 7dba46e4..eae98ebf 100644 --- a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php +++ b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php @@ -29,12 +29,17 @@ class RetailCrmOrder * * Creates order or returns order for mass upload * - * @param array $arFields - * @param $api - * @param $arParams - * @param $send + * @param array $arFields + * @param $api + * @param $arParams + * @param bool $send + * @param null $site + * @param string $methodApi + * * @return boolean - * @return array - array('order' = $order, 'customer' => $customer) + * @throws \Bitrix\Main\ArgumentException + * @throws \Bitrix\Main\ObjectPropertyException + * @throws \Bitrix\Main\SystemException */ public static function orderSend($arFields, $api, $arParams, $send = false, $site = null, $methodApi = 'ordersEdit') { @@ -200,17 +205,15 @@ class RetailCrmOrder } $discount = (double) $product['DISCOUNT_PRICE']; + $dpItem = $product['BASE_PRICE'] - $product['PRICE']; - if ($discount < 0) { - $item['discountManualAmount'] = 0; - $initialPrice = (double) $product['PRICE']; - } else { - $item['discountManualAmount'] = (double) $product['DISCOUNT_PRICE']; - $initialPrice = (double) $product['PRICE'] + (double) $product['DISCOUNT_PRICE']; + if ( $dpItem > 0 && $discount <= 0) { + $discount = $dpItem; } $item['discountManualPercent'] = 0; - $item['initialPrice'] = $initialPrice; + $item['discountManualAmount'] = $discount; + $item['initialPrice'] = (double) $product['BASE_PRICE']; $order['items'][] = $item; @@ -298,9 +301,16 @@ class RetailCrmOrder /** * Mass order uploading, without repeating; always returns true, but writes error log - * @param $pSize - * @param $failed -- flag to export failed orders + * + * @param int $pSize + * @param bool $failed -- flag to export failed orders + * @param bool $orderList + * * @return boolean + * @throws \Bitrix\Main\ArgumentNullException + * @throws \Bitrix\Main\ObjectPropertyException + * @throws \Bitrix\Main\SystemException + * @throws \Bitrix\Main\ArgumentException */ public static function uploadOrders($pSize = 50, $failed = false, $orderList = false) { @@ -440,6 +450,14 @@ class RetailCrmOrder return true; } + /** + * Converts order object to array + * + * @param \Bitrix\Sale\Order $obOrder + * + * @return array + * @throws \Bitrix\Main\SystemException + */ public static function orderObjToArr($obOrder) { $culture = new \Bitrix\Main\Context\Culture(array("FORMAT_DATETIME" => "Y-m-d HH:i:s")); diff --git a/intaro.retailcrm/options.php b/intaro.retailcrm/options.php index 11ff85c4..fb995d66 100644 --- a/intaro.retailcrm/options.php +++ b/intaro.retailcrm/options.php @@ -45,6 +45,8 @@ $CRM_ADDRESS_OPTIONS = 'address_options'; $CRM_DIMENSIONS = 'order_dimensions'; $PROTOCOL = 'protocol'; +$CRM_DISCOUNT_ROUND = 'discount_round'; + if(!CModule::IncludeModule('intaro.retailcrm') || !CModule::IncludeModule('sale') || !CModule::IncludeModule('iblock') || !CModule::IncludeModule('catalog')) return; @@ -440,6 +442,15 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { UnRegisterModuleDependences("main", "OnBeforeProlog", $mid, "RetailCrmUa", "add"); } + //discount_round + if (htmlspecialchars(trim($_POST['discount_round'])) == 'Y') { + $discount_round = 'Y'; + RegisterModuleDependences("main", "OnBeforeProlog", $mid, "RetailCrmDc", "add"); + } else { + $discount_round = 'N'; + UnRegisterModuleDependences("main", "OnBeforeProlog", $mid, "RetailCrmDc", "add"); + } + //version $version = COption::GetOptionString($mid, $CRM_API_VERSION); @@ -514,6 +525,8 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { COption::SetOptionString($mid, $CRM_UA_KEYS, serialize(RCrmActions::clearArr($uaKeys))); COption::SetOptionString($mid, $CRM_DIMENSIONS, $orderDimensions); + COption::SetOptionString($mid, $CRM_DISCOUNT_ROUND, $discount_round); + $request = \Bitrix\Main\Application::getInstance()->getContext()->getRequest(); if ($request->isHttps() === true) { @@ -620,6 +633,8 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { $optionUa = COption::GetOptionString($mid, $CRM_UA, 0); $optionUaKeys = unserialize(COption::GetOptionString($mid, $CRM_UA_KEYS)); + $optionDiscRound = COption::GetOptionString($mid, $CRM_DISCOUNT_ROUND, 0); + $version = COption::GetOptionString($mid, $CRM_API_VERSION, 0); //currency @@ -658,807 +673,832 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) { ); $tabControl = new CAdminTabControl("tabControl", $aTabs); $tabControl->Begin(); -?> -AddHeadString(''); ?> -'); ?> + - -
-BeginNextTab(); -?> - - - - - - - - - - - - - 1):?> - - - - - - - - - - - - - - - - - -BeginNextTab(); ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- - - value="Y" type="checkbox" /> -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -BeginNextTab(); ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4) echo 'class="address-detail-' . $bitrixOrderType['ID'] . '"'; if(($countProps > 4) && ($addressOptions[$bitrixOrderType['ID']] == 0)) echo 'style="display:none;"';?>> - - - - - - - - - 0):?> - - - - - - - - - - - - - - - - - - - > - - - - - - - - > - - - - - - - - - - -BeginNextTab(); ?> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0) :?> - - - - - - - - > - - - - - - > - - - - - - - > - - - - - - - - > - - - - - - > - - - - - - - - > - - - - - - - 0) :?> - - - - - - - - > - - - - - - - - > - - - - - - - > - - - - - - - - > - - - - - - > - - - - - - - - > - - - - - - - - - - - - - - - > - - - - - - > - () - - - - - - - - - - - - - - > - - () - - - > - - - - - - > - - - - - - - -Buttons(); ?> - - -End(); ?> -
- - - - - - - -
-
- -
- - + + + + BeginNextTab(); + ?> + + + + + + + + + + + + + 1):?> + + + + + + + + + + + + BeginNextTab(); ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BeginNextTab(); ?> + + + + + + + + + + + + + + + + + + + 4) echo 'class="address-detail-' . $bitrixOrderType['ID'] . '"'; if(($countProps > 4) && ($addressOptions[$bitrixOrderType['ID']] == 0)) echo 'style="display:none;"';?>> + + + + + 0):?> + + + + + + + + + + + > + + + + > + + + + + + + BeginNextTab(); ?> + + + + + + + + + + + + + + + + + + + + + + + + + + 0) :?> + + + + > + + + + > + + + + + > + + + + > + + + + > + + + + > + + + + + 0) :?> + + + + > + + + + > + + + + + > + + + + > + + + + > + + + + > + + + + + + + + + > + + + + > + + + + + + + + + + > + + + + + + + + > + + + > + + + + > + + + + + + Buttons(); ?> + + + End(); ?> + + + + + + + + +
+ + +
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+ + + + + +
+
+ + + + + + + +
+ + + value="Y" type="checkbox" /> +
+
+ + + +
+ + + +
+ + + +
+ + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + +
+ +
+ +
+ + + +
+ +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
() + +
+ + + +
+ +
+ + + +
+ () +
+ +
+ +
+ - -
-
-
+ + +
+
-
-
-
-
0%
+
+
+
+
0%
+
+ 0%
- 0% +
+
+
+
+
+
-
-
-
- -
-
-
- +