From 6d398f7160522a326ba5f1d9f5eba9011dd703e2 Mon Sep 17 00:00:00 2001
From: Akolzin Dmitry <iyzoer@users.noreply.github.com>
Date: Mon, 4 Dec 2017 17:44:30 +0300
Subject: [PATCH] v.2.3.0 (#35)

* v.2.2.8
* v.2.2.10
* v.2.3.0
* Displaying error message about forbidden api method
---
 CHANGELOG.md                                  |   6 +
 .../classes/general/RCrmActions.php           |   3 +-
 .../classes/general/events/RetailCrmEvent.php |   2 +-
 .../general/history/RetailCrmHistory_v5.php   | 384 ++++++------------
 .../general/order/RetailCrmOrder_v4.php       |   2 +-
 .../general/order/RetailCrmOrder_v5.php       |   2 +-
 intaro.retailcrm/description.ru               |   7 +-
 intaro.retailcrm/install/index.php            |  14 +-
 intaro.retailcrm/install/version.php          |   4 +-
 intaro.retailcrm/lang/ru/options.php          |   2 +
 intaro.retailcrm/options.php                  |  57 ++-
 11 files changed, 198 insertions(+), 285 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1bbef375..444e1586 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 2017-12-04 v.2.3.0
+* Добавлен выбор валюты в настройках, для выгрузки заказов из CRM
+* Исправлена выборка свойств заказа
+* Устранен баг в настройках соответствия полей свойств заказа
+* Улучшена механика выгрузки заказов из CRM
+
 ## 2017-11-20 v.2.2.10
 * Устранен баг с созданием чеков
 * Улучшен механизм работы с оплатами
diff --git a/intaro.retailcrm/classes/general/RCrmActions.php b/intaro.retailcrm/classes/general/RCrmActions.php
index 5feecf42..2ce047be 100644
--- a/intaro.retailcrm/classes/general/RCrmActions.php
+++ b/intaro.retailcrm/classes/general/RCrmActions.php
@@ -98,7 +98,8 @@ class RCrmActions
     {
         $bitrixPropsList = array();
         $arPropsAll = \Bitrix\Sale\Internals\OrderPropsTable::getList(array(
-            'select' => array('*')
+            'select' => array('*'),
+            'filter' => array('CODE' => '_%')
         ));
         while ($prop = $arPropsAll->Fetch()) {
             $bitrixPropsList[$prop['PERSON_TYPE_ID']][] = $prop;
diff --git a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php
index e9b91d9f..6afcc2a4 100644
--- a/intaro.retailcrm/classes/general/events/RetailCrmEvent.php
+++ b/intaro.retailcrm/classes/general/events/RetailCrmEvent.php
@@ -356,7 +356,7 @@ class RetailCrmEvent
         $api_host = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_HOST_OPTION, 0);
         $api_key = COption::GetOptionString(self::$MODULE_ID, self::$CRM_API_KEY_OPTION, 0);
         $api = new RetailCrm\ApiClient($api_host, $api_key);
-        $orderCrm = RCrmActions::apiMethod($api, 'ordersGet', __METHOD__, $arPayment('ORDER_ID'), $site);
+        $orderCrm = RCrmActions::apiMethod($api, 'ordersGet', __METHOD__, $arPayment['ORDER_ID'], $site);
 
         if (isset($orderCrm['order']['payments']) && $orderCrm['order']['payments']) {
             foreach ($orderCrm['order']['payments'] as $payment) {
diff --git a/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php
index 99203dcd..de3cc187 100644
--- a/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php
+++ b/intaro.retailcrm/classes/general/history/RetailCrmHistory_v5.php
@@ -22,6 +22,7 @@ class RetailCrmHistory
     public static $CRM_CATALOG_BASE_PRICE = 'catalog_base_price';
     public static $CRM_ORDER_NUMBERS = 'order_numbers';
     public static $CRM_CANSEL_ORDER = 'cansel_order';
+    public static $CRM_CURRENCY = 'currency';
 
     const CANCEL_PROPERTY_CODE = 'INTAROCRM_IS_CANCELED';
 
@@ -252,9 +253,11 @@ class RetailCrmHistory
         $optionsSitesList = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_SITES_LIST, 0));
         $optionsOrderNumbers = COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_NUMBERS, 0);
         $optionsCanselOrder = unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_CANSEL_ORDER, 0));
+        $optionsCurrency = COption::GetOptionString(self::$MODULE_ID, self::$CRM_CURRENCY, 0);
+        $currency = $optionsCurrency ? $optionsCurrency : \Bitrix\Currency\CurrencyManager::getBaseCurrency();
 
         $api = new RetailCrm\ApiClient($api_host, $api_key);
-        
+
         $historyFilter = array();
         $historyStart = COption::GetOptionString(self::$MODULE_ID, self::$CRM_ORDER_HISTORY);
         if ($historyStart && $historyStart > 0) {
@@ -395,42 +398,38 @@ class RetailCrmHistory
                     }
                     
                     $newOrder = Bitrix\Sale\Order::create($site, $order['customer']['externalId']);
-                    $newOrder->save();
+                    $newOrder->setField('CURRENCY', $currency);
                     $externalId = $newOrder->getId();
-
-                    if (isset($externalId)) {
-                        if(RCrmActions::apiMethod($api, 'ordersFixExternalIds', __METHOD__, array(array('id' => $order['id'], 'externalId' => $externalId))) == false){
-                            continue;
-                        }
-                    } else {
-                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::create', 'Error order create');
-                    }
                     $order['externalId'] = $externalId;
                 }
 
