From f883c6e00798667c1b58f3420a158cee41f658e1 Mon Sep 17 00:00:00 2001 From: Dmitriy Belousov Date: Wed, 21 Mar 2018 09:45:55 +0200 Subject: [PATCH] 1.3.3 (FINAL RELEASE) --- .../Amazon/Account/Edit/Tabs/General.php | 28 +- .../Amazon/Listing/Log/Grid/LastActions.php | 6 +- .../Amazon/Marketplace/Edit/Form.php | 5 - .../Database/Table/Column/Filter/Select.php | 60 ++++ .../ControlPanel/Tabs/Database/Table/Grid.php | 9 + Block/Adminhtml/Ebay/Order/View/Form.php | 1 + .../Template/Description/Edit/Form/Data.php | 4 +- Block/Adminhtml/Magento/Context/Block.php | 110 ++++++ .../Magento/Form/Renderer/Element.php | 34 ++ .../Magento/Form/Renderer/Fieldset.php | 34 ++ .../Magento/Grid/Column/Renderer/Action.php | 2 +- Block/Adminhtml/Magento/Payment/Info.php | 16 +- Block/Adminhtml/Renderer/Description.php | 22 +- Block/Adminhtml/Switcher.php | 3 +- CHANGELOG | 23 ++ .../ControlPanel/Module/Integration.php | 24 +- Helper/Client.php | 13 +- Helper/Module.php | 2 +- Helper/Module/Renderer/Description.php | 2 +- Model/AbstractModel.php | 2 +- Model/ActiveRecord/AbstractModel.php | 5 +- Model/Amazon/Marketplace.php | 8 + Model/Amazon/Order/Item.php | 27 ++ Model/Connector/Command/Pending/Requester.php | 4 +- Model/Cron/Strategy/AbstractModel.php | 1 + Model/Ebay/Connector/Item/Responser.php | 4 + .../Listing/Product/Action/Type/Request.php | 78 +++-- Model/Ebay/Order/Item.php | 29 +- Model/HealthStatus/Task/Result/Factory.php | 8 +- .../Task/Result/LocationResolver.php | 5 +- .../Task/Server/Status/GmtTime.php | 4 +- Model/Listing/Product/PriceCalculator.php | 6 +- Model/Log/AbstractModel.php | 3 +- Model/Magento/Backend/Model/Session/Quote.php | 19 + Model/Magento/Order/Shipment.php | 12 +- Model/Magento/Order/Shipment/Factory.php | 55 +++ Model/Magento/Order/Updater.php | 3 +- Model/Magento/Product/Builder.php | 64 +++- Model/Magento/Product/StockItem.php | 57 ++- Model/Magento/Product/StockItem/Factory.php | 53 +++ Model/Magento/Quote/Builder.php | 324 ++++++++++++++++++ .../Quote/FailDuringEventProcessing.php | 43 +++ Model/Magento/Quote/Manager.php | 114 ++++++ Model/Order.php | 67 +++- Model/Order/Item.php | 16 + Model/Order/Proxy.php | 3 +- Model/Order/Reserve.php | 45 ++- Model/Order/ShippingAddress.php | 14 +- Model/Processing/Runner.php | 5 +- .../Component/Parent/AbstractModel.php | 3 +- .../Magento/Product/Collection.php | 2 +- Observer/Amazon/Order.php | 5 +- Observer/Order/Quote.php | 8 + Observer/StockItem/AbstractStockItem.php | 2 +- Plugin/AbstractPlugin.php | 5 + .../CatalogInventory/Model/Stock/Item.php | 13 + composer.json | 2 +- versions_history.json | 9 + view/adminhtml/templates/amazon/order.phtml | 6 +- view/adminhtml/templates/ebay/order.phtml | 6 +- .../template/description/preview/body.phtml | 8 + view/adminhtml/web/css/style.css | 7 + .../web/js/Ebay/Listing/Template/Switcher.js | 2 +- 63 files changed, 1385 insertions(+), 169 deletions(-) create mode 100644 Block/Adminhtml/ControlPanel/Tabs/Database/Table/Column/Filter/Select.php create mode 100644 Block/Adminhtml/Magento/Context/Block.php create mode 100644 Model/Magento/Backend/Model/Session/Quote.php create mode 100644 Model/Magento/Order/Shipment/Factory.php create mode 100644 Model/Magento/Product/StockItem/Factory.php create mode 100644 Model/Magento/Quote/Builder.php create mode 100644 Model/Magento/Quote/FailDuringEventProcessing.php create mode 100644 Model/Magento/Quote/Manager.php create mode 100644 view/adminhtml/templates/ebay/template/description/preview/body.phtml diff --git a/Block/Adminhtml/Amazon/Account/Edit/Tabs/General.php b/Block/Adminhtml/Amazon/Account/Edit/Tabs/General.php index 48a185377..6dc0c59f9 100644 --- a/Block/Adminhtml/Amazon/Account/Edit/Tabs/General.php +++ b/Block/Adminhtml/Amazon/Account/Edit/Tabs/General.php @@ -190,18 +190,28 @@ protected function _prepareForm() ] )->setFieldExtraAttributes('style="display: none"'); + $accessDataFieldConfig = [ + 'container_id' => 'marketplaces_register_url_container_' . $marketplace['id'], + 'label' => '', + 'href' => '', + 'onclick' => '', + 'target' => '_blank', + 'value' => $this->__('Get Access Data'), + 'class' => 'external-link', + ]; + + if ($marketplace['is_automatic_token_retrieving_available']) { + $accessDataFieldConfig['onclick'] = 'return AmazonAccountObj.getToken('.$marketplace['id'].')'; + } else { + $accessDataFieldConfig['href'] = $this->getHelper('Component\Amazon')->getRegisterUrl( + $marketplace['id'] + ); + } + $fieldset->addField( 'marketplaces_register_url_' . $marketplace['id'], 'link', - [ - 'container_id' => 'marketplaces_register_url_container_' . $marketplace['id'], - 'label' => '', - 'href' => '', - 'onclick' => 'return AmazonAccountObj.getToken('.$marketplace['id'].')', - 'target' => '_blank', - 'value' => $this->__('Get Access Data'), - 'class' => 'external-link', - ] + $accessDataFieldConfig )->setFieldExtraAttributes('style="display: none"'); } diff --git a/Block/Adminhtml/Amazon/Listing/Log/Grid/LastActions.php b/Block/Adminhtml/Amazon/Listing/Log/Grid/LastActions.php index 78f2de025..c32833a03 100644 --- a/Block/Adminhtml/Amazon/Listing/Log/Grid/LastActions.php +++ b/Block/Adminhtml/Amazon/Listing/Log/Grid/LastActions.php @@ -51,13 +51,13 @@ protected function getGroupedActions(array $logs) $descArr = []; foreach ($actionsRow['items'] as $key => &$item) { - if (array_key_exists($item['description'], $descArr)) { - $descArr[$item['description']]['count']++; + if (array_key_exists((string)$item['description'], $descArr)) { + $descArr[(string)$item['description']]['count']++; unset($actionsRow['items'][$key]); continue; } $item['count'] = 1; - $descArr[$item['description']] = $item; + $descArr[(string)$item['description']] = $item; } $actionsRow['items'] = array_values($descArr); } diff --git a/Block/Adminhtml/Amazon/Marketplace/Edit/Form.php b/Block/Adminhtml/Amazon/Marketplace/Edit/Form.php index 3bfe7ff88..2a2db27b3 100644 --- a/Block/Adminhtml/Amazon/Marketplace/Edit/Form.php +++ b/Block/Adminhtml/Amazon/Marketplace/Edit/Form.php @@ -204,11 +204,6 @@ protected function addStaticMarketplaces(\Magento\Framework\Data\Form $form) 'label' => $this->__('India'), 'note' => 'amazon.in', ], - [ - 'group_id' => 1, - 'label' => $this->__('Mexico'), - 'note' => 'amazon.com.mx', - ], ]; foreach ($staticData as $marketplace) { diff --git a/Block/Adminhtml/ControlPanel/Tabs/Database/Table/Column/Filter/Select.php b/Block/Adminhtml/ControlPanel/Tabs/Database/Table/Column/Filter/Select.php new file mode 100644 index 000000000..8a7ae75ab --- /dev/null +++ b/Block/Adminhtml/ControlPanel/Tabs/Database/Table/Column/Filter/Select.php @@ -0,0 +1,60 @@ +helperFactory = $context->getHelperFactory(); + $this->activeRecordFactory = $context->getActiveRecordFactory(); + + parent::__construct($context, $resourceHelper, $data); + } + + protected function _getOptions() + { + $options = array(); + + $modelName = $this->getColumn()->getGrid()->getTableModel()->getModelName(); + $htmlName = $this->_getHtmlName(); + + $colOptions = $this->activeRecordFactory->getObject($modelName) + ->getCollection() + ->getSelect() + ->group($htmlName) + ->query(); + + if (!empty($colOptions)) { + $options = array(array('value' => null, 'label' => '')); + foreach ($colOptions as $colOption) { + $options[] = array( + 'value' => $colOption[$htmlName], + 'label' => $colOption[$htmlName], + ); + } + } + + return $options; + } + + //######################################## +} \ No newline at end of file diff --git a/Block/Adminhtml/ControlPanel/Tabs/Database/Table/Grid.php b/Block/Adminhtml/ControlPanel/Tabs/Database/Table/Grid.php index b0d1ccf55..e9f3e236c 100644 --- a/Block/Adminhtml/ControlPanel/Tabs/Database/Table/Grid.php +++ b/Block/Adminhtml/ControlPanel/Tabs/Database/Table/Grid.php @@ -122,6 +122,10 @@ protected function _prepareColumns() $params['format'] = \IntlDateFormatter::MEDIUM; } + if($this->tableModel->getTableName() == 'm2epro_operation_history' && $column['name'] == 'nick') { + $params['filter'] = '\Ess\M2ePro\Block\Adminhtml\ControlPanel\Tabs\Database\Table\Column\Filter\Select'; + } + $this->addColumn($column['name'], $params); } @@ -404,6 +408,11 @@ public function getRowUrl($row) //return $this->getUrl('*/*/editTableRow', array('id' => $row->getId())); } + public function getTableModel() + { + return $this->tableModel; + } + //######################################## private function getColumnType($columnData) diff --git a/Block/Adminhtml/Ebay/Order/View/Form.php b/Block/Adminhtml/Ebay/Order/View/Form.php index b6dd1e5e6..4eca53955 100644 --- a/Block/Adminhtml/Ebay/Order/View/Form.php +++ b/Block/Adminhtml/Ebay/Order/View/Form.php @@ -76,6 +76,7 @@ protected function _beforeToHtml() if (!is_null($magentoOrder) && $magentoOrder->hasShipments()) { $url = $this->getUrl('*/order/resubmitShippingInfo', array('id' => $this->order->getId())); $data = array( + 'class' => 'primary', 'label' => $this->__('Resend Shipping Information'), 'onclick' => 'setLocation(\''.$url.'\');', ); diff --git a/Block/Adminhtml/Ebay/Template/Description/Edit/Form/Data.php b/Block/Adminhtml/Ebay/Template/Description/Edit/Form/Data.php index d4219e494..5abea5418 100644 --- a/Block/Adminhtml/Ebay/Template/Description/Edit/Form/Data.php +++ b/Block/Adminhtml/Ebay/Template/Description/Edit/Form/Data.php @@ -1419,7 +1419,9 @@ protected function _prepareForm() window.AttributeObj = new Attribute(); } window.EbayTemplateDescriptionObj = new EbayTemplateDescription(); - EbayTemplateDescriptionObj.initObservers(); + setTimeout(function() { + EbayTemplateDescriptionObj.initObservers(); + }, 50); {$initWYSIWYG} window.MagentoAttributeButtonObj = new MagentoAttributeButton(); diff --git a/Block/Adminhtml/Magento/Context/Block.php b/Block/Adminhtml/Magento/Context/Block.php new file mode 100644 index 000000000..0a6c95918 --- /dev/null +++ b/Block/Adminhtml/Magento/Context/Block.php @@ -0,0 +1,110 @@ +helperFactory = $helperFactory; + $this->modelFactory = $modelFactory; + $this->activeRecordFactory = $activeRecordFactory; + $this->parentFactory = $parentFactory; + + parent::__construct( + $request, + $layout, + $eventManager, + $urlBuilder, + $cache, + $design, + $session, + $sidResolver, + $scopeConfig, + $assetRepo, + $viewConfig, + $cacheState, + $logger, + $escaper, + $filterManager, + $localeDate, + $inlineTranslation, + $authorization + ); + } + + /** + * @return \Ess\M2ePro\Helper\Factory + */ + public function getHelperFactory() + { + return $this->helperFactory; + } + + /** + * @return \Ess\M2ePro\Model\Factory + */ + public function getModelFactory() + { + return $this->modelFactory; + } + + /** + * @return \Ess\M2ePro\Model\ActiveRecord\Factory + */ + public function getActiveRecordFactory() + { + return $this->activeRecordFactory; + } + + /** + * @return \Ess\M2ePro\Model\ActiveRecord\Component\Parent\Factory + */ + public function getParentFactory() + { + return $this->parentFactory; + } +} \ No newline at end of file diff --git a/Block/Adminhtml/Magento/Form/Renderer/Element.php b/Block/Adminhtml/Magento/Form/Renderer/Element.php index 51c761771..c0e8b2514 100644 --- a/Block/Adminhtml/Magento/Form/Renderer/Element.php +++ b/Block/Adminhtml/Magento/Form/Renderer/Element.php @@ -7,6 +7,21 @@ class Element extends MagentoElement { + /** @var \Ess\M2ePro\Helper\Factory */ + protected $helperFactory; + + //######################################## + + public function __construct( + \Ess\M2ePro\Block\Adminhtml\Magento\Context\Template $context, + array $data = [] + ){ + $this->helperFactory = $context->getHelperFactory(); + parent::__construct($context, $data); + } + + //######################################## + protected function getTooltipHtml($content) { return <<helperFactory->getObject('Data')->escapeHtml( + $data, ['div', 'a', 'strong', 'br', 'i', 'b', 'ul', 'li'], ENT_NOQUOTES + ); + } + + //######################################## } \ No newline at end of file diff --git a/Block/Adminhtml/Magento/Form/Renderer/Fieldset.php b/Block/Adminhtml/Magento/Form/Renderer/Fieldset.php index 2b1da110d..d7716da1f 100644 --- a/Block/Adminhtml/Magento/Form/Renderer/Fieldset.php +++ b/Block/Adminhtml/Magento/Form/Renderer/Fieldset.php @@ -7,6 +7,21 @@ class Fieldset extends MagentoFieldset { + /** @var \Ess\M2ePro\Helper\Factory */ + protected $helperFactory; + + //######################################## + + public function __construct( + \Ess\M2ePro\Block\Adminhtml\Magento\Context\Template $context, + array $data = [] + ){ + $this->helperFactory = $context->getHelperFactory(); + parent::__construct($context, $data); + } + + //######################################## + protected function getTooltipHtml($content, $directionClass) { return <<helperFactory->getObject('Data')->escapeHtml( + $data, ['div', 'a', 'strong', 'br', 'i', 'b', 'ul', 'li'], ENT_NOQUOTES + ); + } + + //######################################## } \ No newline at end of file diff --git a/Block/Adminhtml/Magento/Grid/Column/Renderer/Action.php b/Block/Adminhtml/Magento/Grid/Column/Renderer/Action.php index c3d5d2695..eb7fc71f7 100644 --- a/Block/Adminhtml/Magento/Grid/Column/Renderer/Action.php +++ b/Block/Adminhtml/Magento/Grid/Column/Renderer/Action.php @@ -163,7 +163,7 @@ protected function _toLinkHtml($action, \Magento\Framework\DataObject $row) if (isset($action['confirm'])) { $action['onclick'] = 'CommonObj.confirm({ - content: \''.addslashes($this->escapeHtml($action['confirm'])).'\', + content: \''.addslashes(htmlspecialchars($this->escapeHtml($action['confirm']))).'\', actions: { confirm: function () { setLocation(this.href); diff --git a/Block/Adminhtml/Magento/Payment/Info.php b/Block/Adminhtml/Magento/Payment/Info.php index a765e20ca..645bec7f9 100644 --- a/Block/Adminhtml/Magento/Payment/Info.php +++ b/Block/Adminhtml/Magento/Payment/Info.php @@ -18,6 +18,8 @@ class Info extends \Magento\Payment\Block\Info private $order = NULL; + protected $_template = 'Ess_M2ePro::magento/order/payment/info.phtml'; + //######################################## public function __construct( @@ -34,12 +36,20 @@ public function __construct( //######################################## - protected function _construct() + /** + * Magento has forcibly set FRONTEND area + * vendor/magento/module-payment/Helper/Data.php::getInfoBlockHtm() + * + * @return string + */ + protected function _toHtml() { - parent::_construct(); - $this->setTemplate('Ess_M2ePro::magento/order/payment/info.phtml'); + $this->setData('area', \Magento\Framework\App\Area::AREA_ADMINHTML); + return parent::_toHtml(); } + //######################################## + /** * @return \Magento\Sales\Model\Order */ diff --git a/Block/Adminhtml/Renderer/Description.php b/Block/Adminhtml/Renderer/Description.php index 05cb78b53..ea3b2bca7 100644 --- a/Block/Adminhtml/Renderer/Description.php +++ b/Block/Adminhtml/Renderer/Description.php @@ -1,14 +1,30 @@ setData('area', 'adminhtml'); + $this->setData('area', \Magento\Framework\App\Area::AREA_ADMINHTML); + return parent::_toHtml(); } + + //######################################## } \ No newline at end of file diff --git a/Block/Adminhtml/Switcher.php b/Block/Adminhtml/Switcher.php index c76e8883d..8409ba0c3 100644 --- a/Block/Adminhtml/Switcher.php +++ b/Block/Adminhtml/Switcher.php @@ -89,7 +89,8 @@ public function getParamName() public function getParamPlaceHolder() { - return '%' . $this->getParamName() . '%'; + // can't use special chars like # or % cause magento's getUrl method decoding them + return 'PLH' . $this->getParamName() . 'PLH'; } public function getDefaultParam() diff --git a/CHANGELOG b/CHANGELOG index ee39ad54d..39461e058 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,26 @@ +* 1.3.3 (r2494) (20/03/2018) + +* Fix: 'Magento Order was not created' error even if Magento Order was actually created in some cases +* Fix: The "Resend Shipping Information" button is not being displayed +* Fix: "Product that you are trying to add is not available" exception on Magento versions >= 2.1.8. (on new product creating or changing product stock status by QTY reservation during Magento Order creating) +* Fix: "Cannot create an empty shipment" on Magento version >= 2.2.0 +* Fix: "Magento Order was not created: This product is out of stock." in some cases on Magento version >= 2.2.0 +* Fix: "StockItem event doesn't have correct StockItem instance" (on Magento versions >= 2.2.0) +* Fix: "Unable to save Stock Item" error during product creating on Magento version >= 2.2.0 +* Fix: "Invalid value of "1" provided for the regionId field." during orders creation (on Magento version >= 2.2.3) +* Fix: Broken content of some Tooltips (on Magento version >= 2.2.3) +* Fix: PHP memory_limit setting was overridden by lower value during Synchronization in some cases +* Fix: Do the forcibly setting of an Adminhtml area for the payment info block +* Fix: 'Class "InterceptorResponser" does not exist' error in some cases +* Fix: A second line of a street is being imploded with a first one for Magento orders (should be stored separately) +* Fix: Capital letters for attributes placeholders in a custom description template may cause unexpected errors +* Fix: "Warning: A non-numeric value encountered in ..." during price calculation (for a Product which is configured to take the price from a Magento Attribute but has no value) +* Fix: The error message "Invalid attribute name: entity_id" (a space at the start of attribute name) appeared in Listing View +* Fix: "QTY was changed from [1] to []" instead of correct integer value +* Fix: "Logs clearing" task does not run +* Fix: [eBay] "Uncaught ReferenceError: wysiwygdescription_template is not defined" (in some cases) when JS Merge is enabled +* Fix: [eBay] "Waring: Invalid argument supplied for foreach() in Model/Ebay/Listing/Product/Action/Type/Request.php" when variation was not allowed by configurator during a Revise Action + * 1.3.2 (r2356) (23/09/2017) * Added: Compatibility with Magento Marketplace (marketplace.magento.com) diff --git a/Controller/Adminhtml/ControlPanel/Module/Integration.php b/Controller/Adminhtml/ControlPanel/Module/Integration.php index 3a6a115bd..080fd8c93 100644 --- a/Controller/Adminhtml/ControlPanel/Module/Integration.php +++ b/Controller/Adminhtml/ControlPanel/Module/Integration.php @@ -392,34 +392,42 @@ public function getPrintOrderQuoteDataAction() $proxy = $order->getProxy()->setStore($order->getStore()); - $magentoQuote = $this->modelFactory->getObject('Magento\Quote', ['proxyOrder' => $proxy]); - $magentoQuote->buildQuote(); - $magentoQuote->getQuote()->setIsActive(false)->save(); + /** @var \Ess\M2ePro\Model\Magento\Quote\Builder $magentoQuoteBuilder */ + $magentoQuoteBuilder = $this->modelFactory->getObject('Magento\Quote\Builder', ['proxyOrder' => $proxy]); + /** @var \Ess\M2ePro\Model\Magento\Quote\Manager $magentoQuoteManager */ + $magentoQuoteManager = $this->modelFactory->getObject('Magento\Quote\Manager'); - $shippingAddressData = $magentoQuote->getQuote()->getShippingAddress()->getData(); + $quote = $magentoQuoteBuilder->build(); + + $shippingAddressData = $quote->getShippingAddress()->getData(); unset( $shippingAddressData['cached_items_all'], $shippingAddressData['cached_items_nominal'], $shippingAddressData['cached_items_nonnominal'] ); - $billingAddressData = $magentoQuote->getQuote()->getBillingAddress()->getData(); + $billingAddressData = $quote->getBillingAddress()->getData(); unset( $billingAddressData['cached_items_all'], $billingAddressData['cached_items_nominal'], $billingAddressData['cached_items_nonnominal'] ); - - $quote = $magentoQuote->getQuote(); + $quoteData = $quote->getData(); + unset( + $quoteData['items'], + $quoteData['extension_attributes'] + ); $html = ''; $html .= '
Grand Total: ' .$quote->getGrandTotal(). '
'; $html .= '
Shipping Amount: ' .$quote->getShippingAddress()->getShippingAmount(). '
'; - $html .= '
Quote Data: ' .print_r($quote->getData(), true). '
'; + $html .= '
Quote Data: ' .print_r($quoteData, true). '
'; $html .= '
Shipping Address Data: ' .print_r($shippingAddressData, true). '
'; $html .= '
Billing Address Data: ' .print_r($billingAddressData, true). '
'; + $magentoQuoteManager->save($quote->setIsActive(false)); + return $html; } diff --git a/Helper/Client.php b/Helper/Client.php index de37f8eb8..0649c1faf 100644 --- a/Helper/Client.php +++ b/Helper/Client.php @@ -326,7 +326,7 @@ public function getMemoryLimit($inMegabytes = true) $memoryLimit *= 1024; } - if ($inMegabytes) { + if ($memoryLimit > 0 && $inMegabytes) { $memoryLimit /= 1024 * 1024; } @@ -338,7 +338,7 @@ public function setMemoryLimit($maxSize = 512) $minSize = 32; $currentMemoryLimit = $this->getMemoryLimit(); - if ($maxSize < $minSize || (int)$currentMemoryLimit >= $maxSize) { + if ($maxSize < $minSize || (int)$currentMemoryLimit >= $maxSize || (float)$currentMemoryLimit <= 0) { return false; } @@ -371,5 +371,14 @@ public function setPcreRecursionLimit($limit = 1000) ini_set('pcre.recursion_limit', $limit); } + public function getClassName($object) + { + if ($object instanceof \Magento\Framework\Interception\InterceptorInterface) { + return get_parent_class($object); + } else { + return get_class($object); + } + } + //######################################## } \ No newline at end of file diff --git a/Helper/Module.php b/Helper/Module.php index 13f28d6ef..0a51fd47e 100644 --- a/Helper/Module.php +++ b/Helper/Module.php @@ -91,7 +91,7 @@ public function getName() public function getPublicVersion() { - return '1.3.2'; + return '1.3.3'; } public function getSetupVersion() diff --git a/Helper/Module/Renderer/Description.php b/Helper/Module/Renderer/Description.php index d2a621174..ad7d95a56 100644 --- a/Helper/Module/Renderer/Description.php +++ b/Helper/Module/Renderer/Description.php @@ -72,7 +72,7 @@ public function parseTemplate($text, \Ess\M2ePro\Model\Magento\Product $magentoP private function insertAttributes($text, \Ess\M2ePro\Model\Magento\Product $magentoProduct) { - preg_match_all("/#([a-zA-Z_0-9]+?)#/", $text, $matches); + preg_match_all("/#([a-z_0-9]+?)#/", $text, $matches); if (!count($matches[0])) { return $text; diff --git a/Model/AbstractModel.php b/Model/AbstractModel.php index caca3e481..2ab87cb45 100644 --- a/Model/AbstractModel.php +++ b/Model/AbstractModel.php @@ -38,7 +38,7 @@ public function getCacheLifetime() public function getCacheGroupTags() { - $modelName = str_replace('Ess\M2ePro\Model\\', '', get_class($this)); + $modelName = str_replace('Ess\M2ePro\Model\\', '', $this->getHelper('Client')->getClassName($this)); $tags[] = $modelName; diff --git a/Model/ActiveRecord/AbstractModel.php b/Model/ActiveRecord/AbstractModel.php index 902dc9415..f7b1ffd0a 100644 --- a/Model/ActiveRecord/AbstractModel.php +++ b/Model/ActiveRecord/AbstractModel.php @@ -60,7 +60,8 @@ public function isObjectCreatingState($value = null) public function getObjectModelName() { - return str_replace('Ess\M2ePro\Model\\', '', get_class($this)); + $className = $this->getHelper('Client')->getClassName($this); + return str_replace('Ess\M2ePro\Model\\', '', $className); } //######################################## @@ -488,7 +489,7 @@ public function getCacheLifetime() public function getCacheGroupTags() { - $modelName = str_replace('Ess\M2ePro\Model\\', '', get_class($this)); + $modelName = str_replace('Ess\M2ePro\Model\\', '', $this->getHelper('Client')->getClassName($this)); $tags[] = $modelName; diff --git a/Model/Amazon/Marketplace.php b/Model/Amazon/Marketplace.php index ce1c35271..d47155bc8 100644 --- a/Model/Amazon/Marketplace.php +++ b/Model/Amazon/Marketplace.php @@ -117,6 +117,14 @@ public function isProductTaxCodePolicyAvailable() return (bool)$this->getData('is_product_tax_code_policy_available'); } + /** + * @return bool + */ + public function isAutomaticTokenRetrievingAvailable() + { + return (bool)$this->getData('is_automatic_token_retrieving_available'); + } + //######################################## public function isCacheEnabled() diff --git a/Model/Amazon/Order/Item.php b/Model/Amazon/Order/Item.php index 36c28a39b..36c06d8f0 100644 --- a/Model/Amazon/Order/Item.php +++ b/Model/Amazon/Order/Item.php @@ -253,6 +253,33 @@ public function getVariationChannelOptions() return $channelItem->getVariationChannelOptions(); } + public function canCreateMagentoOrder() + { + return $this->isOrdersCreationEnabled(); + } + + public function isReservable() + { + return $this->isOrdersCreationEnabled(); + } + + // --------------------------------------- + + private function isOrdersCreationEnabled() + { + $channelItem = $this->getChannelItem(); + + if (!is_null($channelItem) && !$this->getAmazonAccount()->isMagentoOrdersListingsModeEnabled()) { + return false; + } + + if (is_null($channelItem) && !$this->getAmazonAccount()->isMagentoOrdersListingsOtherModeEnabled()) { + return false; + } + + return true; + } + //######################################## /** diff --git a/Model/Connector/Command/Pending/Requester.php b/Model/Connector/Command/Pending/Requester.php index 45a196e97..fba957216 100644 --- a/Model/Connector/Command/Pending/Requester.php +++ b/Model/Connector/Command/Pending/Requester.php @@ -113,7 +113,9 @@ protected function getProcessingParams() protected function getResponserModelName() { - $responserModelName = preg_replace('/Requester$/', '', get_class($this)).'Responser'; + $className = $this->getHelper('Client')->getClassName($this); + + $responserModelName = preg_replace('/Requester$/', '', $className).'Responser'; $responserModelName = str_replace('Ess\M2ePro\Model\\', '', $responserModelName); return $responserModelName; diff --git a/Model/Cron/Strategy/AbstractModel.php b/Model/Cron/Strategy/AbstractModel.php index aa9eaabcf..5215a9238 100644 --- a/Model/Cron/Strategy/AbstractModel.php +++ b/Model/Cron/Strategy/AbstractModel.php @@ -84,6 +84,7 @@ public function getAllowedTasks() \Ess\M2ePro\Model\Cron\Task\ConnectorRequesterPendingSingle::NICK, \Ess\M2ePro\Model\Cron\Task\ConnectorRequesterPendingPartial::NICK, \Ess\M2ePro\Model\Cron\Task\Amazon\Actions::NICK, + \Ess\M2ePro\Model\Cron\Task\LogsClearing::NICK, \Ess\M2ePro\Model\Cron\Task\Ebay\Actions::NICK, \Ess\M2ePro\Model\Cron\Task\Servicing::NICK, \Ess\M2ePro\Model\Cron\Task\HealthStatus::NICK, diff --git a/Model/Ebay/Connector/Item/Responser.php b/Model/Ebay/Connector/Item/Responser.php index 21ca9d911..4708b7101 100644 --- a/Model/Ebay/Connector/Item/Responser.php +++ b/Model/Ebay/Connector/Item/Responser.php @@ -393,6 +393,9 @@ protected function isNewRequiredSpecificNeeded(array $messages) * 21916585: Duplicate custom variation label. * 21916582: Duplicate VariationSpecifics trait value in the VariationSpecificsSet container. * 21916672: The tags (MPN) is/are disabled as Variant. + * 21919061: This item was created from Selling Manager product, but the VariationSpecifics or V + * ariationSpecificsSet provided for this item does not match with the product. + * Please update variation specifics on the product and try again. */ protected function isVariationErrorAppeared(array $messages) { @@ -404,6 +407,7 @@ protected function isVariationErrorAppeared(array $messages) 21916585, 21916582, 21916672, + 21919061, ); foreach ($messages as $message) { diff --git a/Model/Ebay/Listing/Product/Action/Type/Request.php b/Model/Ebay/Listing/Product/Action/Type/Request.php index ab714ee38..13085fc69 100644 --- a/Model/Ebay/Listing/Product/Action/Type/Request.php +++ b/Model/Ebay/Listing/Product/Action/Type/Request.php @@ -289,21 +289,30 @@ protected function resolveVariationMpnIssue(array $data) return $data; } - $additionalData = $this->getListingProduct()->getAdditionalData(); - if (!empty($additionalData['without_mpn_variation_issue'])) { + $withoutMpnIssue = $this->getListingProduct()->getSetting('additional_data', 'without_mpn_variation_issue'); + $isMpnOnChannel = $this->getListingProduct()->getSetting('additional_data', 'is_variation_mpn_filled'); + + if ($withoutMpnIssue === true) { $data['without_mpn_variation_issue'] = true; - return $data; } - foreach ($data['variation'] as &$variationData) { - if (!empty($variationData['details']['mpn'])) { - continue; - } + if (isset($data['variation']) && is_array($data['variation'])) { + + foreach ($data['variation'] as &$variationData) { - if (!isset($additionalData['is_variation_mpn_filled']) || - $additionalData['is_variation_mpn_filled'] === true - ) { - $variationData['details']['mpn'] = Description::PRODUCT_DETAILS_DOES_NOT_APPLY; + /** + * Item was listed without MPN, but then the Description Policy setting was changed and + * MPN values are being send to eBay + */ + if (isset($variationData['details']['mpn']) && $isMpnOnChannel === false) { + unset($variationData['details']['mpn']); + } + + if (!isset($variationData['details']['mpn']) && + ($isMpnOnChannel === true || (is_null($isMpnOnChannel) && !$withoutMpnIssue)) + ) { + $variationData['details']['mpn'] = Description::PRODUCT_DETAILS_DOES_NOT_APPLY; + } } } @@ -322,39 +331,42 @@ protected function doReplaceVariationSpecifics(array $data, array $replacements) } } - foreach ($data['variation'] as &$variationItem) { - foreach ($replacements as $findIt => $replaceBy) { + if (isset($data['variation']) && is_array($data['variation'])) { - if (!isset($variationItem['specifics'][$findIt])) { - continue; - } + foreach ($data['variation'] as &$variationItem) { + foreach ($replacements as $findIt => $replaceBy) { - $variationItem['specifics'][$replaceBy] = $variationItem['specifics'][$findIt]; - unset($variationItem['specifics'][$findIt]); + if (!isset($variationItem['specifics'][$findIt])) { + continue; + } + + $variationItem['specifics'][$replaceBy] = $variationItem['specifics'][$findIt]; + unset($variationItem['specifics'][$findIt]); + } } - } - foreach ($replacements as $findIt => $replaceBy) { + foreach ($replacements as $findIt => $replaceBy) { - if (!isset($data['variations_sets'][$findIt])) { - continue; - } + if (!isset($data['variations_sets'][$findIt])) { + continue; + } - $data['variations_sets'][$replaceBy] = $data['variations_sets'][$findIt]; - unset($data['variations_sets'][$findIt]); + $data['variations_sets'][$replaceBy] = $data['variations_sets'][$findIt]; + unset($data['variations_sets'][$findIt]); - // M2ePro\TRANSLATIONS - // The Variational Attribute Label "%replaced_it%" was changed to "%replaced_by%". For Item Specific "%replaced_by%" you select an Attribute by which your Variational Item varies. As it is impossible to send a correct Value for this Item Specific, it’s Label will be used as Variational Attribute Label instead of "%replaced_it%". This replacement cannot be edit in future by Relist/Revise Actions. - $this->addWarningMessage( - $this->getHelper('Module\Translation')->__( - 'The Variational Attribute Label "%replaced_it%" was changed to "%replaced_by%". For Item Specific + // M2ePro\TRANSLATIONS + // The Variational Attribute Label "%replaced_it%" was changed to "%replaced_by%". For Item Specific "%replaced_by%" you select an Attribute by which your Variational Item varies. As it is impossible to send a correct Value for this Item Specific, it’s Label will be used as Variational Attribute Label instead of "%replaced_it%". This replacement cannot be edit in future by Relist/Revise Actions. + $this->addWarningMessage( + $this->getHelper('Module\Translation')->__( + 'The Variational Attribute Label "%replaced_it%" was changed to "%replaced_by%". For Item Specific "%replaced_by%" you select an Attribute by which your Variational Item varies. As it is impossible to send a correct Value for this Item Specific, it’s Label will be used as Variational Attribute Label instead of "%replaced_it%". This replacement cannot be edit in future by Relist/Revise Actions.', - $findIt, $replaceBy - ) - ); + $findIt, $replaceBy + ) + ); + } } return $data; diff --git a/Model/Ebay/Order/Item.php b/Model/Ebay/Order/Item.php index da4a0e81b..37411ea21 100644 --- a/Model/Ebay/Order/Item.php +++ b/Model/Ebay/Order/Item.php @@ -306,6 +306,33 @@ public function getVariationChannelOptions() return $this->getVariationOptions(); } + public function canCreateMagentoOrder() + { + return $this->isOrdersCreationEnabled(); + } + + public function isReservable() + { + return $this->isOrdersCreationEnabled(); + } + + // --------------------------------------- + + private function isOrdersCreationEnabled() + { + $ebayItem = $this->getChannelItem(); + + if (!is_null($ebayItem) && !$this->getEbayAccount()->isMagentoOrdersListingsModeEnabled()) { + return false; + } + + if (is_null($ebayItem) && !$this->getEbayAccount()->isMagentoOrdersListingsOtherModeEnabled()) { + return false; + } + + return true; + } + //######################################## /** @@ -493,7 +520,7 @@ public function updateShippingStatus(array $trackingDetails = array()) ); $this->activeRecordFactory->getObject('Order\Change')->create( - $this->getId(), $action, $creator, $component, $params + $this->getParentObject()->getOrderId(), $action, $creator, $component, $params ); return true; diff --git a/Model/HealthStatus/Task/Result/Factory.php b/Model/HealthStatus/Task/Result/Factory.php index 30181abd4..b8141116b 100644 --- a/Model/HealthStatus/Task/Result/Factory.php +++ b/Model/HealthStatus/Task/Result/Factory.php @@ -18,6 +18,10 @@ class Factory /** @var \Magento\Framework\ObjectManagerInterface */ protected $_objectManager = null; + protected $helperFactory; + + protected $modelFactory; + //######################################## public function __construct( @@ -28,6 +32,8 @@ public function __construct( ){ $this->locationResolver = $locationResolver; $this->_objectManager = $objectManager; + $this->helperFactory = $helperFactory; + $this->modelFactory = $modelFactory; } //######################################## @@ -39,7 +45,7 @@ public function __construct( public function create(\Ess\M2ePro\Model\HealthStatus\Task\AbstractModel $task) { return $this->_objectManager->create(TaskResult::class, [ - 'taskHash' => get_class($task), + 'taskHash' => $this->helperFactory->getObject('Client')->getClassName($task), 'taskType' => $task->getType(), 'taskMustBeShownIfSuccess' => $task->mustBeShownIfSuccess(), 'tabName' => $this->locationResolver->resolveTabName($task), diff --git a/Model/HealthStatus/Task/Result/LocationResolver.php b/Model/HealthStatus/Task/Result/LocationResolver.php index f62e8931c..f7a3d274e 100644 --- a/Model/HealthStatus/Task/Result/LocationResolver.php +++ b/Model/HealthStatus/Task/Result/LocationResolver.php @@ -66,13 +66,14 @@ public function resolveFieldName(Task\AbstractModel $task) private function usingMap(Task\AbstractModel $task) { - $key = get_class($task); + $key = $this->helperFactory->getObject('Client')->getClassName($task); return array_key_exists($key, $this->getMap()) ? $this->getMap()[$key] : null; } private function usingClassName(Task\AbstractModel $task) { - $className = str_replace('Ess\M2ePro\Model\HealthStatus\Task\\', '', get_class($task)); + $fullClassName = $this->getHelper('Client')->getClassName($task); + $className = str_replace('Ess\M2ePro\Model\HealthStatus\Task\\', '', $fullClassName); $className = explode('\\', $className); if (count($className) != 3) { diff --git a/Model/HealthStatus/Task/Server/Status/GmtTime.php b/Model/HealthStatus/Task/Server/Status/GmtTime.php index 44364e544..8b8625fca 100644 --- a/Model/HealthStatus/Task/Server/Status/GmtTime.php +++ b/Model/HealthStatus/Task/Server/Status/GmtTime.php @@ -39,9 +39,9 @@ public function process() $dispatcherObject = $this->modelFactory->getObject('M2ePro\Connector\Dispatcher'); $connectorObj = $dispatcherObject->getVirtualConnector('server','get','gmtTime'); - $requestTimeStart = microtime(); + $requestTimeStart = microtime(true); $dispatcherObject->process($connectorObj); - $requestTimeEnd = microtime(); + $requestTimeEnd = microtime(true); $responseData = $connectorObj->getResponseData(); $requestTime = (int)($requestTimeEnd - $requestTimeStart); diff --git a/Model/Listing/Product/PriceCalculator.php b/Model/Listing/Product/PriceCalculator.php index 25fabd5b4..f82793383 100644 --- a/Model/Listing/Product/PriceCalculator.php +++ b/Model/Listing/Product/PriceCalculator.php @@ -397,7 +397,7 @@ protected function getProductBaseValue() throw new Logic('Unknown Mode in Database.'); } - return $this->productValueCache = $value; + return $this->productValueCache = (float)$value; } protected function getVariationBaseValue(Variation $variation) @@ -421,7 +421,7 @@ protected function getVariationBaseValue(Variation $variation) )); } - return $value; + return (float)$value; } protected function getOptionBaseValue(Variation\Option $option) @@ -443,7 +443,7 @@ protected function getOptionBaseValue(Variation\Option $option) throw new Logic('Unknown Mode in Database.'); } - return $value; + return (float)$value; } //######################################## diff --git a/Model/Log/AbstractModel.php b/Model/Log/AbstractModel.php index 5ae71c155..df19794bb 100644 --- a/Model/Log/AbstractModel.php +++ b/Model/Log/AbstractModel.php @@ -78,7 +78,8 @@ public function getComponentMode() public function getActionsTitles() { - return $this->getHelper('Module\Log')->getActionsTitlesByClass(static::class); + $className = $this->getHelper('Client')->getClassName($this); + return $this->getHelper('Module\Log')->getActionsTitlesByClass($className); } //######################################## diff --git a/Model/Magento/Backend/Model/Session/Quote.php b/Model/Magento/Backend/Model/Session/Quote.php new file mode 100644 index 000000000..8898af01a --- /dev/null +++ b/Model/Magento/Backend/Model/Session/Quote.php @@ -0,0 +1,19 @@ +_quote = null; + return $this; + } +} \ No newline at end of file diff --git a/Model/Magento/Order/Shipment.php b/Model/Magento/Order/Shipment.php index 1638f54a5..69df06a4a 100644 --- a/Model/Magento/Order/Shipment.php +++ b/Model/Magento/Order/Shipment.php @@ -2,20 +2,18 @@ /* * @author M2E Pro Developers Team - * @copyright 2011-2015 ESS-UA [M2E Pro] + * @copyright M2E LTD * @license Commercial use is forbidden */ namespace Ess\M2ePro\Model\Magento\Order; -use Magento\Sales\Model\Order\ShipmentFactory; - class Shipment extends \Ess\M2ePro\Model\AbstractModel { /** @var \Magento\Framework\DB\Transaction */ protected $transaction = NULL; - /** @var ShipmentFactory */ + /** @var \Ess\M2ePro\Model\Magento\Order\Shipment\Factory|null */ protected $shipmentFactory = NULL; /** @var $magentoOrder \Magento\Sales\Model\Order */ @@ -27,14 +25,14 @@ class Shipment extends \Ess\M2ePro\Model\AbstractModel //######################################## public function __construct( - \Magento\Sales\Model\Order\ShipmentFactory $shipmentFactory, + \Ess\M2ePro\Model\Magento\Order\Shipment\Factory $shipmentFactory, \Magento\Framework\DB\Transaction $transaction, \Ess\M2ePro\Helper\Factory $helperFactory, \Ess\M2ePro\Model\Factory $modelFactory ) { - $this->shipmentFactory = $shipmentFactory; - $this->transaction = $transaction; + $this->shipmentFactory = $shipmentFactory; + $this->transaction = $transaction; parent::__construct($helperFactory, $modelFactory); } diff --git a/Model/Magento/Order/Shipment/Factory.php b/Model/Magento/Order/Shipment/Factory.php new file mode 100644 index 000000000..1faffe9b2 --- /dev/null +++ b/Model/Magento/Order/Shipment/Factory.php @@ -0,0 +1,55 @@ +objectManager = $objectManager; + $this->helperFactory = $helperFactory; + $this->modelFactory = $modelFactory; + } + + //######################################## + + /** + * @param \Magento\Sales\Model\Order $order + * @return \Magento\Sales\Api\Data\ShipmentInterface + */ + public function create(\Magento\Sales\Model\Order $order) + { + return $this->resolveFactory()->create($order); + } + + //######################################## + + private function resolveFactory() + { + if (version_compare($this->helperFactory->getObject('Magento')->getVersion(), '2.2.0', '<')) { + return $this->objectManager->get('\Magento\Sales\Model\Order\ShipmentFactory'); + } + + return $this->objectManager->get('\Magento\Sales\Model\Order\ShipmentDocumentFactory'); + } + + //######################################## +} \ No newline at end of file diff --git a/Model/Magento/Order/Updater.php b/Model/Magento/Order/Updater.php index 1f4d5a4b5..bd51fc5e9 100644 --- a/Model/Magento/Order/Updater.php +++ b/Model/Magento/Order/Updater.php @@ -97,13 +97,12 @@ public function updateShippingAddress(array $addressInfo) $shippingAddress = $this->magentoOrder->getShippingAddress(); if ($shippingAddress instanceof \Magento\Sales\Model\Order\Address) { $shippingAddress->addData($addressInfo); - $shippingAddress->implodeStreetAddress()->save(); + $shippingAddress->save(); } else { /** @var $shippingAddress \Magento\Sales\Model\Order\Address */ $shippingAddress = $this->addressFactory->create(); $shippingAddress->setCustomerId($this->magentoOrder->getCustomerId()); $shippingAddress->addData($addressInfo); - $shippingAddress->implodeStreetAddress(); // we need to set shipping address to order before address save to init parent_id field $this->magentoOrder->setShippingAddress($shippingAddress); diff --git a/Model/Magento/Product/Builder.php b/Model/Magento/Product/Builder.php index eec1f08fe..ae85e03e7 100644 --- a/Model/Magento/Product/Builder.php +++ b/Model/Magento/Product/Builder.php @@ -2,7 +2,7 @@ /* * @author M2E Pro Developers Team - * @copyright 2011-2015 ESS-UA [M2E Pro] + * @copyright M2E LTD * @license Commercial use is forbidden */ @@ -10,16 +10,28 @@ class Builder extends \Ess\M2ePro\Model\AbstractModel { + /** @var \Magento\Framework\Filesystem\DriverPool */ protected $driverPool; + /** @var \Magento\Framework\Filesystem */ protected $filesystem; + /** @var \Magento\Store\Model\StoreFactory */ protected $storeFactory; + /** @var StockItem\Factory */ protected $stockItemFactory; + /** @var \Magento\Catalog\Model\Product\Media\Config */ protected $productMediaConfig; + /** @var \Magento\Catalog\Model\ProductFactory */ protected $productFactory; + /** @var \Ess\M2ePro\Helper\Factory */ protected $helperFactory; - - /** @var $product \Magento\Catalog\Model\Product */ - private $product = NULL; + /** @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor */ + protected $indexStockProcessor; + /** @var \Magento\CatalogInventory\Api\StockConfigurationInterface */ + protected $stockConfiguration; + /** @var \Magento\Catalog\Model\Product */ + private $product; + /** @var \Magento\CatalogInventory\Model\Stock\Item */ + private $stockItem; //######################################## @@ -27,21 +39,25 @@ public function __construct( \Magento\Framework\Filesystem\DriverPool $driverPool, \Magento\Framework\Filesystem $filesystem, \Magento\Store\Model\StoreFactory $storeFactory, - \Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory $stockItemFactory, \Magento\Catalog\Model\Product\Media\Config $productMediaConfig, \Magento\Catalog\Model\ProductFactory $productFactory, \Ess\M2ePro\Model\ActiveRecord\Factory $activeRecordFactory, \Ess\M2ePro\Helper\Factory $helperFactory, - \Ess\M2ePro\Model\Factory $modelFactory + \Ess\M2ePro\Model\Factory $modelFactory, + \Magento\CatalogInventory\Model\Indexer\Stock\Processor $indexStockProcessor, + \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration, + \Ess\M2ePro\Model\Magento\Product\StockItem\Factory $stockItemFactory ) { - $this->driverPool = $driverPool; - $this->filesystem = $filesystem; - $this->storeFactory = $storeFactory; - $this->stockItemFactory = $stockItemFactory; - $this->productMediaConfig = $productMediaConfig; - $this->productFactory = $productFactory; - $this->helperFactory = $helperFactory; + $this->driverPool = $driverPool; + $this->filesystem = $filesystem; + $this->storeFactory = $storeFactory; + $this->stockItemFactory = $stockItemFactory; + $this->productMediaConfig = $productMediaConfig; + $this->productFactory = $productFactory; + $this->helperFactory = $helperFactory; + $this->indexStockProcessor = $indexStockProcessor; + $this->stockConfiguration = $stockConfiguration; parent::__construct( $helperFactory, $modelFactory @@ -60,6 +76,16 @@ public function getProduct() public function buildProduct() { $this->createProduct(); + $this->createStockItem(); + + /* + * Since version 2.1.8 Magento performs check if there is a record for product in table + * cataloginventory_stock_status during quantity validation. Force reindex for new product will be helpful + * if scheduled reindexing is enabled for stock status. + */ + if ($this->indexStockProcessor->isIndexerScheduled() && $this->product->getId()) { + $this->indexStockProcessor->reindexRow($this->product->getId(), true); + } } private function createProduct() @@ -122,21 +148,23 @@ private function createProduct() // --------------------------------------- $this->product->getResource()->save($this->product); - - $this->createStockItem(); } //######################################## private function createStockItem() { - /** @var $stockItem \Magento\CatalogInventory\Model\Stock\Item */ - $stockItem = $this->stockItemFactory->create(); + $stockItem = $this->stockItemFactory + ->create( + $this->product->getId(), + $this->stockConfiguration->getDefaultScopeId() + ); $stockItem->setProduct($this->product); $stockItem->addData(array( 'qty' => $this->getData('qty'), - 'stock_id' => 1, + 'stock_id' => \Magento\CatalogInventory\Model\Stock::DEFAULT_STOCK_ID, + 'website_id' => $this->stockConfiguration->getDefaultScopeId(), 'is_in_stock' => 1, 'use_config_min_qty' => 1, 'use_config_min_sale_qty' => 1, diff --git a/Model/Magento/Product/StockItem.php b/Model/Magento/Product/StockItem.php index f289a3793..249c55cbb 100644 --- a/Model/Magento/Product/StockItem.php +++ b/Model/Magento/Product/StockItem.php @@ -15,30 +15,35 @@ class StockItem extends \Ess\M2ePro\Model\AbstractModel /** @var \Magento\CatalogInventory\Model\Stock\Item */ private $stockItem = null; + /** @var \Magento\CatalogInventory\Model\Indexer\Stock\Processor */ + private $indexStockProcessor = null; + + /** @var \Magento\CatalogInventory\Model\Spi\StockStateProviderInterface */ + private $stockStateProvider; + + /** @var bool */ + private $stockStatusChanged = false; + //######################################## public function __construct( \Magento\CatalogInventory\Api\StockConfigurationInterface $stockConfiguration, \Ess\M2ePro\Helper\Factory $helperFactory, - \Ess\M2ePro\Model\Factory $modelFactory - ) - { - $this->stockConfiguration = $stockConfiguration; + \Ess\M2ePro\Model\Factory $modelFactory, + \Magento\CatalogInventory\Model\Indexer\Stock\Processor $indexStockProcessor, + \Magento\CatalogInventory\Model\Spi\StockStateProviderInterface $stockStateProvider, + \Magento\CatalogInventory\Model\Stock\Item $stockItem + ){ + $this->stockConfiguration = $stockConfiguration; + $this->indexStockProcessor = $indexStockProcessor; + $this->stockStateProvider = $stockStateProvider; + $this->stockItem = $stockItem; + parent::__construct($helperFactory, $modelFactory); } //######################################## - /** - * @param \Magento\CatalogInventory\Model\Stock\Item $stockItem - * @return $this - */ - public function setStockItem(\Magento\CatalogInventory\Model\Stock\Item $stockItem) - { - $this->stockItem = $stockItem; - return $this; - } - /** * @return \Magento\CatalogInventory\Model\Stock\Item * @throws \Ess\M2ePro\Model\Exception\Logic @@ -70,8 +75,13 @@ public function subtractQty($qty, $save = true) $stockItem->setQty($stockItem->getQty() - $qty); } + if ($stockItem->getManageStock() && !$this->stockStateProvider->verifyStock($stockItem)) { + $this->stockStatusChanged = true; + } + if ($save) { $stockItem->save(); + $this->afterSave(); } } @@ -82,12 +92,31 @@ public function addQty($qty, $save = true) if ($stockItem->getQty() > $stockItem->getMinQty()) { $stockItem->setIsInStock(true); + $this->stockStatusChanged = true; } if ($save) { $stockItem->save(); + $this->afterSave(); } } //######################################## + + public function afterSave() + { + if ($this->indexStockProcessor->isIndexerScheduled()) { + + $this->indexStockProcessor->reindexRow($this->stockItem->getProductId(), true); + } + } + + //---------------------------------------- + + public function isStockStatusChanged() + { + return (bool)$this->stockStatusChanged; + } + + //######################################## } \ No newline at end of file diff --git a/Model/Magento/Product/StockItem/Factory.php b/Model/Magento/Product/StockItem/Factory.php new file mode 100644 index 000000000..143ec8fa1 --- /dev/null +++ b/Model/Magento/Product/StockItem/Factory.php @@ -0,0 +1,53 @@ +objectManager = $objectManager; + $this->helperFactory = $helperFactory; + $this->modelFactory = $modelFactory; + } + + //######################################## + + /** + * @param int $productId + * @param int $scopeId + * @return \Magento\CatalogInventory\Model\Stock\Item + */ + public function create($productId, $scopeId) + { + if (version_compare($this->helperFactory->getObject('Magento')->getVersion(), '2.2.0', '<')) { + return $this->objectManager + ->get('\Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory') + ->create(); + } + + return $this->objectManager + ->get('\Magento\CatalogInventory\Model\StockRegistryStorage') + ->getStockItem($productId, $scopeId); + } + + //######################################## +} \ No newline at end of file diff --git a/Model/Magento/Quote/Builder.php b/Model/Magento/Quote/Builder.php new file mode 100644 index 000000000..11e3ad7e7 --- /dev/null +++ b/Model/Magento/Quote/Builder.php @@ -0,0 +1,324 @@ +proxyOrder = $proxyOrder; + $this->currency = $currency; + $this->magentoCurrencyFactory = $magentoCurrencyFactory; + $this->calculation = $calculation; + $this->storeConfig = $storeConfig; + $this->productResource = $productResource; + $this->quoteManager = $quoteManager; + parent::__construct($helperFactory, $modelFactory); + } + + public function __destruct() + { + if (is_null($this->storeConfigurator)) { + return; + } + + $this->storeConfigurator->restoreOriginalStoreConfigForOrder(); + } + + //######################################## + + public function build() + { + try { + // do not change invoke order + // --------------------------------------- + $this->initializeQuote(); + $this->initializeCustomer(); + $this->initializeAddresses(); + + $this->configureStore(); + $this->configureTaxCalculation(); + + $this->initializeCurrency(); + $this->initializeShippingMethodData(); + $this->initializeQuoteItems(); + $this->initializePaymentMethodData(); + + $this->quote = $this->quoteManager->save($this->quote); + + $this->prepareOrderNumber(); + return $this->quote; + // --------------------------------------- + } catch (\Exception $e) { + // Remove ordered items from customer cart + $this->quote->setIsActive(false)->save(); + throw $e; + } + } + + //######################################## + + private function initializeQuote() + { + $this->quote = $this->quoteManager->getBlankQuote(); + + $this->quote->setCheckoutMethod($this->proxyOrder->getCheckoutMethod()); + $this->quote->setStore($this->proxyOrder->getStore()); + $this->quote->getStore()->setData('current_currency', $this->quote->getStore()->getBaseCurrency()); + $this->quote = $this->quoteManager->save($this->quote); + + $this->quote->setIsM2eProQuote(true); + $this->quote->setNeedProcessChannelTaxes( + $this->proxyOrder->isTaxModeChannel() || + ($this->proxyOrder->isTaxModeMixed() && + ($this->proxyOrder->hasTax() || $this->proxyOrder->getWasteRecyclingFee())) + ); + + $this->quoteManager->replaceCheckoutQuote($this->quote); + } + + //######################################## + + private function initializeCustomer() + { + if ($this->proxyOrder->isCheckoutMethodGuest()) { + $this->quote + ->setCustomerId(null) + ->setCustomerEmail($this->proxyOrder->getBuyerEmail()) + ->setCustomerFirstname($this->proxyOrder->getCustomerFirstName()) + ->setCustomerLastname($this->proxyOrder->getCustomerLastName()) + ->setCustomerIsGuest(true) + ->setCustomerGroupId(\Magento\Customer\Model\Group::NOT_LOGGED_IN_ID); + + return; + } + + $this->quote->assignCustomer($this->proxyOrder->getCustomer()); + } + + //######################################## + + private function initializeAddresses() + { + $billingAddress = $this->quote->getBillingAddress(); + $billingAddress->addData($this->proxyOrder->getBillingAddressData()); + + $billingAddress->setLimitCarrier('m2eproshipping'); + $billingAddress->setShippingMethod('m2eproshipping_m2eproshipping'); + $billingAddress->setCollectShippingRates(true); + $billingAddress->setShouldIgnoreValidation($this->proxyOrder->shouldIgnoreBillingAddressValidation()); + + // --------------------------------------- + + $shippingAddress = $this->quote->getShippingAddress(); + $shippingAddress->setSameAsBilling(0); // maybe just set same as billing? + $shippingAddress->addData($this->proxyOrder->getAddressData()); + + $shippingAddress->setLimitCarrier('m2eproshipping'); + $shippingAddress->setShippingMethod('m2eproshipping_m2eproshipping'); + $shippingAddress->setCollectShippingRates(true); + + // --------------------------------------- + } + + //######################################## + + private function initializeCurrency() + { + /** @var $currencyHelper \Ess\M2ePro\Model\Currency */ + $currencyHelper = $this->currency; + + if ($currencyHelper->isConvertible($this->proxyOrder->getCurrency(), $this->quote->getStore())) { + $currentCurrency = $this->magentoCurrencyFactory->create()->load( + $this->proxyOrder->getCurrency() + ); + } else { + $currentCurrency = $this->quote->getStore()->getBaseCurrency(); + } + + $this->quote->getStore()->setData('current_currency', $currentCurrency); + } + + //######################################## + + /** + * Configure store (invoked only after address, customer and store initialization and before price calculations) + */ + private function configureStore() + { + $this->storeConfigurator = $this->modelFactory->getObject( + 'Magento\Quote\Store\Configurator', ['quote' => $this->quote, 'proxyOrder' => $this->proxyOrder] + ); + + $this->storeConfigurator->prepareStoreConfigForOrder(); + } + + //######################################## + + private function configureTaxCalculation() + { + // this prevents customer session initialization (which affects cookies) + // see Mage_Tax_Model_Calculation::getCustomer() + $this->calculation->setCustomer($this->quote->getCustomer()); + } + + //######################################## + + private function initializeQuoteItems() + { + foreach ($this->proxyOrder->getItems() as $item) { + + $this->clearQuoteItemsCache(); + + /** @var $quoteItemBuilder \Ess\M2ePro\Model\Magento\Quote\Item */ + $quoteItemBuilder = $this->modelFactory->getObject('Magento\Quote\Item', [ + 'quote' => $this->quote, + 'proxyItem' => $item + ]); + + $product = $quoteItemBuilder->getProduct(); + $request = $quoteItemBuilder->getRequest(); + + // --------------------------------------- + $productOriginalPrice = (float)$product->getPrice(); + + $price = $item->getBasePrice(); + $product->setPrice($price); + $product->setSpecialPrice($price); + // --------------------------------------- + + // see Mage_Sales_Model_Observer::substractQtyFromQuotes + $this->quote->setItemsCount($this->quote->getItemsCount() + 1); + $this->quote->setItemsQty((float)$this->quote->getItemsQty() + $request->getQty()); + + $result = $this->quote->addProduct($product, $request); + if (is_string($result)) { + throw new \Ess\M2ePro\Model\Exception($result); + } + + $quoteItem = $this->quote->getItemByProduct($product); + + if ($quoteItem !== false) { + $quoteItem->setStoreId($this->quote->getStoreId()); + $quoteItem->setOriginalCustomPrice($item->getPrice()); + $quoteItem->setOriginalPrice($productOriginalPrice); + $quoteItem->setBaseOriginalPrice($productOriginalPrice); + $quoteItem->setNoDiscount(1); + + $giftMessageId = $quoteItemBuilder->getGiftMessageId(); + if (!empty($giftMessageId)) { + $quoteItem->setGiftMessageId($giftMessageId); + } + + $quoteItem->setAdditionalData($quoteItemBuilder->getAdditionalData($quoteItem)); + + $quoteItem->setWasteRecyclingFee($item->getWasteRecyclingFee() / $item->getQty()); + } + } + + $allItems = $this->quote->getAllItems(); + $this->quote->getItemsCollection()->removeAllItems(); + + foreach ($allItems as $item) { + $item->save(); + $this->quote->getItemsCollection()->addItem($item); + } + } + + /** + * Mage_Sales_Model_Quote_Address caches items after each collectTotals call. Some extensions calls collectTotals + * after adding new item to quote in observers. So we need clear this cache before adding new item to quote. + */ + private function clearQuoteItemsCache() + { + foreach ($this->quote->getAllAddresses() as $address) { + + $address->unsetData('cached_items_all'); + $address->unsetData('cached_items_nominal'); + $address->unsetData('cached_items_nonnominal'); + } + } + + //######################################## + + private function initializeShippingMethodData() + { + $this->getHelper('Data\GlobalData')->unsetValue('shipping_data'); + $this->getHelper('Data\GlobalData')->setValue('shipping_data', $this->proxyOrder->getShippingData()); + } + + //######################################## + + private function initializePaymentMethodData() + { + $quotePayment = $this->quote->getPayment(); + $quotePayment->importData($this->proxyOrder->getPaymentData()); + } + + //######################################## + + private function prepareOrderNumber() + { + if ($this->proxyOrder->isOrderNumberPrefixSourceChannel()) { + $orderNumber = $this->addPrefixToOrderNumberIfNeed($this->proxyOrder->getChannelOrderNumber()); + $this->quote->setReservedOrderId($orderNumber); + return; + } + + $orderNumber = $this->quote->getReservedOrderId(); + if (empty($orderNumber)) { + $orderNumber = $this->quote->getResource()->getReservedOrderId($this->quote); + } + + $orderNumber = $this->addPrefixToOrderNumberIfNeed($orderNumber); + + $this->quote->setReservedOrderId($orderNumber); + } + + private function addPrefixToOrderNumberIfNeed($orderNumber) + { + $prefix = $this->proxyOrder->getOrderNumberPrefix(); + if (empty($prefix)) { + return $orderNumber; + } + + return $prefix.$orderNumber; + } + + //######################################## +} \ No newline at end of file diff --git a/Model/Magento/Quote/FailDuringEventProcessing.php b/Model/Magento/Quote/FailDuringEventProcessing.php new file mode 100644 index 000000000..a8385f6fc --- /dev/null +++ b/Model/Magento/Quote/FailDuringEventProcessing.php @@ -0,0 +1,43 @@ +order = $order; + } + + public function getOrder() + { + return $this->order; + } + + //######################################## +} \ No newline at end of file diff --git a/Model/Magento/Quote/Manager.php b/Model/Magento/Quote/Manager.php new file mode 100644 index 000000000..b17d5c3d3 --- /dev/null +++ b/Model/Magento/Quote/Manager.php @@ -0,0 +1,114 @@ +quoteRepository = $quoteRepository; + $this->sessionQuote = $sessionQuote; + $this->quoteManagement = $quoteManagement; + $this->checkoutSession = $checkoutSession; + $this->orderFactory = $orderFactory; + } + + //######################################## + + /** + * @return \Magento\Quote\Model\Quote + */ + public function getBlankQuote() + { + $this->clearQuoteSessionStorage(); + return $this->sessionQuote->getQuote(); + } + + /** + * @param \Magento\Quote\Model\Quote $quote + * @return \Magento\Framework\Model\AbstractExtensibleModel|\Magento\Sales\Api\Data\OrderInterface|null|object + * @throws FailDuringEventProcessing + * @throws \Exception + */ + public function submit(\Magento\Quote\Model\Quote $quote) + { + try { + $order = $this->quoteManagement->submit($quote); + return $order; + } catch (\Exception $e) { + + $order = $this->orderFactory->create()->loadByIncrementId($quote->getReservedOrderId()); + + if ($order->getId()) { + $this->helperFactory->getObject('Module\Exception')->process($e, false); + throw new \Ess\M2ePro\Model\Magento\Quote\FailDuringEventProcessing( + $order, + $e->getMessage() + ); + } + // Remove ordered items from customer cart + $quote->setIsActive(false)->save(); + throw $e; + } + } + + /** + * @param \Magento\Quote\Model\Quote $quote + * @return \Magento\Quote\Api\Data\CartInterface + */ + public function save(\Magento\Quote\Model\Quote $quote) + { + $this->quoteRepository->save($quote); + + /** + * vendor/magento/module-quote/Model/QuoteRepository.php::loadQuote() + * is going to override store_id for a quote, so we are forced to set it again + */ + $reloadedQuote = $this->quoteRepository->get($quote->getId()); + $reloadedQuote->setStoreId($quote->getStoreId()); + + return $reloadedQuote; + } + + public function replaceCheckoutQuote(\Magento\Quote\Model\Quote $quote) + { + $this->checkoutSession->replaceQuote($quote); + } + + public function clearQuoteSessionStorage() + { + $this->sessionQuote->clearStorage(); + } + + //######################################## +} \ No newline at end of file diff --git a/Model/Order.php b/Model/Order.php index 4308ee6fc..c7c8a3704 100644 --- a/Model/Order.php +++ b/Model/Order.php @@ -7,6 +7,7 @@ */ namespace Ess\M2ePro\Model; +use Ess\M2ePro\Model\Magento\Quote\FailDuringEventProcessing; /** * @method \Ess\M2ePro\Model\Amazon\Order|\Ess\M2ePro\Model\Amazon\Order getChildObject() @@ -29,6 +30,9 @@ class Order extends ActiveRecord\Component\Parent\AbstractModel // Payment method "M2E Pro Payment" is disabled in Magento Configuration. // Shipping method "M2E Pro Shipping" is disabled in Magento Configuration. + const MAGENTO_ORDER_CREATION_FAILED_NO = 0; + const MAGENTO_ORDER_CREATION_FAILED_YES = 1; + private $storeManager; private $orderFactory; @@ -58,6 +62,11 @@ class Order extends ActiveRecord\Component\Parent\AbstractModel /** @var \Ess\M2ePro\Model\Order\Log */ private $logModel = NULL; + private $productHelper = NULL; + + /** @var Magento\Quote\Manager|null */ + private $quoteManager = NULL; + // ######################################## public function __construct( @@ -70,6 +79,8 @@ public function __construct( \Ess\M2ePro\Helper\Factory $helperFactory, \Magento\Framework\Model\Context $context, \Magento\Framework\Registry $registry, + \Magento\Catalog\Helper\Product $productHelper, + \Ess\M2ePro\Model\Magento\Quote\Manager $quoteManager, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = []) @@ -77,6 +88,8 @@ public function __construct( $this->storeManager = $storeManager; $this->orderFactory = $orderFactory; $this->resourceConnection = $resourceConnection; + $this->productHelper = $productHelper; + $this->quoteManager = $quoteManager; parent::__construct( $parentFactory, @@ -558,6 +571,14 @@ public function canCreateMagentoOrder() return false; } + foreach ($this->getItemsCollection()->getItems() as $item) { + /** @var $item \Ess\M2ePro\Model\Order\Item */ + + if (!$item->canCreateMagentoOrder()) { + return false; + } + } + return true; } @@ -565,6 +586,10 @@ public function canCreateMagentoOrder() private function beforeCreateMagentoOrder() { + if (!is_null($this->getMagentoOrderId())) { + throw new \Ess\M2ePro\Model\Exception('Magento Order is already created.'); + } + if (method_exists($this->getChildObject(), 'beforeCreateMagentoOrder')) { $this->getChildObject()->beforeCreateMagentoOrder(); } @@ -599,6 +624,13 @@ public function createMagentoOrder() } // --------------------------------------- + /** + * Since version 2.1.8 Magento added check if product is saleable before creating quote. + * When order is creating from back-end, this check is skipped. See example at + * Magento\Sales\Controller\Adminhtml\Order\Create.php + */ + $this->productHelper->setSkipSaleableCheck(true); + // Store must be initialized before products // --------------------------------------- $this->associateWithStore(); @@ -611,27 +643,35 @@ public function createMagentoOrder() // --------------------------------------- $proxy = $this->getProxy()->setStore($this->getStore()); - /** @var $magentoQuoteBuilder \Ess\M2ePro\Model\Magento\Quote */ - $magentoQuoteBuilder = $this->modelFactory->getObject('Magento\Quote', ['proxyOrder' => $proxy]); - $magentoQuoteBuilder->buildQuote(); - - /** @var $magentoOrderBuilder \Ess\M2ePro\Model\Magento\Order */ - $magentoOrderBuilder = $this->modelFactory->getObject( - 'Magento\Order', ['quote' => $magentoQuoteBuilder->getQuote()] - ); - $magentoOrderBuilder->buildOrder(); + /** @var \Ess\M2ePro\Model\Magento\Quote\Builder $magentoQuoteBuilder */ + $magentoQuoteBuilder = $this->modelFactory->getObject('Magento\Quote\Builder', ['proxyOrder' => $proxy]); + $magentoQuote = $magentoQuoteBuilder->build(); - $this->magentoOrder = $magentoOrderBuilder->getOrder(); + try { + $this->magentoOrder = $this->quoteManager->submit($magentoQuote); + } catch (FailDuringEventProcessing $e) { + + $this->addWarningLog( + 'Magento Order was created successfully. + However one or more post-processing actions on Magento Order failed. This may lead to some issues in the future. + Please check the configuration of the ancillary services of your Magento. + For more details, read the original Magento warning: %msg%. + ', + array( + 'msg' => $e->getMessage() + ) + ); + $this->magentoOrder = $e->getOrder(); + } $this->setData('magento_order_id', $this->magentoOrder->getId()); - $this->setMagentoOrder($this->magentoOrder); + $this->setMagentoOrder($this->magentoOrder); $this->save(); $this->afterCreateMagentoOrder(); unset($magentoQuoteBuilder); - unset($magentoOrderBuilder); // --------------------------------------- } catch (\Exception $e) { @@ -660,10 +700,11 @@ public function createMagentoOrder() $this->_eventManager->dispatch('m2epro_order_place_failure', array('order' => $this)); + $this->save(); + $this->addErrorLog('Magento Order was not created. Reason: %msg%', array('msg' => $e->getMessage())); $this->helperFactory->getObject('Module\Exception')->process($e, false); - // reserve qty back only if it was canceled before the order creation process started // --------------------------------------- if ($this->isReservable() && $this->getReserve()->getFlag('order_reservation')) { $this->getReserve()->place(); diff --git a/Model/Order/Item.php b/Model/Order/Item.php index 1af9ec946..12ab9c8bc 100644 --- a/Model/Order/Item.php +++ b/Model/Order/Item.php @@ -226,6 +226,22 @@ public function getStoreId() return array_shift($storeIds); } + /** + * @return bool + */ + public function canCreateMagentoOrder() + { + return $this->getChildObject()->canCreateMagentoOrder(); + } + + /** + * @return bool + */ + public function isReservable() + { + return $this->getChildObject()->isReservable(); + } + //######################################## /** diff --git a/Model/Order/Proxy.php b/Model/Order/Proxy.php index 6cd6186ae..97b03f847 100644 --- a/Model/Order/Proxy.php +++ b/Model/Order/Proxy.php @@ -198,8 +198,7 @@ public function getAddressData() $this->addressData['city'] = $rawAddressData['city']; $this->addressData['postcode'] = $rawAddressData['postcode']; $this->addressData['telephone'] = $rawAddressData['telephone']; - $this->addressData['street'] = !empty($rawAddressData['street']) ? - implode('; ', $rawAddressData['street']) : ''; + $this->addressData['street'] = !empty($rawAddressData['street']) ? $rawAddressData['street'] : []; $this->addressData['company'] = !empty($rawAddressData['company']) ? $rawAddressData['company'] : ''; $this->addressData['save_in_address_book'] = 0; } diff --git a/Model/Order/Reserve.php b/Model/Order/Reserve.php index 63d7ff1b2..916b8432b 100644 --- a/Model/Order/Reserve.php +++ b/Model/Order/Reserve.php @@ -17,9 +17,9 @@ class Reserve extends \Ess\M2ePro\Model\AbstractModel const ACTION_ADD = 'add'; const ACTION_SUB = 'sub'; - - private $stockItem; + /** @var \Magento\Framework\DB\Transaction */ private $transaction; + /** @var \Ess\M2ePro\Model\Order */ private $order = null; @@ -28,14 +28,12 @@ class Reserve extends \Ess\M2ePro\Model\AbstractModel //######################################## public function __construct( - \Ess\M2ePro\Model\Magento\Product\StockItem $stockItem, \Magento\Framework\DB\Transaction $transaction, \Ess\M2ePro\Model\Order $order, \Ess\M2ePro\Helper\Factory $helperFactory, \Ess\M2ePro\Model\Factory $modelFactory ) { - $this->stockItem = $stockItem; $this->transaction = $transaction; $this->order = $order; parent::__construct($helperFactory, $modelFactory); @@ -176,7 +174,8 @@ private function performAction($action, $newState) $productsDeletedCount = 0; $productsExistCount = 0; - $stockItems = array(); + $productStockItems = array(); + $magentoStockItems = array(); foreach ($this->order->getItemsCollection()->getItems() as $item) { /**@var \Ess\M2ePro\Model\Order\Item $item */ @@ -210,15 +209,18 @@ private function performAction($action, $newState) $productsExistCount++; - if (!isset($stockItems[$productId])) { - $stockItems[$productId] = $magentoProduct->getStockItem(); + if (!isset($productStockItems[$productId])) { + $productStockItems[$productId] = $magentoProduct->getStockItem(); } - $stockItem = $stockItems[$productId]; + $stockItem = $productStockItems[$productId]; - $this->stockItem->setStockItem($stockItem); + /** @var \Ess\M2ePro\Model\Magento\Product\StockItem $magentoStockItem */ + $magentoStockItem = $this->modelFactory->getObject('Magento\Product\StockItem', [ + 'stockItem' => $stockItem + ]); - if (!$this->changeProductQty($magentoProduct, $this->stockItem, $action, $qty)) { + if (!$this->changeProductQty($magentoProduct, $magentoStockItem, $action, $qty)) { if ($action == self::ACTION_SUB) { unset($products[$key]); } @@ -232,18 +234,31 @@ private function performAction($action, $newState) $productsAffectedCount++; - $this->transaction->addObject($this->stockItem->getStockItem()); + $this->transaction->addObject($magentoStockItem->getStockItem()); + + //-------------------------------------- if ($item->getMagentoProduct()->isSimpleType() || $item->getMagentoProduct()->isDownloadableType()) { - $item->getProduct()->setStockItem($this->stockItem->getStockItem()); + $item->getProduct()->setStockItem($magentoStockItem->getStockItem()); + } + + /** + * After making changes to Stock Item, Magento Product model will contain invalid "salable" status. + * Reset Magento Product model for further reload. + */ + if ($magentoStockItem->isStockStatusChanged()) { + $item->setProduct(NULL); } + //-------------------------------------- + + $magentoStockItems[] = $magentoStockItem; } $item->setReservedProducts($products); $this->transaction->addObject($item); } - unset($stockItems); + unset($productStockItems); if ($productsExistCount == 0 && $productsDeletedCount == 0) { $this->order->setData('reservation_state', self::STATE_UNKNOWN)->save(); @@ -277,6 +292,10 @@ private function performAction($action, $newState) $this->transaction->addObject($this->order); $this->transaction->save(); + + foreach ($magentoStockItems as $magentoStockItem) { + $magentoStockItem->afterSave(); + } } private function changeProductQty( diff --git a/Model/Order/ShippingAddress.php b/Model/Order/ShippingAddress.php index 8d91258ae..d0b2a7305 100644 --- a/Model/Order/ShippingAddress.php +++ b/Model/Order/ShippingAddress.php @@ -23,15 +23,20 @@ abstract class ShippingAddress extends \Magento\Framework\DataObject /** @var \Magento\Directory\Model\Region */ protected $region; + /** @var \Magento\Directory\Helper\Data*/ + protected $directoryHelper; + //######################################## public function __construct( \Magento\Directory\Model\CountryFactory $countryFactory, + \Magento\Directory\Helper\Data $directoryHelper, \Ess\M2ePro\Model\Order $order, array $data = [] ) { $this->countryFactory = $countryFactory; + $this->directoryHelper = $directoryHelper; $this->order = $order; parent::__construct($data); } @@ -70,6 +75,13 @@ public function getRegion() sprintf('State/Region "%s" in the shipping address is invalid.', $this->getState()) ); } + + $isRegionRequired = $this->directoryHelper->isRegionRequired($this->getCountry()->getId()); + + if ($isRegionRequired && !$this->region->getId()) { + $countryRegions = $this->getCountry()->getRegionCollection(); + $this->region = $countryRegions->getFirstItem(); + } } return $this->region; @@ -97,7 +109,7 @@ public function getRegionId() $region = $this->getRegion(); if (is_null($region) || is_null($region->getId())) { - return 1; + return NULL; } return $region->getId(); diff --git a/Model/Processing/Runner.php b/Model/Processing/Runner.php index f7fe2f294..d533980c7 100644 --- a/Model/Processing/Runner.php +++ b/Model/Processing/Runner.php @@ -97,7 +97,10 @@ protected function buildProcessingObject() { $processingObject = $this->activeRecordFactory->getObject('Processing'); - $processingObject->setData('model', str_replace('Ess\M2ePro\Model\\', '', get_class($this))); + $processingObject->setData( + 'model', + str_replace('Ess\M2ePro\Model\\', '', $this->getHelper('Client')->getClassName($this)) + ); $processingObject->setSettings('params', $this->getParams()); $processingObject->setData('expiration_date', $this->helperFactory->getObject('Data')->getDate( diff --git a/Model/ResourceModel/ActiveRecord/Component/Parent/AbstractModel.php b/Model/ResourceModel/ActiveRecord/Component/Parent/AbstractModel.php index 38a7d1996..6a9477f60 100644 --- a/Model/ResourceModel/ActiveRecord/Component/Parent/AbstractModel.php +++ b/Model/ResourceModel/ActiveRecord/Component/Parent/AbstractModel.php @@ -21,7 +21,8 @@ public function getChildModel($childMode) return NULL; } - return str_replace('Ess\M2ePro\Model\ResourceModel',ucwords($childMode), get_class($this)); + $className = $this->getHelper('Client')->getClassName($this); + return str_replace('Ess\M2ePro\Model\ResourceModel',ucwords($childMode), $className); } public function getChildTable($childMode) diff --git a/Model/ResourceModel/Magento/Product/Collection.php b/Model/ResourceModel/Magento/Product/Collection.php index 3d94d8dbb..78704862c 100644 --- a/Model/ResourceModel/Magento/Product/Collection.php +++ b/Model/ResourceModel/Magento/Product/Collection.php @@ -466,7 +466,7 @@ public function joinStockItem($columnsMap = array('qty' => 'qty')) { $this->joinTable( array('cisi' => $this->getTable('cataloginventory_stock_item')), - 'product_id = entity_id', + 'product_id=entity_id', $columnsMap, array( 'stock_id' => \Magento\CatalogInventory\Model\Stock::DEFAULT_STOCK_ID, diff --git a/Observer/Amazon/Order.php b/Observer/Amazon/Order.php index dcec478bd..452372c01 100644 --- a/Observer/Amazon/Order.php +++ b/Observer/Amazon/Order.php @@ -50,8 +50,9 @@ public function process() continue; } - $magentoStockItem = $this->modelFactory->getObject('Magento\Product\StockItem'); - $magentoStockItem->setStockItem($stockItem); + $magentoStockItem = $this->modelFactory->getObject('Magento\Product\StockItem', [ + 'stockItem' => $stockItem + ]); $magentoStockItem->addQty($orderItem->getQtyOrdered()); } } diff --git a/Observer/Order/Quote.php b/Observer/Order/Quote.php index b06f79cbf..d2a29045c 100644 --- a/Observer/Order/Quote.php +++ b/Observer/Order/Quote.php @@ -75,6 +75,10 @@ private function processQty() /* @var $quoteItem \Magento\Quote\Model\Quote\Item */ $quoteItem = $this->getEvent()->getItem(); + if ($quoteItem->getHasChildren()) { + return; + } + $oldValue = (int)$this->getStockItem()->getQty(); $newValue = $oldValue - (int)$quoteItem->getTotalQty(); @@ -97,6 +101,10 @@ private function processStockAvailability() /* @var $quoteItem \Magento\Quote\Model\Quote\Item */ $quoteItem = $this->getEvent()->getItem(); + if ($quoteItem->getHasChildren()) { + return; + } + $oldQty = (int)$this->getStockItem()->getQty(); $newQty = $oldQty - (int)$quoteItem->getTotalQty(); diff --git a/Observer/StockItem/AbstractStockItem.php b/Observer/StockItem/AbstractStockItem.php index 9b0aaed9a..613a99e32 100644 --- a/Observer/StockItem/AbstractStockItem.php +++ b/Observer/StockItem/AbstractStockItem.php @@ -45,7 +45,7 @@ public function __construct( public function beforeProcess() { - $stockItem = $this->getEventObserver()->getData('object'); + $stockItem = $this->getEventObserver()->getData('item'); if (!($stockItem instanceof \Magento\CatalogInventory\Model\Stock\Item)) { throw new \Ess\M2ePro\Model\Exception('StockItem event doesn\'t have correct StockItem instance.'); diff --git a/Plugin/AbstractPlugin.php b/Plugin/AbstractPlugin.php index 57f029158..530447461 100644 --- a/Plugin/AbstractPlugin.php +++ b/Plugin/AbstractPlugin.php @@ -52,5 +52,10 @@ protected function canExecute() $this->helperFactory->getObject('Module')->isReadyToWork(); } + protected function getHelper($helperName, array $arguments = []) + { + return $this->helperFactory->getObject($helperName, $arguments); + } + //######################################## } \ No newline at end of file diff --git a/Plugin/StockItem/Magento/CatalogInventory/Model/Stock/Item.php b/Plugin/StockItem/Magento/CatalogInventory/Model/Stock/Item.php index a60c93159..dcfe240b0 100644 --- a/Plugin/StockItem/Magento/CatalogInventory/Model/Stock/Item.php +++ b/Plugin/StockItem/Magento/CatalogInventory/Model/Stock/Item.php @@ -26,6 +26,17 @@ public function __construct( //######################################## + public function canExecute() + { + if (!parent::canExecute()) { + return false; + } + + return version_compare($this->getHelper('Magento')->getVersion(), '2.2.0', '<'); + } + + //######################################## + public function aroundBeforeSave($interceptor, \Closure $callback, ...$arguments) { return $this->execute('beforeSave', $interceptor, $callback, $arguments); @@ -42,6 +53,7 @@ protected function processBeforeSave($interceptor, \Closure $callback, array $ar [ 'data_object' => $interceptor, 'object' => $interceptor, + 'item' => $interceptor, ] ); @@ -66,6 +78,7 @@ protected function processAfterSave($interceptor, \Closure $callback) [ 'data_object' => $interceptor, 'object' => $interceptor, + 'item' => $interceptor, ] ); diff --git a/composer.json b/composer.json index e417a08bb..6db1ccdfc 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "m2e/ebay-amazon-magento2", "description": "M2E Pro is a Magento trusted (TM), award-winning extension, which allows merchants of all sizes to fully integrate Magento based system(s) into eBay/Amazon/Rakuten.com platforms.", "type": "magento2-module", - "version": "1.3.2", + "version": "1.3.3", "license": "Refer to Terms and Conditions on m2epro.com", "keywords": ["ebay", "amazon", "rakuten", "magento"], "homepage": "http://www.m2epro.com/", diff --git a/versions_history.json b/versions_history.json index 505acab6c..272470518 100644 --- a/versions_history.json +++ b/versions_history.json @@ -1,4 +1,13 @@ { + "1.3.3": { + "versions": { + "setup": "1.3.3", + "files": "1.3.3" + }, + "revisions": { + "svn": "2494" + } + }, "1.3.2": { "versions": { "setup": "1.3.3", diff --git a/view/adminhtml/templates/amazon/order.phtml b/view/adminhtml/templates/amazon/order.phtml index 2b92232c6..0f92e9297 100644 --- a/view/adminhtml/templates/amazon/order.phtml +++ b/view/adminhtml/templates/amazon/order.phtml @@ -275,11 +275,11 @@ - getChild('resubmit_shipping_info')): ?> + getChildHtml('resubmit_shipping_info')): ?> - - getChildHtml('resubmit_shipping_info') ?> + + diff --git a/view/adminhtml/templates/ebay/order.phtml b/view/adminhtml/templates/ebay/order.phtml index b8d5fff81..eabf7b49b 100644 --- a/view/adminhtml/templates/ebay/order.phtml +++ b/view/adminhtml/templates/ebay/order.phtml @@ -481,11 +481,11 @@ - getChild('resubmit_shipping_info')): ?> + getChildHtml('resubmit_shipping_info')): ?> - - getChildHtml('resubmit_shipping_info') ?> + + diff --git a/view/adminhtml/templates/ebay/template/description/preview/body.phtml b/view/adminhtml/templates/ebay/template/description/preview/body.phtml new file mode 100644 index 000000000..153c988a2 --- /dev/null +++ b/view/adminhtml/templates/ebay/template/description/preview/body.phtml @@ -0,0 +1,8 @@ +getData('title'))) { ?> + +
+

