From cc995b83f5a1329e93a6fc843dc401b575b10a5e Mon Sep 17 00:00:00 2001 From: Akolzin Dmitry Date: Tue, 21 Aug 2018 10:19:08 +0300 Subject: [PATCH 1/2] v2.3.0 --- CHACNGELOG.md | 9 + VERSION | 2 +- src/Api/CustomerManagerInterface.php | 8 + src/Api/OrderManagerInterface.php | 8 + src/Block/Adminhtml/System/Config/Button.php | 2 +- .../System/Config/Form/Fieldset/Payment.php | 9 +- .../System/Config/Form/Fieldset/Shipping.php | 10 +- .../System/Config/Form/Fieldset/Site.php | 11 +- .../System/Config/Form/Fieldset/Sites.php | 10 +- .../System/Config/Form/Fieldset/Status.php | 12 +- src/Console/Command/CustomersExport.php | 117 +++++++++ src/Console/Command/OrdersExport.php | 103 ++++++++ .../Adminhtml/System/Config/Button.php | 26 +- src/Cron/Icml.php | 11 +- src/Helper/Data.php | 12 +- src/Model/Config/Backend/ApiUrl.php | 6 +- src/Model/Config/Backend/ApiVersion.php | 6 +- src/Model/History/Exchange.php | 6 - src/Model/Icml/Icml.php | 114 ++++----- src/Model/Observer/Customer.php | 20 +- src/Model/Observer/OrderCreate.php | 167 +------------ src/Model/Observer/OrderUpdate.php | 2 +- src/Model/Order/OrderNumber.php | 135 +++------- src/Model/Service/Customer.php | 111 +++++++++ src/Model/Service/Order.php | 176 +++++++++++++ src/Model/Setting/Attribute.php | 10 +- src/Test/Helpers/FieldsetTest.php | 11 +- .../Config/Form/Fieldset/PaymentTest.php | 11 +- .../Config/Form/Fieldset/ShippingTest.php | 9 +- .../System/Config/Form/Fieldset/SiteTest.php | 7 +- .../System/Config/Form/Fieldset/SitesTest.php | 9 +- .../Config/Form/Fieldset/StatusTest.php | 9 +- src/Test/Unit/Model/Observer/CustomerTest.php | 54 ++-- .../Unit/Model/Observer/OrderCreateTest.php | 235 ++++++------------ src/Test/Unit/Model/Service/CustomerTest.php | 191 ++++++++++++++ src/Test/Unit/Model/Service/OrderTest.php | 232 +++++++++++++++++ src/etc/adminhtml/system.xml | 44 ++-- src/etc/di.xml | 8 + src/i18n/es_ES.csv | 24 ++ src/i18n/ru_RU.csv | 24 ++ .../templates/system/config/button.phtml | 12 +- 41 files changed, 1355 insertions(+), 628 deletions(-) create mode 100644 CHACNGELOG.md create mode 100644 src/Api/CustomerManagerInterface.php create mode 100644 src/Api/OrderManagerInterface.php create mode 100644 src/Console/Command/CustomersExport.php create mode 100644 src/Console/Command/OrdersExport.php create mode 100644 src/Model/Service/Customer.php create mode 100644 src/Model/Service/Order.php create mode 100644 src/Test/Unit/Model/Service/CustomerTest.php create mode 100644 src/Test/Unit/Model/Service/OrderTest.php create mode 100644 src/i18n/es_ES.csv create mode 100644 src/i18n/ru_RU.csv diff --git a/CHACNGELOG.md b/CHACNGELOG.md new file mode 100644 index 0000000..01d13c8 --- /dev/null +++ b/CHACNGELOG.md @@ -0,0 +1,9 @@ +## 2018-08-21 v.2.3.0 +* Добавлены консольные команды для выгрузки архива клиентов и заказов +* Обработка данных для формирования структуры перед отправкой вынесена в сервисы +* Теперь при ручной выгрузке заказов из админки не нужно сохранять номера заказов +* ICML каталог теперь формируется для каждого сайта +* При формировании каталога выгружаются выбранные атрибуты товаров +* Улучшена выгрузка товаров в заказе (теперь учитываются конфигурируемые товары) +* Добавлены переводы на русский и испанский языки +* Из обработки истории удален менеджер объектов \ No newline at end of file diff --git a/VERSION b/VERSION index ccbccc3..cc6612c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.0 +2.3.0 \ No newline at end of file diff --git a/src/Api/CustomerManagerInterface.php b/src/Api/CustomerManagerInterface.php new file mode 100644 index 0000000..68de629 --- /dev/null +++ b/src/Api/CustomerManagerInterface.php @@ -0,0 +1,8 @@ +setData( [ 'id' => 'order_button', - 'label' => __('Run'), + 'label' => __('Send'), ] ); diff --git a/src/Block/Adminhtml/System/Config/Form/Fieldset/Payment.php b/src/Block/Adminhtml/System/Config/Form/Fieldset/Payment.php index 014bf89..7328b3d 100644 --- a/src/Block/Adminhtml/System/Config/Form/Fieldset/Payment.php +++ b/src/Block/Adminhtml/System/Config/Form/Fieldset/Payment.php @@ -20,6 +20,7 @@ class Payment extends \Magento\Config\Block\System\Config\Form\Fieldset */ protected $_fieldRenderer; + private $objectFactory; private $paymentConfig; private $client; @@ -29,10 +30,12 @@ class Payment extends \Magento\Config\Block\System\Config\Form\Fieldset \Magento\Framework\View\Helper\Js $jsHelper, \Magento\Payment\Model\Config $paymentConfig, \Retailcrm\Retailcrm\Helper\Proxy $client, + \Magento\Framework\DataObjectFactory $objectFactory, array $data = [] ) { $this->paymentConfig = $paymentConfig; $this->client = $client; + $this->objectFactory = $objectFactory; parent::__construct($context, $authSession, $jsHelper, $data); } @@ -61,7 +64,7 @@ class Payment extends \Magento\Config\Block\System\Config\Form\Fieldset protected function _getDummyElement() { if (empty($this->_dummyElement)) { - $this->_dummyElement = new \Magento\Framework\DataObject(['showInDefault' => 1, 'showInWebsite' => 1]); + $this->_dummyElement = $this->objectFactory->create(['showInDefault' => 1, 'showInWebsite' => 1]); } return $this->_dummyElement; @@ -70,7 +73,9 @@ class Payment extends \Magento\Config\Block\System\Config\Form\Fieldset public function render(AbstractElement $element) { $html = ''; - $htmlError = '
Please check your API Url & API Key
'; + $htmlError = ' +
' . __('Enter API of your URL and API key') . '
+ '; $html .= $this->_getHeaderHtml($element); if ($this->client->isConfigured()) { diff --git a/src/Block/Adminhtml/System/Config/Form/Fieldset/Shipping.php b/src/Block/Adminhtml/System/Config/Form/Fieldset/Shipping.php index 1def2f3..a30d143 100644 --- a/src/Block/Adminhtml/System/Config/Form/Fieldset/Shipping.php +++ b/src/Block/Adminhtml/System/Config/Form/Fieldset/Shipping.php @@ -20,6 +20,7 @@ class Shipping extends \Magento\Config\Block\System\Config\Form\Fieldset */ protected $_fieldRenderer; + private $objectFactory; private $shippingConfig; private $client; @@ -29,10 +30,12 @@ class Shipping extends \Magento\Config\Block\System\Config\Form\Fieldset \Magento\Framework\View\Helper\Js $jsHelper, \Magento\Shipping\Model\Config $shippingConfig, \Retailcrm\Retailcrm\Helper\Proxy $client, + \Magento\Framework\DataObjectFactory $objectFactory, array $data = [] ) { $this->shippingConfig = $shippingConfig; $this->client = $client; + $this->objectFactory = $objectFactory; parent::__construct($context, $authSession, $jsHelper, $data); } @@ -61,7 +64,7 @@ class Shipping extends \Magento\Config\Block\System\Config\Form\Fieldset protected function _getDummyElement() { if (empty($this->_dummyElement)) { - $this->_dummyElement = new \Magento\Framework\DataObject(['showInDefault' => 1, 'showInWebsite' => 1]); + $this->_dummyElement = $this->objectFactory->create(['showInDefault' => 1, 'showInWebsite' => 1]); } return $this->_dummyElement; @@ -76,7 +79,10 @@ class Shipping extends \Magento\Config\Block\System\Config\Form\Fieldset public function render(AbstractElement $element) { $html = ''; - $htmlError = '
Please check your API Url & API Key
'; + $htmlError = ' +
' . __('Enter API of your URL and API key') . '
+ '; + $html .= $this->_getHeaderHtml($element); if ($this->client->isConfigured()) { diff --git a/src/Block/Adminhtml/System/Config/Form/Fieldset/Site.php b/src/Block/Adminhtml/System/Config/Form/Fieldset/Site.php index e27af0b..5caabda 100644 --- a/src/Block/Adminhtml/System/Config/Form/Fieldset/Site.php +++ b/src/Block/Adminhtml/System/Config/Form/Fieldset/Site.php @@ -20,6 +20,7 @@ class Site extends \Magento\Config\Block\System\Config\Form\Fieldset */ protected $_fieldRenderer; + private $objectFactory; private $client; public function __construct( @@ -27,9 +28,11 @@ class Site extends \Magento\Config\Block\System\Config\Form\Fieldset \Magento\Backend\Model\Auth\Session $authSession, \Magento\Framework\View\Helper\Js $jsHelper, \Retailcrm\Retailcrm\Helper\Proxy $client, + \Magento\Framework\DataObjectFactory $objectFactory, array $data = [] ) { $this->client = $client; + $this->objectFactory = $objectFactory; parent::__construct($context, $authSession, $jsHelper, $data); } @@ -58,7 +61,7 @@ class Site extends \Magento\Config\Block\System\Config\Form\Fieldset protected function _getDummyElement() { if (empty($this->_dummyElement)) { - $this->_dummyElement = new \Magento\Framework\DataObject(['showInDefault' => 1, 'showInWebsite' => 0]); + $this->_dummyElement = $this->objectFactory->create(['showInDefault' => 1, 'showInWebsite' => 0]); } return $this->_dummyElement; @@ -73,7 +76,9 @@ class Site extends \Magento\Config\Block\System\Config\Form\Fieldset public function render(AbstractElement $element) { $html = ''; - $htmlError = '
Please check your API Url & API Key
'; + $htmlError = ' +
' . __('Enter API of your URL and API key') . '
+ '; $html .= $this->_getHeaderHtml($element); if ($this->client->isConfigured()) { @@ -145,7 +150,7 @@ class Site extends \Magento\Config\Block\System\Config\Form\Fieldset 'select', [ 'name' => 'groups[' . $fieldset->getId() . '][fields][default][value]', - 'label' => 'Default site', + 'label' => __('Default site'), 'value' => isset($data) ? $data : '', 'values' => $this->getValues(), 'inherit' => isset($data['inherit']) ? $data['inherit'] : '', diff --git a/src/Block/Adminhtml/System/Config/Form/Fieldset/Sites.php b/src/Block/Adminhtml/System/Config/Form/Fieldset/Sites.php index 0d13cfe..3267413 100644 --- a/src/Block/Adminhtml/System/Config/Form/Fieldset/Sites.php +++ b/src/Block/Adminhtml/System/Config/Form/Fieldset/Sites.php @@ -20,6 +20,7 @@ class Sites extends \Magento\Config\Block\System\Config\Form\Fieldset */ protected $_fieldRenderer; + private $objectFactory; private $storeManager; private $client; @@ -29,11 +30,12 @@ class Sites extends \Magento\Config\Block\System\Config\Form\Fieldset \Magento\Framework\View\Helper\Js $jsHelper, \Magento\Store\Model\StoreManagerInterface $storeManager, \Retailcrm\Retailcrm\Helper\Proxy $client, + \Magento\Framework\DataObjectFactory $objectFactory, array $data = [] ) { $this->storeManager = $storeManager; $this->client = $client; - + $this->objectFactory = $objectFactory; parent::__construct($context, $authSession, $jsHelper, $data); } @@ -61,7 +63,7 @@ class Sites extends \Magento\Config\Block\System\Config\Form\Fieldset protected function _getDummyElement() { if (empty($this->_dummyElement)) { - $this->_dummyElement = new \Magento\Framework\DataObject(['showInDefault' => 1, 'showInWebsite' => 0]); + $this->_dummyElement = $this->objectFactory->create(['showInDefault' => 1, 'showInWebsite' => 0]); } return $this->_dummyElement; @@ -76,7 +78,9 @@ class Sites extends \Magento\Config\Block\System\Config\Form\Fieldset public function render(AbstractElement $element) { $html = ''; - $htmlError = '
Please check your API Url & API Key
'; + $htmlError = ' +
' . __('Enter API of your URL and API key') . '
+ '; $html .= $this->_getHeaderHtml($element); if ($this->client->isConfigured()) { diff --git a/src/Block/Adminhtml/System/Config/Form/Fieldset/Status.php b/src/Block/Adminhtml/System/Config/Form/Fieldset/Status.php index 7a4a669..8bbe1b9 100644 --- a/src/Block/Adminhtml/System/Config/Form/Fieldset/Status.php +++ b/src/Block/Adminhtml/System/Config/Form/Fieldset/Status.php @@ -20,6 +20,7 @@ class Status extends \Magento\Config\Block\System\Config\Form\Fieldset */ protected $_fieldRenderer; + private $objectFactory; private $statusCollection; private $client; @@ -29,10 +30,12 @@ class Status extends \Magento\Config\Block\System\Config\Form\Fieldset \Magento\Framework\View\Helper\Js $jsHelper, \Magento\Sales\Model\ResourceModel\Order\Status\Collection $statusCollection, \Retailcrm\Retailcrm\Helper\Proxy $client, + \Magento\Framework\DataObjectFactory $objectFactory, array $data = [] ) { $this->statusCollection = $statusCollection; $this->client = $client; + $this->objectFactory = $objectFactory; parent::__construct($context, $authSession, $jsHelper, $data); } @@ -61,7 +64,7 @@ class Status extends \Magento\Config\Block\System\Config\Form\Fieldset protected function _getDummyElement() { if (empty($this->_dummyElement)) { - $this->_dummyElement = new \Magento\Framework\DataObject(['showInDefault' => 1, 'showInWebsite' => 1]); + $this->_dummyElement = $this->objectFactory->create(['showInDefault' => 1, 'showInWebsite' => 1]); } return $this->_dummyElement; @@ -70,11 +73,14 @@ class Status extends \Magento\Config\Block\System\Config\Form\Fieldset public function render(AbstractElement $element) { $html = ''; - $htmlError = '
Please check your API Url & API Key
'; + $htmlError = ' +
'. __('Enter API of your URL and API key') . '
+ '; + $html .= $this->_getHeaderHtml($element); if ($this->client->isConfigured()) { - $statuses = $this->statusCollection->toOptionArray();; + $statuses = $this->statusCollection->toOptionArray(); foreach ($statuses as $code => $status) { $html .= $this->_getFieldHtml($element, $status); diff --git a/src/Console/Command/CustomersExport.php b/src/Console/Command/CustomersExport.php new file mode 100644 index 0000000..ceb538d --- /dev/null +++ b/src/Console/Command/CustomersExport.php @@ -0,0 +1,117 @@ +appState = $appState; + $this->api = $api; + $this->helper = $helper; + $this->customerCollectionFactory = $customerCollectionFactory; + $this->serviceCustomer = $serviceCustomer; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('retailcrm:customers:export') + ->setDescription('Upload archive customers to retailCRM from Magento') + ->addArgument('from', InputArgument::OPTIONAL, 'Beginning order number') + ->addArgument('to', InputArgument::OPTIONAL, 'End order number'); + + parent::configure(); + } + + /** + * Upload customers to retailCRM + * + * @param InputInterface $input + * @param OutputInterface $output + * + * @throws \Exception + * + * @return boolean + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL); + + $arguments = $input->getArguments(); + $this->collection = $this->customerCollectionFactory->create(); + $this->collection->addAttributeToSelect('*'); + + if ($arguments['from'] !== null && $arguments['to'] !== null) { + $this->collection->addAttributeToFilter( + [ + [ + 'attribute' => 'entity_id', + 'from' => $arguments['from'] + ], + [ + 'attribute' => 'entity_id', + 'to' => $arguments['to'] + ] + ] + ); + } + + $customers = $this->collection->getItems(); + + if (empty($customers)) { + $output->writeln('Customers not found'); + + return false; + } + + /** @var \Magento\Customer\Model\Customer $customer */ + foreach ($customers as $customer) { + $ordersToCrm[$customer->getStore()->getId()][] = $this->serviceCustomer->process($customer); + } + + foreach ($ordersToCrm as $storeId => $ordersStore) { + $chunked = array_chunk($ordersStore, 50); + unset($ordersStore); + + foreach ($chunked as $chunk) { + $this->api->setSite($this->helper->getSite($storeId)); + $this->api->customersUpload($chunk); + time_nanosleep(0, 250000000); + } + + unset($chunked); + } + + $output->writeln('Uploading customers finished'); + + return true; + } +} diff --git a/src/Console/Command/OrdersExport.php b/src/Console/Command/OrdersExport.php new file mode 100644 index 0000000..838e5f9 --- /dev/null +++ b/src/Console/Command/OrdersExport.php @@ -0,0 +1,103 @@ +orderRepository = $orderRepository; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->appState = $appState; + $this->serviceOrder = $serviceOrder; + $this->api = $api; + $this->helper = $helper; + + parent::__construct(); + } + + protected function configure() + { + $this->setName('retailcrm:orders:export') + ->setDescription('Upload archive orders to retailCRM from Magento') + ->addArgument('from', InputArgument::OPTIONAL, 'Beginning order number') + ->addArgument('to', InputArgument::OPTIONAL, 'End order number'); + + parent::configure(); + } + + /** + * Upload orders to retailCRM + * + * @param InputInterface $input + * @param OutputInterface $output + * + * @throws \Exception + * + * @return boolean + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_GLOBAL); + + $arguments = $input->getArguments(); + + if ($arguments['from'] !== null && $arguments['to'] !== null) { + $searchCriteria = $this->searchCriteriaBuilder + ->addFilter('increment_id', $arguments['from'], 'from') + ->addFilter('increment_id', $arguments['to'], 'to') + ->create(); + } else { + $searchCriteria = $this->searchCriteriaBuilder->create(); + } + + $resultSearch = $this->orderRepository->getList($searchCriteria); + $orders = $resultSearch->getItems(); + + if (empty($orders)) { + $output->writeln('Orders not found'); + + return false; + } + + /** @var \Magento\Sales\Model\Order $order */ + foreach ($orders as $order) { + $ordersToCrm[$order->getStore()->getId()][] = $this->serviceOrder->process($order); + } + + foreach ($ordersToCrm as $storeId => $ordersStore) { + $chunked = array_chunk($ordersStore, 50); + unset($ordersStore); + + foreach ($chunked as $chunk) { + $this->api->setSite($this->helper->getSite($storeId)); + $this->api->ordersUpload($chunk); + time_nanosleep(0, 250000000); + } + + unset($chunked); + } + + $output->writeln('Uploading orders finished'); + + return true; + } +} diff --git a/src/Controller/Adminhtml/System/Config/Button.php b/src/Controller/Adminhtml/System/Config/Button.php index 39a85d4..33f0086 100644 --- a/src/Controller/Adminhtml/System/Config/Button.php +++ b/src/Controller/Adminhtml/System/Config/Button.php @@ -4,28 +4,36 @@ namespace Retailcrm\Retailcrm\Controller\Adminhtml\System\Config; class Button extends \Magento\Backend\App\Action { - /** - * @var \Psr\Log\LoggerInterface - */ - private $logger; private $order; + private $jsonFactory; /** * @param \Magento\Backend\App\Action\Context $context - * @param \Psr\Log\LoggerInterface $logger + * @param \Retailcrm\Retailcrm\Model\Order\OrderNumber $order + * @param \Magento\Framework\Controller\Result\JsonFactory $jsonFactory */ public function __construct( \Magento\Backend\App\Action\Context $context, - \Psr\Log\LoggerInterface $logger, - \Retailcrm\Retailcrm\Model\Order\OrderNumber $order + \Retailcrm\Retailcrm\Model\Order\OrderNumber $order, + \Magento\Framework\Controller\Result\JsonFactory $jsonFactory ) { $this->order = $order; - $this->logger = $logger; + $this->jsonFactory = $jsonFactory; + parent::__construct($context); } + /** + * Upload selected orders + * + * @return \Magento\Framework\Controller\Result\Json + */ public function execute() { - $this->order->exportOrderNumber(); + $numbers = $this->getRequest()->getParam('numbers'); + $result = $this->order->exportOrderNumber($numbers); + $resultJson = $this->jsonFactory->create(); + + return $resultJson->setData($result); } } diff --git a/src/Cron/Icml.php b/src/Cron/Icml.php index 70cc5e0..7ea11e2 100644 --- a/src/Cron/Icml.php +++ b/src/Cron/Icml.php @@ -6,17 +6,24 @@ class Icml { private $logger; private $icml; + private $storeManager; public function __construct( \Retailcrm\Retailcrm\Model\Logger\Logger $logger, - \Retailcrm\Retailcrm\Model\Icml\Icml $icml + \Retailcrm\Retailcrm\Model\Icml\Icml $icml, + \Magento\Store\Model\StoreManagerInterface $storeManager ) { $this->logger = $logger; $this->icml = $icml; + $this->storeManager = $storeManager; } public function execute() { - $this->icml->generate(); + $websites = $this->storeManager->getWebsites(); + + foreach ($websites as $website) { + $this->icml->generate($website); + } } } diff --git a/src/Helper/Data.php b/src/Helper/Data.php index fbbdb1d..bfe613b 100644 --- a/src/Helper/Data.php +++ b/src/Helper/Data.php @@ -23,6 +23,13 @@ class Data extends AbstractHelper parent::__construct($context); } + public function getGeneralSettings($setting = null) + { + return $setting === null + ? $this->getConfigValue(self::XML_PATH_RETAILCRM . 'general') + : $this->getConfigValue(self::XML_PATH_RETAILCRM . 'general/' . $setting); + } + public function getConfigValue($field, $storeId = null) { return $this->scopeConfig->getValue( @@ -32,11 +39,6 @@ class Data extends AbstractHelper ); } - public function getGeneralConfig($code, $storeId = null) - { - return $this->getConfigValue(self::XML_PATH_RETAILCRM . $code, $storeId); - } - /** * Get site code * diff --git a/src/Model/Config/Backend/ApiUrl.php b/src/Model/Config/Backend/ApiUrl.php index f61234a..6814613 100644 --- a/src/Model/Config/Backend/ApiUrl.php +++ b/src/Model/Config/Backend/ApiUrl.php @@ -78,11 +78,11 @@ class ApiUrl extends \Magento\Framework\App\Config\Value $response = $api->availableVersions(); if ($response === false) { - throw new \Magento\Framework\Exception\ValidatorException(__('Verify that the data entered is correct')); + throw new \Magento\Framework\Exception\ValidatorException(__('Make sure that the entered data is correct')); } elseif (!$response->isSuccessful() && $response['errorMsg'] == $api->getErrorText('errorApiKey')) { - throw new \Magento\Framework\Exception\ValidatorException(__('Invalid CRM api key')); + throw new \Magento\Framework\Exception\ValidatorException(__('Incorrect API key')); } elseif (isset($response['errorMsg']) && $response['errorMsg'] == $api->getErrorText('errorAccount')) { - throw new \Magento\Framework\Exception\ValidatorException(__('Invalid CRM api url')); + throw new \Magento\Framework\Exception\ValidatorException(__('Incorrect URL of retailCRM')); } return true; diff --git a/src/Model/Config/Backend/ApiVersion.php b/src/Model/Config/Backend/ApiVersion.php index d99e1a1..ce7356a 100644 --- a/src/Model/Config/Backend/ApiVersion.php +++ b/src/Model/Config/Backend/ApiVersion.php @@ -73,14 +73,16 @@ class ApiVersion extends \Magento\Framework\App\Config\Value if ($response->isSuccessful()) { $availableVersions = $response['versions']; } else { - throw new \Magento\Framework\Exception\ValidatorException(__('Invalid CRM url or api key')); + throw new \Magento\Framework\Exception\ValidatorException(__('Incorrect URL of retailCRM or API key')); } if (isset($availableVersions)) { if (in_array($apiVersions[$apiVersion], $availableVersions)) { $this->setValue($this->getValue()); } else { - throw new \Magento\Framework\Exception\ValidatorException(__('Selected api version forbidden')); + throw new \Magento\Framework\Exception\ValidatorException( + __('The selected API version is unavailable') + ); } } } diff --git a/src/Model/History/Exchange.php b/src/Model/History/Exchange.php index c32d416..b84347f 100644 --- a/src/Model/History/Exchange.php +++ b/src/Model/History/Exchange.php @@ -19,14 +19,11 @@ class Exchange private $cacheTypeList; private $order; private $orderManagement; - private $eventManager; - private $objectManager; private $orderInterface; private $storeManager; private $regionFactory; public function __construct( - \Magento\Framework\App\ObjectManager $objectManager, \Retailcrm\Retailcrm\Helper\Data $helper, \Magento\Framework\App\Config\ScopeConfigInterface $config, \Magento\Config\Model\ResourceModel\Config $resourceConfig, @@ -40,7 +37,6 @@ class Exchange \Magento\Framework\App\Cache\TypeListInterface $cacheTypeList, \Magento\Sales\Api\Data\OrderInterface $orderInterface, \Magento\Sales\Api\OrderManagementInterface $orderManagement, - \Magento\Framework\Event\Manager $eventManager, \Retailcrm\Retailcrm\Model\Logger\Logger $logger, \Magento\Sales\Model\Order $order, \Magento\Store\Model\StoreManagerInterface $storeManager, @@ -61,8 +57,6 @@ class Exchange $this->cacheTypeList = $cacheTypeList; $this->orderInterface = $orderInterface; $this->orderManagement = $orderManagement; - $this->eventManager = $eventManager; - $this->objectManager = $objectManager; $this->order = $order; $this->storeManager = $storeManager; $this->regionFactory = $regionFactory; diff --git a/src/Model/Icml/Icml.php b/src/Model/Icml/Icml.php index d884b19..51bda60 100644 --- a/src/Model/Icml/Icml.php +++ b/src/Model/Icml/Icml.php @@ -10,49 +10,57 @@ class Icml private $shop; private $manager; private $category; - private $product; private $storeManager; private $StockState; private $configurable; private $config; private $dirList; private $ddFactory; + private $resourceModelProduct; + private $searchCriteriaBuilder; + private $productRepository; public function __construct( \Magento\Store\Model\StoreManagerInterface $manager, \Magento\Catalog\Model\ResourceModel\Category\CollectionFactory $categoryCollectionFactory, - \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $product, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\CatalogInventory\Api\StockStateInterface $StockState, \Magento\ConfigurableProduct\Model\Product\Type\Configurable $configurable, \Magento\Framework\App\Config\ScopeConfigInterface $config, \Magento\Framework\DomDocument\DomDocumentFactory $ddFactory, - \Magento\Framework\Filesystem\DirectoryList $dirList + \Magento\Framework\Filesystem\DirectoryList $dirList, + \Magento\Catalog\Model\ResourceModel\Product $resourceModelProduct, + \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder, + \Magento\Catalog\Model\ProductRepository $productRepository ) { $this->configurable = $configurable; $this->StockState = $StockState; $this->storeManager = $storeManager; - $this->product = $product; $this->category = $categoryCollectionFactory; $this->manager = $manager; $this->config = $config; $this->ddFactory = $ddFactory; $this->dirList = $dirList; + $this->resourceModelProduct = $resourceModelProduct; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->productRepository = $productRepository; } /** * Generate icml catelog * + * @param \Magento\Store\Model\Website $website + * * @return void */ - public function generate() + public function generate($website) { - $this->shop = $this->manager->getStore()->getId(); + $this->shop = $website; $string = ' - '.$this->manager->getStore()->getName().' + ' . $website->getName() . ' @@ -79,8 +87,7 @@ class Icml $this->addOffers(); $this->dd->saveXML(); - $shopCode = $this->manager->getStore()->getCode(); - $this->dd->save($this->dirList->getRoot() . '/retailcrm_' . $shopCode . '.xml'); + $this->dd->save($this->dirList->getRoot() . '/retailcrm_' . $website->getCode() . '.xml'); } /** @@ -226,22 +233,22 @@ class Icml { $offers = []; - $collection = $this->product->create(); - $collection->addFieldToFilter('visibility', 4);//catalog, search visible - $collection->addAttributeToSelect('*'); - $picUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA); - $customAdditionalAttributes = $this->config->getValue('retailcrm/Misc/attributes_to_export_into_icml'); + $criteria = $this->searchCriteriaBuilder + ->addFilter('website_id', $this->shop->getId(), 'eq') + ->create(); + $collection = $this->productRepository->getList($criteria); + $customAdditionalAttributes = $this->config->getValue('retailcrm/catalog/attributes_to_export_into_icml'); - foreach ($collection as $product) { + foreach ($collection->getItems() as $product) { if ($product->getTypeId() == 'simple') { - $offers[] = $this->buildOffer($product); + $offers[] = $this->buildOffer($product, $customAdditionalAttributes); } if ($product->getTypeId() == 'configurable') { $associated_products = $this->getAssociatedProducts($product); foreach ($associated_products as $associatedProduct) { - $offers[] = $this->buildOffer($product, $associatedProduct); + $offers[] = $this->buildOffer($product, $customAdditionalAttributes, $associatedProduct); } } } @@ -253,14 +260,17 @@ class Icml * Build offer array * * @param object $product + * @param $customAdditionalAttributes * @param object $associatedProduct + * * @return array $offer */ - private function buildOffer($product, $associatedProduct = null) + private function buildOffer($product, $customAdditionalAttributes, $associatedProduct = null) { $offer = []; - $picUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA); + $store = $this->shop->getDefaultStore() ? $this->shop->getDefaultStore() : $this->storeManager->getStore(); + $picUrl = $store->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA); $offer['id'] = $associatedProduct === null ? $product->getId() : $associatedProduct->getId(); $offer['productId'] = $product->getId(); @@ -276,7 +286,7 @@ class Icml $offer['initialPrice'] = $associatedProduct === null ? $product->getFinalPrice() : $associatedProduct->getFinalPrice(); - $offer['url'] = $product->getProductUrl(); + $offer['url'] = $product->getUrlInStore(); if ($associatedProduct === null) { $offer['picture'] = $picUrl . 'catalog/product' . $product->getImage(); @@ -294,7 +304,7 @@ class Icml ? $product->getAttributeText('manufacturer') : $associatedProduct->getAttributeText('manufacturer'); - $offer['params'] = $this->getOfferParams($product, $associatedProduct); + $offer['params'] = $this->getOfferParams($product, $customAdditionalAttributes, $associatedProduct); return $offer; } @@ -303,59 +313,35 @@ class Icml * Get parameters offers * * @param object $product + * @param $customAdditionalAttributes * @param object $associatedProduct + * * @return array $params */ - private function getOfferParams($product, $associatedProduct = null) + private function getOfferParams($product, $customAdditionalAttributes, $associatedProduct = null) { $params = []; - if ($associatedProduct !== null) { - if ($associatedProduct->getResource()->getAttribute('color')) { - $colorAttribute = $associatedProduct->getResource()->getAttribute('color'); - $color = $colorAttribute->getSource()->getOptionText($associatedProduct->getColor()); - } - - if (isset($color)) { - $params[] = [ - 'name' => 'Color', - 'code' => 'color', - 'value' => $color - ]; - } - - if ($associatedProduct->getResource()->getAttribute('size')) { - $sizeAttribute = $associatedProduct->getResource()->getAttribute('size'); - $size = $sizeAttribute->getSource()->getOptionText($associatedProduct->getSize()); - } - - if (isset($size)) { - $params[] = [ - 'name' => 'Size', - 'code' => 'size', - 'value' => $size - ]; - } + if (!$customAdditionalAttributes) { + return $params; } - $article = $associatedProduct === null ? $product->getSku() : $associatedProduct->getSku(); + $attributes = explode(',', $customAdditionalAttributes); - if (!empty($article)) { - $params[] = [ - 'name' => 'Article', - 'code' => 'article', - 'value' => $article - ]; - } + foreach ($attributes as $attributeCode) { + $attribute = $this->resourceModelProduct->getAttribute($attributeCode); + $attributeValue = $associatedProduct + ? $associatedProduct->getData($attributeCode) + : $product->getData($attributeCode); + $attributeText = $attribute->getSource()->getOptionText($attributeValue); - $weight = $associatedProduct === null ? $product->getWeight() : $associatedProduct->getWeight(); - - if (!empty($weight)) { - $params[] = [ - 'name' => 'Weight', - 'code' => 'weight', - 'value' => $weight - ]; + if ($attribute && $attributeValue) { + $params[] = [ + 'name' => $attribute->getDefaultFrontendLabel(), + 'code' => $attributeCode, + 'value' => $attributeText ? $attributeText : $attributeValue + ]; + } } return $params; diff --git a/src/Model/Observer/Customer.php b/src/Model/Observer/Customer.php index 3432dfa..2f5753e 100644 --- a/src/Model/Observer/Customer.php +++ b/src/Model/Observer/Customer.php @@ -11,15 +11,18 @@ class Customer implements \Magento\Framework\Event\ObserverInterface private $registry; private $customer; private $helper; + private $serviceCustomer; public function __construct( \Magento\Framework\Registry $registry, Helper $helper, - ApiClient $api + ApiClient $api, + \Retailcrm\Retailcrm\Model\Service\Customer $serviceCustomer ) { $this->api = $api; $this->helper = $helper; $this->registry = $registry; + $this->serviceCustomer = $serviceCustomer; $this->customer = []; } @@ -31,17 +34,8 @@ class Customer implements \Magento\Framework\Event\ObserverInterface return false; } - $data = $observer->getEvent()->getCustomer(); - - $this->customer = [ - 'externalId' => $data->getId(), - 'email' => $data->getEmail(), - 'firstName' => $data->getFirstname(), - 'patronymic' => $data->getMiddlename(), - 'lastName' => $data->getLastname(), - 'createdAt' => date('Y-m-d H:i:s', strtotime($data->getCreatedAt())) - ]; - + $customer = $observer->getEvent()->getCustomer(); + $this->customer = $this->serviceCustomer->process($customer); $response = $this->api->customersEdit($this->customer); if ($response === false) { @@ -49,7 +43,7 @@ class Customer implements \Magento\Framework\Event\ObserverInterface } if (!$response->isSuccessful() && $response->errorMsg == $this->api->getErrorText('errorNotFound')) { - $this->api->setSite($this->helper->getSite($data->getStore())); + $this->api->setSite($this->helper->getSite($customer->getStore())); $this->api->customersCreate($this->customer); } diff --git a/src/Model/Observer/OrderCreate.php b/src/Model/Observer/OrderCreate.php index 39404ce..3aa543e 100644 --- a/src/Model/Observer/OrderCreate.php +++ b/src/Model/Observer/OrderCreate.php @@ -4,41 +4,37 @@ namespace Retailcrm\Retailcrm\Model\Observer; use Magento\Framework\Event\Observer; use Retailcrm\Retailcrm\Helper\Proxy as ApiClient; -use RetailCrm\Retailcrm\Helper\Data as Helper; +use Retailcrm\Retailcrm\Helper\Data as Helper; class OrderCreate implements \Magento\Framework\Event\ObserverInterface { protected $api; - protected $config; protected $logger; protected $helper; private $registry; - private $product; private $order; + private $serviceOrder; /** * Constructor * - * @param \Magento\Framework\App\Config\ScopeConfigInterface $config * @param \Magento\Framework\Registry $registry * @param \Retailcrm\Retailcrm\Model\Logger\Logger $logger - * @param \Magento\Catalog\Model\ProductRepository $product + * @param \Retailcrm\Retailcrm\Model\Service\Order $serviceOrder * @param Helper $helper * @param ApiClient $api */ public function __construct( - \Magento\Framework\App\Config\ScopeConfigInterface $config, \Magento\Framework\Registry $registry, \Retailcrm\Retailcrm\Model\Logger\Logger $logger, - \Magento\Catalog\Model\ProductRepository $product, + \Retailcrm\Retailcrm\Model\Service\Order $serviceOrder, Helper $helper, ApiClient $api ) { $this->logger = $logger; - $this->config = $config; $this->registry = $registry; - $this->product = $product; + $this->serviceOrder = $serviceOrder; $this->helper = $helper; $this->api = $api; $this->order = []; @@ -60,101 +56,18 @@ class OrderCreate implements \Magento\Framework\Event\ObserverInterface } $order = $observer->getEvent()->getOrder(); - $this->api->setSite($this->helper->getSite($order->getStore())); if ($this->existsInCrm($order->getId()) === true) { return false; } - $addressObj = $order->getBillingAddress(); - - $shippingCode = $this->getShippingCode($order->getShippingMethod()); - - $this->order = [ - 'externalId' => $order->getId(), - 'number' => $order->getRealOrderId(), - 'createdAt' => $order->getCreatedAt(), - 'lastName' => $order->getCustomerLastname() - ? $order->getCustomerLastname() - : $addressObj->getLastname(), - 'firstName' => $order->getCustomerFirstname() - ? $order->getCustomerFirstname() - : $addressObj->getFirstname(), - 'patronymic' => $order->getCustomerMiddlename() - ? $order->getCustomerMiddlename() - : $addressObj->getMiddlename(), - 'email' => $order->getCustomerEmail(), - 'phone' => $addressObj->getTelephone(), - 'status' => $this->config->getValue('retailcrm/retailcrm_status/' . $order->getStatus()), - 'items' => $this->getOrderItems($order), - 'delivery' => [ - 'code' => $this->config->getValue('retailcrm/retailcrm_shipping/' . $shippingCode), - 'cost' => $order->getShippingAmount(), - 'address' => [ - 'index' => $addressObj->getData('postcode'), - 'city' => $addressObj->getData('city'), - 'street' => $addressObj->getData('street'), - 'region' => $addressObj->getData('region'), - 'text' => trim( - ',', - implode( - ',', - [ - $addressObj->getData('postcode'), - $addressObj->getData('city'), - $addressObj->getData('street'), - ] - ) - ) - ] - ] - ]; - - if ($addressObj->getData('country_id')) { - $this->order['countryIso'] = $addressObj->getData('country_id'); - } - - if ($this->api->getVersion() == 'v4') { - $this->order['paymentType'] = $this->config->getValue( - 'retailcrm/retailcrm_payment/' . $order->getPayment()->getMethodInstance()->getCode() - ); - $this->order['discount'] = abs($order->getDiscountAmount()); - } elseif ($this->api->getVersion() == 'v5') { - $this->order['discountManualAmount'] = abs($order->getDiscountAmount()); - - $payment = [ - 'type' => $this->config->getValue( - 'retailcrm/retailcrm_payment/' . $order->getPayment()->getMethodInstance()->getCode() - ), - 'externalId' => $order->getId(), - 'order' => [ - 'externalId' => $order->getId(), - ] - ]; - - if ($order->getBaseTotalDue() == 0) { - $payment['status'] = 'paid'; - } - - $this->order['payments'][] = $payment; - } - - if (trim($this->order['delivery']['code']) == '') { - unset($this->order['delivery']['code']); - } - - if (isset($this->order['paymentType']) && trim($this->order['paymentType']) == '') { - unset($this->order['paymentType']); - } - - if (trim($this->order['status']) == '') { - unset($this->order['status']); - } + $billingAddress = $order->getBillingAddress(); + $this->order = $this->serviceOrder->process($order); $this->setCustomer( $order, - $addressObj + $billingAddress ); Helper::filterRecursive($this->order); @@ -168,9 +81,9 @@ class OrderCreate implements \Magento\Framework\Event\ObserverInterface /** * @param $order - * @param $addressObj + * @param $billingAddress */ - private function setCustomer($order, $addressObj) + private function setCustomer($order, $billingAddress) { if ($order->getCustomerIsGuest() == 1) { $customer = $this->getCustomerByEmail($order->getCustomerEmail()); @@ -191,9 +104,9 @@ class OrderCreate implements \Magento\Framework\Event\ObserverInterface 'email' => $order->getCustomerEmail() ]; - if ($addressObj->getTelephone()) { + if ($billingAddress->getTelephone()) { $preparedCustomer['phones'][] = [ - 'number' => $addressObj->getTelephone() + 'number' => $billingAddress->getTelephone() ]; } @@ -204,62 +117,6 @@ class OrderCreate implements \Magento\Framework\Event\ObserverInterface } } - /** - * Get order products - * - * @param object $order - * - * @return array $items - */ - private function getOrderItems($order) - { - $items = []; - - foreach ($order->getAllItems() as $item) { - if ($item->getProductType() == "simple") { - $price = $item->getPrice(); - - if ($price == 0) { - $magentoProduct = $this->product->getById($item->getProductId()); - $price = $magentoProduct->getPrice(); - } - - $product = [ - 'productId' => $item->getProductId(), - 'productName' => $item->getName(), - 'quantity' => $item->getQtyOrdered(), - 'initialPrice' => $price, - 'offer' => [ - 'externalId' => $item->getProductId() - ] - ]; - - unset($magentoProduct); - unset($price); - - $items[] = $product; - } - } - - return $items; - } - - /** - * Get shipping code - * - * @param string $string - * - * @return string - */ - public function getShippingCode($string) - { - $split = array_values(explode('_', $string)); - $length = count($split); - $prepare = array_slice($split, 0, $length/2); - - return implode('_', $prepare); - } - /** * Check exists order or customer in CRM * diff --git a/src/Model/Observer/OrderUpdate.php b/src/Model/Observer/OrderUpdate.php index d324d09..0f65184 100644 --- a/src/Model/Observer/OrderUpdate.php +++ b/src/Model/Observer/OrderUpdate.php @@ -4,7 +4,7 @@ namespace Retailcrm\Retailcrm\Model\Observer; use Magento\Framework\Event\Observer; use Retailcrm\Retailcrm\Helper\Proxy as ApiClient; -use RetailCrm\Retailcrm\Helper\Data as Helper; +use Retailcrm\Retailcrm\Helper\Data as Helper; class OrderUpdate implements \Magento\Framework\Event\ObserverInterface { diff --git a/src/Model/Order/OrderNumber.php b/src/Model/Order/OrderNumber.php index e8b1c67..fd0179c 100644 --- a/src/Model/Order/OrderNumber.php +++ b/src/Model/Order/OrderNumber.php @@ -2,36 +2,41 @@ namespace Retailcrm\Retailcrm\Model\Order; -use RetailCrm\Retailcrm\Helper\Data as Helper; +use Retailcrm\Retailcrm\Helper\Data as Helper; use Retailcrm\Retailcrm\Helper\Proxy as ApiClient; -use Retailcrm\Retailcrm\Model\Observer\OrderCreate; -class OrderNumber extends OrderCreate +class OrderNumber { private $salesOrder; + private $orderService; + private $helper; + private $api; public function __construct( - \Magento\Framework\App\Config\ScopeConfigInterface $config, - \Magento\Framework\Registry $registry, - \Retailcrm\Retailcrm\Model\Logger\Logger $logger, - \Magento\Catalog\Model\ProductRepository $product, Helper $helper, ApiClient $api, + \Retailcrm\Retailcrm\Model\Service\Order $orderService, \Magento\Sales\Api\Data\OrderInterface $salesOrder ) { + $this->api = $api; + $this->helper = $helper; $this->salesOrder = $salesOrder; - parent::__construct($config, $registry, $logger, $product, $helper, $api); + $this->orderService = $orderService; } - public function exportOrderNumber() + /** + * @param string $orderNumbers + * + * @return array + */ + public function exportOrderNumber($orderNumbers) { - $ordernumber = $this->config->getValue('retailcrm/Load/number_order'); - $ordersId = explode(",", $ordernumber); + $ordersId = explode(",", $orderNumbers); $orders = []; foreach ($ordersId as $id) { $magentoOrder = $this->salesOrder->load($id); - $orders[$magentoOrder->getStore()->getId()][] = $this->prepareOrder($magentoOrder); + $orders[$magentoOrder->getStore()->getId()][] = $this->orderService->process($magentoOrder); } foreach ($orders as $storeId => $ordersStore) { @@ -40,106 +45,22 @@ class OrderNumber extends OrderCreate foreach ($chunked as $chunk) { $this->api->setSite($this->helper->getSite($storeId)); - $this->api->ordersUpload($chunk); + $response = $this->api->ordersUpload($chunk); + + /** @var \RetailCrm\Response\ApiResponse $response */ + if (!$response->isSuccessful()) { + return [ + 'success' => false, + 'error' => $response->getErrorMsg() + ]; + } + time_nanosleep(0, 250000000); } unset($chunked); } - return true; - } - - public function prepareOrder($magentoOrder) - { - $items = []; - $addressObj = $magentoOrder->getBillingAddress(); - - foreach ($magentoOrder->getAllItems() as $item) { - if ($item->getProductType() == "simple") { - $price = $item->getPrice(); - - if ($price == 0) { - $magentoProduct = $this->productRepository->getById($item->getProductId()); - $price = $magentoProduct->getPrice(); - } - - $product = [ - 'productId' => $item->getProductId(), - 'productName' => $item->getName(), - 'quantity' => $item->getQtyOrdered(), - 'initialPrice' => $price, - 'offer' => [ - 'externalId'=>$item->getProductId() - ] - ]; - - unset($magentoProduct); - unset($price); - - $items[] = $product; - } - } - - $ship = $this->getShippingCode($magentoOrder->getShippingMethod()); - - $preparedOrder = [ - 'externalId' => $magentoOrder->getRealOrderId(), - 'number' => $magentoOrder->getRealOrderId(), - 'createdAt' => date('Y-m-d H:i:s'), - 'lastName' => $magentoOrder->getCustomerLastname(), - 'firstName' => $magentoOrder->getCustomerFirstname(), - 'patronymic' => $magentoOrder->getCustomerMiddlename(), - 'email' => $magentoOrder->getCustomerEmail(), - 'phone' => $addressObj->getTelephone(), - 'paymentType' => $this->config->getValue( - 'retailcrm/Payment/' . $magentoOrder->getPayment()->getMethodInstance()->getCode() - ), - 'status' => $this->config->getValue('retailcrm/Status/'.$magentoOrder->getStatus()), - 'discount' => abs($magentoOrder->getDiscountAmount()), - 'items' => $items, - 'delivery' => [ - 'code' => $this->config->getValue('retailcrm/Shipping/'.$ship), - 'cost' => $magentoOrder->getShippingAmount(), - 'address' => [ - 'index' => $addressObj->getData('postcode'), - 'city' => $addressObj->getData('city'), - 'country' => $addressObj->getData('country_id'), - 'street' => $addressObj->getData('street'), - 'region' => $addressObj->getData('region'), - 'text' => trim( - ',', - implode( - ',', - [ - $addressObj->getData('postcode'), - $addressObj->getData('city'), - $addressObj->getData('street'), - ] - ) - ) - ] - ] - ]; - - if (trim($preparedOrder['delivery']['code']) == '') { - unset($preparedOrder['delivery']['code']); - } - - if (trim($preparedOrder['paymentType']) == '') { - unset($preparedOrder['paymentType']); - } - - if (trim($preparedOrder['status']) == '') { - unset($preparedOrder['status']); - } - - if ($magentoOrder->getCustomerIsGuest() == 0) { - $preparedOrder['customer']['externalId'] = $magentoOrder->getCustomerId(); - } - - $this->logger->writeDump($preparedOrder, 'OrderNumber'); - - return Helper::filterRecursive($preparedOrder); + return ['success' => true]; } } diff --git a/src/Model/Service/Customer.php b/src/Model/Service/Customer.php new file mode 100644 index 0000000..bce18f8 --- /dev/null +++ b/src/Model/Service/Customer.php @@ -0,0 +1,111 @@ +helper = $helper; + } + + /** + * Process customer + * + * @param \Magento\Customer\Model\Customer $customer + * + * @return array $preparedCustomer + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function process(\Magento\Customer\Model\Customer $customer) + { + $preparedCustomer = [ + 'externalId' => $customer->getId(), + 'email' => $customer->getEmail(), + 'firstName' => $customer->getFirstname(), + 'patronymic' => $customer->getMiddlename(), + 'lastName' => $customer->getLastname(), + 'createdAt' => $customer->getCreatedAt() + ]; + + $address = $this->getAddress($customer); + $phones = $this->getPhones($customer); + + if ($address) { + $preparedCustomer['address'] = $address; + } + + if ($phones) { + $preparedCustomer['phones'] = $this->getPhones($customer); + } + + if ($this->helper->getGeneralSettings('api_version') == 'v5') { + if ($customer->getGender()) { + $preparedCustomer['sex'] = $customer->getGender() == 1 ? 'male' : 'female'; + } + + $preparedCustomer['birthday'] = $customer->getDob(); + } + + return $preparedCustomer; + } + + private function getAddress(\Magento\Customer\Model\Customer $customer) + { + $billingAddress = $customer->getDefaultBillingAddress(); + + if ($billingAddress) { + $address = [ + 'index' => $billingAddress->getData('postcode'), + 'countryIso' => $billingAddress->getData('country_id'), + 'region' => $billingAddress->getData('region'), + 'city' => $billingAddress->getData('city'), + 'street' => $billingAddress->getData('street'), + 'text' => sprintf( + '%s %s %s %s', + $billingAddress->getData('postcode'), + $billingAddress->getData('region'), + $billingAddress->getData('city'), + $billingAddress->getData('street') + ) + ]; + + return $address; + } + + return false; + } + + /** + * Set customer phones + * + * @param \Magento\Customer\Model\Customer $customer + * + * @return array $phones + */ + private function getPhones(\Magento\Customer\Model\Customer $customer) + { + $addresses = $customer->getAddressesCollection(); + $phones = []; + + if (!empty($addresses)) { + foreach ($addresses as $address) { + $phone = []; + $phone['number'] = $address->getTelephone(); + $phones[] = $phone; + } + } + + return $phones; + } +} diff --git a/src/Model/Service/Order.php b/src/Model/Service/Order.php new file mode 100644 index 0000000..a130aac --- /dev/null +++ b/src/Model/Service/Order.php @@ -0,0 +1,176 @@ +productRepository = $productRepository; + $this->config = $config; + $this->helper = $helper; + $this->configurableProduct = $configurableProduct; + } + + /** + * Process order + * + * @param \Magento\Sales\Model\Order $order + * + * @return mixed + */ + public function process(\Magento\Sales\Model\Order $order) + { + $items = $order->getAllItems(); + $products = $this->addProducts($items); + $billingAddress = $order->getBillingAddress(); + $shippingAddress = $order->getShippingAddress(); + $shipping = $this->getShippingCode($order->getShippingMethod()); + + $preparedOrder = [ + 'externalId' => $order->getId(), + 'number' => $order->getRealOrderId(), + 'createdAt' => $order->getCreatedAt(), + 'lastName' => $order->getCustomerLastname(), + 'firstName' => $order->getCustomerFirstname(), + 'patronymic' => $order->getCustomerMiddlename(), + 'email' => $order->getCustomerEmail(), + 'phone' => $billingAddress->getTelephone(), + 'status' => $this->config->getValue('retailcrm/retailcrm_status/' . $order->getStatus()), + 'items' => $products, + 'delivery' => [ + 'code' => $this->config->getValue('retailcrm/retailcrm_shipping/' . $shipping), + 'cost' => $order->getShippingAmount(), + 'address' => [ + 'index' => $shippingAddress->getData('postcode'), + 'city' => $shippingAddress->getData('city'), + 'countryIso' => $shippingAddress->getData('country_id'), + 'street' => $shippingAddress->getData('street'), + 'region' => $shippingAddress->getData('region'), + 'text' => trim( + ',', + implode( + ',', + [ + $shippingAddress->getData('postcode'), + $shippingAddress->getData('city'), + $shippingAddress->getData('street'), + ] + ) + ) + ] + ] + ]; + + if ($billingAddress->getData('country_id')) { + $preparedOrder['countryIso'] = $billingAddress->getData('country_id'); + } + + if ($this->helper->getGeneralSettings('api_version') == 'v4') { + $preparedOrder['discount'] = abs($order->getDiscountAmount()); + $preparedOrder['paymentType'] = $this->config->getValue( + 'retailcrm/retailcrm_payment/' . $order->getPayment()->getMethodInstance()->getCode() + ); + } elseif ($this->helper->getGeneralSettings('api_version') == 'v5') { + $preparedOrder['discountManualAmount'] = abs($order->getDiscountAmount()); + $payment = [ + 'type' => $this->config->getValue( + 'retailcrm/retailcrm_payment/' . $order->getPayment()->getMethodInstance()->getCode() + ), + 'externalId' => $order->getId(), + 'order' => [ + 'externalId' => $order->getId(), + ] + ]; + + if ($order->getBaseTotalDue() == 0) { + $payment['status'] = 'paid'; + } + + $preparedOrder['payments'][] = $payment; + } + + if ($order->getCustomerIsGuest() == 0) { + $preparedOrder['customer']['externalId'] = $order->getCustomerId(); + } + + return Helper::filterRecursive($preparedOrder); + } + + /** + * Get shipping code + * + * @param string $string + * + * @return string + */ + public function getShippingCode($string) + { + $split = array_values(explode('_', $string)); + $length = count($split); + $prepare = array_slice($split, 0, $length/2); + + return implode('_', $prepare); + } + + /** + * Add products in order array + * + * @param $items + * + * @return array + */ + protected function addProducts($items) + { + $products = []; + + foreach ($items as $item) { + if ($item->getProductType() == 'configurable') { + $attributesInfo = $item->getProductOptions()['attributes_info']; + $attributes = []; + + foreach ($attributesInfo as $attributeInfo) { + $attributes[$attributeInfo['option_id']] = $attributeInfo['option_value']; + } + + $product = $this->configurableProduct->getProductByAttributes($attributes, $item->getProduct()); + } else { + $product = $item->getProduct(); + } + + $price = $item->getPrice(); + + if ($price == 0) { + $magentoProduct = $this->productRepository->getById($item->getProductId()); + $price = $magentoProduct->getPrice(); + } + + $resultProduct = [ + 'productName' => $item->getName(), + 'quantity' => $item->getQtyOrdered(), + 'initialPrice' => $price, + 'offer' => [ + 'externalId' => $product ? $product->getId() : '' + ] + ]; + + unset($magentoProduct); + unset($price); + + $products[] = $resultProduct; + } + + return $products; + } +} diff --git a/src/Model/Setting/Attribute.php b/src/Model/Setting/Attribute.php index 99de0ee..de7ea42 100644 --- a/src/Model/Setting/Attribute.php +++ b/src/Model/Setting/Attribute.php @@ -17,7 +17,13 @@ class Attribute implements \Magento\Framework\Option\ArrayInterface public function toOptionArray() { - $types = ['text', 'multiselect', 'decimal']; + $types = [ + 'text', + 'decimal', + 'boolean', + 'select', + 'price' + ]; $attributes = $this->entityType->loadByCode('catalog_product')->getAttributeCollection(); $attributes->addFieldToFilter('frontend_input', $types); @@ -26,7 +32,7 @@ class Attribute implements \Magento\Framework\Option\ArrayInterface foreach ($attributes as $attr) { if ($attr->getFrontendLabel()) { $result[] = [ - 'value' => $attr->getAttributeId(), + 'value' => $attr->getAttributeCode(), 'label' => $attr->getFrontendLabel(), 'title' => $attr->getAttributeCode() ]; diff --git a/src/Test/Helpers/FieldsetTest.php b/src/Test/Helpers/FieldsetTest.php index e139d96..4b9138c 100644 --- a/src/Test/Helpers/FieldsetTest.php +++ b/src/Test/Helpers/FieldsetTest.php @@ -17,6 +17,7 @@ class FieldsetTest extends \PHPUnit\Framework\TestCase protected $form; protected $testElementId = 'test_element_id'; protected $testFieldSetCss = 'test_fieldset_css'; + protected $objectFactory; public function setUp() { @@ -26,7 +27,7 @@ class FieldsetTest extends \PHPUnit\Framework\TestCase $escaperMock = $this->createMock(\Magento\Framework\Escaper::class); $formElementMock = $this->createMock(\Magento\Framework\Data\Form\Element\Select::class); $factoryMock->expects($this->any())->method('create')->willReturn($formElementMock); - + $this->objectFactory = $this->objectManager->getObject(\Magento\Framework\DataObjectFactory::class); $formElementMock->expects($this->any())->method('setRenderer')->willReturn($formElementMock); $elementCollection = $this->objectManager->getObject(\Magento\Framework\Data\Form\Element\Collection::class); @@ -88,13 +89,17 @@ class FieldsetTest extends \PHPUnit\Framework\TestCase $this->urlModelMock = $this->createMock(\Magento\Backend\Model\Url::class); $this->layoutMock = $this->createMock(\Magento\Framework\View\Layout::class); $this->groupMock = $this->createMock(\Magento\Config\Model\Config\Structure\Element\Group::class); - $this->groupMock->expects($this->any())->method('getFieldsetCss')->will($this->returnValue($this->testFieldSetCss)); + $this->groupMock->expects($this->any())->method('getFieldsetCss') + ->will($this->returnValue($this->testFieldSetCss)); $this->context = $this->createMock(\Magento\Backend\Block\Context::class); $this->context->expects($this->any())->method('getRequest')->willReturn($this->requestMock); $this->context->expects($this->any())->method('getUrlBuilder')->willReturn($this->urlModelMock); $this->layoutMock->expects($this->any())->method('getBlockSingleton')->willReturn($rendererMock); $this->helperMock = $this->createMock(\Magento\Framework\View\Helper\Js::class); - $this->form = $this->createPartialMock(\Magento\Config\Block\System\Config\Form::class, ['getElements', 'getRequest']); + $this->form = $this->createPartialMock( + \Magento\Config\Block\System\Config\Form::class, + ['getElements', 'getRequest'] + ); $this->form->expects($this->any())->method('getElements')->willReturn($elementCollection); $this->form->expects($this->any())->method('getRequest')->willReturn($this->requestMock); } diff --git a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/PaymentTest.php b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/PaymentTest.php index 8edf18f..5f87fca 100644 --- a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/PaymentTest.php +++ b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/PaymentTest.php @@ -51,7 +51,8 @@ class PaymentTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest 'data' => ['group' => $this->groupMock], 'client' => $client, 'paymentConfig' => $paymentConfig, - 'context' => $this->context + 'context' => $this->context, + 'objectFactory' => $this->objectFactory ]; $payment = $this->objectManager->getObject( @@ -68,7 +69,9 @@ class PaymentTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest $this->assertContains($this->testFieldSetCss, $html); if (!$isConfigured) { - $expected = '
Please check your API Url & API Key
'; + $expected = ' +
' . __('Enter API of your URL and API key') . '
+ '; $this->assertContains($expected, $html); } } @@ -76,11 +79,13 @@ class PaymentTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest protected function getTestActiveMethods() { $payment = $this->getMockBuilder(\Magento\Payment\Model\MethodInterface::class) + ->setMethods(['getData']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $payment->expects($this->any()) - ->method('getTitle') + ->method('getData') + ->with('title') ->willReturn('Test Payment'); return ['test_payment' => $payment]; diff --git a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/ShippingTest.php b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/ShippingTest.php index a1511c8..4b3f7e8 100644 --- a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/ShippingTest.php +++ b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/ShippingTest.php @@ -51,7 +51,8 @@ class ShippingTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest 'data' => ['group' => $this->groupMock], 'client' => $client, 'shippingConfig' => $shippingConfig, - 'context' => $this->context + 'context' => $this->context, + 'objectFactory' => $this->objectFactory ]; $shipping = $this->objectManager->getObject( @@ -68,12 +69,14 @@ class ShippingTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest $this->assertContains($this->testFieldSetCss, $html); if (!$isConfigured) { - $expected = '
Please check your API Url & API Key
'; + $expected = ' +
' . __('Enter API of your URL and API key') . '
+ '; $this->assertContains($expected, $html); } } - protected function getTestActiveCarriers() + private function getTestActiveCarriers() { $shipping = $this->getMockBuilder(\Magento\Shipping\Model\Carrier\AbstractCarrierInterface::class) ->disableOriginalConstructor() diff --git a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SiteTest.php b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SiteTest.php index 82e5f4e..c71a441 100644 --- a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SiteTest.php +++ b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SiteTest.php @@ -42,7 +42,8 @@ class SiteTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest 'jsHelper' => $this->helperMock, 'data' => ['group' => $this->groupMock], 'client' => $client, - 'context' => $this->context + 'context' => $this->context, + 'objectFactory' => $this->objectFactory ]; $site = $this->objectManager->getObject( @@ -59,7 +60,9 @@ class SiteTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest $this->assertContains($this->testFieldSetCss, $html); if (!$isConfigured) { - $expected = '
Please check your API Url & API Key
'; + $expected = ' +
' . __('Enter API of your URL and API key') . '
+ '; $this->assertContains($expected, $html); } } diff --git a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SitesTest.php b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SitesTest.php index 7e81c88..ddfe761 100644 --- a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SitesTest.php +++ b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/SitesTest.php @@ -54,7 +54,8 @@ class SitesTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest 'data' => ['group' => $this->groupMock], 'client' => $client, 'storeManager' => $storeManager, - 'context' => $this->context + 'context' => $this->context, + 'objectFactory' => $this->objectFactory ]; $sites = $this->objectManager->getObject( @@ -71,12 +72,14 @@ class SitesTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest $this->assertContains($this->testFieldSetCss, $html); if (!$isConfigured) { - $expected = '
Please check your API Url & API Key
'; + $expected = ' +
' . __('Enter API of your URL and API key') . '
+ '; $this->assertContains($expected, $html); } } - protected function getTestStores() + private function getTestStores() { $store = $this->getMockBuilder(\Magento\Store\Model\Store::class) ->disableOriginalConstructor() diff --git a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/StatusTest.php b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/StatusTest.php index 16da0ff..66fc10b 100644 --- a/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/StatusTest.php +++ b/src/Test/Unit/Block/Adminhtml/System/Config/Form/Fieldset/StatusTest.php @@ -51,7 +51,8 @@ class StatusTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest 'data' => ['group' => $this->groupMock], 'client' => $client, 'statusCollection' => $statusCollection, - 'context' => $this->context + 'context' => $this->context, + 'objectFactory' => $this->objectFactory ]; $status = $this->objectManager->getObject( @@ -68,12 +69,14 @@ class StatusTest extends \Retailcrm\Retailcrm\Test\Helpers\FieldsetTest $this->assertContains($this->testFieldSetCss, $html); if (!$isConfigured) { - $expected = '
Please check your API Url & API Key
'; + $expected = ' +
' . __('Enter API of your URL and API key') . '
+ '; $this->assertContains($expected, $html); } } - protected function getTestStatuses() + private function getTestStatuses() { $status = [ 'label' => 'Test Status', diff --git a/src/Test/Unit/Model/Observer/CustomerTest.php b/src/Test/Unit/Model/Observer/CustomerTest.php index e1bd331..50f7d12 100644 --- a/src/Test/Unit/Model/Observer/CustomerTest.php +++ b/src/Test/Unit/Model/Observer/CustomerTest.php @@ -1,6 +1,6 @@ mockCustomer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) ->disableOriginalConstructor() ->setMethods([ - 'getId', - 'getEmail', - 'getFirstname', - 'getMiddlename', - 'getLastname', 'getStore' ]) ->getMock(); + $this->mockServiceCustomer = $this->getMockBuilder(\Retailcrm\Retailcrm\Model\Service\Customer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->mockServiceCustomer->expects($this->any())->method('process')->willReturn($this->getCustomerTestData()); + $this->helper = $this->createMock(\Retailcrm\Retailcrm\Helper\Data::class); $this->unit = new \Retailcrm\Retailcrm\Model\Observer\Customer( $this->registry, $this->helper, - $this->mockApi + $this->mockApi, + $this->mockServiceCustomer ); } @@ -73,8 +75,6 @@ class CustomerTest extends \PHPUnit\Framework\TestCase $isSuccessful, $isConfigured ) { - $testData = $this->getAfterSaveCustomerTestData(); - // mock Response $this->mockResponse->expects($this->any()) ->method('isSuccessful') @@ -95,27 +95,6 @@ class CustomerTest extends \PHPUnit\Framework\TestCase ->method('isConfigured') ->willReturn($isConfigured); - // mock Customer - $this->mockCustomer->expects($this->any()) - ->method('getId') - ->willReturn($testData['id']); - - $this->mockCustomer->expects($this->any()) - ->method('getEmail') - ->willReturn($testData['email']); - - $this->mockCustomer->expects($this->any()) - ->method('getFirstname') - ->willReturn($testData['firstname']); - - $this->mockCustomer->expects($this->any()) - ->method('getMiddlename') - ->willReturn($testData['middlename']); - - $this->mockCustomer->expects($this->any()) - ->method('getLastname') - ->willReturn($testData['lastname']); - $store = $this->createMock(\Magento\Store\Model\Store::class); $this->mockCustomer->expects($this->any()) @@ -142,25 +121,24 @@ class CustomerTest extends \PHPUnit\Framework\TestCase $this->assertArrayHasKey('lastName', $this->unit->getCustomer()); $this->assertArrayHasKey('patronymic', $this->unit->getCustomer()); $this->assertArrayHasKey('createdAt', $this->unit->getCustomer()); - $this->assertInstanceOf(\RetailCrm\Retailcrm\Model\Observer\Customer::class, $customerObserver); + $this->assertInstanceOf(\Retailcrm\Retailcrm\Model\Observer\Customer::class, $customerObserver); } else { $this->assertEmpty($this->unit->getCustomer()); } } /** - * Get test customer data - * * @return array */ - private function getAfterSaveCustomerTestData() + private function getCustomerTestData() { return [ - 'id' => 1, + 'externalId' => 1, 'email' => 'test@mail.com', - 'firstname' => 'TestFirstname', - 'lastname' => 'Testlastname', - 'middlename' => 'Testmiddlename' + 'firstName' => 'TestFirstname', + 'lastName' => 'Testlastname', + 'patronymic' => 'Testmiddlename', + 'createdAt' => \date('Y-m-d H:i:s') ]; } diff --git a/src/Test/Unit/Model/Observer/OrderCreateTest.php b/src/Test/Unit/Model/Observer/OrderCreateTest.php index 143528e..2899799 100644 --- a/src/Test/Unit/Model/Observer/OrderCreateTest.php +++ b/src/Test/Unit/Model/Observer/OrderCreateTest.php @@ -7,20 +7,19 @@ namespace Retailcrm\Retailcrm\Test\Unit\Observer; */ class OrderCreateTest extends \PHPUnit\Framework\TestCase { - private $config; private $unit; private $mockEvent; private $mockObserver; - private $registry; + private $mockRegistry; private $mockApi; private $mockOrder; private $mockItem; private $mockStore; private $mockBillingAddress; private $mockResponse; - private $mockPayment; - private $mockPaymentMethod; - private $logger; + private $mockLogger; + private $mockServiceOrder; + private $mockHelper; public function setUp() { @@ -46,61 +45,19 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase ->disableOriginalConstructor() ->setMethods(['getOrder']) ->getMock(); - - $this->config = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) - ->getMockForAbstractClass(); - $this->logger = $this->getMockBuilder(\Retailcrm\Retailcrm\Model\Logger\Logger::class) + $this->mockLogger = $this->getMockBuilder(\Retailcrm\Retailcrm\Model\Logger\Logger::class) ->disableOriginalConstructor() ->getMock(); - $this->registry = $this->getMockBuilder(\Magento\Framework\Registry::class) + $this->mockRegistry = $this->getMockBuilder(\Magento\Framework\Registry::class) ->disableOriginalConstructor() ->getMock(); - $this->mockOrder = $this->getMockBuilder(\Magento\Sales\Order::class) - ->setMethods([ - 'getId', - 'getRealOrderId', - 'getCreatedAt', - 'getStore', - 'getBillingAddress', - 'getShippingMethod', - 'getCustomerId', - 'getCustomerLastname', - 'getCustomerFirstname', - 'getCustomerMiddlename', - 'getCustomerEmail', - 'getShippingAmount', - 'getDiscountAmount', - 'getPayment', - 'getBaseTotalDue', - 'getCustomerIsGuest', - 'getAllItems', - 'getStatus' - ]) - ->getMock(); - - $this->mockPayment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class) - ->setMethods(['getMethodInstance']) + $this->mockOrder = $this->getMockBuilder(\Magento\Sales\Model\Order::class) ->disableOriginalConstructor() ->getMock(); - $this->mockPaymentMethod = $this->getMockBuilder(\Magento\Payment\Model\MethodInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->mockItem = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) - ->disableOriginalConstructor() - ->setMethods([ - 'getPrice', - 'getProductId', - 'getName', - 'getQtyOrdered', - 'getProductType' - ]) - ->getMock(); - $this->mockStore = $this->getMockBuilder(\Magento\Store\Model\Store::class) ->disableOriginalConstructor() ->setMethods(['getCode']) @@ -116,18 +73,19 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase ->setMethods(['isSuccessful']) ->getMock(); - $product = $this->getMockBuilder(\Magento\Catalog\Model\ProductRepository::class) + $this->mockServiceOrder = $this->getMockBuilder(\Retailcrm\Retailcrm\Model\Service\Order::class) ->disableOriginalConstructor() ->getMock(); - $helper = $this->createMock(\Retailcrm\Retailcrm\Helper\Data::class); + $this->mockHelper = $this->getMockBuilder(\Retailcrm\Retailcrm\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); $this->unit = new \Retailcrm\Retailcrm\Model\Observer\OrderCreate( - $this->config, - $this->registry, - $this->logger, - $product, - $helper, + $this->mockRegistry, + $this->mockLogger, + $this->mockServiceOrder, + $this->mockHelper, $this->mockApi ); } @@ -206,27 +164,6 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase ->method('getCode') ->willReturn(1); - // order item mock set data - $this->mockItem->expects($this->any()) - ->method('getProductType') - ->willReturn('simple'); - - $this->mockItem->expects($this->any()) - ->method('getPrice') - ->willReturn(999.99); - - $this->mockItem->expects($this->any()) - ->method('getProductId') - ->willReturn(10); - - $this->mockItem->expects($this->any()) - ->method('getName') - ->willReturn('Product name'); - - $this->mockItem->expects($this->any()) - ->method('getQtyOrdered') - ->willReturn(3); - // order mock set data $this->mockOrder->expects($this->any()) ->method('getId') @@ -236,68 +173,10 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase ->method('getBillingAddress') ->willReturn($this->mockBillingAddress); - $this->mockOrder->expects($this->any()) - ->method('getShippingMethod') - ->willReturn($testData['order.shippingMethod']); - $this->mockOrder->expects($this->any()) ->method('getStore') ->willReturn($this->mockStore); - $this->mockOrder->expects($this->any()) - ->method('getRealOrderId') - ->willReturn($testData['order.realOrderId']); - - $this->mockOrder->expects($this->any()) - ->method('getCreatedAt') - ->willReturn(date('Y-m-d H:i:s')); - - $this->mockOrder->expects($this->any()) - ->method('getCustomerLastname') - ->willReturn($testData['order.customerLastname']); - - $this->mockOrder->expects($this->any()) - ->method('getCustomerFirstname') - ->willReturn($testData['order.customerFirstname']); - - $this->mockOrder->expects($this->any()) - ->method('getCustomerMiddlename') - ->willReturn($testData['order.customerMiddlename']); - - $this->mockOrder->expects($this->any()) - ->method('getCustomerEmail') - ->willReturn($testData['order.customerEmail']); - - $this->mockOrder->expects($this->any()) - ->method('getAllItems') - ->willReturn($testData['order.allItems']); - - $this->mockOrder->expects($this->any()) - ->method('getStatus') - ->willReturn($testData['order.status']); - - $this->mockOrder->expects($this->any()) - ->method('getCustomerIsGuest') - ->willReturn($customerIsGuest); - - $this->mockOrder->expects($this->any()) - ->method('getCustomerId') - ->willReturn(1); - - $this->mockOrder->expects($this->any()) - ->method('getPayment') - ->willReturn($this->mockPayment); - - // mock Payment Method - $this->mockPaymentMethod->expects($this->any()) - ->method('getCode') - ->willReturn($testData['order.paymentMethod']); - - // mock Payment - $this->mockPayment->expects($this->any()) - ->method('getMethodInstance') - ->willReturn($this->mockPaymentMethod); - // mock Event $this->mockEvent->expects($this->any()) ->method('getOrder') @@ -308,6 +187,8 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase ->method('getEvent') ->willReturn($this->mockEvent); + $this->mockServiceOrder->expects($this->any())->method('process') + ->willReturn($this->getOrderTestData($apiVersion, $customerIsGuest)); $orderCreateObserver = $this->unit->execute($this->mockObserver); if ($isConfigured && !$isSuccessful) { @@ -320,7 +201,7 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase $this->assertArrayHasKey('patronymic', $this->unit->getOrder()); $this->assertArrayHasKey('email', $this->unit->getOrder()); $this->assertArrayHasKey('phone', $this->unit->getOrder()); -// $this->assertArrayHasKey('status', $this->unit->getOrder()); + $this->assertArrayHasKey('status', $this->unit->getOrder()); $this->assertArrayHasKey('items', $this->unit->getOrder()); $this->assertArrayHasKey('delivery', $this->unit->getOrder()); @@ -336,6 +217,67 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase } } + private function getOrderTestData($apiVersion, $customerIsGuest) + { + $order = [ + 'countryIso' => 'RU', + 'externalId' => 1, + 'number' => '000000001', + 'status' => 'new', + 'phone' => '890000000000', + 'email' => 'test@gmail.com', + 'createdAt' => date('Y-m-d H:i:s'), + 'lastName' => 'Test', + 'firstName' => 'Test', + 'patronymic' => 'Tests', + 'items' => [ + [ + 'productName' => 'Test product', + 'quantity' => 2, + 'initialPrice' => 1.000, + 'offer' => [ + 'externalId' => 1 + ] + ] + ], + 'delivery' => [ + 'code' => 'test', + 'cost' => '100', + 'address' => [ + 'index' => '111111', + 'city' => 'Moscow', + 'countryIso' => 'RU', + 'street' => 'Test street', + 'region' => 'Test region', + 'text' => '111111, Moscow, Test region, Test street' + ] + ] + ]; + + if ($apiVersion == 'v5') { + $order['discountManualAmount'] = 0; + $payment = [ + 'type' => 'test', + 'externalId' => 1, + 'order' => [ + 'externalId' => 1, + ], + 'status' => 'paid' + ]; + + $order['payments'][] = $payment; + } else { + $order['paymentType'] = 'test'; + $order['discount'] = 0; + } + + if ($customerIsGuest == 0) { + $order['customer']['externalId'] = 1; + } + + return $order; + } + /** * Get test order data * @@ -376,25 +318,6 @@ class OrderCreateTest extends \PHPUnit\Framework\TestCase return $testData['order.billingAddress']['data'][$dataKey]; } - public function getCallbackDataClasses($class) - { - $helper = $this->getMockBuilder(\Retailcrm\Retailcrm\Helper\Data::class) - ->disableOriginalConstructor() - ->getMock(); - - $logger = $this->getMockBuilder(\Retailcrm\Retailcrm\Model\Logger\Logger::class) - ->disableOriginalConstructor() - ->getMock(); - - if ($class == '\Retailcrm\Retailcrm\Helper\Data') { - return $helper; - } - - if ($class == '\Retailcrm\Retailcrm\Model\Logger\Logger') { - return $logger; - } - } - public function dataProviderOrderCreate() { return [ diff --git a/src/Test/Unit/Model/Service/CustomerTest.php b/src/Test/Unit/Model/Service/CustomerTest.php new file mode 100644 index 0000000..c24f98a --- /dev/null +++ b/src/Test/Unit/Model/Service/CustomerTest.php @@ -0,0 +1,191 @@ +mockData = $this->getMockBuilder(\Retailcrm\Retailcrm\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->mockCustomer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getId', + 'getEmail', + 'getFirstname', + 'getMiddlename', + 'getLastname', + 'getStore', + 'getGender', + 'getDob', + 'getDefaultBillingAddress', + 'getAddressesCollection' + ]) + ->getMock(); + } + + /** + * @param $apiVersion + * + * @dataProvider dataProvider + */ + public function testProcess($apiVersion) + { + $mockAddress = $this->getMockBuilder(\Magento\Customer\Model\Address::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getData', + 'getTelephone' + ]) + ->getMock(); + + $mockAddress->expects($this->any()) + ->method('getData') + ->with( + $this->logicalOr( + $this->equalTo('postcode'), + $this->equalTo('country_id'), + $this->equalTo('region'), + $this->equalTo('city'), + $this->equalTo('street') + ) + ) + ->will($this->returnCallback([$this, 'getCallbackDataAddress'])); + + $mockAddress->expects($this->any()) + ->method('getTelephone') + ->willReturn('000-00-00'); + + $this->mockData->expects($this->any()) + ->method('getGeneralSettings') + ->with('api_version') + ->willReturn($apiVersion); + + $testData = $this->getAfterSaveCustomerTestData(); + + // mock Customer + $this->mockCustomer->expects($this->any()) + ->method('getId') + ->willReturn($testData['id']); + + $this->mockCustomer->expects($this->any()) + ->method('getEmail') + ->willReturn($testData['email']); + + $this->mockCustomer->expects($this->any()) + ->method('getFirstname') + ->willReturn($testData['firstname']); + + $this->mockCustomer->expects($this->any()) + ->method('getMiddlename') + ->willReturn($testData['middlename']); + + $this->mockCustomer->expects($this->any()) + ->method('getLastname') + ->willReturn($testData['lastname']); + + $this->mockCustomer->expects($this->any()) + ->method('getGender') + ->willReturn($testData['gender']); + + $this->mockCustomer->expects($this->any()) + ->method('getDob') + ->willReturn($testData['birthday']); + + $this->mockCustomer->expects($this->any()) + ->method('getDefaultBillingAddress') + ->willReturn($mockAddress); + + $this->mockCustomer->expects($this->any()) + ->method('getAddressesCollection') + ->willReturn([$mockAddress]); + + $this->unit = new \Retailcrm\Retailcrm\Model\Service\Customer( + $this->mockData + ); + + $result = $this->unit->process($this->mockCustomer); + + $this->assertNotEmpty($result); + $this->assertInternalType('array', $result); + $this->assertArrayHasKey('externalId', $result); + $this->assertNotEmpty($result['externalId']); + $this->assertEquals($this->getAfterSaveCustomerTestData()['id'], $result['externalId']); + $this->assertArrayHasKey('email', $result); + $this->assertNotEmpty($result['email']); + $this->assertEquals($this->getAfterSaveCustomerTestData()['email'], $result['email']); + $this->assertArrayHasKey('firstName', $result); + $this->assertNotEmpty($result['firstName']); + $this->assertEquals($this->getAfterSaveCustomerTestData()['firstname'], $result['firstName']); + $this->assertArrayHasKey('lastName', $result); + $this->assertNotEmpty($result['lastName']); + $this->assertEquals($this->getAfterSaveCustomerTestData()['lastname'], $result['lastName']); + $this->assertArrayHasKey('patronymic', $result); + $this->assertNotEmpty($result['patronymic']); + $this->assertEquals($this->getAfterSaveCustomerTestData()['middlename'], $result['patronymic']); + + if ($apiVersion == 'v5') { + $this->assertArrayHasKey('birthday', $result); + $this->assertNotEmpty($result['birthday']); + $this->assertEquals($this->getAfterSaveCustomerTestData()['birthday'], $result['birthday']); + $this->assertArrayHasKey('sex', $result); + $this->assertNotEmpty($result['sex']); + $this->assertEquals('male', $result['sex']); + } + } + + public function getCallbackDataAddress($dataKey) + { + $address = [ + 'postcode' => 'test-index', + 'country_id' => 'US', + 'region' => 'test-region', + 'city' => 'test-city', + 'street' => 'test-street' + ]; + + return $address[$dataKey]; + } + + /** + * Get test customer data + * + * @return array + */ + private function getAfterSaveCustomerTestData() + { + return [ + 'id' => 1, + 'email' => 'test@mail.com', + 'firstname' => 'TestFirstname', + 'lastname' => 'Testlastname', + 'middlename' => 'Testmiddlename', + 'birthday' => '1990-01-01', + 'gender' => 1 + ]; + } + + /** + * Data provider + * + * @return array + */ + public function dataProvider() + { + return [ + [ + 'api_version' => 'v4', + ], + [ + 'api_version' => 'v5' + ] + ]; + } +} diff --git a/src/Test/Unit/Model/Service/OrderTest.php b/src/Test/Unit/Model/Service/OrderTest.php new file mode 100644 index 0000000..e568740 --- /dev/null +++ b/src/Test/Unit/Model/Service/OrderTest.php @@ -0,0 +1,232 @@ +mockProductRepository = $this->getMockBuilder(\Magento\Catalog\Model\ProductRepository::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->mockConfigurableProduct = $this->getMockBuilder( + \Magento\ConfigurableProduct\Model\Product\Type\Configurable::class + )->disableOriginalConstructor()->getMock(); + + $this->mockHelper = $this->createMock(\Retailcrm\Retailcrm\Helper\Data::class); + + $this->mockConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->getMockForAbstractClass(); + + $this->mockOrder = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->unit = new \Retailcrm\Retailcrm\Model\Service\Order( + $this->mockProductRepository, + $this->mockConfig, + $this->mockConfigurableProduct, + $this->mockHelper + ); + } + + /** + * @dataProvider dataProvider + * + * @param $productType + * @param $customerIsGuest + * @param $apiVersion + */ + public function testProcess($productType, $customerIsGuest, $apiVersion) + { + $this->mockHelper->expects($this->any())->method('getGeneralSettings') + ->with('api_version')->willReturn($apiVersion); + + $this->mockConfig->expects($this->any())->method('getValue') + ->with($this->logicalOr( + $this->equalTo('retailcrm/retailcrm_status/processing'), + $this->equalTo('retailcrm/retailcrm_payment/checkmo'), + $this->equalTo('retailcrm/retailcrm_shipping/flatrate') + ))->will($this->returnCallback([$this, 'getCallbackDataConfig'])); + + $mockProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->disableOriginalConstructor() + ->getMock(); + $mockProduct->expects($this->any())->method('getId')->willReturn(1); + + $mockItem = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) + ->disableOriginalConstructor() + ->getMock(); + + $mockItem->expects($this->any())->method('getProductType')->willReturn($productType); + $mockItem->expects($this->any())->method('getProductOptions') + ->willReturn([ + 'attributes_info' => [ + [ + 'option_id' => 1, + 'option_value' => 1 + ] + ] + ]); + $mockItem->expects($this->any())->method('getProduct')->willReturn($mockProduct); + $mockItem->expects($this->any())->method('getPrice')->willReturn(100.000); + $mockItem->expects($this->any())->method('getName')->willReturn('Test product'); + $mockItem->expects($this->any())->method('getQtyOrdered')->willReturn(2); + + $mockConfigurableProduct = $this->getMockBuilder( + \Magento\ConfigurableProduct\Model\Product\Type\Configurable::class + ) + ->disableOriginalConstructor() + ->getMock(); + $mockConfigurableProduct->expects($this->any())->method('getProductByAttributes')->willReturn($mockProduct); + + $mockShippingAddress = $this->getMockBuilder(\Magento\Sales\Model\Order\Address::class) + ->disableOriginalConstructor() + ->setMethods(['getData']) + ->getMock(); + $mockShippingAddress->expects($this->any()) + ->method('getData') + ->with($this->logicalOr( + $this->equalTo('city'), + $this->equalTo('region'), + $this->equalTo('street'), + $this->equalTo('postcode'), + $this->equalTo('country_id') + )) + ->will($this->returnCallback([$this, 'getCallbackDataAddress'])); + + $mockBillingAddress = $this->getMockBuilder(\Magento\Sales\Model\Order\Address::class) + ->disableOriginalConstructor() + ->setMethods(['getTelephone']) + ->getMock(); + $mockBillingAddress->expects($this->any())->method('getTelephone')->willReturn('89000000000'); + + $mockPaymentMethod = $this->getMockBuilder(\Magento\Payment\Model\MethodInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mockPaymentMethod->expects($this->any())->method('getCode')->willReturn('checkmo'); + + $mockPayment = $this->getMockBuilder(\Magento\Sales\Model\Order\Payment::class) + ->setMethods(['getMethodInstance']) + ->disableOriginalConstructor() + ->getMock(); + $mockPayment->expects($this->any())->method('getMethodInstance')->willReturn($mockPaymentMethod); + + $this->mockOrder->expects($this->any())->method('getAllItems')->willReturn([$mockItem]); + $this->mockOrder->expects($this->any())->method('getBillingAddress')->willReturn($mockBillingAddress); + $this->mockOrder->expects($this->any())->method('getShippingAddress')->willReturn($mockShippingAddress); + $this->mockOrder->expects($this->any())->method('getShippingMethod')->willReturn('flatrate_flatrate'); + $this->mockOrder->expects($this->any())->method('getId')->willReturn(1); + $this->mockOrder->expects($this->any())->method('getRealOrderId')->willReturn('000000001'); + $this->mockOrder->expects($this->any())->method('getCreatedAt')->willReturn(date('Y-m-d H:i:s')); + $this->mockOrder->expects($this->any())->method('getCustomerLastname')->willReturn('Test'); + $this->mockOrder->expects($this->any())->method('getCustomerFirstname')->willReturn(date('Test')); + $this->mockOrder->expects($this->any())->method('getCustomerMiddlename')->willReturn(date('Test')); + $this->mockOrder->expects($this->any())->method('getCustomerEmail')->willReturn('test@mail.com'); + $this->mockOrder->expects($this->any())->method('getStatus')->willReturn('processing'); + $this->mockOrder->expects($this->any())->method('getShippingAmount')->willReturn(100); + $this->mockOrder->expects($this->any())->method('getDiscountAmount')->willReturn(0); + $this->mockOrder->expects($this->any())->method('getPayment')->willReturn($mockPayment); + $this->mockOrder->expects($this->any())->method('getBaseTotalDue')->willReturn(0); + $this->mockOrder->expects($this->any())->method('getCustomerIsGuest')->willReturn($customerIsGuest); + $this->mockOrder->expects($this->any())->method('getCustomerId')->willReturn(1); + + $resultOrder = $this->unit->process($this->mockOrder); + + $this->assertNotEmpty($resultOrder); + $this->assertArrayHasKey('externalId', $resultOrder); + $this->assertArrayHasKey('number', $resultOrder); + $this->assertArrayHasKey('createdAt', $resultOrder); + $this->assertArrayHasKey('lastName', $resultOrder); + $this->assertArrayHasKey('firstName', $resultOrder); + $this->assertArrayHasKey('patronymic', $resultOrder); + $this->assertArrayHasKey('email', $resultOrder); + $this->assertArrayHasKey('phone', $resultOrder); + $this->assertArrayHasKey('items', $resultOrder); + $this->assertArrayHasKey('delivery', $resultOrder); + + if ($apiVersion == 'v5') { + $this->assertArrayHasKey('payments', $resultOrder); + } else { + $this->assertArrayHasKey('paymentType', $resultOrder); + } + } + + public function getCallbackDataConfig($key) + { + $data = [ + 'retailcrm/retailcrm_status/processing' => 'new', + 'retailcrm/retailcrm_payment/checkmo' => 'test', + 'retailcrm/retailcrm_shipping/flatrate' => 'test' + ]; + + return $data[$key]; + } + + public function dataProvider() + { + return [ + [ + 'product_type' => 'simple', + 'customer_is_guest' => 1, + 'api_version' => 'v4' + ], + [ + 'product_type' => 'configurable', + 'customer_is_guest' => 1, + 'api_version' => 'v4' + ], + [ + 'product_type' => 'simple', + 'customer_is_guest' => 0, + 'api_version' => 'v4' + ], + [ + 'product_type' => 'configurable', + 'customer_is_guest' => 0, + 'api_version' => 'v4' + ], + [ + 'product_type' => 'simple', + 'customer_is_guest' => 1, + 'api_version' => 'v5' + ], + [ + 'product_type' => 'configurable', + 'customer_is_guest' => 1, + 'api_version' => 'v5' + ], + [ + 'product_type' => 'simple', + 'customer_is_guest' => 0, + 'api_version' => 'v5' + ], + [ + 'product_type' => 'configurable', + 'customer_is_guest' => 0, + 'api_version' => 'v5' + ] + ]; + } + + public function getCallbackDataAddress($dataKey) + { + $address = [ + 'city' => 'Moscow', + 'region' => 'Moscow', + 'street' => 'Test street', + 'postcode' => '111111', + 'country_id' => 'RU' + ]; + + return $address[$dataKey]; + } +} diff --git a/src/etc/adminhtml/system.xml b/src/etc/adminhtml/system.xml index b1868a6..6e48678 100644 --- a/src/etc/adminhtml/system.xml +++ b/src/etc/adminhtml/system.xml @@ -6,72 +6,62 @@
separator-top - + retailcrm Retailcrm_Retailcrm::retailcrm_configuration - - + https://YourCrmName.retailcrm.ru Retailcrm\Retailcrm\Model\Config\Backend\ApiUrl - - - To generate an API Key, log in to RetailCRM then select Admin > Integration > API Keys + + You can create an API key in the administration section of retailCRM - - + Retailcrm\Retailcrm\Model\Setting\ApiVersions Retailcrm\Retailcrm\Model\Config\Backend\ApiVersion - - - + + - - Attributes to export into icml + + Select attributes which will be uploaded to ICML Retailcrm\Retailcrm\Model\Setting\Attribute - - + Retailcrm\Retailcrm\Block\Adminhtml\System\Config\Form\Fieldset\Shipping - - + Retailcrm\Retailcrm\Block\Adminhtml\System\Config\Form\Fieldset\Payment - - + Retailcrm\Retailcrm\Block\Adminhtml\System\Config\Form\Fieldset\Status - - - + + - Enter your order number, separated by commas + Enter order numbers separated by a comma for uploading Retailcrm\Retailcrm\Block\Adminhtml\System\Config\Button - - + Retailcrm\Retailcrm\Block\Adminhtml\System\Config\Form\Fieldset\Site - - + Retailcrm\Retailcrm\Block\Adminhtml\System\Config\Form\Fieldset\Sites
diff --git a/src/etc/di.xml b/src/etc/di.xml index 43ec649..b317515 100644 --- a/src/etc/di.xml +++ b/src/etc/di.xml @@ -8,4 +8,12 @@ Retailcrm\Retailcrm\Api\ConfigManagerInterface::API_VERSION_PATH + + + + Retailcrm\Retailcrm\Console\Command\OrdersExport + Retailcrm\Retailcrm\Console\Command\CustomersExport + + + diff --git a/src/i18n/es_ES.csv b/src/i18n/es_ES.csv new file mode 100644 index 0000000..57780a2 --- /dev/null +++ b/src/i18n/es_ES.csv @@ -0,0 +1,24 @@ +"Settings","La configuración" +"Main settings","La configuración general" +"API key","La llave API" +"You can create an API key in the administration section of retailCRM","Puede crear la llave API en la sección administrativa del retailCRM" +"API version","La versión API" +"Catalogue settings","La configuración del catálogo" +"Attributes for uploading to ICML","Los atributos para importar al ICML" +"Select attributes which will be uploaded to ICML","Seleccione los atributos que se importarán al ICML" +"Delivery types","Los métodos del envío" +"Payment types","Los métodos de pago" +"Order statuses","Los estados de pedidos" +"Uploading orders","La importación de los pedidos" +"Order number","El número del pedido" +"Enter order numbers separated by a comma for uploading","Introduce el número del pedido separado por coma para la importación" +"Setting the store by default","La configuración de la tienda por defecto" +"Setting the stores correspondence","La configuración de la concordancia de tienda" +"Enter API of your URL and API key","Introduce el enlace API y la llave API" +"Incorrect URL of retailCRM","La dirección del retailCRM es incorrecto" +"Make sure that the entered data is correct","Asegúrese de que los datos introducidos son correctos" +"Incorrect API key","La llave API es incorrecta" +"Incorrect URL of retailCRM or API key","La dirección del retailCRM o la llave API son incorrectos" +"The selected API version is unavailable","La versión de la API seleccionada no está disponible" +"Send","Enviar" +"Default site","Tienda por defecto" \ No newline at end of file diff --git a/src/i18n/ru_RU.csv b/src/i18n/ru_RU.csv new file mode 100644 index 0000000..4dffff2 --- /dev/null +++ b/src/i18n/ru_RU.csv @@ -0,0 +1,24 @@ +"Settings","Настройки" +"Main settings","Главные настройки" +"API key","API ключ" +"You can create an API key in the administration section of retailCRM","Вы можете создать API ключ в административном разделе retailCRM" +"API version","Версия API" +"Catalogue settings","Настройки каталога" +"Attributes for uploading to ICML","Атрибуты для выгрузки в ICML" +"Select attributes which will be uploaded to ICML","Выберите атрибуты, которые будут выгружены в ICML" +"Delivery types","Способы доставки" +"Payment types","Способы оплаты" +"Order statuses","Статусы заказа" +"Uploading orders","Выгрузка заказов" +"Order number","Номер заказа" +"Enter order numbers separated by a comma for uploading","Введите номера заказов для выгрузки через запятую" +"Setting the store by default","Настройка магазина по умолчанию" +"Setting the stores correspondence","Настройка соответствия магазинов" +"Enter API of your URL and API key","Введите Ваш API URL и API ключ" +"Incorrect URL of retailCRM","Некорректный адрес retailCRM" +"Make sure that the entered data is correct","Убедитесь, что введенные данные верны" +"Incorrect API key","Некорректный API ключ" +"Incorrect URL of retailCRM or API key","Некорректный адрес retailCRM или API ключ" +"The selected API version is unavailable","Выбранная версия API недоступна" +"Send","Выгрузить" +"Default site","Сайт по умолчанию" \ No newline at end of file diff --git a/src/view/adminhtml/templates/system/config/button.phtml b/src/view/adminhtml/templates/system/config/button.phtml index e7d39dc..6b8e0e0 100644 --- a/src/view/adminhtml/templates/system/config/button.phtml +++ b/src/view/adminhtml/templates/system/config/button.phtml @@ -1,19 +1,19 @@ -