├── .github └── CONTRIBUTING.md ├── CODEOWNERS ├── LICENSE ├── README.md ├── app └── code │ └── Ometria │ ├── AbandonedCarts │ ├── Block │ │ ├── Redirect.php │ │ └── System │ │ │ └── Config │ │ │ └── Form │ │ │ └── Fieldset │ │ │ └── Modules │ │ │ └── Group.php │ ├── Controller │ │ └── Cartlink │ │ │ └── Index.php │ ├── Helper │ │ ├── Config.php │ │ └── Data.php │ ├── etc │ │ ├── adminhtml │ │ │ └── system.xml │ │ ├── config.xml │ │ ├── frontend │ │ │ └── routes.xml │ │ └── module.xml │ ├── registration.php │ └── view │ │ └── frontend │ │ ├── layout │ │ └── omcart_cartlink_index.xml │ │ ├── templates │ │ └── redirect.phtml │ │ └── web │ │ └── js │ │ └── cart-redirect.js │ ├── Api │ ├── Api │ │ └── Data │ │ │ └── ProductInterface.php │ ├── Controller │ │ ├── V1 │ │ │ ├── Attribute │ │ │ │ └── Types.php │ │ │ ├── Attributes.php │ │ │ ├── Base.php │ │ │ ├── Categories.php │ │ │ ├── Customers.php │ │ │ ├── Get │ │ │ │ └── Settings.php │ │ │ ├── Magento │ │ │ │ └── Info.php │ │ │ ├── OrderIds.php │ │ │ ├── Orders.php │ │ │ ├── Products.php │ │ │ ├── Salesrules │ │ │ │ ├── Delete │ │ │ │ │ └── Coupons.php │ │ │ │ ├── Insert │ │ │ │ │ └── Coupons.php │ │ │ │ ├── Items.php │ │ │ │ └── Items │ │ │ │ │ └── Coupons.php │ │ │ ├── Stores.php │ │ │ ├── Subscribers.php │ │ │ └── Version.php │ │ └── V2 │ │ │ └── Products.php │ ├── Helper │ │ ├── Category.php │ │ ├── Config.php │ │ ├── CustomerData.php │ │ ├── Filter │ │ │ ├── V1 │ │ │ │ └── Service.php │ │ │ └── V2 │ │ │ │ └── Service.php │ │ ├── Format │ │ │ ├── V1 │ │ │ │ ├── Attribute │ │ │ │ │ └── Types.php │ │ │ │ ├── Attributes.php │ │ │ │ ├── Categories.php │ │ │ │ ├── Customers.php │ │ │ │ ├── Get │ │ │ │ │ └── Settings.php │ │ │ │ ├── Magento │ │ │ │ │ └── Info.php │ │ │ │ ├── Orders.php │ │ │ │ ├── Products.php │ │ │ │ ├── Stores.php │ │ │ │ ├── Subscribers.php │ │ │ │ └── Version.php │ │ │ └── V2 │ │ │ │ └── Products.php │ │ ├── Order │ │ │ └── IsValid.php │ │ ├── Override.php │ │ ├── Service │ │ │ └── Filterable │ │ │ │ ├── Service.php │ │ │ │ └── Service │ │ │ │ └── Product.php │ │ └── StoreUrl.php │ ├── Model │ │ ├── Hash.php │ │ ├── Observer │ │ │ └── Auth.php │ │ └── ResourceModel │ │ │ └── Product.php │ ├── Plugin │ │ ├── BaseController.php │ │ └── Magento │ │ │ └── Checkout │ │ │ └── Controller │ │ │ └── Cart │ │ │ └── CouponPost.php │ ├── Test │ │ └── Integration │ │ │ └── ProductTest.php │ ├── etc │ │ ├── di.xml │ │ ├── events.xml │ │ ├── frontend │ │ │ └── routes.xml │ │ └── module.xml │ └── registration.php │ └── Core │ ├── Block │ ├── Head.php │ └── System │ │ └── Config │ │ └── Form │ │ └── Fieldset │ │ └── Modules │ │ └── Group.php │ ├── Data │ └── Form │ │ └── Element │ │ └── Text │ │ └── Disabled.php │ ├── Helper │ ├── Config.php │ ├── Cookiechannel.php │ ├── Get │ │ └── Request.php │ ├── Is │ │ └── Frontend.php │ ├── MageConfig.php │ ├── Ping.php │ ├── Product.php │ └── Session.php │ ├── Model │ ├── Config │ │ └── Source │ │ │ ├── PreferredProduct.php │ │ │ └── StockPushScope.php │ ├── ConfigSourceProductIdentifierMode.php │ └── Observer │ │ ├── Cart.php │ │ ├── Cart │ │ ├── BasketUpdated.php │ │ └── OrderPlaced.php │ │ ├── Customer.php │ │ ├── Customer │ │ ├── CustomerSaveAfter.php │ │ ├── LoggedIn.php │ │ ├── LoggedOut.php │ │ └── Registered.php │ │ ├── Newsletter.php │ │ ├── Newsletter │ │ ├── HandleSubscriberDeletion.php │ │ └── HandleSubscriberUpdate.php │ │ ├── Order.php │ │ ├── Order │ │ └── SalesOrderSaveAfter.php │ │ ├── Product.php │ │ └── Product │ │ ├── CatalogProductDeleteAfter.php │ │ ├── CatalogProductSaveAfter.php │ │ ├── CatalogProductUpdateAttributes.php │ │ └── CatalogProductUpdateStatus.php │ ├── Plugin │ └── OrderManagementPlugin.php │ ├── Service │ ├── Customer │ │ └── RewardPoints.php │ ├── Product │ │ └── Inventory.php │ └── PushApi.php │ ├── etc │ ├── acl.xml │ ├── adminhtml │ │ └── system.xml │ ├── config.xml │ ├── di.xml │ ├── events.xml │ └── module.xml │ ├── registration.php │ └── view │ └── frontend │ ├── layout │ └── default.xml │ ├── requirejs-config.js │ ├── templates │ └── head.phtml │ └── web │ └── js │ ├── configurable-mixin.js │ └── swatch-renderer-mixin.js ├── composer.json └── composer.lock /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Support 2 | ------- 3 | 4 | If you have concerns or questions, please send an email to support@ometria.com 5 | with all relevant details that are needed to investigate or resolve an issue. 6 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Ometria/devs 2 | ci/* @Ometria/platform 3 | terraform/* @Ometria/platform 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ometria 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Installing the Extension 2 | -------------------------------------------------- 3 | 4 | While you're free to manually install the Ometria extension (the use of the `app/code` folder structure supports this), we recommend using Magento's [PHP composer](https://getcomposer.org/) integration to install the extension. All Magento 2 systems have a `composer.json` file, and this file is how developers **and** Magento Marketplace users get new packages in and out of their system. 5 | 6 | Installing the extension is a 4 step process 7 | 8 | 1. Add this GitHub repository to your project's composer.json as a composer repository 9 | 2. Add the `ometria/magento2` composer package to your project's composer.json as a required dependency 10 | 3. Update your project's composer dependencies 11 | 4. Install the downloaded package via Magento's standard command line tool 12 | 13 | Support 14 | ------- 15 | 16 | If you have any concerns or questions, please send an email to support@ometria.com 17 | with all relevant details that are needed to investigate or resolve the issue. 18 | 19 | Quick Start 20 | -------------------------------------------------- 21 | After backing up your composer.json file 22 | 23 | cp composer.json composer.json.bak 24 | 25 | Run 26 | 27 | composer.phar config repositories.ometria vcs https://github.com/Ometria/magento2-extension 28 | composer require ometria/magento2 --no-update 29 | composer update ometria/magento2 30 | php bin/magento module:enable Ometria_AbandonedCarts Ometria_Api Ometria_Core 31 | php bin/magento setup:upgrade 32 | 33 | After running the above, the Ometria extension will be installed, ready for configuration. 34 | 35 | Please note, if you are running PHP OPcache on your server and have configured it not to clear automatically then you will need to clear the OPcache in order for the new module to become available after the above steps. 36 | 37 | Composer Details 38 | -------------------------------------------------- 39 | The first composer command 40 | 41 | composer.phar config repositories.foo vcs https://github.com/Ometria/magento2-extension 42 | 43 | add this GitHub repository as a composer repository 44 | 45 | #File: composer.json 46 | //... 47 | "repositories": { 48 | "ometria": { 49 | "type": "vcs", 50 | "url": "https://github.com/Ometria/magento2-extension" 51 | } 52 | }, 53 | //... 54 | 55 | This tells composer it should look for additional packages in this GitHub repository. 56 | 57 | The second command 58 | 59 | composer require ometria/magento2 --no-update 60 | 61 | add the latest stable version of `ometria/magento2` to your `composer.json` file's `require` section. 62 | 63 | #File: composer.json 64 | //... 65 | "require": { 66 | //... 67 | "ometria/magento2": "^2.0" 68 | }, 69 | //... 70 | 71 | The third command 72 | 73 | composer update ometria/magento2 74 | 75 | Updates any composer packages that match the string `ometria/magento2`. This is what triggers the download of the Ometria extension source code to `vendor/ometria`. 76 | 77 | The final two commands are **Magento** commands. This command enables the three modules that make up the Ometria extension 78 | 79 | php bin/magento module:enable Ometria_AbandonedCarts Ometria_Api Ometria_Core 80 | 81 | Once a module is enabled, the rest of Magento can "see" it. The last command tells Magento to actually install the module. 82 | 83 | php bin/magento setup:upgrade 84 | 85 | Upgrading the Extension 86 | -------------------------------------------------- 87 | 88 | Composer can be used to upgrade an existing install of the module to the latest release using the following commands: 89 | 90 | composer require ometria/magento2 --no-update 91 | composer update ometria/magento2 92 | php bin/magento setup:upgrade 93 | 94 | This will update your `composer.json` file's `require` section with the latest stable version of `ometria/magento2`. Then the latest code at that version will be pulled in by `composer update`. Finally re-running the Magento `setup:upgrade` command will ensure the module is installed correctly at the new version. 95 | 96 | If you installed the module manually in to app/code please ensure you remove all of the existing module files before replacing with the new files from the latest release and re-running the Magento `setup:upgrade` command. 97 | 98 | **Important:** Changing a Magento system running in production is **not** a recommended practice. Depending on your system software, or other running extensions, running `setup:upgrade` may trigger undesired behaviors. As with installing **any** new software on your system, don't forget to take appropriate backup steps, and to test your new module in a development or staging environment before deploying to production. 99 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/Block/Redirect.php: -------------------------------------------------------------------------------- 1 | configHelper = $configHelper; 38 | $this->quoteModel = $quoteModel; 39 | $this->session = $context->getSession(); 40 | 41 | parent::__construct($context, $data); 42 | } 43 | 44 | /** 45 | * @return mixed 46 | */ 47 | public function getCookieLifeTime() 48 | { 49 | return $this->configHelper->getCookieLifeTime(); 50 | } 51 | 52 | /** 53 | * @return string 54 | */ 55 | public function getRedirectUrl() 56 | { 57 | $params = []; 58 | 59 | $currentStore = $this->_storeManager->getStore(); 60 | $quoteStore = $this->getStoreFromQuote(); 61 | 62 | if ($currentStore->getId() != $quoteStore->getId()) { 63 | $params['_query']['___store'] = $quoteStore->getCode(); 64 | $params['_query']['___from_store'] = $currentStore->getCode(); 65 | } 66 | 67 | return $this->_urlBuilder->getUrl( 68 | $this->getRedirectPath(), 69 | $params 70 | ); 71 | } 72 | 73 | /** 74 | * @return string 75 | */ 76 | private function getRedirectPath() 77 | { 78 | $redirectPath = $this->configHelper->getCartPath(); 79 | 80 | if (!isset($redirectPath)) { 81 | $redirectPath = 'checkout/cart'; 82 | } 83 | 84 | return ltrim($redirectPath, '/'); 85 | } 86 | 87 | /** 88 | * @return array 89 | */ 90 | private function getStoreFromQuote() 91 | { 92 | $quote = $this->getQuoteFromSession(); 93 | 94 | if ($quote !== false && $quote->getStoreId()) { 95 | return $this->_storeManager->getStore(htmlspecialchars($quote->getStoreId())); 96 | } 97 | 98 | /** 99 | * If for any reason the quote was not found or storeId is not 100 | * set on it, the current store context will be used for the redirect. 101 | */ 102 | return $this->_storeManager->getStore(); 103 | } 104 | 105 | /** 106 | * @return bool|QuoteModel 107 | * @throws NoSuchEntityException 108 | */ 109 | private function getQuoteFromSession() 110 | { 111 | $data = $this->session->getVisitorData(); 112 | 113 | /** 114 | * This should never happen as the controller would catch 115 | * the condition but just incase, return false here to 116 | * allow the block to still render. 117 | */ 118 | if (!isset($data['quote_id'])) { 119 | return false; 120 | } 121 | 122 | /** 123 | * Using the quote model rather than repository here is not ideal 124 | * however during loading of a quote using the repository, its storeId 125 | * is hard coded to the current store context. 126 | * 127 | * @see \Magento\Quote\Model\QuoteRepository::loadQuote() 128 | */ 129 | $quote = $this->quoteModel->loadByIdWithoutStore($data['quote_id']); 130 | 131 | return $quote; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/Block/System/Config/Form/Fieldset/Modules/Group.php: -------------------------------------------------------------------------------- 1 | visitor = $visitor; 31 | $this->session = $session; 32 | $this->messageManager = $context->getMessageManager(); 33 | $this->customerModelSession = $customerModelSession; 34 | $this->abandonedCartsHelperConfig = $abandonedCartsHelperConfig; 35 | $this->controllerResultRedirectFactory = $context->getResultRedirectFactory(); 36 | $this->salesModelQuote = $salesModelQuote; 37 | $this->checkoutSession = $checkoutSession; 38 | $this->cart = $cart; 39 | $this->cookieHelper = $cookieHelper; 40 | 41 | return parent::__construct($context); 42 | } 43 | 44 | public function execute() 45 | { 46 | $session = $this->customerModelSession; 47 | $helper = $this->abandonedCartsHelperConfig; 48 | 49 | if (!$helper->isDeeplinkEnabled()) 50 | { 51 | return $this->resultFactory->create( 52 | \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT 53 | )->setUrl('/'); 54 | } 55 | 56 | $token = $this->getRequest()->getParam('token'); 57 | $id = $this->getRequest()->getParam('id'); 58 | 59 | $is_ok = false; 60 | 61 | if ($id && $token) 62 | { 63 | $quote = $this->salesModelQuote->load($id); 64 | if (!$quote || !$quote->getId() || !$quote->getIsActive()) 65 | { 66 | $this->messageManager->addNotice(self::CART_LINK_QUOTE_INVALID); 67 | return $this->resultFactory->create( 68 | \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT 69 | )->setUrl('/'); 70 | } 71 | 72 | if ($helper->shouldCheckDeeplinkgToken()) 73 | { 74 | $computed_token = substr(md5($quote->getCreatedAt().$quote->getId()), 0, 12); 75 | if ($token!=$computed_token) 76 | { 77 | $this->messageManager->addNotice(self::CART_LINK_TOKEN_INVALID); 78 | return $this->resultFactory->create( 79 | \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT 80 | )->setUrl('/'); 81 | } 82 | } 83 | 84 | $this->checkoutSession->setQuoteId($quote->getId()); 85 | $data = $this->session->getVisitorData(); 86 | $data['quote_id'] = $quote->getId(); 87 | $data['last_visit_at'] = $data['last_visit_at'] ?? (new \DateTime())->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT); 88 | $this->session->setVisitorData($data); 89 | $this->visitor->setData($data)->save(); 90 | 91 | return $this->resultFactory->create( 92 | \Magento\Framework\Controller\ResultFactory::TYPE_PAGE 93 | ); 94 | } 95 | else 96 | { 97 | return $this->resultFactory->create( 98 | \Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT 99 | )->setUrl('/'); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/Helper/Config.php: -------------------------------------------------------------------------------- 1 | scopeConfig->getValue( 20 | self::XML_CONFIG_CART_PATH 21 | ); 22 | } 23 | 24 | /** 25 | * @return bool 26 | */ 27 | public function isDeeplinkEnabled() 28 | { 29 | return $this->scopeConfig->isSetFlag( 30 | self::XML_CONFIG_LINK_ENABLED 31 | ); 32 | } 33 | 34 | /** 35 | * @return bool 36 | */ 37 | public function shouldCheckDeeplinkgToken() 38 | { 39 | return $this->scopeConfig->isSetFlag( 40 | self::XML_CONFIG_TOKEN_ENABLED 41 | ); 42 | } 43 | 44 | /** 45 | * @return mixed 46 | */ 47 | public function getCookieLifeTime() 48 | { 49 | return $this->scopeConfig->getValue( 50 | SessionConfig::XML_PATH_COOKIE_LIFETIME, 51 | ScopeInterface::SCOPE_STORE 52 | ); 53 | } 54 | } -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/Helper/Data.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | ometria 7 | Ometria_Core::config_ometria 8 | 9 | 10 | Ometria\AbandonedCarts\Block\System\Config\Form\Fieldset\Modules\Group 11 | 12 | 13 | 14 | 15 | 16 | 17 | Magento\Config\Model\Config\Source\Yesno 18 | 19 | 20 | 21 | Magento\Config\Model\Config\Source\Yesno 22 | 23 | 24 |
25 |
26 |
27 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | checkout/cart 6 | 1 7 | 1 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/view/frontend/templates/redirect.phtml: -------------------------------------------------------------------------------- 1 | 2 | helper(\Magento\Framework\Json\Helper\Data::class) ?> 3 | 4 | 13 | 14 |