escapeHtml($title); ?>

+
getData('description'); ?> +
+ + \ No newline at end of file diff --git a/view/adminhtml/web/css/style.css b/view/adminhtml/web/css/style.css index ecaa9c077..2bcc30005 100644 --- a/view/adminhtml/web/css/style.css +++ b/view/adminhtml/web/css/style.css @@ -42,6 +42,13 @@ } /* ================================================ */ +/* Magento 2.2 compatibility */ +/* ================================================ */ +.admin__field-value { + display: block; +} +/* ================================================ */ + .admin__old .fieldset > .legend { position: static; float: left; diff --git a/view/adminhtml/web/js/Ebay/Listing/Template/Switcher.js b/view/adminhtml/web/js/Ebay/Listing/Template/Switcher.js index a6ddf69b4..4f52f2d8a 100644 --- a/view/adminhtml/web/js/Ebay/Listing/Template/Switcher.js +++ b/view/adminhtml/web/js/Ebay/Listing/Template/Switcher.js @@ -406,7 +406,7 @@ define([ EbayListingTemplateSwitcherObj.updateButtonsVisibility(template.nick); EbayListingTemplateSwitcherObj.updateEditVisibility(template.nick); EbayListingTemplateSwitcherObj.updateTemplateLabelVisibility(template.nick); - EbayListingTemplateSwitcherHandlerObj.checkMessages(template.nick); + EbayListingTemplateSwitcherObj.checkMessages(template.nick); }); }.bind(this) });