-                if (isset($order['externalId']) && $order['externalId']) {
+                if (isset($order['externalId'])) {
                     $itemUpdate = false;
-                    try {
-                        $newOrder = Bitrix\Sale\Order::load($order['externalId']);
-                    } catch (Bitrix\Main\ArgumentNullException $e) {
-                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', $e->getMessage() . ': ' . $order['externalId']);
+
+                    if ($order['externalId']) {
+                        try {
+                            $newOrder = Bitrix\Sale\Order::load($order['externalId']);
+                        } catch (Bitrix\Main\ArgumentNullException $e) {
+                            RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', $e->getMessage() . ': ' . $order['externalId']);
+
+                            continue;
+                        }
+                    }
+
+                    if (!$newOrder instanceof \Bitrix\Sale\Order) {
+                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', 'Error order load number=' . $order['number']);
                         
                         continue;
                     }
 
-                    if (!$newOrder instanceof \Bitrix\Sale\Order) {
-                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::load', 'Error order load id=' . $order['externalId']);
-                        
-                        continue;
-                    }
-                    
                     if ($optionsSitesList) {
                         $site = array_search($order['site'], $optionsSitesList);
                     } else {
                         $site = CSite::GetDefSite();
                     }
+
                     if (empty($site)) {
-                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::edit', 'Site = ' . $order['site'] . ' not found in setting. Order id=' . $order['externalId']);
+                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::edit', 'Site = ' . $order['site'] . ' not found in setting. Order number=' . $order['number']);
                         
                         continue;
                     }
@@ -448,7 +447,7 @@ class RetailCrmHistory
                                 continue;
                             }
                         }
-                        
+
                         $newOrder->setField('ACCOUNT_NUMBER', $order['number']);
                     }
 
@@ -569,7 +568,7 @@ class RetailCrmHistory
                                         } elseif (count($loc) == 2) {
                                             $parameters['filter']['PHRASE'] = RCrmActions::fromJSON(trim($loc[1]));
                                         } else{
-                                            RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' not found add in order id=' . $order['externalId']);
+                                            RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' not found add in order number=' . $order['number']);
                                             continue;
                                         }
                                         $parameters['filter']['NAME.LANGUAGE_ID'] = 'ru';
@@ -578,7 +577,7 @@ class RetailCrmHistory
                                         $somePropValue = $propertyCollection->getItemByOrderPropertyId($propsKey[$orderProp]['ID']);
                                         self::setProp($somePropValue, $location['CODE']);
                                     }  else {
-                                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' is empty in order id=' . $order['externalId']);
+                                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'RetailCrmHistory::setProp', 'Error location. ' . $order['delivery']['address'][$key] . ' is empty in order number=' . $order['number']);
 
                                         continue;
                                     }
@@ -614,6 +613,12 @@ class RetailCrmHistory
 
                     //items
                     $basket = $newOrder->getBasket();
+                    
+                    if (!$basket) {
+                        $basket = Bitrix\Sale\Basket::create($site);
+                        $newOrder->setBasket($basket);
+                    }
+
                     if (isset($order['items'])) {
                         $itemUpdate = true;
                         foreach ($order['items'] as $product) {
@@ -626,7 +631,7 @@ class RetailCrmHistory
                                 if ($item instanceof \Bitrix\Sale\BasketItem) {
                                     $elem = self::getInfoElement($product['offer']['externalId']);
                                     $item->setFields(array(
-                                        'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
+                                        'CURRENCY' => $newOrder->getCurrency(),
                                         'LID' => $site,
                                         'BASE_PRICE' => $product['initialPrice'],
                                         'NAME' => $product['offer']['name'] ? RCrmActions::fromJSON($product['offer']['name']) : $elem['NAME'],
@@ -682,7 +687,6 @@ class RetailCrmHistory
 
                     $newOrder->setField('PRICE', $orderSumm);
                     $order['summ'] = $orderSumm;
-                    $newOrder->save();
                     
                     //payment
                     if (array_key_exists('payments', $order)) {
@@ -693,53 +697,47 @@ class RetailCrmHistory
                             $newOrder = self::paymentsUpdate($newOrder, $orderCrm['order'], $api);
                         }
                     }
-                    
+
                     //delivery
-                    if (array_key_exists('code', $order['delivery'])) {
+                    if (array_key_exists('delivery', $order)) {
                         $itemUpdate = true;
                         //delete empty
                         if (!isset($orderCrm)) {
                             $orderCrm = RCrmActions::apiMethod($api, 'orderGet', __METHOD__, $order['id']);
                         }
                         if ($orderCrm) {
-                            self::shipmentUpdate($orderCrm['order'], $optionsDelivTypes, $newOrder->getField('ACCOUNT_NUMBER'));
+                            $newOrder = self::deliveryEdit($newOrder, $optionsDelivTypes, $orderCrm['order']);
                         }
                     }
+
                     if (isset($orderCrm)) {
                         unset($orderCrm); 
                     }
                     
-                    //delivery cost
-                    if (array_key_exists('cost', $order['delivery'])) {
-                        $shipment = Bitrix\Sale\Internals\ShipmentTable::getList(array(
-                            'filter' => array('ORDER_ID' => $order['externalId'], 'SYSTEM' => 'N'),
-                            'order' => array('ID')
-                        ))->fetch();
-                        if ($shipment) {
-                            Bitrix\Sale\Internals\ShipmentTable::update($shipment['ID'], array('BASE_PRICE_DELIVERY' => $order['delivery']['cost'], 'PRICE_DELIVERY' => $order['delivery']['cost'], 'CUSTOM_PRICE_DELIVERY' => 'Y'));
+                    $newOrder->save();
+
+                    if (!$order['externalId']) {
+                        if(RCrmActions::apiMethod($api, 'ordersFixExternalIds', __METHOD__, array(array('id' => $order['id'], 'externalId' => $newOrder->getId()))) == false){
+                            continue;
                         }
-                        
-                        Bitrix\Sale\OrderTable::update($order['externalId'], array('PRICE_DELIVERY' => $order['delivery']['cost']));
-                    }  
-                    
-                    Bitrix\Sale\OrderTable::update($order['externalId'], array('MARKED' => 'N', 'EMP_MARKED_ID' => '', 'REASON_MARKED' => ''));
-                    
-                    if ($itemUpdate) {
-                        self::updateShipmentItem($order['externalId']);
+                    } else {
+                        RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'Bitrix\Sale\Order::create', 'Error order create');
                     }
-                    
+
                     if (function_exists('retailCrmAfterOrderSave')) {
                         retailCrmAfterOrderSave($order);
                     }
                 }
+                
+                unset($newOrder);
             }
-            
+
             $GLOBALS['RETAIL_CRM_HISTORY'] = false;
-            
+
             //end id
             $end = array_pop($orderH);
             COption::SetOptionString(self::$MODULE_ID, self::$CRM_ORDER_HISTORY, $end['id']);
-            
+
             if ($orderHistory['pagination']['totalPageCount'] == 1) {
                 return true;
             }
@@ -798,7 +796,7 @@ class RetailCrmHistory
                 }
             }
         }
-        
+
         return $customers;
     }
     