-------------------------------------------------------------------------------- /app/code/Ometria/AbandonedCarts/view/frontend/web/js/cart-redirect.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery', 3 | 'Magento_Customer/js/customer-data' 4 | ], function( 5 | $, 6 | customerData 7 | ){ 8 | "use strict"; 9 | 10 | $.widget('ometria.redirect', { 11 | options: { 12 | redirectTimeout: 1000, 13 | cookieLifeTime: 3600, 14 | redirectUrl: '/checkout/cart/' 15 | }, 16 | 17 | /** 18 | * @private 19 | */ 20 | _create: function () { 21 | setTimeout(function () { 22 | this._clearStorage(); 23 | this._invalidateCacheTimeOut(); 24 | 25 | if (this.options.redirectUrl) { 26 | this._redirect(this.options.redirectUrl); 27 | } 28 | }.bind(this), this.options.redirectTimeout); 29 | }, 30 | 31 | /** 32 | * @private 33 | */ 34 | _clearStorage: function () { 35 | var storage = $.initNamespaceStorage('mage-cache-storage').localStorage; 36 | storage.removeAll(); 37 | }, 38 | 39 | /** 40 | * @private 41 | */ 42 | _invalidateCacheTimeOut: function () { 43 | var date = new Date(Date.now() + parseInt(this.options.cookieLifeTime, 10) * 1000); 44 | $.localStorage.set('mage-cache-timeout', date); 45 | }, 46 | 47 | /** 48 | * @private 49 | */ 50 | _redirect: function (redirectUrl) { 51 | document.location = redirectUrl; 52 | } 53 | }); 54 | 55 | return $.ometria.redirect; 56 | }); 57 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Api/Data/ProductInterface.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 25 | $this->attributeCollectionFactory = $attributeCollectionFactory; 26 | } 27 | 28 | public function execute() 29 | { 30 | $collection = $this->attributeCollectionFactory->create(); 31 | 32 | if ($this->_request->getParam('count') != null) { 33 | $data = $this->getCountData($collection); 34 | } else { 35 | $data = $this->getItemsData($collection); 36 | } 37 | 38 | return $this->resultJsonFactory->create()->setData($data); 39 | } 40 | 41 | /** 42 | * @param $collection 43 | * @return array 44 | */ 45 | private function getCountData($collection) 46 | { 47 | return [ 48 | 'count' => $collection->count() 49 | ]; 50 | } 51 | 52 | /** 53 | * @param $collection 54 | * @return array 55 | */ 56 | public function getItemsData($collection) 57 | { 58 | $data = []; 59 | 60 | /** @var ProductAttributeInterface $attribute */ 61 | foreach ($collection as $attribute) { 62 | $data[] = $this->serializeAttribute($attribute); 63 | } 64 | 65 | return $data; 66 | } 67 | 68 | /** 69 | * @param $attribute 70 | * @return null[] 71 | */ 72 | private function serializeAttribute($attribute) 73 | { 74 | $item = Helper::getBlankArray(); 75 | $item['id'] = $attribute->getId(); 76 | $item['title'] = $attribute->getFrontendLabel(); 77 | $item['attribute_code'] = $attribute->getAttributeCode(); 78 | 79 | switch ($attribute->getData('frontend_input')) { 80 | case 'multiselect': 81 | $item['attribute_type'] = 'OPTION_LIST'; 82 | break; 83 | case 'select': 84 | $item['attribute_type'] = 'OPTION'; 85 | break; 86 | case 'boolean': 87 | $item['attribute_type'] = 'OPTION'; 88 | break; 89 | default: 90 | $item['attribute_type'] = 'FREETEXT'; 91 | } 92 | 93 | return $item; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Attributes.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 19 | $this->attributes = $attributes; 20 | } 21 | 22 | 23 | protected function extractAttributeCodeFromUrl() 24 | { 25 | $params = $this->getRequest()->getParams(); 26 | $params = array_keys($params); 27 | $value = array_shift($params); 28 | return $value; 29 | } 30 | 31 | protected function serializeAttribute($attribute) 32 | { 33 | $options = $attribute->getOptions(); 34 | $options = array_map(function($item){ 35 | return $item->getData(); 36 | }, $options); 37 | 38 | $options = array_filter($options, function($item){ 39 | return $item['value']; 40 | }); 41 | 42 | $type = $attribute->getAttributeCode(); 43 | foreach($options as $key=>$option) 44 | { 45 | $option['@type'] = 'attribute'; 46 | $option['type'] = $type; 47 | $options[$key] = $option; 48 | 49 | $options[$key]['id'] = $options[$key]['value']; 50 | $options[$key]['title'] = $options[$key]['label']; 51 | 52 | unset($options[$key]['value']); 53 | unset($options[$key]['label']); 54 | // unset($options['value']); 55 | // unset($options['title']); 56 | } 57 | 58 | sort($options); 59 | return $options; 60 | // $data = Helper::getBlankArray(); 61 | // $data['type'] = $attribute->getAttributeCode(); 62 | // $data['id'] = $attribute->getId(); 63 | // $data['title'] = $attribute->getFrontend()->getLabel(); 64 | // $data['options'] = $options; 65 | 66 | return $data; 67 | } 68 | 69 | public function execute() 70 | { 71 | $attribute_code = $this->extractAttributeCodeFromUrl(); 72 | $attribute = $this->attributes->addFieldToFilter('attribute_code', $attribute_code) 73 | ->getFirstItem(); 74 | 75 | $data = $this->serializeAttribute($attribute); 76 | $result = $this->resultJsonFactory->create(); 77 | return $result->setData($data); 78 | } 79 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Base.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 26 | $this->treeFactory = $treeFactory; 27 | } 28 | 29 | public function execute() 30 | { 31 | $categoryTree = $this->getCategoryTree(); 32 | 33 | if ($this->_request->getParam('count') != null) { 34 | $data = $this->getCountData($categoryTree); 35 | } else { 36 | $data = $this->getItemsData($categoryTree); 37 | } 38 | 39 | return $this->resultJsonFactory->create()->setData($data); 40 | } 41 | 42 | /** 43 | * @return CategoryTreeInterface 44 | * @throws LocalizedException 45 | * @throws NoSuchEntityException 46 | */ 47 | private function getCategoryTree() 48 | { 49 | /** @var Tree $tree */ 50 | $tree = $this->treeFactory->create(); 51 | 52 | return $tree->getTree($tree->getRootNode()); 53 | } 54 | 55 | /** 56 | * @param CategoryTreeInterface $categoryTree 57 | * @return array 58 | */ 59 | private function getCountData(CategoryTreeInterface $categoryTree) 60 | { 61 | return [ 62 | 'count' => $this->countChildrenData($categoryTree) 63 | ]; 64 | } 65 | 66 | /** 67 | * @param CategoryTreeInterface $categoryTree 68 | * @return array 69 | */ 70 | private function getItemsData(CategoryTreeInterface $categoryTree) 71 | { 72 | return $this->serializeChildrenData($categoryTree); 73 | } 74 | 75 | /** 76 | * @param CategoryTreeInterface $categoryTree 77 | * @return array 78 | */ 79 | private function serializeChildrenData(CategoryTreeInterface $categoryTree) 80 | { 81 | $serialized = $categoryTree->getData(); 82 | 83 | if (count($serialized['children_data']) > 0) { 84 | foreach ($serialized['children_data'] as $key => $child) { 85 | $serialized['children_data'][$key] = $this->serializeChildrenData($child); 86 | } 87 | } 88 | 89 | return $serialized; 90 | } 91 | 92 | /** 93 | * @param CategoryTreeInterface $categoryTree 94 | * @param int $count 95 | * @return int 96 | */ 97 | private function countChildrenData(CategoryTreeInterface $categoryTree, $count = 1) 98 | { 99 | $serialized = $categoryTree->getData(); 100 | 101 | if (count($serialized['children_data']) > 0) { 102 | foreach ($serialized['children_data'] as $key => $child) { 103 | $count += $this->countChildrenData($child); 104 | } 105 | } 106 | 107 | return $count; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Customers.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 71 | $this->apiHelperServiceFilterable = $apiHelperServiceFilterable; 72 | $this->repository = $customerRepository; 73 | $this->subscriberCollection = $subscriberCollection; 74 | $this->customerMetadataInterface = $customerMetadataInterface; 75 | $this->customerDataHelper = $customerDataHelper; 76 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 77 | $this->groupRepository = $groupRepository; 78 | $this->rewardPointsService = $rewardPointsService; 79 | $this->genderOptions = $this->customerMetadataInterface 80 | ->getAttributeMetadata('gender') 81 | ->getOptions(); 82 | } 83 | 84 | public function execute() 85 | { 86 | $items = $this->getCustomerItems(); 87 | 88 | if ($this->_request->getParam('count') != null) { 89 | $data = $this->getCountData($items); 90 | } else { 91 | $data = $this->getItemsData($items); 92 | } 93 | 94 | return $this->resultJsonFactory->create()->setData($data); 95 | } 96 | 97 | /** 98 | * @return array 99 | */ 100 | private function getCustomerItems() 101 | { 102 | return $this->apiHelperServiceFilterable->createResponse( 103 | $this->repository, 104 | CustomerInterface::class 105 | ); 106 | } 107 | 108 | /** 109 | * @param $items 110 | * @return array 111 | */ 112 | private function getCountData($items) 113 | { 114 | return [ 115 | 'count' => count($items) 116 | ]; 117 | } 118 | 119 | /** 120 | * @param $items 121 | * @return array[] 122 | * @throws LocalizedException 123 | */ 124 | public function getItemsData($items) 125 | { 126 | $subscriberCollection = $this->getSubscriberCollection($items); 127 | 128 | $items = array_map(function ($item) use ($subscriberCollection) { 129 | 130 | $new = Helper::getBlankArray(); 131 | 132 | $new["@type"] = "contact"; 133 | $new["id"] = array_key_exists('id', $item) ? $item['id'] : ''; 134 | $new["email"] = array_key_exists('email', $item) ? $item['email'] : ''; 135 | $new["prefix"] = array_key_exists('prefix', $item) ? $item['prefix'] : ''; 136 | $new["firstname"] = array_key_exists('firstname', $item) ? $item['firstname'] : ''; 137 | $new["middlename"] = array_key_exists('middlename', $item) ? $item['middlename'] : ''; 138 | $new["lastname"] = array_key_exists('lastname', $item) ? $item['lastname'] : ''; 139 | $new["gender"] = $this->customerDataHelper->getGenderLabel($item); 140 | $new["date_of_birth"] = array_key_exists('dob', $item) ? $item['dob'] : ''; 141 | $new["marketing_optin"] = $this->getMarketingOption($item, $subscriberCollection); 142 | $new["country_id"] = $this->customerDataHelper->getCountryId($item); 143 | $new["store_id"] = array_key_exists('store_id', $item) ? $item['store_id'] : null; 144 | 145 | if ($this->_request->getParam('raw') != null) { 146 | $new['_raw'] = $item; 147 | 148 | $new['_raw']['_ometria'] = [ 149 | 'group_name' => $this->getCustomerGroupName($item['group_id']) 150 | ]; 151 | } 152 | 153 | return $new; 154 | }, $items); 155 | 156 | if ($this->rewardPointsService->isRewardsAvailable()) { 157 | $this->appendRewardPoints($items); 158 | } 159 | 160 | return $items; 161 | } 162 | 163 | public function getMarketingOption($item, $subscriber_collection) 164 | { 165 | if (!array_key_exists('id', $item)) { 166 | return false; 167 | } 168 | 169 | if (!$this->customerIdsOfNewsLetterSubscribers) { 170 | foreach ($subscriber_collection as $subscriber) { 171 | $this->customerIdsOfNewsLetterSubscribers[] = $subscriber->getCustomerId(); 172 | } 173 | } 174 | 175 | return in_array($item['id'], $this->customerIdsOfNewsLetterSubscribers); 176 | } 177 | 178 | /** 179 | * @param $items 180 | * @return SubscriberCollection 181 | */ 182 | public function getSubscriberCollection($items) 183 | { 184 | $customerIds = $this->getCustomerIds($items); 185 | 186 | return $this->subscriberCollection 187 | ->addFieldToFilter('customer_id', ['in' => $customerIds]) 188 | ->addFieldToFilter('subscriber_status', \Magento\Newsletter\Model\Subscriber::STATUS_SUBSCRIBED); 189 | } 190 | 191 | /** 192 | * Add reward points to items 193 | * 194 | * @param $items 195 | */ 196 | private function appendRewardPoints(&$items) 197 | { 198 | $customerIds = $this->getCustomerIds($items); 199 | 200 | $rewardPointsCollection = $this->rewardPointsService->getRewardPointsCollection($customerIds) 201 | ->addFieldToFilter('customer_id', ['in' => $customerIds]); 202 | 203 | $websiteIds = $this->_request->getParam('website_ids'); 204 | if ($websiteIds) { 205 | $rewardPointsCollection->addWebsiteFilter($websiteIds); 206 | } 207 | 208 | foreach ($items as &$item) { 209 | $reward = $rewardPointsCollection->getItemByColumnValue('customer_id', $item['id']); 210 | if ($reward) { 211 | $item['reward_points'] = $reward->getPointsBalance(); 212 | } 213 | } 214 | } 215 | 216 | /** 217 | * @param $items 218 | * @return array 219 | */ 220 | private function getCustomerIds($items) 221 | { 222 | $customerIds = array_map(function($item){ 223 | return $item['id']; 224 | }, $items); 225 | 226 | return $customerIds; 227 | } 228 | 229 | /** 230 | * @param $id 231 | * @return mixed|string|null 232 | * @throws LocalizedException 233 | */ 234 | protected function getCustomerGroupName($id) 235 | { 236 | if ($this->customerGroupNames === null) { 237 | $this->customerGroupNames = []; 238 | 239 | $searchCriteria = $this->searchCriteriaBuilder->create(); 240 | $groups = $this->groupRepository->getList($searchCriteria)->getItems(); 241 | 242 | foreach ($groups as $_group) { 243 | $this->customerGroupNames[$_group->getId()] = $_group->getCode(); 244 | } 245 | } 246 | 247 | return array_key_exists($id, $this->customerGroupNames) 248 | ? $this->customerGroupNames[$id] 249 | : null; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Get/Settings.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 21 | $this->helperConfig = $helperConfig; 22 | $this->resourceConfig = $resourceConfig; 23 | $this->_cacheTypeList = $cacheTypeList; 24 | } 25 | 26 | public function execute() 27 | { 28 | $values = $this->helperConfig->get(); 29 | $data = [Config::CONFIG_TOP=>$values]; 30 | 31 | $values = $this->helperConfig->get(null, Config::CONFIG_TOP_ABANDONEDCARTS); 32 | $data[Config::CONFIG_TOP_ABANDONEDCARTS] = $values; 33 | 34 | $path = 'advanced/unique_id'; 35 | if(!$this->helperConfig->get($path)) 36 | { 37 | $unique_id = md5(uniqid().time()); 38 | $this->resourceConfig->saveConfig(Config::CONFIG_TOP . '/' . $path, $unique_id, 'default', 0); 39 | $data[Config::CONFIG_TOP]['advanced']['unique_id'] = $unique_id; 40 | $this->_cacheTypeList->cleanType('config'); 41 | } 42 | 43 | $result = $this->resultJsonFactory->create(); 44 | return $result->setData($data); 45 | } 46 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Magento/Info.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 27 | $this->scopeConfig = $scopeConfig; 28 | $this->helperMetadata = $helperMetadata; 29 | } 30 | 31 | protected function getMagentoVersion() 32 | { 33 | return $this->helperMetadata->getVersion(); 34 | } 35 | 36 | public function execute() 37 | { 38 | $data = Helper::getBlankArray(); 39 | $result = $this->resultJsonFactory->create(); 40 | 41 | $data['version_magento'] = $this->getMagentoVersion(); 42 | $data['version_php'] = phpversion(); 43 | $data['timezone_php'] = date_default_timezone_get(); 44 | $data['timezone_magento'] = $this->scopeConfig->getValue( 45 | 'general/locale/timezone', 46 | ScopeInterface::SCOPE_STORE 47 | ); 48 | 49 | return $result->setData($data); 50 | } 51 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/OrderIds.php: -------------------------------------------------------------------------------- 1 | orderCollectionFactory = $orderCollectionFactory; 55 | $this->storeManager = $storeManager; 56 | $this->resultJsonFactory = $resultJsonFactory; 57 | } 58 | 59 | /** 60 | * @return Json 61 | */ 62 | public function execute() 63 | { 64 | $items = $this->getOrderIds(); 65 | 66 | $result = $this->resultJsonFactory->create(); 67 | return $result->setData($items); 68 | } 69 | 70 | /** 71 | * @return array 72 | */ 73 | private function getOrderIds() 74 | { 75 | $collection = $this->getOrderCollection(); 76 | 77 | foreach ($this->getFilters() as $attribute => $filters) { 78 | foreach ($filters as $condition => $value) { 79 | if ($value !== null) { 80 | $collection->addFieldToFilter( 81 | $attribute, 82 | array($condition => $value) 83 | ); 84 | } 85 | } 86 | } 87 | 88 | return $collection->getData(); 89 | } 90 | 91 | /** 92 | * @return OrderCollection 93 | */ 94 | private function getOrderCollection() 95 | { 96 | $collection = $this->orderCollectionFactory->create(); 97 | 98 | $collection->addAttributeToSelect(OrderInterface::ENTITY_ID); 99 | $collection->addAttributeToSelect(OrderInterface::INCREMENT_ID); 100 | $collection->addAttributeToSelect(OrderInterface::CREATED_AT); 101 | $collection->addAttributeToSelect(OrderInterface::UPDATED_AT); 102 | 103 | if ($pageSize = $this->getRequestParam(self::PAGE_SIZE)) { 104 | $collection->setPageSize($pageSize); 105 | } 106 | 107 | if ($currentPage = $this->getRequestParam(self::CURRENT_PAGE)) { 108 | $collection->setCurPage($currentPage); 109 | } 110 | 111 | return $collection; 112 | } 113 | 114 | /** 115 | * @return array 116 | */ 117 | private function getFilters() 118 | { 119 | return [ 120 | OrderInterface::CREATED_AT => [ 121 | self::SINCE_CONDITION => $this->formatDate( 122 | $this->getRequestParam(self::CREATED_SINCE) 123 | ), 124 | self::BEFORE_CONDITION => $this->formatDate( 125 | $this->getRequestParam(self::CREATED_BEFORE) 126 | ) 127 | ], 128 | OrderInterface::UPDATED_AT => [ 129 | self::SINCE_CONDITION => $this->formatDate( 130 | $this->getRequestParam(self::UPDATED_SINCE) 131 | ), 132 | self::BEFORE_CONDITION => $this->formatDate( 133 | $this->getRequestParam(self::UPDATED_BEFORE) 134 | ) 135 | ], 136 | OrderInterface::STORE_ID => [ 137 | self::EQUAL_CONDITION => $this->getRequestParam(self::STORE_ID) 138 | ] 139 | ]; 140 | } 141 | 142 | /** 143 | * @param $key 144 | * @return mixed 145 | */ 146 | private function getRequestParam($key) 147 | { 148 | return $this->getRequest()->getParam($key, null); 149 | } 150 | 151 | /** 152 | * @param $date 153 | * @return false|string 154 | * @throws InputException 155 | */ 156 | private function formatDate($date) 157 | { 158 | // Don't format dates that have not been set a value. 159 | if ($date === null) { 160 | return $date; 161 | } 162 | 163 | $timestamp = strToTime($date); 164 | 165 | if ($timestamp === false) { 166 | throw new InputException(__(sprintf('Invalid date filter parameter provided: %s', $date))); 167 | } 168 | 169 | return date(Mysql::DATETIME_FORMAT, $timestamp); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Salesrules/Delete/Coupons.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 32 | $this->couponmgmtservice = $couponmgmtservice; 33 | parent::__construct($context); 34 | } 35 | /** 36 | * Execute 37 | * 38 | * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\Result\Json 39 | * @throws \Magento\Framework\Exception\InputException 40 | * @throws \Magento\Framework\Exception\LocalizedException 41 | * @throws \Magento\Framework\Exception\NoSuchEntityException 42 | */ 43 | public function execute() 44 | { 45 | 46 | $ruleId = $this->getRequest()->getParam('rule_id'); 47 | $couponCodesToDelete = $this->getRequest()->getParam('codes'); 48 | 49 | if (empty($couponCodesToDelete) || !is_array($couponCodesToDelete)) { 50 | $result = $this->resultJsonFactory->create(); 51 | $result->setData(['error' => 'Invalid or empty list of coupons to delete']); 52 | return $result; 53 | } 54 | 55 | $coupon_res = ''; 56 | try { 57 | $coupon_res = $this->couponmgmtservice->deleteByCodes($couponCodesToDelete, true); 58 | } catch(\Exception $e) { 59 | $result = $this->resultJsonFactory->create(); 60 | $result->setData(['error' => "Failed to delete coupons for ruleid $ruleId"]); 61 | return $result; 62 | } 63 | 64 | $result = $this->resultJsonFactory->create(); 65 | return $result->setData([ 66 | 'deleted_coupons' => array_diff($couponCodesToDelete, $coupon_res->getFailedItems(), $coupon_res->getMissingItems()), 67 | 'missing_coupons' => $coupon_res->getMissingItems(), 68 | 'failed_coupons' => $coupon_res->getFailedItems() 69 | ]); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Salesrules/Insert/Coupons.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 20 | $this->couponRepository = $couponRepository; 21 | $this->couponFactory = $couponFactory; 22 | 23 | return parent::__construct($context); 24 | } 25 | 26 | protected function getRuleId() 27 | { 28 | return $this->getRequest()->getParam('rule_id');; 29 | } 30 | 31 | protected function getCouponCodes() 32 | { 33 | return $this->getRequest()->getParam('codes'); 34 | } 35 | 36 | protected function getUsageLimit() 37 | { 38 | return $this->getRequest()->getParam('usage_limit'); 39 | } 40 | 41 | protected function getUsageLimitPerCustomer() 42 | { 43 | return $this->getRequest()->getParam('usage_limit_per_customer'); 44 | } 45 | 46 | protected function getExpirationDate() 47 | { 48 | $expire_ts = strToTime($this->getRequest()->getParam('expiration_date')); 49 | $expiration_date = date('Y-m-d H:i:s', $expire_ts); 50 | return $expiration_date; 51 | } 52 | 53 | public function execute() 54 | { 55 | $coupons = []; 56 | 57 | $usage_limit = $this->getUsageLimit(); 58 | $usage_per_customer = $this->getUsageLimitPerCustomer(); 59 | $expiration_date = $this->getExpirationDate(); 60 | 61 | foreach($this->getCouponCodes() as $code) 62 | { 63 | $coupon = $this->couponFactory->create(); 64 | $coupon->setRuleId($this->getRuleId()) 65 | ->setCode($code) 66 | ->setUsageLimit($usage_limit) 67 | ->setUsagePerCustomer($usage_per_customer) 68 | ->setExpirationDate($expiration_date) 69 | ->setCreatedAt(time()) 70 | ->setType($coupon::TYPE_GENERATED); 71 | 72 | //use repository to get validation 73 | $this->couponRepository->save($coupon); 74 | 75 | //cheat and set our own expiration date 76 | $coupon->setExpirationDate($expiration_date)->save(); 77 | $coupons[] = $coupon->getData(); 78 | } 79 | $result = $this->resultJsonFactory->create(); 80 | return $result->setData($coupons); 81 | } 82 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Salesrules/Items.php: -------------------------------------------------------------------------------- 1 | ruleRepository = $ruleRepository; 20 | $this->resultJsonFactory = $resultJsonFactory; 21 | $this->apiHelperServiceFilterable = $apiHelperServiceFilterable; 22 | 23 | return parent::__construct($context); 24 | } 25 | 26 | public function execute() 27 | { 28 | $items = $this->getItemsForJson(); 29 | $result = $this->resultJsonFactory->create(); 30 | return $result->setData($items); 31 | } 32 | 33 | public function getItemsForJson() 34 | { 35 | $items = $this->apiHelperServiceFilterable->createResponse( 36 | $this->ruleRepository, 37 | 'Magento\SalesRule\Api\Data\RuleInterface' 38 | ); 39 | return $items; 40 | // return ['hello'=>'goodbye']; 41 | } 42 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Salesrules/Items/Coupons.php: -------------------------------------------------------------------------------- 1 | couponRepository = $couponRepository; 18 | $this->resultJsonFactory = $resultJsonFactory; 19 | $this->apiHelperServiceFilterable = $apiHelperServiceFilterable; 20 | return parent::__construct($context); 21 | } 22 | 23 | public function execute() 24 | { 25 | $items = $this->getItemsForJson(); 26 | $result = $this->resultJsonFactory->create(); 27 | return $result->setData($items); 28 | } 29 | 30 | public function getItemsForJson() 31 | { 32 | $items = $this->apiHelperServiceFilterable->createResponse( 33 | $this->couponRepository, 34 | null//'Magento\SalesRule\Api\Data\CouponInterface' 35 | ); 36 | return $items; 37 | }} -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Stores.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 19 | $this->storeFactory = $storeFactory; 20 | $this->scopeConfig = $scopeConfig; 21 | } 22 | 23 | public function execute() 24 | { 25 | $stores = $this->storeFactory->create()->getCollection()->getItems(); 26 | $stores = array_map(function($item){ 27 | return $item->getData(); 28 | }, $stores); 29 | sort($stores); 30 | 31 | $formated = []; 32 | foreach($stores as $store) 33 | { 34 | $tmp = Helper::getBlankArray(); 35 | $tmp['id'] = $store['store_id']; 36 | $tmp['title'] = $store['name']; 37 | $tmp['group_id'] = $store['group_id']; 38 | $tmp['website_id'] = $store['website_id']; 39 | $tmp['url'] = $this->scopeConfig->getValue( 40 | 'web/unsecure/base_url', 41 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE, 42 | $store['code'] 43 | ); 44 | $formated[] = $tmp; 45 | } 46 | $result = $this->resultJsonFactory->create(); 47 | return $result->setData($formated); 48 | } 49 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Subscribers.php: -------------------------------------------------------------------------------- 1 | customerCollection = $customerCollection; 27 | $this->resultJsonFactory = $resultJsonFactory; 28 | $this->subscriberFactory = $subscriberFactory; 29 | $this->helperOmetriaApiFilter = $helperOmetriaApiFilter; 30 | $this->searchCriteria = $searchCriteria; 31 | $this->customerDataHelper = $customerDataHelper; 32 | } 33 | 34 | protected function getMarketingOption($status) 35 | { 36 | switch($status) 37 | { 38 | case \Magento\Newsletter\Model\Subscriber::STATUS_SUBSCRIBED: 39 | return true; 40 | case \Magento\Newsletter\Model\Subscriber::STATUS_UNSUBSCRIBED: 41 | return false; 42 | default; 43 | return null; 44 | } 45 | } 46 | 47 | protected function addCustomerDataAndFormat($items) 48 | { 49 | $customer_ids = array_map(function($item){ 50 | return array_key_exists('customer_id', $item) ? $item['customer_id'] : 0; 51 | }, $items); 52 | 53 | $customer_ids = array_filter($customer_ids, function($item){ 54 | return $item > 0; 55 | }); 56 | 57 | $this->customerCollection->addFieldToFilter('entity_id', $customer_ids); 58 | 59 | $new_items = []; 60 | foreach($items as $key=>$item) 61 | { 62 | $new = Helper::getBlankArray(); 63 | $new["@type"] = "contact"; 64 | $new["id"] = array_key_exists('subscriber_id', $item) ? $item['subscriber_id'] : ''; 65 | $new["email"] = array_key_exists('subscriber_email', $item) ? $item['subscriber_email'] : ''; 66 | $status = array_key_existS('subscriber_status', $item) ? $item['subscriber_status'] : ''; 67 | $new["marketing_optin"] = $this->getMarketingOption($status); 68 | $new['store_id'] = $item['store_id']; 69 | $new_items[] = $new; 70 | } 71 | return $new_items; 72 | } 73 | 74 | public function execute() 75 | { 76 | $searchCriteria = $this->helperOmetriaApiFilter 77 | ->applyFilertsToSearchCriteria($this->searchCriteria); 78 | 79 | $collection = $this->subscriberFactory->create()->getCollection(); 80 | 81 | foreach ($searchCriteria->getFilterGroups() as $group) { 82 | $this->addFilterGroupToCollection($group, $collection); 83 | } 84 | 85 | if($page_size = $searchCriteria->getPageSize()) 86 | { 87 | $collection->setPageSize($page_size); 88 | } 89 | 90 | if($current_page = $searchCriteria->getCurrentPage()) 91 | { 92 | $collection->setCurPage($current_page); 93 | } 94 | 95 | $items = array_map(function($item){ 96 | return $item->getData(); 97 | }, $collection->getItems()); 98 | sort($items); 99 | 100 | $items = $this->addCustomerDataAndFormat($items); 101 | 102 | $result = $this->resultJsonFactory->create(); 103 | return $result->setData($items); 104 | } 105 | 106 | protected function addFilterGroupToCollection( 107 | \Magento\Framework\Api\Search\FilterGroup $filterGroup, 108 | \Magento\Newsletter\Model\ResourceModel\Subscriber\Collection $collection 109 | ) { 110 | $fields = []; 111 | foreach ($filterGroup->getFilters() as $filter) { 112 | $condition = $filter->getConditionType() ? $filter->getConditionType() : 'eq'; 113 | $fields[] = ['attribute' => $filter->getField(), $condition => $filter->getValue()]; 114 | } 115 | 116 | if(count($fields) > 1) 117 | { 118 | throw new \Exception("Can't handle multiple OR filters"); 119 | } 120 | if ($fields) { 121 | $attribute = $this->swapAttributes($fields[0]['attribute']); 122 | unset($fields[0]['attribute']); 123 | $filter = $fields[0]; 124 | $collection->addFieldToFilter($attribute, $filter); 125 | } 126 | } 127 | 128 | protected function swapAttributes($attribute) 129 | { 130 | switch($attribute) 131 | { 132 | case 'updated_at'; 133 | return 'change_status_at'; 134 | default: 135 | return $attribute; 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Controller/V1/Version.php: -------------------------------------------------------------------------------- 1 | resultJsonFactory = $resultJsonFactory; 19 | $this->moduleResource = $moduleResource; 20 | } 21 | 22 | public function execute() 23 | { 24 | $data = Helper::getBlankArray(); 25 | $result = $this->resultJsonFactory->create(); 26 | $data['version'] = self::VERSION_STRING . '/' . $this->moduleResource->getDbVersion('Ometria_Api'); 27 | return $result->setData($data); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Category.php: -------------------------------------------------------------------------------- 1 | categoryRepository = $categoryRepository; 10 | } 11 | 12 | public function getOmetriaAttributeFromCategoryIds($ids) 13 | { 14 | $ret = []; 15 | 16 | foreach($ids as $id){ 17 | try{ 18 | $category = $this->categoryRepository->get($id); 19 | 20 | if ($category) $ret[] = [ 21 | 'type' =>'category', 22 | 'id' =>$id, 23 | 'url_key' =>$category->getUrlKey(), 24 | 'url_path' =>$category->getUrlPath(), 25 | 'label' =>$category->getName() 26 | ]; 27 | } catch(\Exception $e) { 28 | // pass, prevent issues with missing categories 29 | } 30 | } 31 | 32 | return $ret; 33 | } 34 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Config.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 17 | } 18 | 19 | public function get($path=null, $top=null) 20 | { 21 | $top = $top ? $top : self::CONFIG_TOP; 22 | $config = $this->scopeConfig->getValue( 23 | $top, 24 | ScopeInterface::SCOPE_STORE 25 | ); 26 | if($config === null) 27 | { 28 | return null; 29 | } 30 | if(!$path) 31 | { 32 | return $config; 33 | } 34 | $parts = explode('/',$path); 35 | 36 | foreach($parts as $part) 37 | { 38 | if(!array_key_exists($part, $config)) 39 | { 40 | return null; 41 | } 42 | $config = $config[$part]; 43 | } 44 | 45 | return $config; 46 | } 47 | 48 | protected function getTopLevelName() 49 | { 50 | return self::CONFIG_TOP_ABANDONEDCARTS; 51 | return self::CONFIG_TOP; 52 | } 53 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/CustomerData.php: -------------------------------------------------------------------------------- 1 | customerMetadataInterface = $customerMetadataInterface; 12 | 13 | $this->genderOptions = $this->customerMetadataInterface 14 | ->getAttributeMetadata('gender') 15 | ->getOptions(); 16 | } 17 | 18 | public function getGenderLabel($item) 19 | { 20 | $value = array_key_exists('gender', $item) ? $item['gender'] : false; 21 | foreach($this->genderOptions as $option) 22 | { 23 | if($option->getValue() == $value) 24 | { 25 | return $option->getLabel(); 26 | } 27 | } 28 | 29 | return ''; 30 | } 31 | 32 | public function getCountryId($item) 33 | { 34 | $addresses = array_key_exists('addresses', $item) ? $item['addresses'] : []; 35 | foreach($addresses as $address) 36 | { 37 | if(array_key_exists('country_id', $address)) 38 | { 39 | return $address['country_id']; 40 | } 41 | } 42 | return false; 43 | } 44 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Filter/V1/Service.php: -------------------------------------------------------------------------------- 1 | searchCriteriaBuilder = $searchCriteriaBuilder; 22 | $this->filterBuilder = $filterBuilder; 23 | $this->filterGroupBuilder = $filterGroupBuilder; 24 | $this->request = $request; 25 | } 26 | 27 | protected function applyFilertsToSearchCriteriaEntityId($searchCriteria) 28 | { 29 | $groups = []; 30 | $fullAction = $this->request->getFullActionName(); 31 | $ids = $this->request->getParam('ids'); 32 | 33 | if($ids && $fullAction !== 'ometria_api_v1_orders') 34 | { 35 | $ids = is_array($ids) ? $ids : [$ids]; 36 | $group_ids = $this->createSingleFilterFilterGroup('entity_id', $ids, 'in'); 37 | $groups[] = $group_ids; 38 | } 39 | 40 | if($ids && $fullAction === 'ometria_api_v1_orders') 41 | { 42 | $ids = is_array($ids) ? $ids : [$ids]; 43 | $group_ids = $this->createSingleFilterFilterGroup('increment_id', $ids, 'in'); 44 | $groups[] = $group_ids; 45 | } 46 | return $groups; 47 | } 48 | 49 | public function applyFilertsToSearchCriteria($searchCriteria) 50 | { 51 | $groups = []; 52 | $groups = array_merge($groups, $this->applyFilertsToSearchCriteriaEntityId($searchCriteria)); 53 | 54 | $website_ids = $this->request->getParam('website_ids'); 55 | if($website_ids) { 56 | $website_ids = is_array($website_ids) ? $website_ids : [$website_ids]; 57 | $groups[] = $this->createSingleFilterFilterGroup( 58 | 'website_ids', 59 | $website_ids, 60 | 'in' 61 | ); 62 | } 63 | 64 | //store ids 65 | $store_ids = $this->request->getParam('stores'); 66 | if($store_ids) { 67 | $store_ids = is_array($store_ids) ? $store_ids : [$store_ids]; 68 | $groups[] = $this->createSingleFilterFilterGroup( 69 | 'store_id', 70 | $store_ids, 71 | 'in' 72 | ); 73 | } 74 | 75 | $created_since = $this->request->getParam('created_since'); 76 | if($created_since) { 77 | $created_since = date('Y-m-d H:i:s', strToTime($created_since)); 78 | $groups[] = $this->createSingleFilterFilterGroup( 79 | 'created_at', 80 | $created_since, 81 | 'gt' 82 | ); 83 | } 84 | 85 | $created_before = $this->request->getParam('created_before'); 86 | if($created_before) { 87 | $created_before = date('Y-m-d H:i:s', strToTime($created_before)); 88 | $groups[] = $this->createSingleFilterFilterGroup( 89 | 'created_at', 90 | $created_before, 91 | 'lt' 92 | ); 93 | } 94 | 95 | $updated_since = $this->request->getParam('updated_since'); 96 | if($updated_since) { 97 | $updated_since = date('Y-m-d H:i:s', strToTime($updated_since)); 98 | $groups[] = $this->createSingleFilterFilterGroup( 99 | 'updated_at', 100 | $updated_since, 101 | 'gt' 102 | ); 103 | } 104 | 105 | $updated_before = $this->request->getParam('updated_before'); 106 | if($updated_before) { 107 | $updated_before = date('Y-m-d H:i:s', strToTime($updated_before)); 108 | $groups[] = $this->createSingleFilterFilterGroup( 109 | 'updated_at', 110 | $updated_before, 111 | 'lt' 112 | ); 113 | } 114 | 115 | //product_type 116 | $product_type = $this->request->getParam('product_type'); 117 | if($product_type === 'parent') { 118 | $groups[] = $this->createSingleFilterFilterGroup( 119 | 'visibility', 120 | [ \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG, 121 | \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH], 122 | 'in'); 123 | } 124 | if($product_type === 'variant') { 125 | //$group_simple = $this->createSingleFilterFilterGroup('type_id', 'simple', 'eq'); 126 | //$groups[] = $group_simple; 127 | $groups[] = $this->createSingleFilterFilterGroup( 128 | 'visibility', 129 | [\Magento\Catalog\Model\Product\Visibility::VISIBILITY_NOT_VISIBLE], 130 | 'in'); 131 | } 132 | 133 | $rule_id = $this->request->getParam('rule_id'); 134 | if($rule_id) { 135 | $group_rule_id = $this->createSingleFilterFilterGroup( 136 | 'rule_id', $rule_id, 'eq'); 137 | $groups[] = $group_rule_id; 138 | } 139 | 140 | // Set default page size based on 'count' parameter being present or not 141 | $defaultPageSize = $this->request->getParam(self::PARAM_COUNT) ? false : 100; 142 | $pageSize = (int) $this->request->getParam(self::PARAM_PAGE_SIZE, $defaultPageSize); 143 | 144 | $currentPage = (int) $this->request->getParam(self::PARAM_CURRENT_PAGE, 1); 145 | 146 | return $this->searchCriteriaBuilder 147 | ->setFilterGroups($groups) 148 | ->setPageSize($pageSize) 149 | ->setCurrentPage($currentPage) 150 | ->create(); 151 | } 152 | 153 | protected function createSingleFilterFilterGroup($field, $value, $conditionType = 'eq') 154 | { 155 | return $this->filterGroupBuilder 156 | ->addFilter($this->createFilter($field,$value,$conditionType)) 157 | ->create(); 158 | } 159 | 160 | /** 161 | * Targeting public beta -- no addFilter on searchCriteriaBuilder 162 | */ 163 | protected function createFilter($field, $value, $conditionType = 'eq') 164 | { 165 | return $this->filterBuilder->setField($field) 166 | ->setValue($value) 167 | ->setConditionType($conditionType) 168 | ->create(); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Filter/V2/Service.php: -------------------------------------------------------------------------------- 1 | request = $request; 38 | } 39 | 40 | /** 41 | * @param AbstractCollection $collection 42 | */ 43 | public function applyFiltersToCollection(AbstractCollection $collection) 44 | { 45 | // Set page size 46 | $pageSize = $this->request->getParam(self::PARAM_PAGE_SIZE, self::DEFAULT_PAGE_SIZE); 47 | $collection->setPageSize($pageSize); 48 | 49 | // Set current page 50 | $currentPage = $this->request->getParam(self::PARAM_CURRENT_PAGE, self::DEFAULT_PAGE); 51 | $collection->setCurPage($currentPage); 52 | 53 | if ($entityIds = $this->request->getParam(self::PARAM_ENTITY_IDS)) { 54 | $entityIds = is_array($entityIds) ? $entityIds : [$entityIds]; 55 | $collection->addFieldToFilter( 56 | 'entity_id', 57 | $entityIds 58 | ); 59 | } 60 | 61 | if ($websiteIds = $this->request->getParam(self::PARAM_WEBSITE_IDS)) { 62 | $collection->addWebsiteFilter($websiteIds); 63 | } 64 | 65 | if ($storeIds = $this->request->getParam(self::PARAM_STORES)) { 66 | $storeIds = is_array($storeIds) ? $storeIds : [$storeIds]; 67 | foreach ($storeIds as $storeId) { 68 | $collection->addStoreFilter($storeId); 69 | } 70 | } 71 | 72 | if ($createdSince = $this->request->getParam(self::PARAM_CREATED_SINCE)) { 73 | $createdSince = date('Y-m-d H:i:s', strToTime($createdSince)); 74 | $collection->addFieldToFilter( 75 | 'created_at', 76 | ['gt' => $createdSince] 77 | ); 78 | } 79 | 80 | if ($createdBefore = $this->request->getParam(self::PARAM_CREATED_BEFORE)) { 81 | $createdBefore = date('Y-m-d H:i:s', strToTime($createdBefore)); 82 | $collection->addFieldToFilter( 83 | 'created_at', 84 | ['lt' => $createdBefore] 85 | ); 86 | } 87 | 88 | if ($updatedSince = $this->request->getParam(self::PARAM_UPDATED_SINCE)) { 89 | $updatedSince = date('Y-m-d H:i:s', strToTime($updatedSince)); 90 | $collection->addFieldToFilter( 91 | 'updated_at', 92 | ['gt' => $updatedSince] 93 | ); 94 | } 95 | 96 | if ($updatedBefore = $this->request->getParam(self::PARAM_UPDATED_BEFORE)) { 97 | $updatedBefore = date('Y-m-d H:i:s', strToTime($updatedBefore)); 98 | $collection->addFieldToFilter( 99 | 'updated_at', 100 | ['lt' => $updatedBefore] 101 | ); 102 | } 103 | 104 | if ($this->request->getParam(self::PARAM_PRODUCT_TYPE) == 'parent') { 105 | $collection->addFieldToFilter( 106 | 'visibility', 107 | [ 108 | 'in' => [ 109 | Visibility::VISIBILITY_IN_CATALOG, 110 | Visibility::VISIBILITY_BOTH 111 | ] 112 | ] 113 | ); 114 | } 115 | 116 | if ($this->request->getParam(self::PARAM_PRODUCT_TYPE) == 'variant') { 117 | $collection->addFieldToFilter( 118 | 'visibility', 119 | [ 120 | 'in' => [Visibility::VISIBILITY_NOT_VISIBLE] 121 | ] 122 | ); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Attribute/Types.php: -------------------------------------------------------------------------------- 1 | null, 9 | "attribute_type" => null, 10 | "title" => null, 11 | "attribute_code" => null 12 | ]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Attributes.php: -------------------------------------------------------------------------------- 1 | "attribute", 9 | "type" => "code", 10 | "id"=>"", 11 | "title"=>"", 12 | ]; 13 | } 14 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Categories.php: -------------------------------------------------------------------------------- 1 | null, 9 | "id"=>null, 10 | "parent_id"=>null, 11 | "name"=>null, 12 | "position"=>null, 13 | "level"=>null, 14 | "is_active"=>null, 15 | "product_count"=>null, 16 | "children_data"=>null 17 | ]; 18 | } 19 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Customers.php: -------------------------------------------------------------------------------- 1 | "contact", 9 | "id" => "", 10 | "email" => "", 11 | "prefix" => "", 12 | "firstname" => "", 13 | "middlename" => "", 14 | "lastname" => "", 15 | "gender" => "", 16 | "date_of_birth" => "", 17 | "store_id" => "", 18 | "marketing_optin" => true, 19 | "country_id" => "GB" 20 | ]; 21 | } 22 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Get/Settings.php: -------------------------------------------------------------------------------- 1 | "", 9 | "ometria_abandonedcarts"=>"" 10 | ]; 11 | } 12 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Magento/Info.php: -------------------------------------------------------------------------------- 1 | "", 9 | "version_php"=>"", 10 | "timezone_php"=>"", 11 | "timezone_magento"=>"", 12 | ]; 13 | } 14 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Orders.php: -------------------------------------------------------------------------------- 1 | "order", 9 | 'state' => '', 10 | "id" => "", 11 | "increment_id" => "", 12 | "status" => "", 13 | "state" => "", 14 | 'ip_address'=>"", 15 | 'x_forwarded_for'=>'', 16 | "is_valid" => '', 17 | "customer" => self::getBlankCustomer(), 18 | "lineitems"=>[self::getBlankLineItem()], 19 | "timestamp"=>"", 20 | "subtotal"=>'', 21 | "discount"=>'', 22 | "shipping"=>'', 23 | "tax"=>'', 24 | "grand_total"=>'', 25 | "total_refunded"=>'', 26 | "currency"=>"", 27 | "channel"=>"", 28 | "store"=>"", 29 | "payment_method"=>"", 30 | "shipping_method"=>"", 31 | "shipping_address"=>self::getBlankAddress(), 32 | "billing_address"=>self::getBlankAddress(), 33 | "coupon_code"=>"" 34 | ]; 35 | } 36 | 37 | static public function getBlankAddress() 38 | { 39 | return [ 40 | "city" => "", 41 | "state" => "", 42 | "postcode" => "", 43 | "country_code" => "" 44 | ]; 45 | } 46 | 47 | static public function getBlankLineItem() 48 | { 49 | return [ 50 | "product" => '', 51 | "variant_id" => "", 52 | "variant_options" => '', 53 | "sku" => '', 54 | "quantity" => '', 55 | "unit_price" => '', 56 | "total" => '' 57 | ]; 58 | } 59 | 60 | static public function getBlankCustomer() 61 | { 62 | return [ 63 | "id" => "", 64 | "firstname" => "", 65 | "lastname" => "", 66 | "email" => "" 67 | ]; 68 | } 69 | 70 | 71 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Products.php: -------------------------------------------------------------------------------- 1 | "product", 9 | "id"=>null, 10 | "title"=>null, 11 | "sku"=>null, 12 | "price"=>null, 13 | "url"=>null, 14 | "image_url"=>null, 15 | "is_variant"=>false, 16 | "parent_id"=>null, 17 | "attributes"=>null, 18 | "is_active"=>null, 19 | "stores"=>null, 20 | ]; 21 | } 22 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Stores.php: -------------------------------------------------------------------------------- 1 | null, 9 | "title" => null, 10 | "group_id" => null, 11 | "website_id" => null, 12 | "url" => null 13 | ]; 14 | } 15 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Subscribers.php: -------------------------------------------------------------------------------- 1 | "contact", 9 | "id" =>null, 10 | "email" =>null, 11 | "marketing_optin" =>null, 12 | "store_id" =>null 13 | ]; 14 | } 15 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V1/Version.php: -------------------------------------------------------------------------------- 1 | "", 9 | ]; 10 | } 11 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Format/V2/Products.php: -------------------------------------------------------------------------------- 1 | "product", 9 | "id"=>null, 10 | "title"=>null, 11 | "sku"=>null, 12 | "price"=>null, 13 | "url"=>null, 14 | "image_url"=>null, 15 | "attributes"=>null, 16 | "is_active"=>null, 17 | "stores"=>null, 18 | "store_listing"=>null 19 | ]; 20 | } 21 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Order/IsValid.php: -------------------------------------------------------------------------------- 1 | scopeConfig->isSetFlag('ometria/advanced/override_memory')) { 14 | ini_set('memory_limit', '-1'); 15 | } 16 | 17 | if ($this->scopeConfig->isSetFlag('ometria/advanced/override_execution')) { 18 | ini_set('max_execution_time', 0); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Service/Filterable/Service.php: -------------------------------------------------------------------------------- 1 | searchCriteria = $searchCriteria; 16 | $this->helperOmetriaApiFilter = $helperOmetriaApiFilter; 17 | $this->dataObjectProcessor = $dataObjectProcessor; 18 | } 19 | 20 | /** 21 | * @param $repository 22 | * @param $serializeAs 23 | * @return array 24 | */ 25 | public function createResponse($repository, $serializeAs) 26 | { 27 | $searchCriteria = $this->helperOmetriaApiFilter 28 | ->applyFilertsToSearchCriteria($this->searchCriteria); 29 | 30 | $list = $repository->getList($searchCriteria); 31 | 32 | $items = []; 33 | 34 | foreach($list->getItems() as $item) { 35 | if ($serializeAs) { 36 | $new = $this->dataObjectProcessor->buildOutputDataArray( 37 | $item, 38 | $serializeAs 39 | ); 40 | } else if(is_callable([$item, 'getData'])) { 41 | $new = $item->getData(); 42 | } else { 43 | $new = $item; 44 | } 45 | 46 | $items[] = $new; 47 | } 48 | 49 | return $items; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/Service/Filterable/Service/Product.php: -------------------------------------------------------------------------------- 1 | urlModel = $urlModel; 34 | $this->storeUrlHelper = $storeUrlHelper; 35 | $this->productHelper = $productHelper; 36 | return parent::__construct($searchCriteria, $helperOmetriaApiFilter, $dataObjectProcessor); 37 | } 38 | 39 | public function processList($list, $serialize_as, $imageId = 'image') 40 | { 41 | $items = []; 42 | foreach($list->getItems() as $item) 43 | { 44 | $new; 45 | if($serialize_as) 46 | { 47 | $new = $this->dataObjectProcessor->buildOutputDataArray( 48 | $item, 49 | $serialize_as 50 | ); 51 | } 52 | else 53 | { 54 | $new = $item->getData(); 55 | } 56 | 57 | $new['parent_id'] = $item->getParentId(); 58 | $new['url'] = $item->getProductUrl(); 59 | $new['category_ids'] = $item->getCategoryIds(); 60 | $new['store_ids'] = $item->getStoreIds(); 61 | $new['image_url'] = $this->productHelper->getProductImageUrl($item, $imageId); 62 | $this->storeUrlHelper->saveAllStoreUrls($item); 63 | $items[] = $new; 64 | } 65 | 66 | return $items; 67 | } 68 | 69 | public function createResponse($repository, $serialize_as) 70 | { 71 | $searchCriteria = $this->helperOmetriaApiFilter 72 | ->applyFilertsToSearchCriteria($this->searchCriteria); 73 | 74 | $list = $repository->getList($searchCriteria, $serialize_as); 75 | 76 | return $this->processList($list, $serialize_as); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Helper/StoreUrl.php: -------------------------------------------------------------------------------- 1 | storeManager = $storeManager; 12 | 13 | } 14 | public function saveAllStoreUrls($product) 15 | { 16 | $urls = []; 17 | $originalStore = $this->storeManager->getStore(); 18 | foreach($this->storeManager->getStores() as $store) 19 | { 20 | $this->storeManager->setCurrentStore($store); 21 | $urls[$store->getId()] = $product->getProductUrl(); 22 | } 23 | $this->storeManager->setCurrentStore($originalStore); 24 | $this->urlsByProductId[$product->getId()] = $urls; 25 | } 26 | 27 | public function getStoreUrlByProductIdAndStoreId($product_id, $store_id) 28 | { 29 | return $this->urlsByProductId[$product_id][$store_id]; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /app/code/Ometria/Api/Model/Hash.php: -------------------------------------------------------------------------------- 1 | request = $request; 18 | } 19 | 20 | /** 21 | * @param $domain 22 | * @param $method 23 | * @param $public_key 24 | * @param $private_key 25 | * @param array $data 26 | * @return string 27 | */ 28 | public function signRequest($domain, $method, $public_key, $private_key, $data=array()) 29 | { 30 | $data = array_filter($data); 31 | 32 | if (array_key_exists('request_timestamp', $data)) { 33 | $data['request_timestamp'] = (int) $data['request_timestamp']; 34 | } 35 | 36 | ksort($data); 37 | 38 | $data = json_encode($data); 39 | $buffer = array($domain, $method, $data, $public_key); 40 | $buffer_str = implode(":", $buffer); 41 | 42 | return hash_hmac('sha256', $buffer_str, $private_key); 43 | } 44 | 45 | /** 46 | * @param $method 47 | * @param $public_key 48 | * @param $private_key 49 | * @return bool 50 | */ 51 | public function checkRequest($method, $public_key, $private_key) 52 | { 53 | $data = $this->request->getParams(); 54 | 55 | if (!isset($data['signature'])) { 56 | return false; 57 | } 58 | 59 | // Dont check the signature param 60 | $signature = $data['signature']; 61 | unset($data['signature']); 62 | 63 | $calculated_signature = $this->signRequest($_SERVER['HTTP_HOST'], $method, $public_key, $private_key, $data); 64 | 65 | if ($calculated_signature != $signature) { 66 | return false; 67 | } 68 | 69 | // check dates to prevent replay attacks 70 | $ts = (int) $data['request_timestamp']; 71 | 72 | if ($ts < time() - 1200) { 73 | return false; 74 | } 75 | 76 | return true; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Model/Observer/Auth.php: -------------------------------------------------------------------------------- 1 | config = $config; 26 | $this->hash = $hash; 27 | } 28 | 29 | /** 30 | * @param Observer $observer 31 | */ 32 | public function execute(Observer $observer) 33 | { 34 | return $this->checkHeader($observer); 35 | } 36 | 37 | /** 38 | * @param $observer 39 | */ 40 | public function checkHeader($observer) 41 | { 42 | $publicKey = $this->config->get('general/apikey'); 43 | $privateKey = $this->config->get('general/privatekey'); 44 | $methodName = $this->getMethodNameFromObserver($observer); 45 | 46 | $isAuthorized = $this->hash->checkRequest($methodName,$publicKey,$privateKey); 47 | 48 | if (!$isAuthorized) { 49 | echo "Forbidden"; 50 | header('HTTP/1.1 403 Forbidden'); 51 | exit; 52 | } 53 | } 54 | 55 | /** 56 | * @param $observer 57 | * @return mixed 58 | */ 59 | protected function getMethodNameFromObserver($observer) 60 | { 61 | $request = $observer->getRequest(); 62 | return $request->getActionName(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Model/ResourceModel/Product.php: -------------------------------------------------------------------------------- 1 | metadataPool = $metadataPool; 26 | 27 | parent::__construct($context, $connectionName); 28 | } 29 | 30 | protected function _construct() 31 | { 32 | } 33 | 34 | /** 35 | * Bulk version of the native method to retrieve relationships one by one. 36 | * @see \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable::getParentIdsByChild 37 | * 38 | * @param array $childIds 39 | * @return array 40 | */ 41 | public function getConfigurableProductParentIds(array $childIds) 42 | { 43 | $childToParentIds = []; 44 | 45 | $connection = $this->getConnection(); 46 | $metadata = $this->metadataPool->getMetadata(ProductInterface::class); 47 | $linkField = htmlspecialchars($metadata->getLinkField()); 48 | $select = $connection->select() 49 | ->from( 50 | ['link_table' => $connection->getTableName('catalog_product_super_link')], 51 | ['link_id', 'product_id'] 52 | )->join( 53 | ['e' => $this->metadataPool->getMetadata(ProductInterface::class)->getEntityTable()], 54 | 'e.' . $linkField . ' = link_table.parent_id', 55 | ['e.entity_id'] 56 | )->where( 57 | 'link_table.product_id IN(?)', 58 | $childIds 59 | ) 60 | ->order( 61 | 'link_id ASC' 62 | ); 63 | 64 | $result = $connection->fetchAll($select); 65 | 66 | foreach ($result as $_row) { 67 | $childToParentIds[$_row['product_id']] = $_row['entity_id']; 68 | } 69 | 70 | return $childToParentIds; 71 | } 72 | 73 | /** 74 | * Bulk version of the native method to retrieve relationships one by one. 75 | * @see \Magento\Bundle\Model\ResourceModel\Selection::getParentIdsByChild 76 | * 77 | * @param array $childIds 78 | * @return array 79 | */ 80 | public function getBundleProductParentIds(array $childIds) 81 | { 82 | $childToParentIds = []; 83 | 84 | $connection = $this->getConnection(); 85 | $metadata = $this->metadataPool->getMetadata(ProductInterface::class); 86 | $linkField = htmlspecialchars($metadata->getLinkField()); 87 | $select = $connection->select() 88 | ->from( 89 | ['link_table' => $connection->getTableName('catalog_product_bundle_selection')], 90 | ['selection_id', 'product_id'] 91 | )->join( 92 | ['e' => $this->metadataPool->getMetadata(ProductInterface::class)->getEntityTable()], 93 | 'e.' . $linkField . ' = link_table.parent_product_id', 94 | ['e.entity_id'] 95 | )->where( 96 | 'link_table.product_id IN(?)', 97 | $childIds 98 | )->order( 99 | 'selection_id ASC' 100 | ); 101 | 102 | $result = $connection->fetchAll($select); 103 | 104 | foreach ($result as $_row) { 105 | $childToParentIds[$_row['product_id']] = $_row['entity_id']; 106 | } 107 | 108 | return $childToParentIds; 109 | } 110 | 111 | /** 112 | * Bulk version of the native method to retrieve relationships one by one. 113 | * @see \Magento\GroupedProduct\Model\ResourceModel\Product\Link::getParentIdsByChild 114 | * 115 | * @param array $childIds 116 | * @return array 117 | */ 118 | public function getGroupedProductParentIds(array $childIds) 119 | { 120 | $childToParentIds = []; 121 | 122 | $connection = $this->getConnection(); 123 | $metadata = $this->metadataPool->getMetadata(ProductInterface::class); 124 | $linkField = htmlspecialchars($metadata->getLinkField()); 125 | $select = $connection->select() 126 | ->from( 127 | ['link_table' => $connection->getTableName('catalog_product_link')], 128 | ['link_id', 'linked_product_id'] 129 | )->join( 130 | ['e' => $this->metadataPool->getMetadata(ProductInterface::class)->getEntityTable()], 131 | 'e.' . $linkField . ' = link_table.product_id', 132 | ['e.entity_id'] 133 | )->where( 134 | 'link_type_id = ?', 135 | \Magento\GroupedProduct\Model\ResourceModel\Product\Link::LINK_TYPE_GROUPED 136 | ) 137 | ->where( 138 | 'link_table.linked_product_id IN(?)', 139 | $childIds 140 | )->order( 141 | 'link_id ASC' 142 | ); 143 | 144 | $result = $connection->fetchAll($select); 145 | 146 | foreach ($result as $_row) { 147 | $childToParentIds[$_row['linked_product_id']] = $_row['entity_id']; 148 | } 149 | 150 | return $childToParentIds; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Plugin/BaseController.php: -------------------------------------------------------------------------------- 1 | overrideHelper = $overrideHelper; 26 | $this->resultJsonFactory = $resultJsonFactory; 27 | $this->request = $request; 28 | } 29 | 30 | /** 31 | * @param $subject 32 | * @param $proceed 33 | * @param $request 34 | * @return Json 35 | */ 36 | public function aroundDispatch($subject, $proceed, $request) 37 | { 38 | // Override PHP limits if configured to do so 39 | $this->overrideHelper->overridePHPLimits(); 40 | 41 | $result = $this->resultJsonFactory->create(); 42 | 43 | try { 44 | $result = $proceed($request); 45 | } catch (\Exception $e) { 46 | $result = $this->resultJsonFactory->create(); 47 | $result->setData(['error' => get_class($e)." code ".$e->getCode() . 48 | " in " . basename($e->getFile()) . " line " . $e->getLine() ]); 49 | } 50 | 51 | return $result; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Plugin/Magento/Checkout/Controller/Cart/CouponPost.php: -------------------------------------------------------------------------------- 1 | dateManager = $dateManager; 17 | $this->request = $request; 18 | $this->couponFactory = $couponFactory; 19 | } 20 | 21 | public function beforeExecute($subject) 22 | { 23 | if($this->request->getParam('remove') !== '0' && $this->request->getParam('remove') !== null) 24 | { 25 | return; 26 | } 27 | 28 | $coupon = $this->couponFactory->create()->loadByCode($this->request->getParam('coupon_code')); 29 | if(!$coupon->getData('expiration_date')) 30 | { 31 | return; 32 | } 33 | 34 | $expiration_date = $coupon->getData('expiration_date'); 35 | 36 | if(strToTime($this->dateManager->date()) < strToTime($expiration_date)) 37 | { 38 | return; 39 | } 40 | 41 | //we've got an expired coupon here 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/Test/Integration/ProductTest.php: -------------------------------------------------------------------------------- 1 | hash = $this->_objectManager->create(Hash::class); 28 | } 29 | 30 | /** 31 | * @magentoConfigFixture current_store ometria/general/apikey test-public-key 32 | * @magentoConfigFixture current_store ometria/general/privatekey test-private-key 33 | * @magentoConfigFixture current_store ometria/advanced/preferred_product_attribute preferred_product_sku 34 | * @magentoDataFixture Magento/Catalog/_files/multiple_mixed_products_2.php 35 | */ 36 | public function testProductV1() 37 | { 38 | $url = $this->getSignedUrl( 39 | self::PRODUCT_V1_PATH . '?final_price=true&listing=true' 40 | ); 41 | 42 | $this->getRequest()->setMethod(Request::METHOD_GET); 43 | $this->dispatch($url); 44 | 45 | $this->assertSame(200, $this->getResponse()->getHttpResponseCode()); 46 | $this->assertJson($this->getResponse()->getContent()); 47 | $this->assertContains('Configurable Product 12345', $this->getResponse()->getContent()); 48 | 49 | return $this->getResponse(); 50 | } 51 | 52 | /** 53 | * @magentoConfigFixture current_store ometria/general/apikey test-public-key 54 | * @magentoConfigFixture current_store ometria/general/privatekey test-private-key 55 | * @magentoConfigFixture current_store ometria/advanced/preferred_product_attribute preferred_product_sku 56 | * @magentoDataFixture Magento/Catalog/_files/multiple_mixed_products_2.php 57 | */ 58 | public function testProductV2() 59 | { 60 | $url = $this->getSignedUrl( 61 | self::PRODUCT_V2_PATH . '?listing=true' 62 | ); 63 | 64 | $this->getRequest()->setMethod(Request::METHOD_GET); 65 | $this->dispatch($url); 66 | 67 | $this->assertSame(200, $this->getResponse()->getHttpResponseCode()); 68 | $this->assertJson($this->getResponse()->getContent()); 69 | $this->assertContains('Configurable Product 12345', $this->getResponse()->getContent()); 70 | 71 | return $this->getResponse(); 72 | } 73 | 74 | /** 75 | * @depends testProductV1 76 | * @depends testProductV2 77 | */ 78 | public function testCompareV1andV2Response(\Magento\Framework\App\Response\Http $productResponseV1, $productResponseV2) 79 | { 80 | $productsV1 = $this->removeUntestableData($productResponseV1->getContent()); 81 | $productsV2 = $this->removeUntestableData($productResponseV2->getContent()); 82 | 83 | $this->assertJsonStringEqualsJsonString($productsV1, $productsV2); 84 | } 85 | 86 | /** 87 | * Manipulate the data to remove elements which are untestable between the V1 and V2 APIs 88 | * 89 | * @param $products 90 | * @return false|string 91 | */ 92 | private function removeUntestableData($products) 93 | { 94 | $json = json_decode($products, true); 95 | 96 | foreach ($json as &$product) { 97 | /** 98 | * Due to the Magento testing framework creating new attributes for each test, the auto increment IDs will show as a 99 | * difference in the response. For this reason the IDs are set to 0 here for the configurable attributes that would 100 | * exhibit this issue. 101 | */ 102 | foreach ($product['attributes'] as &$attribute) { 103 | if ($attribute['type'] = 'test_configurable') { 104 | $attribute['id'] = 0; 105 | } 106 | } 107 | 108 | /** 109 | * Unset tax and final_price_incl_tax values that are only present in V2 API 110 | */ 111 | unset($product[ProductInterface::FINAL_PRICE_INCL_TAX]); 112 | unset($product[ProductInterface::TAX_AMOUNT]); 113 | } 114 | 115 | return json_encode($json); 116 | } 117 | 118 | /** 119 | * @param $url 120 | * @param $data 121 | * @return string 122 | */ 123 | private function getSignedUrl($url) 124 | { 125 | $time = time(); 126 | $parsedUrl = parse_url($url); 127 | 128 | $data = [ 129 | 'request_timestamp' => $time 130 | ]; 131 | 132 | if (isset($parsedUrl['query'])) { 133 | foreach (explode('&', $parsedUrl['query']) as $param) { 134 | list($key, $value) = explode('=', $param); 135 | $data[$key] = $value; 136 | } 137 | } 138 | 139 | $signature = $this->hash->signRequest( 140 | 'localhost', 141 | 'products', 142 | 'test-public-key', 143 | 'test-private-key', 144 | $data 145 | ); 146 | 147 | $data['signature'] = $signature; 148 | 149 | return sprintf('%s?%s', 150 | $parsedUrl['path'], 151 | http_build_query($data) 152 | ); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/etc/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/code/Ometria/Api/registration.php: -------------------------------------------------------------------------------- 1 | setData('disabled','disabled'); 8 | return parent::getHtml(); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/Config.php: -------------------------------------------------------------------------------- 1 | coreHelperMageConfig = $coreHelperMageConfig; 23 | $this->logger = $context->getLogger(); 24 | } 25 | 26 | public function isEnabled() 27 | { 28 | return $this->coreHelperMageConfig->get('ometria/general/enabled'); 29 | } 30 | 31 | public function isDebugMode() 32 | { 33 | return $this->coreHelperMageConfig->get('ometria/advanced/debug'); 34 | } 35 | 36 | // Is data layer configured? 37 | public function isUnivarEnabled() 38 | { 39 | return $this->coreHelperMageConfig->get('ometria/advanced/univar'); 40 | } 41 | 42 | public function isPingEnabled() 43 | { 44 | return $this->coreHelperMageConfig->get('ometria/advanced/ping'); 45 | } 46 | 47 | public function isScriptDeferred() 48 | { 49 | return $this->coreHelperMageConfig->get('ometria/advanced/scriptload'); 50 | } 51 | 52 | public function getAPIKey($store_id = null) 53 | { 54 | if ($store_id) { 55 | return $this->coreHelperMageConfig->get('ometria/general/apikey', $store_id); 56 | } else { 57 | return $this->coreHelperMageConfig->get('ometria/general/apikey'); 58 | } 59 | } 60 | 61 | /** 62 | * @return string 63 | */ 64 | public function getPushAPIKey() 65 | { 66 | return (string) $this->scopeConfig->getValue( 67 | 'ometria/general/pushapikey', 68 | ScopeInterface::SCOPE_STORE 69 | ); 70 | } 71 | 72 | public function isConfigured() 73 | { 74 | return $this->isEnabled() && $this->getAPIKey() != ""; 75 | } 76 | 77 | public function log($message, $level = \Psr\Log\LogLevel::DEBUG) 78 | { 79 | $this->logger->log($level, $message); 80 | } 81 | 82 | public function isSkuMode() 83 | { 84 | return $this->coreHelperMageConfig->get('ometria/advanced/productmode') == 'sku'; 85 | } 86 | 87 | /** 88 | * @return bool 89 | */ 90 | public function canUseConfigurableImage() 91 | { 92 | return (bool) $this->coreHelperMageConfig->get('ometria/advanced/use_configurable_image'); 93 | } 94 | 95 | /** 96 | * @return string 97 | */ 98 | public function getPreferredProductAttribute() 99 | { 100 | return (string) $this->coreHelperMageConfig->get('ometria/advanced/preferred_product_attribute'); 101 | } 102 | 103 | /** 104 | * @return string 105 | */ 106 | public function getStockPushScope() 107 | { 108 | return (string) $this->coreHelperMageConfig->get('ometria/advanced/stock_push_scope'); 109 | } 110 | 111 | /** 112 | * @return bool 113 | */ 114 | public function isCookiebotEnabled() 115 | { 116 | return (bool) $this->coreHelperMageConfig->get('ometria/advanced/enable_cookiebot'); 117 | } 118 | 119 | /** 120 | * @return string 121 | */ 122 | public function getCookiebotClass() 123 | { 124 | return (string) $this->coreHelperMageConfig->get('ometria/advanced/cookiebot_classification'); 125 | } 126 | 127 | /** 128 | * @param null 129 | * @return string 130 | */ 131 | public function getLogConfig() 132 | { 133 | $statusLogValue = $this->scopeConfig->getValue('ometria/advanced/show_log'); 134 | return $statusLogValue; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/Cookiechannel.php: -------------------------------------------------------------------------------- 1 | helperConfig = $helperConfig; 36 | $this->frontendAreaChecker = $frontendAreaChecker; 37 | 38 | return parent::__construct($context); 39 | } 40 | 41 | /** 42 | * @param $command 43 | * @param bool $replaceIfExists 44 | */ 45 | public function addCommand($command, bool $replaceIfExists = false) 46 | { 47 | if (!$command || !is_array($command)) { 48 | return; 49 | } 50 | 51 | // Return if admin area or API call 52 | if(!$this->frontendAreaChecker->check()) { 53 | return; 54 | } 55 | 56 | if (!$this->helperConfig->isConfigured()) { 57 | return; 58 | } 59 | 60 | if (!$this->helperConfig->isUnivarEnabled()) { 61 | return; 62 | } 63 | 64 | if ($command[0] === 'identify') { 65 | $command[1] = ''; 66 | } 67 | 68 | $str = implode(self::SEPERATOR_IN_COMMANDS, $command); 69 | 70 | $this->appendCookieCommand($command[0], $str, $replaceIfExists); 71 | } 72 | 73 | /** 74 | * @param $commandName 75 | * @param $str 76 | * @param bool $replaceIfExists 77 | */ 78 | private function appendCookieCommand($commandName, $str, bool $replaceIfExists = false) 79 | { 80 | $existingCookie = isset($_COOKIE[self::COOKIE_NAME]) ? $_COOKIE[self::COOKIE_NAME] : ''; 81 | $commands = explode(self::SEPERATOR_BETWEEN_COMMANDS, $existingCookie); 82 | $newCookie = ''; 83 | 84 | if ($replaceIfExists && $commands) { 85 | $commandsFiltered = array(); 86 | foreach($commands as $command){ 87 | if (strpos($command, $commandName . self::SEPERATOR_IN_COMMANDS) !== 0) { 88 | $commandsFiltered[] = $command; 89 | } 90 | } 91 | $commands = $commandsFiltered; 92 | $commands = array_filter($commands); 93 | } 94 | 95 | $commands[] = $str; 96 | if (count($commands) > 6) { 97 | $commands = array_slice($commands, 0, 6); 98 | } 99 | 100 | $commands = array_unique($commands); 101 | $commands = array_filter($commands); 102 | $commands = array_values($commands); 103 | sort($commands); 104 | $commands = array_values($commands); 105 | 106 | $newCookie = implode(self::SEPERATOR_BETWEEN_COMMANDS, $commands); 107 | if (strlen($newCookie) > 1000) { 108 | $newCookie = ''; 109 | } 110 | 111 | if (!headers_sent() && ($newCookie != $existingCookie)) { 112 | $this->cookieDidChange = true; 113 | $_COOKIE[self::COOKIE_NAME] = $newCookie; 114 | 115 | $this->sendCookie(); 116 | } 117 | } 118 | 119 | public function sendCookie() 120 | { 121 | if (!$this->cookieDidChange) { 122 | return; 123 | } 124 | 125 | if ($this->helperConfig->isCookiebotEnabled() && $this->cookiebotCookieAllowed() === false) { 126 | return; 127 | } 128 | 129 | $cookie = isset($_COOKIE[self::COOKIE_NAME]) ? $_COOKIE[self::COOKIE_NAME] : ''; 130 | setcookie(self::COOKIE_NAME, $cookie, 0, '/'); 131 | $this->cookieDidChange = false; 132 | } 133 | 134 | /** 135 | * @return bool 136 | */ 137 | private function cookiebotCookieAllowed() 138 | { 139 | $cookieAllowed = false; 140 | 141 | if (isset($_COOKIE[self::COOKIEBOT_COOKIE_NAME])) { 142 | switch ($_COOKIE[self::COOKIEBOT_COOKIE_NAME]) { 143 | case "-1": 144 | //The user is not within a region that requires consent - all cookies are accepted 145 | $cookieAllowed = true; 146 | break; 147 | 148 | default: 149 | // The user must give their consent 150 | $cookieConsent = $this->getCookiebotConsent(); 151 | if ($cookieConsent) { 152 | $cookieClass = $this->helperConfig->getCookiebotClass(); 153 | // Consent cookie was found 154 | if (isset($cookieConsent[$cookieClass]) && filter_var($cookieConsent[$cookieClass], FILTER_VALIDATE_BOOLEAN)) { 155 | //Current user accepts Ometria cookies 156 | $cookieAllowed = true; 157 | } 158 | } 159 | break; 160 | } 161 | } 162 | 163 | return $cookieAllowed; 164 | } 165 | 166 | /** 167 | * Read current user consent in encoded JavaScript format from Cookiebot cookie 168 | * 169 | * @see https://www.cookiebot.com/en/developer/ 170 | * @return mixed 171 | */ 172 | private function getCookiebotConsent() 173 | { 174 | $json = preg_replace('/\s*:\s*([a-zA-Z0-9_]+?)([}\[,])/', 175 | ':"$1"$2', 176 | preg_replace('/([{\[,])\s*([a-zA-Z0-9_]+?):/', 177 | '$1"$2":', 178 | str_replace("'", 179 | '"', 180 | stripslashes($_COOKIE[self::COOKIEBOT_COOKIE_NAME]) 181 | ) 182 | ) 183 | ); 184 | return json_decode($json, true); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/Get/Request.php: -------------------------------------------------------------------------------- 1 | requestInterface = $requestInterface; 12 | } 13 | 14 | public function __call($method, $params) 15 | { 16 | return call_user_func_array([$this->requestInterface,$method], $params); 17 | } 18 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/Is/Frontend.php: -------------------------------------------------------------------------------- 1 | request = $request; 14 | $this->applicationState = $applicationState; 15 | } 16 | 17 | public function check() 18 | { 19 | /** 20 | * Orders are placed via the restful API in Magento's stock themes 21 | */ 22 | if( $this->request->getModuleName() !== 'ometria_api' && 23 | !in_array($this->applicationState->getAreaCode(), ['frontend', 'webapi_rest'])) 24 | { 25 | return false; 26 | } 27 | return true; 28 | } 29 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/MageConfig.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 12 | } 13 | 14 | public function get($path) 15 | { 16 | $parts = explode('/', $path); 17 | $top = array_shift($parts); 18 | $config = $this->scopeConfig->getValue( 19 | $top, 20 | ScopeInterface::SCOPE_STORE 21 | ); 22 | 23 | if($config === null) { 24 | return null; 25 | } 26 | 27 | foreach($parts as $part) { 28 | if(!array_key_exists($part, $config)) { 29 | return null; 30 | } 31 | $config = $config[$part]; 32 | } 33 | 34 | return $config; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/Ping.php: -------------------------------------------------------------------------------- 1 | helperConfig = $helperConfig; 21 | return parent::__construct($context); 22 | } 23 | 24 | public function sendPing($type, $ids, $extra=array(), $store_id=null){ 25 | //$ometriaConfigHelper = Mage::helper('ometria/config'); 26 | $ometriaConfigHelper = $this->helperConfig; 27 | 28 | if (!$ometriaConfigHelper->isConfigured()) { 29 | return false; 30 | } 31 | 32 | if (!$ometriaConfigHelper->isPingEnabled()) { 33 | return true; 34 | } 35 | 36 | if($ometriaConfigHelper->isDebugMode()) { 37 | if(is_array($ids)) { 38 | $ometriaConfigHelper->log("Sending ping. Type: ".$type." " . implode(',', $ids)); 39 | } else { 40 | $ometriaConfigHelper->log("Sending ping. Type: ".$type." " . $ids); 41 | } 42 | } 43 | 44 | $extra['account'] = $ometriaConfigHelper->getAPIKey($store_id); 45 | $extra['type'] = $type; 46 | $extra['id'] = $ids; 47 | 48 | return $this->_ping($extra); 49 | } 50 | 51 | /** 52 | * Helper function to ping ometria. Manually doing an fsockopen 53 | * so that we don't have to wait for a response. Unless debugging 54 | * when we do wait and log the content body. 55 | * 56 | * @param array $parameters 57 | * 58 | * @return bool 59 | */ 60 | protected function _ping($parameters = array()) { 61 | 62 | //file_put_contents('/tmp/ping', json_encode($parameters)."\n", FILE_APPEND); 63 | //return true; 64 | 65 | //$ometriaConfigHelper = Mage::helper('ometria/config'); 66 | $ometriaConfigHelper = $this->helperConfig; 67 | 68 | $content = http_build_query($parameters); 69 | $path = self::API_PATH; 70 | 71 | 72 | try { 73 | 74 | $fp = fsockopen(self::API_SOCKET_SCHEMA . self::API_HOST, 443, $errorNum, $errorStr, self::API_SOCKET_TIMEOUT); 75 | 76 | if($fp !== false) { 77 | 78 | $out = "POST $path HTTP/1.1\r\n"; 79 | $out .= "Host: " . self::API_HOST. "\r\n"; 80 | $out .= "Content-type: application/x-www-form-urlencoded\r\n"; 81 | $out .= "Content-Length: " . strlen($content) . "\r\n"; 82 | $out .= "Connection: Close\r\n\r\n"; 83 | $out .= $content; 84 | 85 | fwrite($fp, $out); 86 | 87 | // If debug mode, wait for response and log 88 | if($ometriaConfigHelper->isDebugMode()) { 89 | 90 | $responseHeader = ""; 91 | do { 92 | $responseHeader .= fgets($fp, 1024); 93 | } while(strpos($responseHeader, "\r\n\r\n") === false); 94 | 95 | $response = ""; 96 | while (!feof($fp)) { 97 | $response .= fgets($fp, 1024); 98 | } 99 | 100 | $ometriaConfigHelper->log($response); 101 | } 102 | 103 | fclose($fp); 104 | } else { 105 | $ometriaConfigHelper->log("Ping failed: Error $errorNum - $errorStr", \Zend_Log::ERR); 106 | return false; 107 | } 108 | } catch (\Exception $e) { 109 | $ometriaConfigHelper->log($e->getMessage()); 110 | return false; 111 | } 112 | 113 | return true; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/Product.php: -------------------------------------------------------------------------------- 1 | productRepository = $productRepository; 40 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 41 | $this->helperConfig = $helperConfig; 42 | return parent::__construct($context); 43 | } 44 | 45 | public function getIdentifierForProduct($product) { 46 | if (!$product) return null; 47 | 48 | if ($this->helperConfig->isSkuMode()) { 49 | return $product->getSku(); 50 | } else { 51 | return $product->getId(); 52 | } 53 | } 54 | 55 | public function getIdentifiersForProducts($products) { 56 | $is_sku_mode = $this->helperConfig->isSkuMode(); 57 | 58 | $ret = array(); 59 | foreach($products as $product){ 60 | if ($is_sku_mode) { 61 | $ret[] = $product->getSku(); 62 | } else { 63 | $ret[] = $product->getId(); 64 | } 65 | } 66 | 67 | return $ret; 68 | 69 | } 70 | 71 | public function convertProductIdsIfNeeded($ids){ 72 | 73 | if (!$this->helperConfig->isSkuMode()) { 74 | return $ids; 75 | } 76 | 77 | if (!$ids) return $ids; 78 | 79 | $was_array = is_array($ids); 80 | if (!is_array($ids)) $ids = array($ids); 81 | 82 | $products_collection = Mage::getModel('catalog/product') 83 | ->getCollection() 84 | ->addAttributeToFilter('entity_id', array('in' => $ids)); 85 | 86 | $skus = array(); 87 | foreach($products_collection as $product) { 88 | $skus[] = $product->getSku(); 89 | $product->clearInstance(); 90 | } 91 | 92 | if (!$was_array) { 93 | return count($skus)>0 ? $skus[0] : null; 94 | } else { 95 | return $skus; 96 | } 97 | } 98 | 99 | public function getProductByIdentifier($id){ 100 | $product_model = Mage::getModel('catalog/product'); 101 | 102 | if ($this->helperConfig->isSkuMode()){ 103 | return $product_model->load($product_model->getIdBySku($id)); 104 | } else { 105 | return $product_model->load($id); 106 | } 107 | } 108 | 109 | /** 110 | * @param $product 111 | * @param string $imageId 112 | * @param bool $usePreferredProduct 113 | * @return mixed|null 114 | * @throws \Exception 115 | */ 116 | public function getProductImageUrl($product, $imageId = 'image', $usePreferredProduct = true) 117 | { 118 | if ($usePreferredProduct && $product->getTypeId() == Configurable::TYPE_CODE) { 119 | return $this->getPreferredProductImageUrl($product, $imageId); 120 | } 121 | 122 | // Return the relevant image URL for the requested image type (image, small_image, thumbnail, etc) 123 | $attribute = $product->getResource()->getAttribute($imageId); 124 | if ($product->getData($imageId) && $attribute) { 125 | return $attribute->getFrontend()->getUrl($product); 126 | } 127 | 128 | return null; 129 | } 130 | 131 | /** 132 | * @param ProductInterface $product 133 | * @param $imageId 134 | * @return mixed|null 135 | * @throws \Exception 136 | */ 137 | private function getPreferredProductImageUrl(ProductInterface $product, $imageId) 138 | { 139 | // Ensure this is a configurable product 140 | if ($product->getTypeId() != Configurable::TYPE_CODE) { 141 | throw new \Exception("Preferred product image is available for configurable products only"); 142 | } 143 | 144 | // Use the configurable's image if allowed and one is present 145 | if ($this->helperConfig->canUseConfigurableImage() && $product->getData($imageId)) { 146 | return $this->getProductImageUrl($product, $imageId, false); 147 | } 148 | 149 | // Use preferred product logic if configured 150 | $preferredProductAttribute = $this->helperConfig->getPreferredProductAttribute(); 151 | if ($preferredProductAttribute) { 152 | // Load preferred product variant if SKU is defined for this product 153 | $preferredProductSku = $product->getData($preferredProductAttribute); 154 | if ($preferredProductSku) { 155 | try { 156 | // Try to load the defined preferred product variant 157 | $preferredProduct = $this->productRepository->get($preferredProductSku); 158 | } 159 | catch (NoSuchEntityException $e) { 160 | // Prevent error if the preferred product no longer exists 161 | $preferredProduct = false; 162 | } 163 | 164 | // Try to use image of preferred product variant if it has one and is enabled and in stock 165 | if ($preferredProduct && $preferredProduct->isSalable() && $preferredProduct->getData($imageId)) { 166 | return $this->getProductImageUrl($preferredProduct, $imageId, false); 167 | } 168 | } 169 | 170 | // If preferred product is not set, has no stock or has no image then try to use any enabled, in-stock 171 | // variant with an image as the preferred product instead 172 | $preferredProduct = $this->getActiveInStockVariantWithImage($product); 173 | if ($preferredProduct) { 174 | return $this->getProductImageUrl($preferredProduct, $imageId, false); 175 | } 176 | } 177 | 178 | // Default to using the configurable product's image 179 | $attribute = $product->getResource()->getAttribute($imageId); 180 | if ($product->getData($imageId) && $attribute) { 181 | return $attribute->getFrontend()->getUrl($product); 182 | } 183 | 184 | // No valid image could be found 185 | return null; 186 | } 187 | 188 | /** 189 | * @param $product 190 | * @param string $imageId 191 | * @return string|null 192 | */ 193 | public function getProductImageUrlV2($product, $imageId = 'image') 194 | { 195 | $imageUrl = null; 196 | 197 | $attribute = $product->getResource()->getAttribute($imageId); 198 | if ($product->getData($imageId) && $attribute) { 199 | $imageUrl = (string) $attribute->getFrontend()->getUrl($product); 200 | } 201 | 202 | return $imageUrl; 203 | } 204 | 205 | /** 206 | * @param ProductInterface $product 207 | * @param $imageId 208 | * @param false $preferredProduct 209 | * @return string|null 210 | */ 211 | public function getPreferredProductImageUrlV2(ProductInterface $product, $imageId, $preferredProduct = false) 212 | { 213 | // Use the configurable's image if allowed and one is present 214 | if ($this->helperConfig->canUseConfigurableImage() && $product->getData($imageId)) { 215 | return $this->getProductImageUrlV2($product, $imageId); 216 | } 217 | 218 | // Try to use image of preferred product variant if it has one and is enabled and in stock 219 | if ($preferredProduct && 220 | $preferredProduct->isSalable() && 221 | $preferredProduct->getData($imageId)) { 222 | return $this->getProductImageUrlV2($preferredProduct, $imageId); 223 | } 224 | 225 | // If preferred product is not set, has no stock or has no image then try to use any enabled, in-stock 226 | // variant with an image as the preferred product instead 227 | $preferredProduct = $this->getActiveInStockVariantWithImage($product); 228 | if ($preferredProduct) { 229 | return $this->getProductImageUrlV2($preferredProduct, $imageId); 230 | } 231 | 232 | // Default to trying to use the configurable product's image regardless of UseConfigurableImage config 233 | return $this->getProductImageUrlV2($product, $imageId); 234 | } 235 | 236 | /** 237 | * Find a child product which is enabled, in stock and has an image 238 | * @param ProductInterface $product 239 | * @return ProductInterface | bool 240 | */ 241 | private function getActiveInStockVariantWithImage(ProductInterface $product) 242 | { 243 | $childProducts = $product->getTypeInstance() 244 | ->getUsedProductCollection($product) 245 | ->addAttributeToFilter('is_saleable', ['eq' => 1]); 246 | 247 | if ($childProducts) { 248 | // Add media gallery data to collection 249 | $childProducts->addMediaGalleryData(); 250 | 251 | // Can't filter by has image, so loop and return first product with an image 252 | foreach ($childProducts as $childProduct) { 253 | if ($childProduct->getMediaGalleryImages()->getSize() > 0) { 254 | return $childProduct; 255 | } 256 | } 257 | } 258 | 259 | return false; 260 | } 261 | 262 | /** 263 | * @param \Magento\Catalog\Model\Product $product 264 | * @return bool 265 | */ 266 | public function canShowProductPrice($product) 267 | { 268 | // Grouped products have no price themselves, so can't show a price for this product type 269 | if ($product->getTypeId() == \Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE) { 270 | return false; 271 | } 272 | 273 | return true; 274 | } 275 | 276 | /** 277 | * @param \Magento\Catalog\Model\Product $product 278 | * @return mixed 279 | */ 280 | public function getProductFinalPrice($product) 281 | { 282 | return $product->getPriceInfo()->getPrice('final_price')->getAmount()->getValue(); 283 | } 284 | 285 | /** 286 | * @param \Magento\Catalog\Model\Product $product 287 | * @return mixed 288 | */ 289 | public function getProductRegularPrice($product) 290 | { 291 | return $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue(); 292 | } 293 | 294 | /** 295 | * @return string 296 | */ 297 | public function getPreferredProductAttribute() 298 | { 299 | return $this->helperConfig->getPreferredProductAttribute(); 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Helper/Session.php: -------------------------------------------------------------------------------- 1 | searchCriteriaBuilder = $searchCriteriaBuilder; 26 | $this->attributeRepository = $attributeRepository; 27 | } 28 | 29 | /** 30 | * @return array 31 | */ 32 | public function toOptionArray() 33 | { 34 | $optionArray = ['label' => '-- Not Set --', 'value' => '']; 35 | 36 | foreach ($this->getViableAttributes() as $viableAttribute) { 37 | $optionArray[] = [ 38 | 'value' => $viableAttribute->getAttributeCode(), 39 | 'label' => $viableAttribute->getDefaultFrontendLabel() 40 | ]; 41 | } 42 | 43 | return $optionArray; 44 | } 45 | 46 | /** 47 | * @return ProductAttributeInterface[] 48 | */ 49 | private function getViableAttributes() 50 | { 51 | $searchCriteria = $this->searchCriteriaBuilder->create(); 52 | 53 | $attributeList = $this->attributeRepository->getList( 54 | $searchCriteria 55 | ); 56 | 57 | return $attributeList->getItems(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Config/Source/StockPushScope.php: -------------------------------------------------------------------------------- 1 | self::SCOPE_DISABLED, 'label' => __('Disabled')], 20 | ['value' => self::SCOPE_GLOBAL, 'label' => __('Global')], 21 | ['value' => self::SCOPE_CHANNEL, 'label' => __('Sales Channel')] 22 | ]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/ConfigSourceProductIdentifierMode.php: -------------------------------------------------------------------------------- 1 | 'id', 'label' => __('Product ID')], 9 | ['value' => 'sku', 'label' => __('Product SKU')] 10 | ]; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Cart.php: -------------------------------------------------------------------------------- 1 | frontendAreaChecker = $frontendAreaChecker; 31 | $this->helperProduct = $helperProduct; 32 | $this->helperCookiechannel = $helperCookiechannel; 33 | $this->cartModel = $cartModel; 34 | $this->productFactory = $productFactory; 35 | $this->storeManager = $storeManager; 36 | $this->helperPing = $helperPing; 37 | $this->helperSession = $helperSession; 38 | $this->helperConfig = $helperConfig; 39 | } 40 | 41 | public function basketUpdated(Observer $observer){ 42 | // Return if admin area or API call 43 | // if (Mage::app()->getStore()->isAdmin()) return; 44 | // if (Mage::getSingleton('api/server')->getAdapter() != null) return; 45 | if(!$this->frontendAreaChecker->check()) 46 | { 47 | return; 48 | } 49 | 50 | $this->updateBasketCookie(); 51 | } 52 | 53 | public function updateBasketCookie() { 54 | 55 | //$ometria_product_helper = Mage::helper('ometria/product'); 56 | //$ometria_cookiechannel_helper = Mage::helper('ometria/cookiechannel'); 57 | 58 | $ometria_product_helper = $this->helperProduct; 59 | $ometria_cookiechannel_helper = $this->helperCookiechannel; 60 | 61 | // $cart = Mage::getModel('checkout/cart')->getQuote(); 62 | $cart = $this->cartModel->getQuote(); 63 | 64 | // For newly created carts, reload the model to get created_at value added by database 65 | if ($cart->getCreatedAt() == null) { 66 | $cart = $cart->load($cart->getId()); 67 | } 68 | 69 | $cart_token = substr(md5($cart->getCreatedAt().$cart->getId()),0,12); 70 | 71 | $command = array( 72 | 'basket', 73 | $cart->getId(), 74 | $cart->getGrandTotal(), 75 | $this->storeManager->getStore()->getCurrentCurrencyCode(), 76 | $cart_token 77 | ); 78 | 79 | $count = 0; 80 | foreach($cart->getAllVisibleItems() as $item){ 81 | //$product = Mage::getModel('catalog/product')->load($item->getProductId()); 82 | $product = $this->productFactory->create()->load($this->getMasterProductId($item)); 83 | $buffer = array( 84 | 'i'=>$ometria_product_helper->getIdentifierForProduct($product), 85 | //'s'=>$product->getSku(), 86 | 'v'=>$item->getSku(), 87 | 'q'=>(int) $item->getQty(), 88 | 't'=>(float) $item->getRowTotalInclTax() 89 | ); 90 | $command_part = http_build_query($buffer); 91 | $command[] = $command_part; 92 | 93 | $count++; 94 | if ($count>30) break; // Prevent overly long cookies 95 | } 96 | 97 | $ometria_cookiechannel_helper->addCommand($command, true); 98 | 99 | // Identify if needed 100 | if ($cart->getCustomerEmail()) { 101 | $identify_type = 'checkout_billing'; 102 | $data = array('e'=>$cart->getCustomerEmail()); 103 | $command = array('identify', $identify_type, http_build_query($data)); 104 | $ometria_cookiechannel_helper->addCommand($command, true); 105 | } 106 | 107 | return $this; 108 | } 109 | 110 | public function orderPlaced(Observer $observer){ 111 | 112 | $ometria_session_helper = $this->helperSession; 113 | $ometria_cookiechannel_helper = $this->helperCookiechannel; 114 | 115 | try{ 116 | $ometria_ping_helper = $this->helperPing; 117 | $order = $observer->getEvent()->getOrder(); 118 | if(!$order) { return; } 119 | 120 | $session_id = $ometria_session_helper->getSessionId(); 121 | if ($session_id) { 122 | $ometria_ping_helper->sendPing('transaction', $order->getIncrementId(), array('session'=>$session_id), $order->getStoreId()); 123 | } 124 | $ometria_cookiechannel_helper->addCommand(array('trans', $order->getIncrementId())); 125 | 126 | // If via front end, also identify via cookie channel (but do not replace if customer login has done it) 127 | $is_frontend = $this->frontendAreaChecker->check(); 128 | if ($is_frontend){ 129 | $ometria_cookiechannel_helper = $this->helperCookiechannel; 130 | 131 | //assume guest checkout 132 | $identify_type = 'guest_checkout'; 133 | $data = array('e'=>$order->getCustomerEmail()); 134 | 135 | //if we can get a customer from the order, override above 136 | $customer = $order->getCustomer(); 137 | if ($customer) { 138 | $identify_type = 'checkout'; 139 | $data = array('e'=>$customer->getEmail(),'i'=>$customer->getId()); 140 | } 141 | 142 | $command = array('identify', $identify_type, http_build_query($data)); 143 | $ometria_cookiechannel_helper->addCommand($command, true); 144 | } 145 | } catch(Exception $e){ 146 | $this->helperConfig->log($e->getMessage() . ' in ' . __METHOD__); 147 | } 148 | } 149 | 150 | /** 151 | * @param \Magento\Quote\Model\Quote\Item $item 152 | * @return int 153 | */ 154 | protected function getMasterProductId($item) 155 | { 156 | $productIdToLoad = $item->getProductId(); 157 | 158 | // for Grouped Products, use the Parent Product ID instead of the Child ID 159 | $superProductConfig = $item->getBuyRequest()->getData('super_product_config'); 160 | if ( 161 | is_array($superProductConfig) 162 | && array_key_exists('product_type', $superProductConfig) 163 | && $superProductConfig['product_type'] == \Magento\GroupedProduct\Model\Product\Type\Grouped::TYPE_CODE 164 | ) { 165 | $productIdToLoad = !empty($superProductConfig['product_id']) 166 | ? $superProductConfig['product_id'] 167 | : $productIdToLoad; 168 | } 169 | 170 | // For configurable products use the Child Product ID instead of the Parent ID 171 | if ( 172 | $item->getProductType() == \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE 173 | ) { 174 | $childId = $item->getOptionByCode('simple_product')->getProduct()->getId(); 175 | $productIdToLoad = !empty($childId) ? $childId : $productIdToLoad; 176 | } 177 | 178 | return $productIdToLoad; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Cart/BasketUpdated.php: -------------------------------------------------------------------------------- 1 | basketUpdated($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Cart/OrderPlaced.php: -------------------------------------------------------------------------------- 1 | orderPlaced($observer); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Customer.php: -------------------------------------------------------------------------------- 1 | helperPing = $helperPing; 18 | $this->helperCookiechannel = $helperCookiechannel; 19 | $this->customerSession = $customerSession; 20 | } 21 | 22 | public function customerSaveAfter($observer) { 23 | $ometria_ping_helper = $this->helperPing; 24 | $customer = $observer->getEvent()->getCustomer(); 25 | $ometria_ping_helper->sendPing('customer', $customer->getId(), array(), $customer->getStoreId()); 26 | 27 | return $this; 28 | } 29 | 30 | public function loggedOut($observer){ 31 | $this->identify('logout'); 32 | } 33 | 34 | public function loggedIn($observer){ 35 | $this->identify('login'); 36 | } 37 | 38 | public function registered($observer){ 39 | $this->did_register = true; 40 | $this->identify('register'); 41 | } 42 | 43 | protected function identify($event){ 44 | //$ometria_cookiechannel_helper = Mage::helper('ometria/cookiechannel'); 45 | $ometria_cookiechannel_helper = $this->helperCookiechannel; 46 | if ($this->did_register && $event=='login') { 47 | $event = 'register'; 48 | } 49 | 50 | 51 | //$customer = Mage::getSingleton('customer/session')->getCustomer(); 52 | $customer = $this->customerSession->getCustomer(); 53 | 54 | //if (!$customer) return; 55 | $data = array('e'=>$customer->getEmail(),'i'=>$customer->getId()); 56 | $command = array('identify', $event, http_build_query($data)); 57 | 58 | $ometria_cookiechannel_helper->addCommand($command, true); 59 | } 60 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Customer/CustomerSaveAfter.php: -------------------------------------------------------------------------------- 1 | customerSaveAfter($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Customer/LoggedIn.php: -------------------------------------------------------------------------------- 1 | loggedIn($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Customer/LoggedOut.php: -------------------------------------------------------------------------------- 1 | loggedOut($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Customer/Registered.php: -------------------------------------------------------------------------------- 1 | registered($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Newsletter.php: -------------------------------------------------------------------------------- 1 | helperPing = $helperPing; 18 | $this->frontendAreaChecker = $frontendAreaChecker; 19 | $this->helperCookiechannel = $helperCookiechannel; 20 | } 21 | 22 | public function handleSubscriberUpdate(\Magento\Framework\Event\Observer $observer){ 23 | $ometria_ping_helper = $this->helperPing; 24 | 25 | $subscriber = $observer->getEvent()->getSubscriber(); 26 | 27 | $data = $subscriber->getData(); 28 | 29 | $original_data = $subscriber->getOrigData(); 30 | $status_change = false; 31 | if (!$original_data) { 32 | $status_change = true; 33 | } elseif (isset($original_data['subscriber_status'])) { 34 | $status_change = $data['subscriber_status'] != $original_data['subscriber_status']; 35 | } 36 | 37 | // Only if status has changed 38 | if ($status_change) { 39 | $event = null; 40 | if ($data['subscriber_status']==1) $event = 'newsletter_subscribed'; 41 | if ($data['subscriber_status']==3) $event = 'newsletter_unsubscribed'; 42 | if ($event) $ometria_ping_helper->sendPing($event, $subscriber->getEmail(), array('store_id'=>$subscriber->getStoreId()), $subscriber->getStoreId()); 43 | 44 | // Update timestamp column 45 | $subscriber->setData('change_status_at', date("Y-m-d H:i:s", time())); 46 | } 47 | 48 | // If via front end, also identify via cookie channel (but do not replace if customer login has done it) 49 | $is_frontend = true; 50 | if(!$this->frontendAreaChecker->check()) 51 | { 52 | $is_frontend = false; 53 | } 54 | if ($is_frontend){ 55 | $ometria_cookiechannel_helper = $this->helperCookiechannel; 56 | $data = array('e'=>$subscriber->getEmail()); 57 | $command = array('identify', 'newsletter', http_build_query($data)); 58 | $ometria_cookiechannel_helper->addCommand($command, false); 59 | } 60 | } 61 | 62 | public function handleSubscriberDeletion(\Magento\Framework\Event\Observer $observer){ 63 | $ometria_ping_helper = $this->helperPing; 64 | 65 | $subscriber = $observer->getEvent()->getSubscriber(); 66 | $ometria_ping_helper->sendPing('newsletter_unsubscribed', $subscriber->getEmail(), array('store_id'=>$subscriber->getStoreId()), $subscriber->getStoreId()); 67 | } 68 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Newsletter/HandleSubscriberDeletion.php: -------------------------------------------------------------------------------- 1 | handleSubscriberDeletion($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Newsletter/HandleSubscriberUpdate.php: -------------------------------------------------------------------------------- 1 | handleSubscriberUpdate($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Order.php: -------------------------------------------------------------------------------- 1 | helperPing = $helperPing; 12 | } 13 | 14 | /** 15 | * Sales Order After Save 16 | * 17 | * @param Varien_Event_Observer $observer 18 | * @return Ometria_Core_Model_Observer_Order 19 | */ 20 | public function salesOrderSaveAfter(\Magento\Framework\Event\Observer $observer) { 21 | $ometria_ping_helper = $this->helperPing; 22 | $order = $observer->getEvent()->getOrder(); 23 | $ometria_ping_helper->sendPing('transaction', $order->getIncrementId(), array(), $order->getStoreId()); 24 | 25 | return $this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Order/SalesOrderSaveAfter.php: -------------------------------------------------------------------------------- 1 | salesOrderSaveAfter($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Product.php: -------------------------------------------------------------------------------- 1 | catalogProductEditActionAttributeHelper = $catalogProductEditActionAttributeHelper; 31 | $this->helperPing = $helperPing; 32 | $this->helperProduct = $helperProduct; 33 | $this->helperRequest = $request; 34 | $this->configurableType = $configurableType; 35 | } 36 | 37 | /** 38 | * Catalog Product Delete After 39 | * 40 | * @param Varien_Event_Observer $observer 41 | * @return Ometria_Core_Model_Observer_Product 42 | */ 43 | public function catalogProductDeleteAfter(\Magento\Framework\Event\Observer $observer) { 44 | \Magento\Framework\Profiler::start("Ometria::" . __METHOD__); 45 | 46 | $product = $observer->getEvent()->getProduct(); 47 | $this->updateProducts($product->getId()); 48 | $this->updateAssociatedProducts($product->getId()); 49 | 50 | \Magento\Framework\Profiler::stop("Ometria::" . __METHOD__); 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * Catalog Product Save After 57 | * 58 | * @param Varien_Event_Observer $observer 59 | * @return Ometria_Core_Model_Observer_Product 60 | */ 61 | public function catalogProductSaveAfter(\Magento\Framework\Event\Observer $observer) { 62 | \Magento\Framework\Profiler::start("Ometria::" . __METHOD__); 63 | 64 | $product = $observer->getEvent()->getProduct(); 65 | $this->updateProducts($product->getId()); 66 | $this->updateAssociatedProducts($product->getId()); 67 | 68 | \Magento\Framework\Profiler::stop("Ometria::" . __METHOD__); 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Product Mass Action - Update Attributes 75 | * 76 | * @param Varien_Event_Observer $observer 77 | * @return Ometria_Core_Model_Observer_Product 78 | */ 79 | public function catalogProductUpdateAttributes(\Magento\Framework\Event\Observer $observer) { 80 | \Magento\Framework\Profiler::start("Ometria::" . __METHOD__); 81 | 82 | $productIds = $this->catalogProductEditActionAttributeHelper->getProductIds(); 83 | $this->updateProducts($productIds); 84 | $this->updateAssociatedProducts($productIds); 85 | 86 | \Magento\Framework\Profiler::stop("Ometria::" . __METHOD__); 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * Product Mass Action - Update Status 93 | * 94 | * @param Varien_Event_Observer $observer 95 | * @return Ometria_Core_Model_Observer_Product 96 | */ 97 | public function catalogProductUpdateStatus(\Magento\Framework\Event\Observer $observer) { 98 | \Magento\Framework\Profiler::start("Ometria::" . __METHOD__); 99 | 100 | //$productIds = Mage::app()->getFrontController()->getRequest()->getParam('product'); 101 | $productIds = $this->helperRequest->getParam('selected'); 102 | $this->updateProducts($productIds); 103 | $this->updateAssociatedProducts($productIds); 104 | 105 | \Magento\Framework\Profiler::stop("Ometria::" . __METHOD__); 106 | 107 | return $this; 108 | } 109 | 110 | 111 | /** 112 | * Pass product ids to Ometria API model 113 | * @param $ids 114 | */ 115 | private function updateProducts($ids) 116 | { 117 | $ids = $this->helperProduct->convertProductIdsIfNeeded($ids); 118 | $this->helperPing->sendPing('product', $ids); 119 | } 120 | 121 | /** 122 | * Pass product ids of parent configurables affected by updates to Ometria API model 123 | * @param $ids 124 | */ 125 | private function updateAssociatedProducts($ids) 126 | { 127 | $assocIds = array(); 128 | 129 | // Standardise product IDs to array 130 | if ( ! empty( $ids ) && ! is_array($ids) ) { 131 | $ids = explode(',', $ids); 132 | } 133 | 134 | // Check for configurable parent products affected 135 | if (is_array($ids) || is_object($ids)) { 136 | foreach ($ids as $id) { 137 | $parentIds = $this->configurableType->getParentIdsByChild($id); 138 | foreach ($parentIds as $parentId) { 139 | $assocIds[] = $parentId; 140 | } 141 | } 142 | } 143 | 144 | // Ping Ometria with unique parent Ids, if any 145 | if (count($assocIds)) { 146 | $assocIds = $this->helperProduct->convertProductIdsIfNeeded(array_unique($assocIds)); 147 | $this->helperPing->sendPing('product', $assocIds); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Product/CatalogProductDeleteAfter.php: -------------------------------------------------------------------------------- 1 | catalogProductDeleteAfter($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Product/CatalogProductSaveAfter.php: -------------------------------------------------------------------------------- 1 | catalogProductSaveAfter($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Product/CatalogProductUpdateAttributes.php: -------------------------------------------------------------------------------- 1 | catalogProductUpdateAttributes($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Model/Observer/Product/CatalogProductUpdateStatus.php: -------------------------------------------------------------------------------- 1 | catalogProductUpdateStatus($observer); 9 | } 10 | } -------------------------------------------------------------------------------- /app/code/Ometria/Core/Plugin/OrderManagementPlugin.php: -------------------------------------------------------------------------------- 1 | inventoryService = $inventoryService; 34 | $this->pushApiService = $pushApiService; 35 | $this->helperConfig = $helperConfig; 36 | } 37 | 38 | /** 39 | * Plugin to trigger webhook to Ometria where stock value reaches 0 for 40 | * an MSI sales channel after an order is placed. 41 | * 42 | * @param OrderManagementInterface $subject 43 | * @param $result 44 | * @param OrderInterface $order 45 | * @return mixed 46 | */ 47 | public function afterPlace(OrderManagementInterface $subject, $result, OrderInterface $order) 48 | { 49 | try { 50 | $this->sendPushNotifications($order); 51 | } catch (\Exception $e) { 52 | // Catch all errors to ensure this does not affect order placement 53 | } 54 | 55 | return $result; 56 | } 57 | 58 | /** 59 | * @param OrderInterface $order 60 | */ 61 | private function sendPushNotifications(OrderInterface $order) 62 | { 63 | $stockPushScope = $this->helperConfig->getStockPushScope(); 64 | 65 | if ($stockPushScope == StockPushScope::SCOPE_DISABLED) { 66 | // Return early if stock push disabled 67 | return; 68 | } 69 | 70 | foreach ($order->getItems() as $orderItem) { 71 | // Retrieve the salable qty of the product based on configured scope and after placing an order 72 | $salableQty = $this->getSalableQty( 73 | $orderItem->getProduct(), 74 | $stockPushScope 75 | ); 76 | 77 | // if salable qty is set to 0, then push the is_in_stock to false (null infers manage stock is disabled) 78 | if ($salableQty !== null && $salableQty == 0) { 79 | $stockData = $this->inventoryService->getPushApiStockData( 80 | (int)$orderItem->getProductId(), 81 | false 82 | ); 83 | 84 | $this->pushApiService->pushRequest($stockData); 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * @param ProductInterface $product 91 | * @param int $stockPushScope 92 | * @return float|null 93 | */ 94 | private function getSalableQty(ProductInterface $product, int $stockPushScope) 95 | { 96 | $salableQty = null; 97 | 98 | if ($stockPushScope == StockPushScope::SCOPE_GLOBAL) { 99 | // Get current salabale quantity (before order placement) 100 | $salableQty = $this->inventoryService->getGlobalSalableQuantity($product); 101 | } else if ($stockPushScope == StockPushScope::SCOPE_CHANNEL) { 102 | // Get current salabale quantity (before order placement) 103 | $salableQty = $this->inventoryService->getSalableQuantity($product); 104 | } 105 | 106 | return $salableQty; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Service/Customer/RewardPoints.php: -------------------------------------------------------------------------------- 1 | moduleManager = $moduleManager; 39 | } 40 | 41 | /** 42 | * @return bool 43 | */ 44 | public function isRewardsAvailable() 45 | { 46 | return $this->moduleManager->isEnabled('Magento_Reward'); 47 | } 48 | 49 | /** 50 | * @return RewardCollection 51 | */ 52 | public function getRewardPointsCollection() 53 | { 54 | /** @var RewardCollection $rewardCollection */ 55 | $rewardCollection = ObjectManager::getInstance()->get(RewardCollectionFactory::class)->create(); 56 | return $rewardCollection; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Service/Product/Inventory.php: -------------------------------------------------------------------------------- 1 | moduleManager = $moduleManager; 49 | $this->storeManager = $storeManager; 50 | } 51 | 52 | /** 53 | * @return bool 54 | */ 55 | public function isMSIAvailable() 56 | { 57 | return $this->moduleManager->isEnabled('Magento_Inventory'); 58 | } 59 | 60 | /** 61 | * @param ProductInterface $product 62 | * @return bool 63 | */ 64 | public function getStockStatus(ProductInterface $product) 65 | { 66 | if ($this->isMSIAvailable()) { 67 | return $this->getMSIStockStatus($product); 68 | } 69 | 70 | return $this->getLegacyStockStatus($product); 71 | } 72 | 73 | /** 74 | * Get the salable quantity of a product for current sales channel 75 | * 76 | * @param ProductInterface $product 77 | * @return float 78 | */ 79 | public function getSalableQuantity(ProductInterface $product) 80 | { 81 | if ($this->isMSIAvailable()) { 82 | return $this->getMSISalableQuantity($product); 83 | } 84 | 85 | return $this->getLegacySalableQuantity($product); 86 | } 87 | 88 | /** 89 | * Get global salable quantity of a product (all sales channels) 90 | * 91 | * @param ProductInterface $product 92 | * @return float|null 93 | * @throws InputException 94 | * @throws LocalizedException 95 | * @throws SkuIsNotAssignedToStockException 96 | */ 97 | public function getGlobalSalableQuantity(ProductInterface $product) 98 | { 99 | if ($this->isMSIAvailable()) { 100 | return $this->getMSIGlobalSalableQuantity($product); 101 | } 102 | 103 | return $this->getLegacySalableQuantity($product); 104 | } 105 | 106 | /** 107 | * @param int $id 108 | * @param bool $isInStock 109 | * @return array 110 | */ 111 | public function getPushApiStockData(int $id, bool $isInStock) 112 | { 113 | return [ 114 | [ 115 | "@type" => "product", 116 | "id" => $id, 117 | "is_in_stock" => $isInStock, 118 | "@merge" => true 119 | ] 120 | ]; 121 | } 122 | 123 | /** 124 | * @param ProductCollection $collection 125 | */ 126 | public function addLegacyStockFilterToCollection(ProductCollection $collection) 127 | { 128 | if (!$this->isMSIAvailable()) { 129 | /** @var StockHelper $stockHelper */ 130 | $stockHelper = ObjectManager::getInstance()->get(StockHelper::class); 131 | $stockHelper->addIsInStockFilterToCollection($collection); 132 | } 133 | } 134 | 135 | /** 136 | * @param ProductInterface $product 137 | * @param $stockId 138 | * @return bool 139 | */ 140 | private function getMSIStockStatus(ProductInterface $product) 141 | { 142 | /** @var IsProductSalableInterface $isProductSalable */ 143 | $isProductSalable = ObjectManager::getInstance()->get(IsProductSalableInterface::class); 144 | return $isProductSalable->execute($product->getSku(), $this->getMSIStockId()); 145 | } 146 | 147 | /** 148 | * @param ProductInterface $product 149 | * @param $stockId 150 | * @return float 151 | */ 152 | private function getMSISalableQuantity(ProductInterface $product) 153 | { 154 | /** @var GetProductSalableQtyInterface $getProductSalableQty */ 155 | $getProductSalableQty = ObjectManager::getInstance()->get(GetProductSalableQtyInterface::class); 156 | 157 | try { 158 | $qty = $getProductSalableQty->execute($product->getSku(), $this->getMSIStockId()); 159 | } catch (\Exception $e) { 160 | $qty = 0.; 161 | } 162 | 163 | return $qty; 164 | } 165 | 166 | /** 167 | * @param ProductInterface $product 168 | * @return float|null 169 | * @throws InputException 170 | * @throws LocalizedException 171 | * @throws SkuIsNotAssignedToStockException 172 | */ 173 | private function getMSIGlobalSalableQuantity(ProductInterface $product) 174 | { 175 | /** @var GetAssignedStockIdsBySku $getSalableQtyData */ 176 | $getAssignedStockIdsBySku = ObjectManager::getInstance()->get(GetAssignedStockIdsBySku::class); 177 | 178 | /** @var GetStockItemConfigurationInterface $getStockItemConfiguration */ 179 | $getStockItemConfiguration = ObjectManager::getInstance()->get(GetStockItemConfigurationInterface::class); 180 | 181 | /** @var GetProductSalableQtyInterface $getProductSalableQtyInterface */ 182 | $getProductSalableQty = ObjectManager::getInstance()->get(GetProductSalableQtyInterface::class); 183 | 184 | $qty = 0.; 185 | $stockIds = $getAssignedStockIdsBySku->execute($product->getSku()); 186 | 187 | foreach ($stockIds as $stockId) { 188 | $stockItemConfiguration = $getStockItemConfiguration->execute($product->getSku(), $stockId); 189 | $isManageStock = $stockItemConfiguration->isManageStock(); 190 | 191 | if (!$isManageStock) { 192 | // Explicitly return null here to show 'manage stock' disabled rather than zero stock 193 | return null; 194 | } 195 | 196 | try { 197 | // Try to get qty for current stock ID 198 | $qtyForStockId = $getProductSalableQty->execute($product->getSku(), $stockId); 199 | } catch (InputException $e) { 200 | // Catch exception for invalid product types 201 | $qtyForStockId = 0; 202 | } 203 | 204 | $qty += $qtyForStockId; 205 | } 206 | 207 | return $qty; 208 | } 209 | 210 | /** 211 | * @return int|null 212 | * @throws LocalizedException 213 | * @throws NoSuchEntityException 214 | */ 215 | private function getMSIStockId() 216 | { 217 | if (!$this->stockId) { 218 | $websiteCode = $this->storeManager->getWebsite()->getCode(); 219 | 220 | /** @var StockResolverInterface $stockResolver */ 221 | $stockResolver = ObjectManager::getInstance()->get(StockResolverInterface::class); 222 | 223 | $this->stockId = $stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode)->getStockId(); 224 | } 225 | 226 | return $this->stockId; 227 | } 228 | 229 | /** 230 | * Get the legacy stock model is_in_stock value 231 | * 232 | * @param ProductInterface $product 233 | * @return bool 234 | */ 235 | private function getLegacyStockStatus(ProductInterface $product) 236 | { 237 | $stockItem = $this->getStockItem((int) $product->getId()); 238 | 239 | return (bool) $stockItem->getIsInStock(); 240 | } 241 | 242 | /** 243 | * Get the legacy stock model qty value 244 | * 245 | * @param ProductInterface $product 246 | * @return float 247 | */ 248 | private function getLegacySalableQuantity(ProductInterface $product) 249 | { 250 | $stockItem = $this->getStockItem((int) $product->getId()); 251 | 252 | return $stockItem->getManageStock() ? $stockItem->getQty() : 0.; 253 | } 254 | 255 | /** 256 | * @param int $productId 257 | * @return StockItemInterface 258 | */ 259 | private function getStockItem(int $productId) 260 | { 261 | /** @var StockRegistryInterface $stockRegistry */ 262 | $stockRegistry = ObjectManager::getInstance()->get(StockRegistryInterface::class); 263 | 264 | return $stockRegistry->getStockItem($productId); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/Service/PushApi.php: -------------------------------------------------------------------------------- 1 | jsonEncoder = $jsonEncoder; 36 | $this->curlFactory = $curlFactory; 37 | $this->helperConfig = $helperConfig; 38 | } 39 | 40 | /** 41 | * @param array $postData 42 | */ 43 | public function pushRequest( 44 | array $data 45 | ) { 46 | $curl = $this->curlFactory->create(); 47 | 48 | $curl->addHeader('X-Ometria-Auth', $this->getPushAPIKey()); 49 | $curl->addHeader('Accept', 'application/json'); 50 | $curl->addHeader('Content-type', 'application/json'); 51 | 52 | try { 53 | $curl->post( 54 | self::API_URL, 55 | $this->jsonEncoder->serialize($data) 56 | ); 57 | } catch (\Exception $e) { 58 | // Silent catch to prevent API breaking execution path 59 | } 60 | 61 | return $this->jsonEncoder->unserialize($curl->getBody()); 62 | } 63 | 64 | /** 65 | * @return string 66 | */ 67 | private function getPushAPIKey() 68 | { 69 | return $this->helperConfig->getPushAPIKey(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | ometria 10 | Ometria_Core::config_ometria 11 | 12 | 13 | Ometria\Core\Block\System\Config\Form\Fieldset\Modules\Group 14 | 15 | 16 | Magento\Config\Model\Config\Source\Yesno 17 | 18 | 19 | 20 | Sign up for an account at <a href="http://www.ometria.com/" target="_blank">Ometria.com</a> 21 | 22 | 23 | 24 | Log into your Ometria Account to find this key 25 | 26 | 27 | 28 | Log into your Ometria Account to find this key 29 | 30 | 31 | 32 | 33 | Ometria\Core\Block\System\Config\Form\Fieldset\Modules\Group 34 | 35 | 36 | Magento\Config\Model\Config\Source\Yesno 37 | 38 | 39 | 40 | Magento\Config\Model\Config\Source\Yesno 41 | Allow tracking javascript to load from the Ometria CDN on the Magento checkout page. 42 | 43 | 44 | 45 | Magento\Config\Model\Config\Source\Yesno 46 | This applies to configurable/swatch products, should Ometria record a page view on each variant selection. 47 | 48 | 49 | 50 | Magento\Config\Model\Config\Source\Yesno 51 | 52 | 53 | 54 | Ometria\Core\Model\Config\Source\PreferredProduct 55 | Select the configurable product attribute which defines the SKU of the preferred product variant. 56 | 57 | 58 | 59 | Magento\Config\Model\Config\Source\Yesno 60 | Select "yes" here to override using the preferred product's image if the configurable already has an image set. 61 | 62 | 63 | 64 | Ometria\Core\Model\Config\Source\StockPushScope 65 | 66 | 67 | 68 | Magento\Config\Model\Config\Source\Yesno 69 | 70 | 71 | 72 | 73 | 1 74 | 75 | Defines the CookieBot classification Ometria cookies will be allowed by. 76 | 77 | 78 | 79 | Magento\Config\Model\Config\Source\Yesno 80 | 81 | 82 | 83 | Magento\Config\Model\Config\Source\Yesno 84 | 85 | 86 | 87 | Magento\Config\Model\Config\Source\Yesno 88 | 89 | 90 | 91 | This will be auto-generated by the extension. Do not change. 92 | 93 | 94 | 95 | Magento\Config\Model\Config\Source\Yesno 96 | 97 | 98 | 99 | 100 | Enter values separated by new lines. Enter * to check all the stores 101 | 102 | 103 |
104 |
105 |
106 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 1 7 | 8 | 9 | 10 | 11 | 1 12 | 1 13 | 1 14 | 1 15 | 0 16 | id 17 | 0 18 | 19 | 0 20 | 0 21 | 1 22 | 0 23 | marketing 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/etc/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/view/frontend/requirejs-config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | "config": { 3 | "mixins": { 4 | "Magento_Swatches/js/swatch-renderer": { 5 | "Ometria_Core/js/swatch-renderer-mixin": true 6 | }, 7 | "Magento_ConfigurableProduct/js/configurable": { 8 | "Ometria_Core/js/configurable-mixin": true 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/view/frontend/templates/head.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | isDatalayerEnabled()): ?> 4 | 8 | 9 | pageViewOnVariantEnabled()): ?> 10 | 26 | 27 | 28 | 29 | isTrackingEnabled()): ?> 30 | 52 | 53 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/view/frontend/web/js/configurable-mixin.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery' 3 | ], function ($) { 4 | 'use strict'; 5 | 6 | /** 7 | * Mixin to trigger an Ometria data layer push when configurable option is selected 8 | */ 9 | return function (widget) { 10 | $.widget('mage.configurable', widget, { 11 | _configureElement: function (element) { 12 | this._super(element); 13 | 14 | if (this.simpleProduct) { 15 | $(document).trigger('updateOmetriaProductVariant', [ 16 | this.simpleProduct 17 | ]); 18 | } 19 | } 20 | }); 21 | 22 | return $.mage.configurable; 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /app/code/Ometria/Core/view/frontend/web/js/swatch-renderer-mixin.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'jquery' 3 | ], function ($) { 4 | 'use strict'; 5 | 6 | /** 7 | * Mixin to trigger an Ometria data layer push when swatches are selected 8 | */ 9 | return function (widget) { 10 | $.widget('mage.SwatchRenderer', widget, { 11 | _OnClick: function ($this, $widget) { 12 | this._super($this, $widget); 13 | 14 | var simpleProduct = this.getProduct(); 15 | 16 | if (simpleProduct) { 17 | $(document).trigger('updateOmetriaProductVariant', [ 18 | simpleProduct 19 | ]); 20 | } 21 | } 22 | }); 23 | 24 | return $.mage.SwatchRenderer; 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ometria/magento2", 3 | "type": "magento2-module", 4 | "version": "2.6.10", 5 | "description": "Dev composer package for Ometria Extension", 6 | "authors": [ 7 | { 8 | "name": "Ometria", 9 | "email": "support@ometria.com" 10 | } 11 | ], 12 | "minimum-stability": "beta", 13 | "require": {}, 14 | "autoload": { 15 | "files": [ 16 | "app/code/Ometria/AbandonedCarts/registration.php", 17 | "app/code/Ometria/Api/registration.php", 18 | "app/code/Ometria/Core/registration.php" 19 | ], 20 | "psr-4": { 21 | "Ometria\\AbandonedCarts\\": "app/code/Ometria/AbandonedCarts", 22 | "Ometria\\Api\\": "app/code/Ometria/Api", 23 | "Ometria\\Core\\": "app/code/Ometria/Core" 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "86900ea93109656b8677bf1bbf4fd212", 8 | "packages": [], 9 | "packages-dev": [], 10 | "aliases": [], 11 | "minimum-stability": "beta", 12 | "stability-flags": [], 13 | "prefer-stable": false, 14 | "prefer-lowest": false, 15 | "platform": [], 16 | "platform-dev": [], 17 | "plugin-api-version": "2.3.0" 18 | } 19 | --------------------------------------------------------------------------------