├── .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 |
= __('Loading Cart, please wait ...') ?>
-------------------------------------------------------------------------------- /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 |