@@ -909,234 +907,89 @@ class RetailCrmHistory
         
         return $orders;
     }
-    
-    public static function shipmentUpdate($orderCrm, $optionsDelivTypes, $accountNumber = '')
+
+    /**
+     * Update shipment in order
+     *
+     * @param order object
+     * @param options delivery types
+     * @param order from crm
+     * 
+     * @return order object
+     */
+    public static function deliveryEdit(Bitrix\Sale\Order $order, $optionsDelivTypes, $orderCrm)
     {
-        if (strlen($accountNumber) < 1) {
-            RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'shipmentUpdate', 'ACCOUNT_NUMBER not found');
-            
+        if (!$order instanceof Bitrix\Sale\Order) {
             return false;
         }
-        
-        if (isset($orderCrm['delivery']['code'])) {
-            $crmCode = $orderCrm['delivery']['code'];
-            
-            if (isset($orderCrm['delivery']['data']['deliveryType'])) {
-                $crmService = $orderCrm['delivery']['data']['deliveryType'];
-            } elseif (isset($orderCrm['delivery']['service'])) {
-                $crmService = $orderCrm['delivery']['service']['code'];
-            }
 
-            //select bitrix service code
-            $arDeliveryServiceAll = \Bitrix\Sale\Delivery\Services\Manager::getActiveList();
-            foreach ($arDeliveryServiceAll as $arDeliveryService) {
-                $arDeliveryCode[$arDeliveryService['CODE']] = $arDeliveryService['ID'];
-                $arDeliveryID[$arDeliveryService['ID']] = $arDeliveryService;
-                if ($arDeliveryService['ID'] == $optionsDelivTypes[$crmCode]) {
-                    $dCode = $arDeliveryService['CODE'] . ':' . $crmService;
-                } 
-            }
-            //We will change delivery to this id
-            if ($crmService && $arDeliveryCode[$dCode]) {
-                $nowDelivery = $arDeliveryCode[$dCode];
-            } elseif (!empty($optionsDelivTypes[$crmCode])) {
-                $nowDelivery = $optionsDelivTypes[$crmCode];
-            } else {
-                RCrmActions::eventLog('RetailCrmHistory::orderHistory', 'shipmentUpdate', 'Delivery ' . $crmCode . ' not found in options');
-                
-                return false;
-            }
-            
-            //Find the current delivery in the order
-            $cnt = Bitrix\Sale\Internals\ShipmentTable::getCount(array('ORDER_ID' => $orderCrm['externalId']));
-            if ($cnt > 0) {//update 
-                $obDeliverys = \Bitrix\Sale\Internals\ShipmentTable::getList(array('filter' => array('ORDER_ID' => $orderCrm['externalId']),
-                                                                    'order' => array('ID')));
-                while ($arDelivery = $obDeliverys->fetch()) {
-                    if ($arDelivery['DELIVERY_ID'] != $nowDelivery) {
-                        \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $nowDelivery));
-                        \Bitrix\Sale\Internals\ShipmentTable::update($arDelivery['ID'], array('DELIVERY_ID' => $nowDelivery, 'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME']));
-                    }
-                }
-                if ($cnt == 1 && $arDelivery['DELIVERY_ID'] == 0) {
-                    $shipment = Bitrix\Sale\Internals\ShipmentTable::add(array(
-                        'ORDER_ID' => $orderCrm['externalId'],
-                        'STATUS_ID' => 'DN',
-                        'PRICE_DELIVERY' => 0,
-                        'BASE_PRICE_DELIVERY' => 0,
-                        'CUSTOM_PRICE_DELIVERY' => 'N',
-                        'ALLOW_DELIVERY' => 'N',
-                        'DEDUCTED' => 'N',
-                        'RESERVED' => 'N',
-                        'DELIVERY_ID' => $nowDelivery,
-                        'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'],
-                        'CANCELED' => 'N',
-                        'MARKED' => 'N',
-                        'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
-                        'SYSTEM' => 'N',
-                        'ACCOUNT_NUMBER' => $accountNumber . '/2',
-                        'EXTERNAL_DELIVERY' => 'N',
-                        'UPDATED_1C' => 'N',
-                        'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime()
-                    ));
-                }
-            } else {//create
-                \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $nowDelivery));
-                $shipmentSystem = \Bitrix\Sale\Internals\ShipmentTable::add(array(
-                    'ORDER_ID' => $orderCrm['externalId'],
-                    'STATUS_ID' => 'DN',
-                    'CUSTOM_PRICE_DELIVERY' => 'N',
-                    'ALLOW_DELIVERY' => 'N',
-                    'DEDUCTED' => 'N',
-                    'RESERVED' => 'N',
-                    'DELIVERY_ID' => $nowDelivery,
-                    'DELIVERY_NAME' => $nowDelivery[$nowDelivery]['NAME'],
-                    'CANCELED' => 'N',
-                    'MARKED' => 'N',
-                    'SYSTEM' => 'Y',
-                    'ACCOUNT_NUMBER' => $accountNumber . '/1',
-                    'EXTERNAL_DELIVERY' => 'N',
-                    'UPDATED_1C' => 'N',
-                    'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime()
-                ));
-                $shipment = Bitrix\Sale\Internals\ShipmentTable::add(array(
-                    'ORDER_ID' => $orderCrm['externalId'],
-                    'STATUS_ID' => 'DN',
-                    'PRICE_DELIVERY' => 0,
-                    'BASE_PRICE_DELIVERY' => 0,
-                    'CUSTOM_PRICE_DELIVERY' => 'N',
-                    'ALLOW_DELIVERY' => 'N',
-                    'DEDUCTED' => 'N',
-                    'RESERVED' => 'N',
-                    'DELIVERY_ID' => $nowDelivery,
-                    'DELIVERY_NAME' => $arDeliveryID[$nowDelivery]['NAME'],
-                    'CANCELED' => 'N',
-                    'MARKED' => 'N',
-                    'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
-                    'SYSTEM' => 'N',
-                    'ACCOUNT_NUMBER' => $accountNumber . '/2',
-                    'EXTERNAL_DELIVERY' => 'N',
-                    'UPDATED_1C' => 'N',
-                    'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime()
-                ));
-            }   
+        if ($order->getId()) {
+            $update = true;
         } else {
-            //search for the order on the delivery site and delete / replace with no delivery
-            $noOrderId = \Bitrix\Sale\Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId();
-            \Bitrix\Sale\OrderTable::update($orderCrm['externalId'], array('DELIVERY_ID' => $noOrderId));
-            $obDeliverys = Bitrix\Sale\Internals\ShipmentTable::getList(array('filter' => array('ORDER_ID' => $orderCrm['externalId']),
-                                                               'order' => array('ID')));
-            $create = true;
-            while ($arDelivery = $obDeliverys->fetch()) {
-                \Bitrix\Sale\Internals\ShipmentTable::update($arDelivery['ID'], array('DELIVERY_ID' => $noOrderId, 'DELIVERY_NAME' => GetMessage('NO_DELIVERY')));
-                $create = false;
-            }
-            if ($create) {
-                $shipmentSystem = \Bitrix\Sale\Internals\ShipmentTable::add(array(
-                    'ORDER_ID' => $orderCrm['externalId'],
-                    'STATUS_ID' => 'DN',
-                    'CUSTOM_PRICE_DELIVERY' => 'N',
-                    'ALLOW_DELIVERY' => 'N',
-                    'DEDUCTED' => 'N',
-                    'RESERVED' => 'N',
-                    'DELIVERY_ID' => $noOrderId,
-                    'DELIVERY_NAME' => GetMessage('NO_DELIVERY'),
-                    'CANCELED' => 'N',
-                    'MARKED' => 'N',
-                    'SYSTEM' => 'Y',
-                    'ACCOUNT_NUMBER' => $accountNumber . '/1',
-                    'EXTERNAL_DELIVERY' => 'N',
-                    'UPDATED_1C' => 'N',
-                    'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime()
-                ));
-                $shipment = Bitrix\Sale\Internals\ShipmentTable::add(array(
-                    'ORDER_ID' => $orderCrm['externalId'],
-                    'STATUS_ID' => 'DN',
-                    'PRICE_DELIVERY' => 0,
-                    'BASE_PRICE_DELIVERY' => 0,
-                    'CUSTOM_PRICE_DELIVERY' => 'N',
-                    'ALLOW_DELIVERY' => 'N',
-                    'DEDUCTED' => 'N',
-                    'RESERVED' => 'N',
-                    'DELIVERY_ID' => $noOrderId,
-                    'DELIVERY_NAME' => GetMessage('NO_DELIVERY'),
-                    'CANCELED' => 'N',
-                    'MARKED' => 'N',
-                    'CURRENCY' => \Bitrix\Currency\CurrencyManager::getBaseCurrency(),
-                    'SYSTEM' => 'N',
-                    'ACCOUNT_NUMBER' => $accountNumber . '/2',
-                    'EXTERNAL_DELIVERY' => 'N',
-                    'UPDATED_1C' => 'N',
-                    'DATE_INSERT'=> new \Bitrix\Main\Type\DateTime()
-                ));
-            }
-        }
-        
-        return true;
-    }
-    
-    public static function updateShipmentItem($orderId)
-    {
-        $orderBasket = \Bitrix\Sale\Internals\BasketTable::getList(array(
-            'filter' => array('ORDER_ID' => $orderId),
-            'select' => array('ID', 'QUANTITY')
-        ));
-
-        $basketItems = array();
-        while ($basketItem = $orderBasket->fetch()) {
-            $basketItems[] = $basketItem;
-            $bItems[] = $basketItem['ID'];
+            $update = false;
         }
 
-        $obShipments = \Bitrix\Sale\Internals\ShipmentTable::getList(array(
-            'filter' => array('ORDER_ID' => $orderId, 'SYSTEM' => 'N'),
-            'select' => array('ID')
-        ));
+        $crmCode = isset($orderCrm['delivery']['code']) ? $orderCrm['delivery']['code'] : false;
+        $noDeliveryId = \Bitrix\Sale\Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId();
+        $basket = $order->getBasket();
 
-        $shipmentItems = array();
-        while ($arShipment = $obShipments->fetch()) {
-            $dlvBaslet = \Bitrix\Sale\Internals\ShipmentItemTable::getList(array(
-                'order'  => array('ORDER_DELIVERY_ID'),
-                'filter' => array('ORDER_DELIVERY_ID' => $arShipment['ID'])
-            ));
-            $shipmentItems[$arShipment['ID']] = array();
-            while ($item = $dlvBaslet->fetch()) {
-                $shipmentItems[$arShipment['ID']][] = $item;
-            }
-        }
+        if ($crmCode === false || !isset($optionsDelivTypes[$crmCode])) {
+            $deliveryId = $noDeliveryId;
+        } else {
+            $deliveryId = $optionsDelivTypes[$crmCode];
 
-        foreach ($basketItems as $basketItem) {
-            foreach ($shipmentItems as $key => $arShipmentItems) {
-                $found = false;
-                foreach ($arShipmentItems as $elShipmentItem) {
-                    if (!in_array($elShipmentItem['BASKET_ID'], $bItems)) {
-                        //delete the element
-                        \Bitrix\Sale\Internals\ShipmentItemTable::delete($elShipmentItem['ID']);
+            if (isset($orderCrm['delivery']['service']['code'])) {
+                $deliveryCode = \Bitrix\Sale\Delivery\Services\Manager::getCodeById($deliveryId);
+
+                if ($deliveryCode) {
+                    try {
+                        $deliveryService = \Bitrix\Sale\Delivery\Services\Manager::getObjectByCode($deliveryCode . ':' . $orderCrm['delivery']['service']['code']);
+                    } catch (Bitrix\Main\SystemException $systemException) {
+                        RCrmActions::eventLog('RetailCrmHistory::deliveryEdit', '\Bitrix\Sale\Delivery\Services\Manager::getObjectByCode', $systemException->getMessage());
                     }
-                    if ($elShipmentItem['BASKET_ID'] == $basketItem['ID']) {
-                        //found
-                        $found = true;
-                        //update quantity
-                        if ($elShipmentItem['QUANTITY'] != $basketItem['QUANTITY']) {
-                            \Bitrix\Sale\Internals\ShipmentItemTable::update($elShipmentItem['ID'], array('QUANTITY' => $basketItem['QUANTITY']));
-                        }
 
+                    if (isset($deliveryService)) {
+                        $deliveryId = $deliveryService->getId();
                     }
                 }
-                if (!$found) {
-                    //create 
-                    \Bitrix\Sale\Internals\ShipmentItemTable::add(array(
-                        'ORDER_DELIVERY_ID' => $key,
-                        'BASKET_ID'         => $basketItem['ID'],
-                        'DATE_INSERT'       => new \Bitrix\Main\Type\DateTime(),
-                        'QUANTITY'          => $basketItem['QUANTITY'],
-                        'RESERVED_QUANTITY' => '0.00',
+            }
+        }
+
+        $delivery = \Bitrix\Sale\Delivery\Services\Manager::getObjectById($deliveryId);
+        $shipmentColl = $order->getShipmentCollection();
+
+        if ($delivery) {
+            if (!$update) {
+                    $shipment = $shipmentColl->createItem($delivery);
+                    $shipment->setFields(array(
+                        'PRICE_DELIVERY' => $orderCrm['delivery']['cost'],
+                        'BASE_PRICE_DELIVERY' => $orderCrm['delivery']['cost'],
+                        'CURRENCY' => $order->getCurrency(),
+                        'DELIVERY_NAME' => $delivery->getName()
                     ));
+            } else {
+                foreach ($shipmentColl as $shipment) {
+                    if (!$shipment->isSystem()) {
+                        $shipment->setFields(array(
+                            'PRICE_DELIVERY' => $orderCrm['delivery']['cost'],
+                            'BASE_PRICE_DELIVERY' => $orderCrm['delivery']['cost'],
+                            'CURRENCY' => $order->getCurrency(),
+                            'DELIVERY_ID' => $deliveryId,
+                            'DELIVERY_NAME' => $delivery->getName()
+                        ));
+                    }
                 }
             }
         }
+
+        if (isset($shipment) && $shipment) {
+            $shipmentItemColl = $shipment->getShipmentItemCollection();
+            $shipmentItemColl->resetCollection($basket);
+        }
+
+        return $order;
     }
-    
+
     public static function paymentsUpdate($order, $paymentsCrm, $api)
     {
         $optionsPayTypes = array_flip(unserialize(COption::GetOptionString(self::$MODULE_ID, self::$CRM_PAYMENT_TYPES, 0)));
@@ -1177,7 +1030,7 @@ class RetailCrmHistory
                 $newPayment->setField('PAY_SYSTEM_ID', $optionsPayTypes[$paymentCrm['type']]);
                 $newPayment->setField('PAY_SYSTEM_NAME', $arPaySysmems[$optionsPayTypes[$paymentCrm['type']]]);
                 $newPayment->setField('PAID', $optionsPayment[$paymentCrm['status']] ? $optionsPayment[$paymentCrm['status']] : 'N');
-                $newPayment->setField('CURRENCY', \Bitrix\Currency\CurrencyManager::getBaseCurrency());
+                $newPayment->setField('CURRENCY', $order->getCurrency());
                 $newPayment->setField('IS_RETURN', 'N');
                 $newPayment->setField('PRICE_COD', '0.00');
                 $newPayment->setField('EXTERNAL_PAYMENT', 'N');
@@ -1206,11 +1059,10 @@ class RetailCrmHistory
         } else {
             $order->setFieldNoDemand('PAYED', 'N');
         }
-        $order->save();
         
         return $order;
     }
-    
+
     public static function newValue($value)
     {
         if (array_key_exists('code', $value)) {
@@ -1219,7 +1071,7 @@ class RetailCrmHistory
             return $value;
         }
     }
-    
+
     public static function removeEmpty($inputArray)
     {
         $outputArray = array();
@@ -1295,7 +1147,7 @@ class RetailUser extends CUser
 {
     public function GetID()
     {
-        $rsUser = CUser::GetList(($by = 'ID'), ($order = 'DESC'), array('LOGIN' => 'retailcrm%'));
+        $rsUser = CUser::GetList(($by = 'ID'), ($order = 'DESC'), array('LOGIN' => 'retailcrm'));
 
         if ($arUser = $rsUser->Fetch()) {
             return $arUser['ID'];
diff --git a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v4.php b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v4.php
index 7fab2660..e51246cc 100644
--- a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v4.php
+++ b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v4.php
@@ -87,7 +87,7 @@ class RetailCrmOrder
                         if ($arLoc) {
                             $server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot();
                             $countrys = array();
-                            if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/objects.xml')) {
+                            if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/country.xml')) {
                                 $countrysFile = simplexml_load_file($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/country.xml'); 
                                 foreach ($countrysFile->country as $country) {
                                     $countrys[RCrmActions::fromJSON((string) $country->name)] = (string) $country->alpha;
diff --git a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php
index 01320ebf..1efaa835 100644
--- a/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php
+++ b/intaro.retailcrm/classes/general/order/RetailCrmOrder_v5.php
@@ -83,7 +83,7 @@ class RetailCrmOrder
                         if ($arLoc) {
                             $server = \Bitrix\Main\Context::getCurrent()->getServer()->getDocumentRoot();
                             $countrys = array();
-                            if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/objects.xml')) {
+                            if (file_exists($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/country.xml')) {
                                 $countrysFile = simplexml_load_file($server . '/bitrix/modules/intaro.retailcrm/classes/general/config/country.xml'); 
                                 foreach ($countrysFile->country as $country) {
                                     $countrys[RCrmActions::fromJSON((string) $country->name)] = (string) $country->alpha;
diff --git a/intaro.retailcrm/description.ru b/intaro.retailcrm/description.ru
index a4f1f02f..823dad75 100644
--- a/intaro.retailcrm/description.ru
+++ b/intaro.retailcrm/description.ru
@@ -1,2 +1,5 @@
-- Устранен баг с созданием чеков
-- Улучшен механизм работы с оплатами
+- Добавлен выбор валюты в настройках, для выгрузки заказов из CRM
+- Исправлена выборка свойств заказа
+- Устранен баг в настройках соответствия полей свойств заказа
+- Улучшена механика выгрузки заказов из CRM
+
diff --git a/intaro.retailcrm/install/index.php b/intaro.retailcrm/install/index.php
index 2f86137f..70dcf4ce 100644
--- a/intaro.retailcrm/install/index.php
+++ b/intaro.retailcrm/install/index.php
@@ -47,7 +47,9 @@ class intaro_retailcrm extends CModule
     //var $CRM_CATALOG_IBLOCKS = 'catalog_base_iblocks';
     var $CRM_ORDER_NUMBERS = 'order_numbers';
     var $CRM_CANSEL_ORDER = 'cansel_order';
-    
+    var $CRM_CURRENCY = 'currency';
+    var $CRM_ADDRESS_OPTIONS = 'address_options';
+
     var $CRM_INVENTORIES_UPLOAD = 'inventories_upload';
     var $CRM_STORES = 'stores';
     var $CRM_SHOPS = 'shops';
@@ -352,7 +354,15 @@ class intaro_retailcrm extends CModule
                     'intaro.retailcrm/install/index.php', 'RetailCrm\ApiClient::*List::CurlException',
                     $e->getCode() . ': ' . $e->getMessage()
                 );
+            } catch (\InvalidArgumentException $e) {
+                $arResult['errCode'] = 'ERR_METHOD_NOT_FOUND';
+                $APPLICATION->IncludeAdminFile(
+                    GetMessage('MODULE_INSTALL_TITLE'), $this->INSTALL_PATH . '/step1.php'
+                );
+                
+                return;
             }
+
             $delivTypes = array();
             foreach ($arResult['deliveryTypesList'] as $delivType) {
                 if ($delivType['active'] === true) {
@@ -993,6 +1003,8 @@ class intaro_retailcrm extends CModule
         COption::RemoveOption($this->MODULE_ID, $this->CRM_CUSTOMER_HISTORY);
         COption::RemoveOption($this->MODULE_ID, $this->CRM_ORDER_HISTORY);
         COption::RemoveOption($this->MODULE_ID, $this->CRM_CATALOG_BASE_PRICE);
+        COption::RemoveOption($this->MODULE_ID, $this->CRM_CURRENCY);
+        COption::RemoveOption($this->MODULE_ID, $this->CRM_ADDRESS_OPTIONS);
 
         COption::RemoveOption($this->MODULE_ID, $this->CRM_ORDER_NUMBERS);
         COption::RemoveOption($this->MODULE_ID, $this->CRM_CANSEL_ORDER);
diff --git a/intaro.retailcrm/install/version.php b/intaro.retailcrm/install/version.php
index 27e8b0dd..7107a900 100644
--- a/intaro.retailcrm/install/version.php
+++ b/intaro.retailcrm/install/version.php
@@ -1,5 +1,5 @@
 <?
 $arModuleVersion = array(
-    "VERSION" => "2.2.10",
-    "VERSION_DATE" => "2017-11-20 16:00:00"
+    "VERSION" => "2.3.0",
+    "VERSION_DATE" => "2017-12-04 12:00:00"
 );
diff --git a/intaro.retailcrm/lang/ru/options.php b/intaro.retailcrm/lang/ru/options.php
index 4683b5d7..81a188b2 100644
--- a/intaro.retailcrm/lang/ru/options.php
+++ b/intaro.retailcrm/lang/ru/options.php
@@ -27,6 +27,7 @@ $MESS ['ICRM_OPTIONS_SUBMIT_VALUE'] = 'Сохранить';
 
 $MESS ['ERR_404'] = 'Возможно не верно введен адрес CRM.';
 $MESS ['ERR_403'] = 'Неверный apiKey.';
+$MESS ['ERR_JSON'] = 'Получены некорректные данные из CRM, проверьте данные справочников в настройках';
 $MESS ['ERR_0'] = 'Превышено время ожидания ответа от сервера.';
 $MESS ['ICRM_OPTIONS_OK'] = 'Изменения успешно сохранены.';
 $MESS ['CANCELED'] = 'Является флагом «Отменен»';
@@ -71,6 +72,7 @@ $MESS ['ORDERS_OPTIONS'] = 'Настройки заказов';
 $MESS ['ORDER_NUMBERS'] = 'Транслировать номера заказов созданных в црм в магазин';
 
 $MESS ['CRM_API_VERSION'] = 'Версия API клиента';
+$MESS ['CURRENCY'] = 'Валюта, устанавливаемая в заказе при выгрузке из CRM';
 
 $MESS ['INVENTORIES_UPLOAD'] = 'Включить выгрузку остатков в разрезе складов';
 $MESS ['INVENTORIES'] = 'Склады';
diff --git a/intaro.retailcrm/options.php b/intaro.retailcrm/options.php
index fa818c6e..c0658dcc 100644
--- a/intaro.retailcrm/options.php
+++ b/intaro.retailcrm/options.php
@@ -40,6 +40,9 @@ $CRM_UA_KEYS = 'ua_keys';
 
 $CRM_API_VERSION = 'api_version';
 
+$CRM_CURRENCY = 'currency';
+$CRM_ADDRESS_OPTIONS = 'address_options';
+
 if(!CModule::IncludeModule('intaro.retailcrm') || !CModule::IncludeModule('sale') || !CModule::IncludeModule('iblock') || !CModule::IncludeModule('catalog'))
     return;
 
@@ -293,6 +296,10 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
         $propsCount = 0;
         $_orderPropsArr = array();
         foreach ($arResult['orderProps'] as $orderProp) {
+            if (isset($_POST['address-detail-' . $orderType['ID']])) {
+                $addressDatailOptions[$orderType['ID']] = $_POST['address-detail-' . $orderType['ID']];
+            }
+
             if ((!(int) htmlspecialchars(trim($_POST['address-detail-' . $orderType['ID']]))) && $propsCount > 4) {
                 break;
             }
@@ -472,7 +479,12 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
             echo CAdminMessage::ShowMessage(GetMessage('API_NOT_WORK'));
         }
     }
-        
+
+    if ($_POST['currency']) {
+        COption::SetOptionString($mid, $CRM_CURRENCY, $_POST['currency']);
+    }
+
+    COption::SetOptionString($mid, $CRM_ADDRESS_OPTIONS, serialize($addressDatailOptions));
     COption::SetOptionString($mid, $CRM_SITES_LIST, serialize($siteListArr));
     COption::SetOptionString($mid, $CRM_ORDER_TYPES_ARR, serialize(RCrmActions::clearArr($orderTypesArr)));
     COption::SetOptionString($mid, $CRM_DELIVERY_TYPES_ARR, serialize(RCrmActions::clearArr($deliveryTypesArr)));
@@ -532,7 +544,11 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
     } catch (InvalidArgumentException $e) {
         $badKey = true;
         echo CAdminMessage::ShowMessage(GetMessage('ERR_403'));
+    } catch (\RetailCrm\Exception\InvalidJsonException $e) {
+        $badJson = true;
+        echo CAdminMessage::ShowMessage(GetMessage('ERR_JSON'));
     }
+
     $delivTypes = array();
     foreach ($arResult['deliveryTypesList'] as $delivType) {
         if ($delivType['active'] === true) {
@@ -599,6 +615,13 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
     
     $version = COption::GetOptionString($mid, $CRM_API_VERSION, 0);
 
+    //currency
+    $baseCurrency = \Bitrix\Currency\CurrencyManager::getBaseCurrency();
+    $currencyOption = COption::GetOptionString($mid, $CRM_CURRENCY, 0) ? COption::GetOptionString($mid, $CRM_CURRENCY, 0) : $baseCurrency;
+    $currencyList = \Bitrix\Currency\CurrencyManager::getCurrencyList();
+
+    $addressOptions = unserialize(COption::GetOptionString($mid, $CRM_ADDRESS_OPTIONS, 0));
+
     $aTabs = array(
         array(
             "DIV" => "edit1",
@@ -795,7 +818,7 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
     </tr>
     <?php endforeach; ?>
     <?php endif;?>
-<?php if(!$badKey):?>
+<?php if(!$badKey && !$badJson):?>
 <?php $tabControl->BeginNextTab(); ?>
     <input type="hidden" name="tab" value="catalog">
     <tr class="option-head">
@@ -967,13 +990,13 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
     <tr class="heading">
         <td colspan="2" style="background-color: transparent;">
             <b>
-                <label><input class="addr" type="radio" name="address-detail-<?php echo $bitrixOrderType['ID']; ?>" value="0" <?php if(count($optionsOrderProps[$bitrixOrderType['ID']]) < 6) echo "checked"; ?>><?php echo GetMessage('ADDRESS_SHORT'); ?></label>
-                <label><input class="addr" type="radio" name="address-detail-<?php echo $bitrixOrderType['ID']; ?>" value="1" <?php if(count($optionsOrderProps[$bitrixOrderType['ID']]) > 5) echo "checked"; ?>><?php echo GetMessage('ADDRESS_FULL'); ?></label>
+                <label><input class="addr" type="radio" name="address-detail-<?php echo $bitrixOrderType['ID']; ?>" value="0" <?php if($addressOptions[$bitrixOrderType['ID']] == 0) echo "checked"; ?>><?php echo GetMessage('ADDRESS_SHORT'); ?></label>
+                <label><input class="addr" type="radio" name="address-detail-<?php echo $bitrixOrderType['ID']; ?>" value="1" <?php if($addressOptions[$bitrixOrderType['ID']] == 1) echo "checked"; ?>><?php echo GetMessage('ADDRESS_FULL'); ?></label>
             </b>
         </td>
     </tr>
     <?php endif; ?>
-    <tr <?php if ($countProps > 4) echo 'class="address-detail-' . $bitrixOrderType['ID'] . '"'; if(($countProps > 4) && (count($optionsOrderProps[$bitrixOrderType['ID']]) < 6)) echo 'style="display:none;"';?>>
+    <tr <?php if ($countProps > 4) echo 'class="address-detail-' . $bitrixOrderType['ID'] . '"'; if(($countProps > 4) && ($addressOptions[$bitrixOrderType['ID']] == 0)) echo 'style="display:none;"';?>>
         <td width="50%" class="adm-detail-content-cell-l" name="<?php echo $orderProp['ID']; ?>">
             <?php echo $orderProp['NAME']; ?>
         </td>
@@ -1004,7 +1027,7 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
                 </td>
                 <td width="50%" class="">
                     <select name="custom-fields-<?=$customFields['ID'] . '-' . $bitrixOrderType['ID']; ?>" class="typeselect">
-                        <option value=""></option>              
+                        <option value=""></option>
                         <?foreach ($arResult['arProp'][$bitrixOrderType['ID']] as $arProp):?>
                             <option value="<?=$arProp['CODE']?>" <?php if ($optionsCustomFields[$bitrixOrderType['ID']][$customFields['ID']] == $arProp['CODE']) echo 'selected'; ?>>
                             <?=$arProp['NAME']; ?>
@@ -1029,7 +1052,7 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
         </td>
         <td width="50%" class="">
             <select name="legal-detail-<?php echo $legalDetails['ID'] . '-' . $bitrixOrderType['ID']; ?>" class="typeselect">
-                <option value=""></option>              
+                <option value=""></option>
                 <?php foreach ($arResult['arProp'][$bitrixOrderType['ID']] as $arProp): ?>
                 <option value="<?php echo $arProp['CODE']; ?>" <?php if ($optionsLegalDetails[$bitrixOrderType['ID']][$legalDetails['ID']] == $arProp['CODE']) echo 'selected'; ?>>
                     <?php echo $arProp['NAME']; ?>
@@ -1061,12 +1084,12 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
             </b>
         </td>
     </tr>  
-    <tr class="heading" >
+    <tr class="heading">
         <td colspan="2" class="option-other-heading"><b><?php echo GetMessage('CRM_API_VERSION'); ?></b></td>
-    </tr>    
+    </tr>
     <tr>
         <td colspan="2" class="option-head option-other-top option-other-bottom">
-            <select name="api_version" class="typeselect">  
+            <select name="api_version" class="typeselect">
                 <?php for($v = 4; $v <= 5; $v++) { 
                     $ver = 'v' . $v; ?>
                 <option value="<?php echo $ver; ?>" <?php if ($ver == $version) echo 'selected'; ?>>
@@ -1075,6 +1098,20 @@ if (isset($_POST['Update']) && ($_POST['Update'] == 'Y')) {
                 <?php } ?>
             </select>
         </td>
+    </tr>
+    <tr class="heading">
+        <td colspan="2" class="option-other-heading"><b><?php echo GetMessage('CURRENCY'); ?></b></td>
+    </tr>  
+    <tr>
+        <td colspan="2" class="option-head option-other-top option-other-bottom">
+            <select name="currency" class="typeselect">  
+                <?php foreach ($currencyList as $currencyCode => $currencyName) : ?>
+                    <option value="<?php echo $currencyCode; ?>" <?php if ($currencyCode == $currencyOption) echo 'selected'; ?>>
+                       <?php echo $currencyName; ?>
+                    </option>
+                <?php endforeach; ?>
+            </select>
+        </td>
     </tr> 
     <?php if ($optionInventotiesUpload === 'Y' || count($arResult['bitrixStoresExportList']) > 0) :?>
     <tr class="heading inventories-batton">