From 9fa5ddda6108e0432f3f8162307a56ae27c46c8e Mon Sep 17 00:00:00 2001 From: Joachim Vanthuyne Date: Tue, 26 Sep 2017 14:31:25 +0200 Subject: [PATCH 001/528] Fix first day of week in dob customer field --- app/code/Magento/Customer/Block/Widget/Dob.php | 16 +++++++++++++++- .../Magento/Framework/View/Element/Html/Date.php | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Block/Widget/Dob.php b/app/code/Magento/Customer/Block/Widget/Dob.php index f29a9fc76f1d2..e7d4f286464f5 100644 --- a/app/code/Magento/Customer/Block/Widget/Dob.php +++ b/app/code/Magento/Customer/Block/Widget/Dob.php @@ -186,7 +186,8 @@ public function getFieldHtml() 'max_date' => '-1d', 'change_month' => 'true', 'change_year' => 'true', - 'show_on' => 'both' + 'show_on' => 'both', + 'first_day' => $this->getFirstDay() ]); return $this->dateElement->getHtml(); } @@ -307,4 +308,17 @@ public function getMaxDateRange() } return null; } + + /** + * Return first day of the week + * + * @return int + */ + public function getFirstDay() + { + return (int)$this->_scopeConfig->getValue( + 'general/locale/firstday', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + } } diff --git a/lib/internal/Magento/Framework/View/Element/Html/Date.php b/lib/internal/Magento/Framework/View/Element/Html/Date.php index 648d9ad6917e4..558e39427cb44 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Date.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Date.php @@ -26,6 +26,7 @@ protected function _toHtml() $changeYear = $this->getChangeYear(); $maxDate = $this->getMaxDate(); $showOn = $this->getShowOn(); + $firstDay = $this->getFirstDay(); $html .= ''; From cc25f4229cd84eacdff2c06ce40c0ac98598f8d2 Mon Sep 17 00:00:00 2001 From: Rakesh Jesadiya Date: Wed, 27 Sep 2017 10:30:17 +0530 Subject: [PATCH 002/528] Text updated. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 71af5ebc2cbe2..00c6c2195dcfd 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "magento/magento2ce", - "description": "Magento 2 (Community Edition)", + "description": "Magento 2 (Open Source)", "type": "project", "version": "2.2.0", "license": [ From 9c2f3c14ab16ebd1864ba3a531f6dd0a7df351e1 Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 15 Sep 2017 13:17:15 -0500 Subject: [PATCH 003/528] MAGETWO-80488: Apply AR code from previous development - apply analytics-restore-ce.diff --- .../Analytics/Api/Data/LinkInterface.php | 27 ++ .../Analytics/Api/LinkProviderInterface.php | 19 ++ .../System/Config/AdditionalComment.php | 40 +++ .../System/Config/CollectionTimeLabel.php | 31 ++ .../System/Config/SubscriptionStatusLabel.php | 69 ++++ .../Adminhtml/BIEssentials/SignUp.php | 70 ++++ .../Controller/Adminhtml/Reports/Show.php | 80 +++++ .../Adminhtml/Subscription/Activate.php | 142 ++++++++ .../Adminhtml/Subscription/Postpone.php | 103 ++++++ .../Adminhtml/Subscription/Retry.php | 78 +++++ .../Magento/Analytics/Cron/CollectData.php | 58 ++++ app/code/Magento/Analytics/Cron/SignUp.php | 109 ++++++ app/code/Magento/Analytics/Cron/Update.php | 100 ++++++ app/code/Magento/Analytics/LICENSE.txt | 48 +++ app/code/Magento/Analytics/LICENSE_AFL.txt | 48 +++ .../Analytics/Model/AnalyticsToken.php | 101 ++++++ .../Model/Condition/CanViewNotification.php | 87 +++++ app/code/Magento/Analytics/Model/Config.php | 44 +++ .../Baseurl/SubscriptionUpdateHandler.php | 116 +++++++ .../Model/Config/Backend/CollectionTime.php | 95 ++++++ .../Model/Config/Backend/Enabled.php | 88 +++++ .../Backend/Enabled/SubscriptionHandler.php | 198 +++++++++++ .../Model/Config/Backend/Vertical.php | 34 ++ .../Magento/Analytics/Model/Config/Mapper.php | 68 ++++ .../Magento/Analytics/Model/Config/Reader.php | 57 ++++ .../Model/Config/Source/Vertical.php | 55 +++ .../Analytics/Model/ConfigInterface.php | 24 ++ .../Magento/Analytics/Model/Connector.php | 69 ++++ .../Model/Connector/CommandInterface.php | 23 ++ .../Model/Connector/Http/Client/Curl.php | 117 +++++++ .../Model/Connector/Http/ClientInterface.php | 31 ++ .../Connector/Http/ConverterInterface.php | 35 ++ .../Model/Connector/Http/JsonConverter.php | 50 +++ .../Model/Connector/Http/ResponseFactory.php | 25 ++ .../Http/ResponseHandlerInterface.php | 20 ++ .../Model/Connector/Http/ResponseResolver.php | 53 +++ .../Connector/NotifyDataChangedCommand.php | 102 ++++++ .../Analytics/Model/Connector/OTPRequest.php | 124 +++++++ .../Model/Connector/ResponseHandler/OTP.php | 26 ++ .../Connector/ResponseHandler/ReSignUp.php | 65 ++++ .../Connector/ResponseHandler/SignUp.php | 56 +++ .../Connector/ResponseHandler/Update.php | 26 ++ .../Model/Connector/SignUpCommand.php | 134 ++++++++ .../Model/Connector/UpdateCommand.php | 124 +++++++ .../Magento/Analytics/Model/Cryptographer.php | 140 ++++++++ .../Analytics/Model/EncodedContext.php | 58 ++++ .../State/SubscriptionUpdateException.php | 18 + .../Analytics/Model/ExportDataHandler.php | 219 ++++++++++++ .../Model/ExportDataHandlerInterface.php | 21 ++ .../Model/ExportDataHandlerNotification.php | 52 +++ app/code/Magento/Analytics/Model/FileInfo.php | 58 ++++ .../Analytics/Model/FileInfoManager.php | 133 ++++++++ .../Magento/Analytics/Model/FileRecorder.php | 147 ++++++++ .../Analytics/Model/IntegrationManager.php | 135 ++++++++ app/code/Magento/Analytics/Model/Link.php | 60 ++++ .../Magento/Analytics/Model/LinkProvider.php | 95 ++++++ .../Analytics/Model/NotificationTime.php | 72 ++++ .../Model/Plugin/BaseUrlConfigPlugin.php | 66 ++++ .../Analytics/Model/ProviderFactory.php | 43 +++ .../Analytics/Model/ReportUrlProvider.php | 102 ++++++ .../Magento/Analytics/Model/ReportWriter.php | 108 ++++++ .../Analytics/Model/ReportWriterInterface.php | 30 ++ .../Model/ReportXml/ModuleIterator.php | 52 +++ .../Model/StoreConfigurationProvider.php | 109 ++++++ .../Model/SubscriptionStatusProvider.php | 128 +++++++ .../NotificationAboutFailedSubscription.php | 88 +++++ app/code/Magento/Analytics/README.md | 25 ++ .../Magento/Analytics/ReportXml/Config.php | 47 +++ .../ReportXml/Config/Converter/Xml.php | 64 ++++ .../Analytics/ReportXml/Config/Mapper.php | 39 +++ .../Analytics/ReportXml/Config/Reader.php | 62 ++++ .../Analytics/ReportXml/ConfigInterface.php | 25 ++ .../Analytics/ReportXml/ConnectionFactory.php | 70 ++++ .../DB/Assembler/AssemblerInterface.php | 29 ++ .../DB/Assembler/FilterAssembler.php | 69 ++++ .../ReportXml/DB/Assembler/FromAssembler.php | 75 +++++ .../ReportXml/DB/Assembler/JoinAssembler.php | 120 +++++++ .../ReportXml/DB/ColumnsResolver.php | 107 ++++++ .../ReportXml/DB/ConditionResolver.php | 175 ++++++++++ .../Analytics/ReportXml/DB/NameResolver.php | 43 +++ .../ReportXml/DB/ReportValidator.php | 69 ++++ .../Analytics/ReportXml/DB/SelectBuilder.php | 318 ++++++++++++++++++ .../ReportXml/DB/SelectBuilderFactory.php | 47 +++ .../Analytics/ReportXml/IteratorFactory.php | 66 ++++ .../Magento/Analytics/ReportXml/Query.php | 105 ++++++ .../Analytics/ReportXml/QueryFactory.php | 153 +++++++++ .../Analytics/ReportXml/ReportProvider.php | 83 +++++ .../Analytics/ReportXml/SelectHydrator.php | 153 +++++++++ .../Magento/Analytics/Setup/InstallData.php | 47 +++ .../System/Config/AdditionalCommentTest.php | 76 +++++ .../System/Config/CollectionTimeLabelTest.php | 79 +++++ .../Config/SubscriptionStatusLabelTest.php | 86 +++++ .../Adminhtml/BIEssentials/SignUpTest.php | 84 +++++ .../Controller/Adminhtml/Reports/ShowTest.php | 185 ++++++++++ .../Adminhtml/Subscription/ActivateTest.php | 252 ++++++++++++++ .../Adminhtml/Subscription/PostponeTest.php | 168 +++++++++ .../Adminhtml/Subscription/RetryTest.php | 159 +++++++++ .../Test/Unit/Cron/CollectDataTest.php | 91 +++++ .../Analytics/Test/Unit/Cron/SignUpTest.php | 133 ++++++++ .../Analytics/Test/Unit/Cron/UpdateTest.php | 214 ++++++++++++ .../Test/Unit/Model/AnalyticsTokenTest.php | 129 +++++++ .../Condition/CanViewNotificationTest.php | 81 +++++ .../Baseurl/SubscriptionUpdateHandlerTest.php | 178 ++++++++++ .../Config/Backend/CollectionTimeTest.php | 111 ++++++ .../Enabled/SubscriptionHandlerTest.php | 185 ++++++++++ .../Unit/Model/Config/Backend/EnabledTest.php | 184 ++++++++++ .../Model/Config/Backend/VerticalTest.php | 59 ++++ .../Test/Unit/Model/Config/MapperTest.php | 142 ++++++++ .../Test/Unit/Model/Config/ReaderTest.php | 108 ++++++ .../Unit/Model/Config/Source/VerticalTest.php | 60 ++++ .../Analytics/Test/Unit/Model/ConfigTest.php | 68 ++++ .../Model/Connector/Http/Client/CurlTest.php | 218 ++++++++++++ .../Connector/Http/JsonConverterTest.php | 34 ++ .../Connector/Http/ResponseResolverTest.php | 39 +++ .../NotifyDataChangedCommandTest.php | 107 ++++++ .../Unit/Model/Connector/OTPRequestTest.php | 187 ++++++++++ .../Connector/ResponseHandler/OTPTest.php | 22 ++ .../ResponseHandler/ReSignUpTest.php | 36 ++ .../Connector/ResponseHandler/SignUpTest.php | 30 ++ .../Connector/ResponseHandler/UpdateTest.php | 20 ++ .../Model/Connector/SignUpCommandTest.php | 174 ++++++++++ .../Model/Connector/UpdateCommandTest.php | 143 ++++++++ .../Test/Unit/Model/ConnectorTest.php | 70 ++++ .../Test/Unit/Model/CryptographerTest.php | 226 +++++++++++++ .../Test/Unit/Model/EncodedContextTest.php | 61 ++++ .../ExportDataHandlerNotificationTest.php | 74 ++++ .../Test/Unit/Model/ExportDataHandlerTest.php | 270 +++++++++++++++ .../Test/Unit/Model/FileInfoManagerTest.php | 194 +++++++++++ .../Test/Unit/Model/FileInfoTest.php | 62 ++++ .../Test/Unit/Model/FileRecorderTest.php | 209 ++++++++++++ .../Unit/Model/IntegrationManagerTest.php | 228 +++++++++++++ .../Test/Unit/Model/LinkProviderTest.php | 166 +++++++++ .../Test/Unit/Model/NotificationTimeTest.php | 76 +++++ .../Model/Plugin/BaseUrlConfigPluginTest.php | 147 ++++++++ .../Test/Unit/Model/ReportUrlProviderTest.php | 153 +++++++++ .../Test/Unit/Model/ReportWriterTest.php | 213 ++++++++++++ .../Model/ReportXml/ModuleIteratorTest.php | 50 +++ .../Model/StoreConfigurationProviderTest.php | 123 +++++++ .../Model/SubscriptionStatusProviderTest.php | 196 +++++++++++ ...otificationAboutFailedSubscriptionTest.php | 106 ++++++ .../ReportXml/Config/Converter/XmlTest.php | 121 +++++++ .../Test/Unit/ReportXml/Config/MapperTest.php | 47 +++ .../ReportXml/Config/_files/valid_reports.xml | 25 ++ .../Test/Unit/ReportXml/ConfigTest.php | 64 ++++ .../Unit/ReportXml/ConnectionFactoryTest.php | 106 ++++++ .../DB/Assembler/FilterAssemblerTest.php | 143 ++++++++ .../DB/Assembler/FromAssemblerTest.php | 167 +++++++++ .../DB/Assembler/JoinAssemblerTest.php | 279 +++++++++++++++ .../Unit/ReportXml/DB/ColumnsResolverTest.php | 150 +++++++++ .../ReportXml/DB/ConditionResolverTest.php | 108 ++++++ .../Unit/ReportXml/DB/NameResolverTest.php | 90 +++++ .../Unit/ReportXml/DB/ReportValidatorTest.php | 125 +++++++ .../Unit/ReportXml/DB/SelectBuilderTest.php | 103 ++++++ .../Unit/ReportXml/IteratorFactoryTest.php | 59 ++++ .../Test/Unit/ReportXml/QueryFactoryTest.php | 239 +++++++++++++ .../Test/Unit/ReportXml/QueryTest.php | 90 +++++ .../Unit/ReportXml/ReportProviderTest.php | 180 ++++++++++ .../Unit/ReportXml/SelectHydratorTest.php | 257 ++++++++++++++ .../Ui/DataProvider/DummyDataProviderTest.php | 228 +++++++++++++ .../Ui/DataProvider/DummyDataProvider.php | 259 ++++++++++++++ app/code/Magento/Analytics/composer.json | 26 ++ .../Analytics/docs/images/M2_MA_signup.png | Bin 0 -> 11422 bytes .../docs/images/analytics_modules.png | Bin 0 -> 6845 bytes .../Analytics/docs/images/data_transition.png | Bin 0 -> 16397 bytes .../Analytics/docs/images/definition.png | Bin 0 -> 7138 bytes .../docs/images/mbi_file_exchange.png | Bin 0 -> 19199 bytes .../Magento/Analytics/docs/images/signup.png | Bin 0 -> 7289 bytes .../Magento/Analytics/docs/images/update.png | Bin 0 -> 7534 bytes .../Analytics/docs/images/update_request.png | Bin 0 -> 13059 bytes app/code/Magento/Analytics/etc/acl.xml | 31 ++ .../Magento/Analytics/etc/adminhtml/di.xml | 16 + .../Magento/Analytics/etc/adminhtml/menu.xml | 19 ++ .../Analytics/etc/adminhtml/routes.xml | 14 + .../Analytics/etc/adminhtml/system.xml | 47 +++ app/code/Magento/Analytics/etc/analytics.xml | 50 +++ app/code/Magento/Analytics/etc/analytics.xsd | 80 +++++ app/code/Magento/Analytics/etc/config.xml | 25 ++ app/code/Magento/Analytics/etc/crontab.xml | 14 + app/code/Magento/Analytics/etc/di.xml | 262 +++++++++++++++ app/code/Magento/Analytics/etc/module.xml | 17 + app/code/Magento/Analytics/etc/reports.xml | 48 +++ app/code/Magento/Analytics/etc/reports.xsd | 88 +++++ app/code/Magento/Analytics/etc/webapi.xml | 16 + app/code/Magento/Analytics/i18n/en_US.csv | 103 ++++++ app/code/Magento/Analytics/registration.php | 11 + .../layout/adminhtml_dashboard_index.xml | 21 ++ .../templates/dashboard/section.phtml | 28 ++ .../analytics_subscription_form.xml | 247 ++++++++++++++ .../adminhtml/web/js/modal/modal-component.js | 66 ++++ .../web/template/buttons-container.html | 13 + .../form/components/single/checkbox.html | 17 + app/code/Magento/CatalogAnalytics/LICENSE.txt | 48 +++ .../Magento/CatalogAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/CatalogAnalytics/README.md | 3 + .../Magento/CatalogAnalytics/composer.json | 23 ++ .../CatalogAnalytics/etc/analytics.xml | 18 + .../Magento/CatalogAnalytics/etc/module.xml | 15 + .../Magento/CatalogAnalytics/etc/reports.xml | 15 + .../Magento/CatalogAnalytics/registration.php | 11 + .../Magento/CustomerAnalytics/LICENSE.txt | 48 +++ .../Magento/CustomerAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/CustomerAnalytics/README.md | 3 + .../Magento/CustomerAnalytics/composer.json | 23 ++ .../CustomerAnalytics/etc/analytics.xml | 18 + .../Magento/CustomerAnalytics/etc/module.xml | 15 + .../Magento/CustomerAnalytics/etc/reports.xml | 17 + .../CustomerAnalytics/registration.php | 11 + app/code/Magento/QuoteAnalytics/LICENSE.txt | 48 +++ .../Magento/QuoteAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/QuoteAnalytics/README.md | 3 + app/code/Magento/QuoteAnalytics/composer.json | 23 ++ .../Magento/QuoteAnalytics/etc/analytics.xml | 18 + .../Magento/QuoteAnalytics/etc/module.xml | 15 + .../Magento/QuoteAnalytics/etc/reports.xml | 22 ++ .../Magento/QuoteAnalytics/registration.php | 11 + app/code/Magento/ReviewAnalytics/LICENSE.txt | 48 +++ .../Magento/ReviewAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/ReviewAnalytics/README.md | 3 + .../Magento/ReviewAnalytics/composer.json | 23 ++ .../Magento/ReviewAnalytics/etc/analytics.xml | 27 ++ .../Magento/ReviewAnalytics/etc/module.xml | 15 + .../Magento/ReviewAnalytics/etc/reports.xml | 25 ++ .../Magento/ReviewAnalytics/registration.php | 11 + app/code/Magento/SalesAnalytics/LICENSE.txt | 48 +++ .../Magento/SalesAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/SalesAnalytics/README.md | 3 + app/code/Magento/SalesAnalytics/composer.json | 23 ++ .../Magento/SalesAnalytics/etc/analytics.xml | 36 ++ .../Magento/SalesAnalytics/etc/module.xml | 15 + .../Magento/SalesAnalytics/etc/reports.xml | 55 +++ .../Magento/SalesAnalytics/registration.php | 11 + .../Magento/WishlistAnalytics/LICENSE.txt | 48 +++ .../Magento/WishlistAnalytics/LICENSE_AFL.txt | 48 +++ app/code/Magento/WishlistAnalytics/README.md | 3 + .../Magento/WishlistAnalytics/composer.json | 23 ++ .../WishlistAnalytics/etc/analytics.xml | 27 ++ .../Magento/WishlistAnalytics/etc/module.xml | 15 + .../Magento/WishlistAnalytics/etc/reports.xml | 25 ++ .../WishlistAnalytics/registration.php | 11 + composer.json | 7 + .../Analytics/Api/LinkProviderTest.php | 100 ++++++ .../Mtf/App/State/NotificationTimeHandler.php | 55 +++ .../AdvancedReporting/ReportsSectionBlock.php | 31 ++ .../AdvancedReporting/SubscriptionBlock.php | 99 ++++++ .../Block/System/Config/AnalyticsForm.php | 158 +++++++++ .../AssertAdvancedReportingPage.php | 53 +++ .../Constraint/AssertBIEssentialsLink.php | 87 +++++ .../AssertConfigAnalyticsDisabled.php | 49 +++ .../AssertConfigAnalyticsEnabled.php | 50 +++ .../AssertConfigAnalyticsRestored.php | 54 +++ ...ssertConfigAnalyticsSendingTimeAndZone.php | 52 +++ .../AssertConfigAnalyticsVerticalScope.php | 39 +++ .../AssertDisableReportingInPopup.php | 49 +++ .../AssertEmptyVerticalCanNotBeSaved.php | 42 +++ .../AssertEnableReportingInPopup.php | 42 +++ .../Constraint/AssertSkipReportingInPopup.php | 42 +++ .../AssertSubscriptionPopupNotExist.php | 39 +++ .../Test/Constraint/AssertVerticalIsSet.php | 42 +++ .../Test/Page/Adminhtml/ConfigAnalytics.xml | 13 + .../Test/Page/Adminhtml/Dashboard.xml | 14 + .../Test/Repository/DefaultTimeZone.xml | 35 ++ .../Analytics/Test/Repository/Integration.xml | 16 + .../Analytics/Test/Repository/Role.xml | 19 ++ .../Analytics/Test/Repository/User.xml | 24 ++ .../TestCase/AdvancedReportingButtonTest.php | 36 ++ .../TestCase/AdvancedReportingButtonTest.xml | 15 + ...lyticsSubscriptionCheckPermissionsTest.php | 37 ++ ...lyticsSubscriptionCheckPermissionsTest.xml | 15 + .../Test/TestCase/EnableDisableTest.php | 42 +++ .../Test/TestCase/EnableDisableTest.xml | 21 ++ .../Analytics/Test/TestCase/InstallTest.xml | 28 ++ .../Test/TestCase/NavigateMenuTest.xml | 23 ++ .../Test/TestCase/SetTimeToSendDataTest.php | 75 +++++ .../Test/TestCase/SetTimeToSendDataTest.xml | 18 + .../Test/TestCase/SetVerticalTest.php | 40 +++ .../Test/TestCase/SetVerticalTest.xml | 21 ++ .../Test/TestStep/OpenAnalyticsConfigStep.php | 54 +++ .../app/Magento/Analytics/Test/etc/di.xml | 51 +++ .../Magento/Analytics/Test/etc/testcase.xml | 14 + .../Setup/Test/TestCase/UpgradeSystemTest.php | 26 +- .../InjectableTests/travis_acceptance_1.xml | 1 + .../Http/ReSignUpResponseResolverTest.php | 177 ++++++++++ .../Model/Plugin/BaseUrlConfigPluginTest.php | 207 ++++++++++++ .../Analytics/Model/ReportUrlProviderTest.php | 56 +++ .../Magento/Analytics/_files/create_link.php | 21 ++ ...nabled_subscription_with_invalid_token.php | 29 ++ ...bscription_with_invalid_token_rollback.php | 29 ++ .../js/modal/modal-component.test.js | 126 +++++++ 288 files changed, 21119 insertions(+), 4 deletions(-) create mode 100644 app/code/Magento/Analytics/Api/Data/LinkInterface.php create mode 100644 app/code/Magento/Analytics/Api/LinkProviderInterface.php create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php create mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php create mode 100644 app/code/Magento/Analytics/Cron/CollectData.php create mode 100644 app/code/Magento/Analytics/Cron/SignUp.php create mode 100644 app/code/Magento/Analytics/Cron/Update.php create mode 100644 app/code/Magento/Analytics/LICENSE.txt create mode 100644 app/code/Magento/Analytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/Analytics/Model/AnalyticsToken.php create mode 100644 app/code/Magento/Analytics/Model/Condition/CanViewNotification.php create mode 100644 app/code/Magento/Analytics/Model/Config.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Enabled.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php create mode 100644 app/code/Magento/Analytics/Model/Config/Backend/Vertical.php create mode 100644 app/code/Magento/Analytics/Model/Config/Mapper.php create mode 100644 app/code/Magento/Analytics/Model/Config/Reader.php create mode 100644 app/code/Magento/Analytics/Model/Config/Source/Vertical.php create mode 100644 app/code/Magento/Analytics/Model/ConfigInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector.php create mode 100644 app/code/Magento/Analytics/Model/Connector/CommandInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php create mode 100644 app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php create mode 100644 app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php create mode 100644 app/code/Magento/Analytics/Model/Connector/OTPRequest.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php create mode 100644 app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php create mode 100644 app/code/Magento/Analytics/Model/Connector/SignUpCommand.php create mode 100644 app/code/Magento/Analytics/Model/Connector/UpdateCommand.php create mode 100644 app/code/Magento/Analytics/Model/Cryptographer.php create mode 100644 app/code/Magento/Analytics/Model/EncodedContext.php create mode 100644 app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php create mode 100644 app/code/Magento/Analytics/Model/ExportDataHandler.php create mode 100644 app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php create mode 100644 app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php create mode 100644 app/code/Magento/Analytics/Model/FileInfo.php create mode 100644 app/code/Magento/Analytics/Model/FileInfoManager.php create mode 100644 app/code/Magento/Analytics/Model/FileRecorder.php create mode 100644 app/code/Magento/Analytics/Model/IntegrationManager.php create mode 100644 app/code/Magento/Analytics/Model/Link.php create mode 100644 app/code/Magento/Analytics/Model/LinkProvider.php create mode 100644 app/code/Magento/Analytics/Model/NotificationTime.php create mode 100644 app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php create mode 100644 app/code/Magento/Analytics/Model/ProviderFactory.php create mode 100644 app/code/Magento/Analytics/Model/ReportUrlProvider.php create mode 100644 app/code/Magento/Analytics/Model/ReportWriter.php create mode 100644 app/code/Magento/Analytics/Model/ReportWriterInterface.php create mode 100644 app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php create mode 100644 app/code/Magento/Analytics/Model/StoreConfigurationProvider.php create mode 100644 app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php create mode 100644 app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php create mode 100644 app/code/Magento/Analytics/README.md create mode 100644 app/code/Magento/Analytics/ReportXml/Config.php create mode 100644 app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php create mode 100644 app/code/Magento/Analytics/ReportXml/Config/Mapper.php create mode 100644 app/code/Magento/Analytics/ReportXml/Config/Reader.php create mode 100644 app/code/Magento/Analytics/ReportXml/ConfigInterface.php create mode 100644 app/code/Magento/Analytics/ReportXml/ConnectionFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/NameResolver.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php create mode 100644 app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/IteratorFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/Query.php create mode 100644 app/code/Magento/Analytics/ReportXml/QueryFactory.php create mode 100644 app/code/Magento/Analytics/ReportXml/ReportProvider.php create mode 100644 app/code/Magento/Analytics/ReportXml/SelectHydrator.php create mode 100644 app/code/Magento/Analytics/Setup/InstallData.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php create mode 100644 app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php create mode 100644 app/code/Magento/Analytics/composer.json create mode 100644 app/code/Magento/Analytics/docs/images/M2_MA_signup.png create mode 100644 app/code/Magento/Analytics/docs/images/analytics_modules.png create mode 100644 app/code/Magento/Analytics/docs/images/data_transition.png create mode 100644 app/code/Magento/Analytics/docs/images/definition.png create mode 100644 app/code/Magento/Analytics/docs/images/mbi_file_exchange.png create mode 100644 app/code/Magento/Analytics/docs/images/signup.png create mode 100644 app/code/Magento/Analytics/docs/images/update.png create mode 100644 app/code/Magento/Analytics/docs/images/update_request.png create mode 100644 app/code/Magento/Analytics/etc/acl.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/di.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/menu.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/routes.xml create mode 100644 app/code/Magento/Analytics/etc/adminhtml/system.xml create mode 100644 app/code/Magento/Analytics/etc/analytics.xml create mode 100644 app/code/Magento/Analytics/etc/analytics.xsd create mode 100644 app/code/Magento/Analytics/etc/config.xml create mode 100644 app/code/Magento/Analytics/etc/crontab.xml create mode 100644 app/code/Magento/Analytics/etc/di.xml create mode 100644 app/code/Magento/Analytics/etc/module.xml create mode 100644 app/code/Magento/Analytics/etc/reports.xml create mode 100644 app/code/Magento/Analytics/etc/reports.xsd create mode 100644 app/code/Magento/Analytics/etc/webapi.xml create mode 100644 app/code/Magento/Analytics/i18n/en_US.csv create mode 100644 app/code/Magento/Analytics/registration.php create mode 100644 app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml create mode 100644 app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml create mode 100644 app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml create mode 100644 app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js create mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html create mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html create mode 100644 app/code/Magento/CatalogAnalytics/LICENSE.txt create mode 100644 app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/CatalogAnalytics/README.md create mode 100644 app/code/Magento/CatalogAnalytics/composer.json create mode 100644 app/code/Magento/CatalogAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/CatalogAnalytics/etc/module.xml create mode 100644 app/code/Magento/CatalogAnalytics/etc/reports.xml create mode 100644 app/code/Magento/CatalogAnalytics/registration.php create mode 100644 app/code/Magento/CustomerAnalytics/LICENSE.txt create mode 100644 app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/CustomerAnalytics/README.md create mode 100644 app/code/Magento/CustomerAnalytics/composer.json create mode 100644 app/code/Magento/CustomerAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/CustomerAnalytics/etc/module.xml create mode 100644 app/code/Magento/CustomerAnalytics/etc/reports.xml create mode 100644 app/code/Magento/CustomerAnalytics/registration.php create mode 100644 app/code/Magento/QuoteAnalytics/LICENSE.txt create mode 100644 app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/QuoteAnalytics/README.md create mode 100644 app/code/Magento/QuoteAnalytics/composer.json create mode 100644 app/code/Magento/QuoteAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/QuoteAnalytics/etc/module.xml create mode 100644 app/code/Magento/QuoteAnalytics/etc/reports.xml create mode 100644 app/code/Magento/QuoteAnalytics/registration.php create mode 100644 app/code/Magento/ReviewAnalytics/LICENSE.txt create mode 100644 app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/ReviewAnalytics/README.md create mode 100644 app/code/Magento/ReviewAnalytics/composer.json create mode 100644 app/code/Magento/ReviewAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/ReviewAnalytics/etc/module.xml create mode 100644 app/code/Magento/ReviewAnalytics/etc/reports.xml create mode 100644 app/code/Magento/ReviewAnalytics/registration.php create mode 100644 app/code/Magento/SalesAnalytics/LICENSE.txt create mode 100644 app/code/Magento/SalesAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/SalesAnalytics/README.md create mode 100644 app/code/Magento/SalesAnalytics/composer.json create mode 100644 app/code/Magento/SalesAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/SalesAnalytics/etc/module.xml create mode 100644 app/code/Magento/SalesAnalytics/etc/reports.xml create mode 100644 app/code/Magento/SalesAnalytics/registration.php create mode 100644 app/code/Magento/WishlistAnalytics/LICENSE.txt create mode 100644 app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt create mode 100644 app/code/Magento/WishlistAnalytics/README.md create mode 100644 app/code/Magento/WishlistAnalytics/composer.json create mode 100644 app/code/Magento/WishlistAnalytics/etc/analytics.xml create mode 100644 app/code/Magento/WishlistAnalytics/etc/module.xml create mode 100644 app/code/Magento/WishlistAnalytics/etc/reports.xml create mode 100644 app/code/Magento/WishlistAnalytics/registration.php create mode 100644 dev/tests/api-functional/testsuite/Magento/Analytics/Api/LinkProviderTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php create mode 100644 dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php create mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js diff --git a/app/code/Magento/Analytics/Api/Data/LinkInterface.php b/app/code/Magento/Analytics/Api/Data/LinkInterface.php new file mode 100644 index 0000000000000..f2b1ec579c4ab --- /dev/null +++ b/app/code/Magento/Analytics/Api/Data/LinkInterface.php @@ -0,0 +1,27 @@ +' . $element->getLabel() . ''; + $html .= '
' . $element->getComment() . '
'; + return $this->decorateRowHtml($element, $html); + } + + /** + * @param \Magento\Framework\Data\Form\Element\AbstractElement $element + * @param string $html + * @return string + * @since 2.2.0 + */ + private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) + { + return sprintf( + '
%s
', + $element->getHtmlId(), + $html + ); + } +} diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php new file mode 100644 index 0000000000000..9e19a9e6c2388 --- /dev/null +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php @@ -0,0 +1,31 @@ +_localeDate->getConfigTimezone(); + $getLongTimeZoneName = \IntlTimeZone::createTimeZone($timeZoneCode)->getDisplayName(); + $element->setData( + 'comment', + sprintf("%s (%s)", $getLongTimeZoneName, $timeZoneCode) + ); + return parent::render($element); + } +} diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php new file mode 100644 index 0000000000000..bfdee16707618 --- /dev/null +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php @@ -0,0 +1,69 @@ +subscriptionStatusProvider = $labelStatusProvider; + } + + /** + * Add Subscription status to comment + * + * @param \Magento\Framework\Data\Form\Element\AbstractElement $element + * @return string + * @since 2.2.0 + */ + public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) + { + $element->setData( + 'comment', + $this->prepareLabelValue() + ); + return parent::render($element); + } + + /** + * Prepare label for subscription status + * + * @return string + * @since 2.2.0 + */ + private function prepareLabelValue() + { + return __('Subscription status') . ': ' . __($this->subscriptionStatusProvider->getStatus()); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php new file mode 100644 index 0000000000000..4cbfa639d23b4 --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php @@ -0,0 +1,70 @@ +config = $config; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::bi_essentials'); + } + + /** + * Provides link to BI Essentials signup + * + * @return \Magento\Framework\Controller\AbstractResult + * @since 2.2.0 + */ + public function execute() + { + return $this->resultRedirectFactory->create()->setUrl( + $this->config->getValue($this->urlBIEssentialsConfigPath) + ); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php new file mode 100644 index 0000000000000..5fb0085fee43d --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php @@ -0,0 +1,80 @@ +reportUrlProvider = $reportUrlProvider; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller. + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Redirect to resource with reports. + * + * @return Redirect $resultRedirect + * @since 2.2.0 + */ + public function execute() + { + /** @var Redirect $resultRedirect */ + $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + try { + $resultRedirect->setUrl($this->reportUrlProvider->getUrl()); + } catch (SubscriptionUpdateException $e) { + $this->getMessageManager()->addNoticeMessage($e->getMessage()); + $resultRedirect->setPath('adminhtml'); + } catch (LocalizedException $e) { + $this->getMessageManager()->addExceptionMessage($e, $e->getMessage()); + $resultRedirect->setPath('adminhtml'); + } catch (\Exception $e) { + $this->getMessageManager()->addExceptionMessage( + $e, + __('Sorry, there has been an error processing your request. Please try again later.') + ); + $resultRedirect->setPath('adminhtml'); + } + + return $resultRedirect; + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php new file mode 100644 index 0000000000000..59923e82ef46c --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php @@ -0,0 +1,142 @@ +logger = $logger; + $this->notificationTime = $notificationTime; + $this->configValueResource = $configValueResource; + $this->preparedValueFactory = $preparedValueFactory; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Activate subscription to Magento BI via AJAX. + * + * @return Json + * @since 2.2.0 + */ + public function execute() + { + try { + if ($this->getRequest()->getParam($this->subscriptionApprovedField)) { + $configValue = $this->preparedValueFactory->create( + Enabled::XML_ENABLED_CONFIG_STRUCTURE_PATH, + Enabledisable::ENABLE_VALUE, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + + $this->configValueResource + ->save($configValue); + } else { + $this->notificationTime->unsetLastTimeNotificationValue(); + } + $responseContent = [ + 'success' => true, + 'error_message' => '', + ]; + } catch (LocalizedException $e) { + $responseContent = [ + 'success' => false, + 'error_message' => $e->getMessage(), + ]; + $this->logger->error($e->getMessage()); + } catch (\Exception $e) { + $responseContent = [ + 'success' => false, + 'error_message' => __( + 'Sorry, there was an error processing your registration request to Magento Analytics. ' + . 'Please try again later.' + ), + ]; + $this->logger->error($e->getMessage()); + } + /** @var Json $resultJson */ + $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); + return $resultJson->setData($responseContent); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php new file mode 100644 index 0000000000000..068416157ae6a --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php @@ -0,0 +1,103 @@ +dateTimeFactory = $dateTimeFactory; + $this->notificationTime = $notificationTime; + $this->logger = $logger; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Postpones notification about subscription + * + * @return Json + * @since 2.2.0 + */ + public function execute() + { + try { + $dateTime = $this->dateTimeFactory->create(); + $responseContent = [ + 'success' => $this->notificationTime->storeLastTimeNotification($dateTime->getTimestamp()), + 'error_message' => '' + ]; + } catch (LocalizedException $e) { + $this->logger->error($e->getMessage()); + $responseContent = [ + 'success' => false, + 'error_message' => $e->getMessage() + ]; + } catch (\Exception $e) { + $this->logger->error($e->getMessage()); + $responseContent = [ + 'success' => false, + 'error_message' => __('Error occurred during postponement notification') + ]; + } + /** @var Json $resultJson */ + $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); + return $resultJson->setData($responseContent); + } +} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php new file mode 100644 index 0000000000000..85d34e83f0c9f --- /dev/null +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php @@ -0,0 +1,78 @@ +subscriptionHandler = $subscriptionHandler; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + * @since 2.2.0 + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); + } + + /** + * Retry process of subscription. + * + * @return Redirect + * @since 2.2.0 + */ + public function execute() + { + /** @var Redirect $resultRedirect */ + $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + try { + $resultRedirect->setPath('adminhtml'); + $this->subscriptionHandler->processEnabled(); + } catch (LocalizedException $e) { + $this->getMessageManager()->addExceptionMessage($e, $e->getMessage()); + } catch (\Exception $e) { + $this->getMessageManager()->addExceptionMessage( + $e, + __('Sorry, there has been an error processing your request. Please try again later.') + ); + } + + return $resultRedirect; + } +} diff --git a/app/code/Magento/Analytics/Cron/CollectData.php b/app/code/Magento/Analytics/Cron/CollectData.php new file mode 100644 index 0000000000000..d11ade9a812ff --- /dev/null +++ b/app/code/Magento/Analytics/Cron/CollectData.php @@ -0,0 +1,58 @@ +exportDataHandler = $exportDataHandler; + $this->subscriptionStatus = $subscriptionStatus; + } + + /** + * @return bool + * @since 2.2.0 + */ + public function execute() + { + if ($this->subscriptionStatus->getStatus() === SubscriptionStatusProvider::ENABLED) { + $this->exportDataHandler->prepareExportData(); + } + + return true; + } +} diff --git a/app/code/Magento/Analytics/Cron/SignUp.php b/app/code/Magento/Analytics/Cron/SignUp.php new file mode 100644 index 0000000000000..cc5c84e93a6d9 --- /dev/null +++ b/app/code/Magento/Analytics/Cron/SignUp.php @@ -0,0 +1,109 @@ +connector = $connector; + $this->configWriter = $configWriter; + $this->flagManager = $flagManager; + $this->reinitableConfig = $reinitableConfig; + } + + /** + * Execute scheduled subscription operation + * In case of failure writes message to notifications inbox + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $attemptsCount = $this->flagManager->getFlagData(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + + if (($attemptsCount === null) || ($attemptsCount <= 0)) { + $this->deleteAnalyticsCronExpr(); + $this->flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + return false; + } + + $attemptsCount -= 1; + $this->flagManager->saveFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $attemptsCount); + $signUpResult = $this->connector->execute('signUp'); + if ($signUpResult === false) { + return false; + } + + $this->deleteAnalyticsCronExpr(); + $this->flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + return true; + } + + /** + * Delete cron schedule setting into config. + * + * Delete cron schedule setting for subscription handler into config and + * re-initialize config cache to avoid auto-generate new schedule items. + * + * @return bool + * @since 2.2.0 + */ + private function deleteAnalyticsCronExpr() + { + $this->configWriter->delete(SubscriptionHandler::CRON_STRING_PATH); + $this->reinitableConfig->reinit(); + return true; + } +} diff --git a/app/code/Magento/Analytics/Cron/Update.php b/app/code/Magento/Analytics/Cron/Update.php new file mode 100644 index 0000000000000..89a2496e088c1 --- /dev/null +++ b/app/code/Magento/Analytics/Cron/Update.php @@ -0,0 +1,100 @@ +connector = $connector; + $this->configWriter = $configWriter; + $this->reinitableConfig = $reinitableConfig; + $this->flagManager = $flagManager; + $this->analyticsToken = $analyticsToken; + } + + /** + * Execute scheduled update operation + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $result = false; + $attemptsCount = $this->flagManager + ->getFlagData(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE); + + if ($attemptsCount) { + $attemptsCount -= 1; + $result = $this->connector->execute('update'); + } + + if ($result || ($attemptsCount <= 0) || (!$this->analyticsToken->isTokenExist())) { + $this->flagManager + ->deleteFlag(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE); + $this->flagManager->deleteFlag(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE); + $this->configWriter->delete(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH); + $this->reinitableConfig->reinit(); + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/LICENSE.txt b/app/code/Magento/Analytics/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/Analytics/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/Analytics/LICENSE_AFL.txt b/app/code/Magento/Analytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/Analytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/Analytics/Model/AnalyticsToken.php b/app/code/Magento/Analytics/Model/AnalyticsToken.php new file mode 100644 index 0000000000000..58ef45b4f4279 --- /dev/null +++ b/app/code/Magento/Analytics/Model/AnalyticsToken.php @@ -0,0 +1,101 @@ +reinitableConfig = $reinitableConfig; + $this->config = $config; + $this->configWriter = $configWriter; + } + + /** + * Get Magento BI token value. + * + * @return string|null + * @since 2.2.0 + */ + public function getToken() + { + return $this->config->getValue($this->tokenPath); + } + + /** + * Stores Magento BI token value. + * + * @param string $value + * + * @return bool + * @since 2.2.0 + */ + public function storeToken($value) + { + $this->configWriter->save($this->tokenPath, $value); + $this->reinitableConfig->reinit(); + + return true; + } + + /** + * Check Magento BI token value exist. + * + * @return bool + * @since 2.2.0 + */ + public function isTokenExist() + { + return (bool)$this->getToken(); + } +} diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php new file mode 100644 index 0000000000000..9200361322dc2 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -0,0 +1,87 @@ +notificationTime = $notificationTime; + $this->dateTimeFactory = $dateTimeFactory; + } + + /** + * Validate is notification popup can be shown + * + * @inheritdoc + * @since 2.2.0 + */ + public function isVisible(array $arguments) + { + $lastNotificationTime = $this->notificationTime->getLastTimeNotification(); + if (!$lastNotificationTime) { + return false; + } + $datetime = $this->dateTimeFactory->create(); + return ( + $datetime->getTimestamp() >= $lastNotificationTime + $this->notificationInterval + ); + } + + /** + * @return string + * @since 2.2.0 + */ + public function getName() + { + return self::NAME; + } +} diff --git a/app/code/Magento/Analytics/Model/Config.php b/app/code/Magento/Analytics/Model/Config.php new file mode 100644 index 0000000000000..140d7130260a2 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config.php @@ -0,0 +1,44 @@ +data = $data; + } + + /** + * Get config value by key. + * + * @param string|null $key + * @param string|null $default + * @return array + * @since 2.2.0 + */ + public function get($key = null, $default = null) + { + return $this->data->get($key, $default); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php new file mode 100644 index 0000000000000..f9fa38fe7f5fb --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php @@ -0,0 +1,116 @@ +analyticsToken = $analyticsToken; + $this->flagManager = $flagManager; + $this->reinitableConfig = $reinitableConfig; + $this->configWriter = $configWriter; + } + + /** + * Activate process of subscription update handling. + * + * @param string $url + * @return bool + * @since 2.2.0 + */ + public function processUrlUpdate(string $url) + { + if ($this->analyticsToken->isTokenExist()) { + if (!$this->flagManager->getFlagData(self::PREVIOUS_BASE_URL_FLAG_CODE)) { + $this->flagManager->saveFlag(self::PREVIOUS_BASE_URL_FLAG_CODE, $url); + } + + $this->flagManager + ->saveFlag(self::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue); + $this->configWriter->save(self::UPDATE_CRON_STRING_PATH, $this->cronExpression); + $this->reinitableConfig->reinit(); + } + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php new file mode 100644 index 0000000000000..beb6f9d79f7ab --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php @@ -0,0 +1,95 @@ +configWriter = $configWriter; + parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + } + + /** + * {@inheritdoc} + * + * {@inheritdoc}. Set schedule setting for cron. + * + * @return Value + * @since 2.2.0 + */ + public function afterSave() + { + $result = preg_match('#(?\d{2}),(?\d{2}),(?\d{2})#', $this->getValue(), $time); + + if (!$result) { + throw new LocalizedException(__('Time value has an unsupported format')); + } + + $cronExprArray = [ + $time['min'], # Minute + $time['hour'], # Hour + '*', # Day of the Month + '*', # Month of the Year + '*', # Day of the Week + ]; + + $cronExprString = join(' ', $cronExprArray); + + try { + $this->configWriter->save(self::CRON_SCHEDULE_PATH, $cronExprString); + } catch (\Exception $e) { + $this->_logger->error($e->getMessage()); + throw new LocalizedException(__('Cron settings can\'t be saved')); + } + + return parent::afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php new file mode 100644 index 0000000000000..5544cd0df9454 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php @@ -0,0 +1,88 @@ +subscriptionHandler = $subscriptionHandler; + parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); + } + + /** + * Add additional handling after config value was saved. + * + * @return Value + * @throws LocalizedException + * @since 2.2.0 + */ + public function afterSave() + { + try { + if ($this->isValueChanged()) { + $enabled = $this->getData('value'); + + if ($enabled) { + $this->subscriptionHandler->processEnabled(); + } else { + $this->subscriptionHandler->processDisabled(); + } + } + } catch (\Exception $e) { + $this->_logger->error($e->getMessage()); + throw new LocalizedException(__('There was an error save new configuration value.')); + } + + return parent::afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php new file mode 100644 index 0000000000000..95caceddebc88 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -0,0 +1,198 @@ +configWriter = $configWriter; + $this->flagManager = $flagManager; + $this->analyticsToken = $analyticsToken; + $this->notificationTime = $notificationTime; + $this->reinitableConfig = $reinitableConfig; + } + + /** + * Processing of activation MBI subscription. + * + * Activate process of subscription handling if Analytics token is not received. + * + * @return bool + * @since 2.2.0 + */ + public function processEnabled() + { + if (!$this->analyticsToken->isTokenExist()) { + $this->setCronSchedule(); + $this->setAttemptsFlag(); + $this->notificationTime->unsetLastTimeNotificationValue(); + $this->reinitableConfig->reinit(); + } + + return true; + } + + /** + * Set cron schedule setting into config for activation of subscription process. + * + * @return bool + * @since 2.2.0 + */ + private function setCronSchedule() + { + $cronExprArray = [ + '0', # Minute + '*', # Hour + '*', # Day of the Month + '*', # Month of the Year + '*', # Day of the Week + ]; + + $cronExprString = join(' ', $cronExprArray); + + $this->configWriter->save(self::CRON_STRING_PATH, $cronExprString); + + return true; + } + + /** + * Set flag as reserve counter of attempts subscription operation. + * + * @return bool + * @since 2.2.0 + */ + private function setAttemptsFlag() + { + return $this->flagManager + ->saveFlag(self::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue); + } + + /** + * Processing of deactivation MBI subscription. + * + * Disable data collection + * and interrupt subscription handling if Analytics token is not received. + * + * @return bool + * @since 2.2.0 + */ + public function processDisabled() + { + $this->disableCollectionData(); + + if (!$this->analyticsToken->isTokenExist()) { + $this->unsetAttemptsFlag(); + } + + return true; + } + + /** + * Unset flag of attempts subscription operation. + * + * @return bool + * @since 2.2.0 + */ + private function unsetAttemptsFlag() + { + return $this->flagManager + ->deleteFlag(self::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + } + + /** + * Unset schedule of collection data cron. + * + * @return bool + * @since 2.2.0 + */ + private function disableCollectionData() + { + $this->configWriter->delete(CollectionTime::CRON_SCHEDULE_PATH); + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php new file mode 100644 index 0000000000000..0fe9caa4ea0a0 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php @@ -0,0 +1,34 @@ +getValue())) { + throw new LocalizedException(__('Please select a vertical.')); + } + + return $this; + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Mapper.php b/app/code/Magento/Analytics/Model/Config/Mapper.php new file mode 100644 index 0000000000000..d672248777ec5 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Mapper.php @@ -0,0 +1,68 @@ + [ + * 'name' => 'file_name', + * 'providers' => [ + * 'reportProvider' => [ + * 'name' => 'report_provider_name', + * 'class' => 'Magento\Analytics\ReportXml\ReportProvider', + * 'parameters' =>[ + * 'name' => 'report_name', + * ], + * ], + * 'customProvider' => [ + * 'name' => 'custom_provider_name', + * 'class' => 'Magento\Analytics\Model\CustomProvider', + * ], + * ], + * ] + * ]; + * @since 2.2.0 + */ + public function execute($configData) + { + if (!isset($configData['config'][0]['file'])) { + return []; + } + + $files = []; + foreach ($configData['config'][0]['file'] as $fileData) { + /** just one set of providers is allowed by xsd */ + $providers = reset($fileData['providers']); + foreach ($providers as $providerType => $providerDataSet) { + /** just one set of provider data is allowed by xsd */ + $providerData = reset($providerDataSet); + /** just one set of parameters is allowed by xsd */ + $providerData['parameters'] = !empty($providerData['parameters']) + ? reset($providerData['parameters']) + : []; + $providerData['parameters'] = array_map( + 'reset', + $providerData['parameters'] + ); + $providers[$providerType] = $providerData; + } + $files[$fileData['name']] = $fileData; + $files[$fileData['name']]['providers'] = $providers; + } + return $files; + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Reader.php b/app/code/Magento/Analytics/Model/Config/Reader.php new file mode 100644 index 0000000000000..e5e120f95bbd6 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Reader.php @@ -0,0 +1,57 @@ +mapper = $mapper; + $this->readers = $readers; + } + + /** + * Read configuration scope. + * + * @param string|null $scope + * @return array + * @since 2.2.0 + */ + public function read($scope = null) + { + $data = []; + foreach ($this->readers as $reader) { + $data = array_merge_recursive($data, $reader->read($scope)); + } + + return $this->mapper->execute($data); + } +} diff --git a/app/code/Magento/Analytics/Model/Config/Source/Vertical.php b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php new file mode 100644 index 0000000000000..7aac0b070af4b --- /dev/null +++ b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php @@ -0,0 +1,55 @@ +verticals = $verticals; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function toOptionArray() + { + $result = [ + ['value' => '', 'label' => __('--Please Select--')] + ]; + + foreach ($this->verticals as $vertical) { + $result[] = ['value' => $vertical, 'label' => __($vertical)]; + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/ConfigInterface.php b/app/code/Magento/Analytics/Model/ConfigInterface.php new file mode 100644 index 0000000000000..2f84f9bffe8de --- /dev/null +++ b/app/code/Magento/Analytics/Model/ConfigInterface.php @@ -0,0 +1,24 @@ + 'command_class_name'. + * + * The list may be configured in each module via '/etc/di.xml'. + * + * @var string[] + * @since 2.2.0 + */ + private $commands; + + /** + * @var ObjectManagerInterface + * @since 2.2.0 + */ + private $objectManager; + + /** + * @param array $commands + * @param ObjectManagerInterface $objectManager + * @since 2.2.0 + */ + public function __construct( + array $commands, + ObjectManagerInterface $objectManager + ) { + $this->commands = $commands; + $this->objectManager = $objectManager; + } + + /** + * Executes a command in accordance with the given name. + * + * @param string $commandName + * @return bool + * @throws NotFoundException if the command is not found. + * @since 2.2.0 + */ + public function execute($commandName) + { + if (!array_key_exists($commandName, $this->commands)) { + throw new NotFoundException(__('Command was not found.')); + } + + /** @var \Magento\Analytics\Model\Connector\CommandInterface $command */ + $command = $this->objectManager->create($this->commands[$commandName]); + + return $command->execute(); + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/CommandInterface.php b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php new file mode 100644 index 0000000000000..cf7fe4e24f721 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php @@ -0,0 +1,23 @@ +curlFactory = $curlFactory; + $this->responseFactory = $responseFactory; + $this->converter = $converter; + $this->logger = $logger; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function request($method, $url, array $body = [], array $headers = [], $version = '1.1') + { + $response = new \Zend_Http_Response(0, []); + + try { + $curl = $this->curlFactory->create(); + $headers = $this->applyContentTypeHeaderFromConverter($headers); + + $curl->write($method, $url, $version, $headers, $this->converter->toBody($body)); + + $result = $curl->read(); + + if ($curl->getErrno()) { + $this->logger->critical( + new \Exception( + sprintf( + 'MBI service CURL connection error #%s: %s', + $curl->getErrno(), + $curl->getError() + ) + ) + ); + + return $response; + } + + $response = $this->responseFactory->create($result); + } catch (\Exception $e) { + $this->logger->critical($e); + } + + return $response; + } + + /** + * @param array $headers + * + * @return array + * @since 2.2.0 + */ + private function applyContentTypeHeaderFromConverter(array $headers) + { + $contentTypeHeaderKey = array_search($this->converter->getContentTypeHeader(), $headers); + if ($contentTypeHeaderKey === false) { + $headers[] = $this->converter->getContentTypeHeader(); + } + + return $headers; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php new file mode 100644 index 0000000000000..aa2a8ca2cbf1a --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php @@ -0,0 +1,31 @@ +converter = $converter; + $this->responseHandlers = $responseHandlers; + } + + /** + * @param \Zend_Http_Response $response + * + * @return bool|string + * @since 2.2.0 + */ + public function getResult(\Zend_Http_Response $response) + { + $result = false; + $responseBody = $this->converter->fromBody($response->getBody()); + if (array_key_exists($response->getStatus(), $this->responseHandlers)) { + $result = $this->responseHandlers[$response->getStatus()]->handleResponse($responseBody); + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php new file mode 100644 index 0000000000000..a88b87a447072 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php @@ -0,0 +1,102 @@ +analyticsToken = $analyticsToken; + $this->httpClient = $httpClient; + $this->config = $config; + $this->responseResolver = $responseResolver; + $this->logger = $logger; + } + + /** + * Notify MBI about that data collection was finished + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $result = false; + if ($this->analyticsToken->isTokenExist()) { + $response = $this->httpClient->request( + ZendClient::POST, + $this->config->getValue($this->notifyDataChangedUrlPath), + [ + "access-token" => $this->analyticsToken->getToken(), + "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL), + ] + ); + $result = $this->responseResolver->getResult($response); + } + return (bool)$result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php new file mode 100644 index 0000000000000..f0577084cbff3 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php @@ -0,0 +1,124 @@ +analyticsToken = $analyticsToken; + $this->httpClient = $httpClient; + $this->config = $config; + $this->responseResolver = $responseResolver; + $this->logger = $logger; + } + + /** + * Performs obtaining of an OTP from the MBI service. + * + * Returns received OTP or FALSE in case of failure. + * + * @return string|false + * @since 2.2.0 + */ + public function call() + { + $result = false; + + if ($this->analyticsToken->isTokenExist()) { + $response = $this->httpClient->request( + ZendClient::POST, + $this->config->getValue($this->otpUrlConfigPath), + [ + "access-token" => $this->analyticsToken->getToken(), + "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL), + ] + ); + + $result = $this->responseResolver->getResult($response); + if (!$result) { + $this->logger->warning( + sprintf( + 'Obtaining of an OTP from the MBI service has been failed: %s', + !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.' + ) + ); + } + } + + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php new file mode 100644 index 0000000000000..d385f466e2919 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php @@ -0,0 +1,26 @@ +analyticsToken = $analyticsToken; + $this->subscriptionHandler = $subscriptionHandler; + $this->subscriptionStatusProvider = $subscriptionStatusProvider; + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function handleResponse(array $responseBody) + { + if ($this->subscriptionStatusProvider->getStatus() === SubscriptionStatusProvider::ENABLED) { + $this->analyticsToken->storeToken(null); + $this->subscriptionHandler->processEnabled(); + } + return false; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php new file mode 100644 index 0000000000000..49ad1936a3975 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php @@ -0,0 +1,56 @@ +analyticsToken = $analyticsToken; + $this->converter = $converter; + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function handleResponse(array $body) + { + if (isset($body['access-token']) && !empty($body['access-token'])) { + $this->analyticsToken->storeToken($body['access-token']); + return $body['access-token']; + } + + return false; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php new file mode 100644 index 0000000000000..13a7eaa9b1fd8 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php @@ -0,0 +1,26 @@ +analyticsToken = $analyticsToken; + $this->integrationManager = $integrationManager; + $this->config = $config; + $this->httpClient = $httpClient; + $this->logger = $logger; + $this->responseResolver = $responseResolver; + } + + /** + * Executes signUp command + * + * During this call Magento generates or retrieves access token for the integration user + * In case successful generation Magento activates user and sends access token to MA + * As the response, Magento receives a token to MA + * Magento stores this token in System Configuration + * + * This method returns true in case of success + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $result = false; + $integrationToken = $this->integrationManager->generateToken(); + if ($integrationToken) { + $this->integrationManager->activateIntegration(); + $response = $this->httpClient->request( + ZendClient::POST, + $this->config->getValue($this->signUpUrlPath), + [ + "token" => $integrationToken->getData('token'), + "url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL), + ] + ); + + $result = $this->responseResolver->getResult($response); + if (!$result) { + $this->logger->warning( + sprintf( + 'Subscription for MBI service has been failed. An error occurred during token exchange: %s', + !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.' + ) + ); + } + } + + return (bool)$result; + } +} diff --git a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php new file mode 100644 index 0000000000000..ff8ad2ec85a43 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php @@ -0,0 +1,124 @@ +analyticsToken = $analyticsToken; + $this->httpClient = $httpClient; + $this->config = $config; + $this->logger = $logger; + $this->flagManager = $flagManager; + $this->responseResolver = $responseResolver; + } + + /** + * Executes update request to MBI api in case store url was changed + * + * @return bool + * @since 2.2.0 + */ + public function execute() + { + $result = false; + if ($this->analyticsToken->isTokenExist()) { + $response = $this->httpClient->request( + ZendClient::PUT, + $this->config->getValue($this->updateUrlPath), + [ + "url" => $this->flagManager + ->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE), + "new-url" => $this->config->getValue(Store::XML_PATH_SECURE_BASE_URL), + "access-token" => $this->analyticsToken->getToken(), + ] + ); + $result = $this->responseResolver->getResult($response); + if (!$result) { + $this->logger->warning( + sprintf( + 'Update of the subscription for MBI service has been failed: %s', + !empty($response->getBody()) ? $response->getBody() : 'Response body is empty.' + ) + ); + } + } + + return (bool)$result; + } +} diff --git a/app/code/Magento/Analytics/Model/Cryptographer.php b/app/code/Magento/Analytics/Model/Cryptographer.php new file mode 100644 index 0000000000000..848d2911e9a5e --- /dev/null +++ b/app/code/Magento/Analytics/Model/Cryptographer.php @@ -0,0 +1,140 @@ +analyticsToken = $analyticsToken; + $this->encodedContextFactory = $encodedContextFactory; + } + + /** + * Encrypt input data. + * + * @param string $source + * @return EncodedContext + * @throws LocalizedException + * @since 2.2.0 + */ + public function encode($source) + { + if (!is_string($source)) { + try { + $source = (string)$source; + } catch (\Exception $e) { + throw new LocalizedException(__('Input data must be string or convertible into string.')); + } + } elseif (!$source) { + throw new LocalizedException(__('Input data must be non-empty string.')); + } + if (!$this->validateCipherMethod($this->cipherMethod)) { + throw new LocalizedException(__('Not valid cipher method.')); + } + $initializationVector = $this->getInitializationVector(); + + $encodedContext = $this->encodedContextFactory->create([ + 'content' => openssl_encrypt( + $source, + $this->cipherMethod, + $this->getKey(), + OPENSSL_RAW_DATA, + $initializationVector + ), + 'initializationVector' => $initializationVector, + ]); + + return $encodedContext; + } + + /** + * Return key for encryption. + * + * @return string + * @throws LocalizedException + * @since 2.2.0 + */ + private function getKey() + { + $token = $this->analyticsToken->getToken(); + if (!$token) { + throw new LocalizedException(__('Encryption key can\'t be empty.')); + } + return hash('sha256', $token); + } + + /** + * Return established cipher method. + * + * @return string + * @since 2.2.0 + */ + private function getCipherMethod() + { + return $this->cipherMethod; + } + + /** + * Return each time generated random initialization vector which depends on the cipher method. + * + * @return string + * @since 2.2.0 + */ + private function getInitializationVector() + { + $ivSize = openssl_cipher_iv_length($this->getCipherMethod()); + return openssl_random_pseudo_bytes($ivSize); + } + + /** + * Check that cipher method is allowed for encryption. + * + * @param string $cipherMethod + * @return bool + * @since 2.2.0 + */ + private function validateCipherMethod($cipherMethod) + { + $methods = openssl_get_cipher_methods(); + return (false !== array_search($cipherMethod, $methods)); + } +} diff --git a/app/code/Magento/Analytics/Model/EncodedContext.php b/app/code/Magento/Analytics/Model/EncodedContext.php new file mode 100644 index 0000000000000..bffbf29315c11 --- /dev/null +++ b/app/code/Magento/Analytics/Model/EncodedContext.php @@ -0,0 +1,58 @@ +content = $content; + $this->initializationVector = $initializationVector; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getContent() + { + return $this->content; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getInitializationVector() + { + return $this->initializationVector; + } +} diff --git a/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php new file mode 100644 index 0000000000000..74cfd28365678 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php @@ -0,0 +1,18 @@ +filesystem = $filesystem; + $this->archive = $archive; + $this->reportWriter = $reportWriter; + $this->cryptographer = $cryptographer; + $this->fileRecorder = $fileRecorder; + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function prepareExportData() + { + try { + $tmpDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); + + $this->prepareDirectory($tmpDirectory, $this->getTmpFilesDirRelativePath()); + $this->reportWriter->write($tmpDirectory, $this->getTmpFilesDirRelativePath()); + + $tmpFilesDirectoryAbsolutePath = $this->validateSource($tmpDirectory, $this->getTmpFilesDirRelativePath()); + $archiveAbsolutePath = $this->prepareFileDirectory($tmpDirectory, $this->getArchiveRelativePath()); + $this->pack( + $tmpFilesDirectoryAbsolutePath, + $archiveAbsolutePath + ); + + $this->validateSource($tmpDirectory, $this->getArchiveRelativePath()); + $this->fileRecorder->recordNewFile( + $this->cryptographer->encode($tmpDirectory->readFile($this->getArchiveRelativePath())) + ); + } finally { + $tmpDirectory->delete($this->getTmpFilesDirRelativePath()); + $tmpDirectory->delete($this->getArchiveRelativePath()); + } + + return true; + } + + /** + * Return relative path to a directory for temporary files with reports data. + * + * @return string + * @since 2.2.0 + */ + private function getTmpFilesDirRelativePath() + { + return $this->subdirectoryPath . 'tmp/'; + } + + /** + * Return relative path to a directory for an archive. + * + * @return string + * @since 2.2.0 + */ + private function getArchiveRelativePath() + { + return $this->subdirectoryPath . $this->archiveName; + } + + /** + * Clean up a directory. + * + * @param WriteInterface $directory + * @param string $path + * @return string + * @since 2.2.0 + */ + private function prepareDirectory(WriteInterface $directory, $path) + { + $directory->delete($path); + + return $directory->getAbsolutePath($path); + } + + /** + * Remove a file and a create parent directory a file. + * + * @param WriteInterface $directory + * @param string $path + * @return string + * @since 2.2.0 + */ + private function prepareFileDirectory(WriteInterface $directory, $path) + { + $directory->delete($path); + if (dirname($path) !== '.') { + $directory->create(dirname($path)); + } + + return $directory->getAbsolutePath($path); + } + + /** + * Packing data into an archive. + * + * @param string $source + * @param string $destination + * @return bool + * @since 2.2.0 + */ + private function pack($source, $destination) + { + $this->archive->pack( + $source, + $destination, + is_dir($source) ?: false + ); + + return true; + } + + /** + * Validate that data source exist. + * + * Return absolute path in a validated data source. + * + * @param WriteInterface $directory + * @param string $path + * @return string + * @throws LocalizedException If source is not exist. + * @since 2.2.0 + */ + private function validateSource(WriteInterface $directory, $path) + { + if (!$directory->isExist($path)) { + throw new LocalizedException(__('Source "%1" is not exist', $directory->getAbsolutePath($path))); + } + + return $directory->getAbsolutePath($path); + } +} diff --git a/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php new file mode 100644 index 0000000000000..c8af595c2aadf --- /dev/null +++ b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php @@ -0,0 +1,21 @@ +exportDataHandler = $exportDataHandler; + $this->analyticsConnector = $connector; + } + + /** + * {@inheritdoc} + * Execute notification command. + * + * @return bool + * @since 2.2.0 + */ + public function prepareExportData() + { + $result = $this->exportDataHandler->prepareExportData(); + $this->analyticsConnector->execute('notifyDataChanged'); + return $result; + } +} diff --git a/app/code/Magento/Analytics/Model/FileInfo.php b/app/code/Magento/Analytics/Model/FileInfo.php new file mode 100644 index 0000000000000..edfac858d6f68 --- /dev/null +++ b/app/code/Magento/Analytics/Model/FileInfo.php @@ -0,0 +1,58 @@ +path = $path; + $this->initializationVector = $initializationVector; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getPath() + { + return $this->path; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getInitializationVector() + { + return $this->initializationVector; + } +} diff --git a/app/code/Magento/Analytics/Model/FileInfoManager.php b/app/code/Magento/Analytics/Model/FileInfoManager.php new file mode 100644 index 0000000000000..204995e133d20 --- /dev/null +++ b/app/code/Magento/Analytics/Model/FileInfoManager.php @@ -0,0 +1,133 @@ +flagManager = $flagManager; + $this->fileInfoFactory = $fileInfoFactory; + } + + /** + * Save FileInfo object. + * + * @param FileInfo $fileInfo + * @return bool + * @throws LocalizedException + * @since 2.2.0 + */ + public function save(FileInfo $fileInfo) + { + $parameters = []; + $parameters['initializationVector'] = $fileInfo->getInitializationVector(); + $parameters['path'] = $fileInfo->getPath(); + + $emptyParameters = array_diff($parameters, array_filter($parameters)); + if ($emptyParameters) { + throw new LocalizedException( + __('These arguments can\'t be empty "%1"', implode(', ', array_keys($emptyParameters))) + ); + } + + foreach ($this->encodedParameters as $encodedParameter) { + $parameters[$encodedParameter] = $this->encodeValue($parameters[$encodedParameter]); + } + + $this->flagManager->saveFlag($this->flagCode, $parameters); + + return true; + } + + /** + * Load FileInfo object. + * + * @return FileInfo + * @since 2.2.0 + */ + public function load() + { + $parameters = $this->flagManager->getFlagData($this->flagCode) ?: []; + + $encodedParameters = array_intersect($this->encodedParameters, array_keys($parameters)); + foreach ($encodedParameters as $encodedParameter) { + $parameters[$encodedParameter] = $this->decodeValue($parameters[$encodedParameter]); + } + + $fileInfo = $this->fileInfoFactory->create($parameters); + + return $fileInfo; + } + + /** + * Encode value. + * + * @param string $value + * @return string + * @since 2.2.0 + */ + private function encodeValue($value) + { + return base64_encode($value); + } + + /** + * Decode value. + * + * @param string $value + * @return string + * @since 2.2.0 + */ + private function decodeValue($value) + { + return base64_decode($value); + } +} diff --git a/app/code/Magento/Analytics/Model/FileRecorder.php b/app/code/Magento/Analytics/Model/FileRecorder.php new file mode 100644 index 0000000000000..94e0c59d9321b --- /dev/null +++ b/app/code/Magento/Analytics/Model/FileRecorder.php @@ -0,0 +1,147 @@ +fileInfoManager = $fileInfoManager; + $this->fileInfoFactory = $fileInfoFactory; + $this->filesystem = $filesystem; + } + + /** + * Save new encrypted file, register it and remove old registered file. + * + * @param EncodedContext $encodedContext + * @return bool + * @since 2.2.0 + */ + public function recordNewFile(EncodedContext $encodedContext) + { + $directory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + + $fileRelativePath = $this->getFileRelativePath(); + $directory->writeFile($fileRelativePath, $encodedContext->getContent()); + + $fileInfo = $this->fileInfoManager->load(); + $this->registerFile($encodedContext, $fileRelativePath); + $this->removeOldFile($fileInfo, $directory); + + return true; + } + + /** + * Return relative path to encoded file. + * + * @return string + * @since 2.2.0 + */ + private function getFileRelativePath() + { + return $this->fileSubdirectoryPath . hash('sha256', time()) + . '/' . $this->encodedFileName; + } + + /** + * Register encoded file. + * + * @param EncodedContext $encodedContext + * @param string $fileRelativePath + * @return bool + * @since 2.2.0 + */ + private function registerFile(EncodedContext $encodedContext, $fileRelativePath) + { + $newFileInfo = $this->fileInfoFactory->create( + [ + 'path' => $fileRelativePath, + 'initializationVector' => $encodedContext->getInitializationVector(), + ] + ); + $this->fileInfoManager->save($newFileInfo); + + return true; + } + + /** + * Remove previously registered file. + * + * @param FileInfo $fileInfo + * @param WriteInterface $directory + * @return bool + * @since 2.2.0 + */ + private function removeOldFile(FileInfo $fileInfo, WriteInterface $directory) + { + if (!$fileInfo->getPath()) { + return true; + } + + $directory->delete($fileInfo->getPath()); + + $directoryName = dirname($fileInfo->getPath()); + if ($directoryName !== '.') { + $directory->delete($directoryName); + } + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/IntegrationManager.php b/app/code/Magento/Analytics/Model/IntegrationManager.php new file mode 100644 index 0000000000000..b2694ac8241c1 --- /dev/null +++ b/app/code/Magento/Analytics/Model/IntegrationManager.php @@ -0,0 +1,135 @@ +integrationService = $integrationService; + $this->config = $config; + $this->oauthService = $oauthService; + } + + /** + * Activate predefined integration user + * + * @return bool + * @throws NoSuchEntityException + * @since 2.2.0 + */ + public function activateIntegration() + { + $integration = $this->integrationService->findByName( + $this->config->getConfigDataValue('analytics/integration_name') + ); + if (!$integration->getId()) { + throw new NoSuchEntityException(__('Cannot find predefined integration user!')); + } + $integrationData = $this->getIntegrationData(Integration::STATUS_ACTIVE); + $integrationData['integration_id'] = $integration->getId(); + $this->integrationService->update($integrationData); + return true; + } + + /** + * This method execute Generate Token command and enable integration + * + * @return bool|\Magento\Integration\Model\Oauth\Token + * @since 2.2.0 + */ + public function generateToken() + { + $consumerId = $this->generateIntegration()->getConsumerId(); + $accessToken = $this->oauthService->getAccessToken($consumerId); + if (!$accessToken && $this->oauthService->createAccessToken($consumerId, true)) { + $accessToken = $this->oauthService->getAccessToken($consumerId); + } + return $accessToken; + } + + /** + * Returns consumer Id for MA integration user + * + * @return \Magento\Integration\Model\Integration + * @since 2.2.0 + */ + private function generateIntegration() + { + $integration = $this->integrationService->findByName( + $this->config->getConfigDataValue('analytics/integration_name') + ); + if (!$integration->getId()) { + $integration = $this->integrationService->create($this->getIntegrationData()); + } + return $integration; + } + + /** + * Returns default attributes for MA integration user + * + * @param int $status + * @return array + * @since 2.2.0 + */ + private function getIntegrationData($status = Integration::STATUS_INACTIVE) + { + $integrationData = [ + 'name' => $this->config->getConfigDataValue('analytics/integration_name'), + 'status' => $status, + 'all_resources' => false, + 'resource' => [ + 'Magento_Analytics::analytics', + 'Magento_Analytics::analytics_api' + ], + ]; + return $integrationData; + } +} diff --git a/app/code/Magento/Analytics/Model/Link.php b/app/code/Magento/Analytics/Model/Link.php new file mode 100644 index 0000000000000..34479e9ae4f61 --- /dev/null +++ b/app/code/Magento/Analytics/Model/Link.php @@ -0,0 +1,60 @@ +url = $url; + $this->initializationVector = $initializationVector; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getUrl() + { + return $this->url; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getInitializationVector() + { + return $this->initializationVector; + } +} diff --git a/app/code/Magento/Analytics/Model/LinkProvider.php b/app/code/Magento/Analytics/Model/LinkProvider.php new file mode 100644 index 0000000000000..6d09e20fef1a4 --- /dev/null +++ b/app/code/Magento/Analytics/Model/LinkProvider.php @@ -0,0 +1,95 @@ +linkFactory = $linkFactory; + $this->fileInfoManager = $fileInfoManager; + $this->storeManager = $storeManager; + } + + /** + * Returns base url to file according to store configuration + * + * @param FileInfo $fileInfo + * @return string + * @since 2.2.0 + */ + private function getBaseUrl(FileInfo $fileInfo) + { + return $this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA) . $fileInfo->getPath(); + } + + /** + * Verify is requested file ready + * + * @param FileInfo $fileInfo + * @return bool + * @since 2.2.0 + */ + private function isFileReady(FileInfo $fileInfo) + { + return $fileInfo->getPath() && $fileInfo->getInitializationVector(); + } + + /** + * @inheritdoc + * @since 2.2.0 + */ + public function get() + { + $fileInfo = $this->fileInfoManager->load(); + if (!$this->isFileReady($fileInfo)) { + throw new NoSuchEntityException(__('File is not ready yet.')); + } + return $this->linkFactory->create( + [ + 'url' => $this->getBaseUrl($fileInfo), + 'initializationVector' => base64_encode($fileInfo->getInitializationVector()) + ] + ); + } +} diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php new file mode 100644 index 0000000000000..c36f830a70762 --- /dev/null +++ b/app/code/Magento/Analytics/Model/NotificationTime.php @@ -0,0 +1,72 @@ +flagManager = $flagManager; + } + + /** + * Stores last notification time + * + * @param string $value + * @return bool + * @since 2.2.0 + */ + public function storeLastTimeNotification($value) + { + return $this->flagManager->saveFlag(self::NOTIFICATION_TIME, $value); + } + + /** + * Returns last time when merchant was notified about Analytic services + * + * @return int + * @since 2.2.0 + */ + public function getLastTimeNotification() + { + return $this->flagManager->getFlagData(self::NOTIFICATION_TIME); + } + + /** + * Remove last notification time flag. + * + * @return bool + * @since 2.2.0 + */ + public function unsetLastTimeNotificationValue() + { + return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME); + } +} diff --git a/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php new file mode 100644 index 0000000000000..e2bdf354b040c --- /dev/null +++ b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php @@ -0,0 +1,66 @@ +subscriptionUpdateHandler = $subscriptionUpdateHandler; + } + + /** + * Add additional handling after config value was saved. + * + * @param Value $subject + * @param Value $result + * @return Value + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function afterAfterSave( + Value $subject, + Value $result + ) { + if ($this->isPluginApplicable($result)) { + $this->subscriptionUpdateHandler->processUrlUpdate($result->getOldValue()); + } + + return $result; + } + + /** + * @param Value $result + * @return bool + * @since 2.2.0 + */ + private function isPluginApplicable(Value $result) + { + return $result->isValueChanged() + && ($result->getPath() === Store::XML_PATH_SECURE_BASE_URL) + && ($result->getScope() === ScopeConfigInterface::SCOPE_TYPE_DEFAULT); + } +} diff --git a/app/code/Magento/Analytics/Model/ProviderFactory.php b/app/code/Magento/Analytics/Model/ProviderFactory.php new file mode 100644 index 0000000000000..35af7d5ddaa1c --- /dev/null +++ b/app/code/Magento/Analytics/Model/ProviderFactory.php @@ -0,0 +1,43 @@ +objectManager = $objectManager; + } + + /** + * @param string $providerName + * @return object + * @since 2.2.0 + */ + public function create($providerName) + { + return $this->objectManager->get($providerName); + } +} diff --git a/app/code/Magento/Analytics/Model/ReportUrlProvider.php b/app/code/Magento/Analytics/Model/ReportUrlProvider.php new file mode 100644 index 0000000000000..dfa27358e252b --- /dev/null +++ b/app/code/Magento/Analytics/Model/ReportUrlProvider.php @@ -0,0 +1,102 @@ +analyticsToken = $analyticsToken; + $this->otpRequest = $otpRequest; + $this->config = $config; + $this->flagManager = $flagManager; + } + + /** + * Provide URL on resource with reports. + * + * @return string + * @throws SubscriptionUpdateException + * @since 2.2.0 + */ + public function getUrl() + { + if ($this->flagManager->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)) { + throw new SubscriptionUpdateException(__( + 'Your Base URL has been changed and your reports are being updated. ' + . 'Advanced Reporting will be available once this change has been processed. Please try again later.' + )); + } + + $url = $this->config->getValue($this->urlReportConfigPath); + if ($this->analyticsToken->isTokenExist()) { + $otp = $this->otpRequest->call(); + if ($otp) { + $query = http_build_query(['otp' => $otp], '', '&'); + $url .= '?' . $query; + } + } + + return $url; + } +} diff --git a/app/code/Magento/Analytics/Model/ReportWriter.php b/app/code/Magento/Analytics/Model/ReportWriter.php new file mode 100644 index 0000000000000..ae3522c6f4351 --- /dev/null +++ b/app/code/Magento/Analytics/Model/ReportWriter.php @@ -0,0 +1,108 @@ +config = $config; + $this->reportValidator = $reportValidator; + $this->providerFactory = $providerFactory; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function write(WriteInterface $directory, $path) + { + $errorsList = []; + foreach ($this->config->get() as $file) { + $provider = reset($file['providers']); + if (isset($provider['parameters']['name'])) { + $error = $this->reportValidator->validate($provider['parameters']['name']); + if ($error) { + $errorsList[] = $error; + continue; + } + } + /** @var $providerObject */ + $providerObject = $this->providerFactory->create($provider['class']); + $fileName = $provider['parameters'] ? $provider['parameters']['name'] : $provider['name']; + $fileFullPath = $path . $fileName . '.csv'; + $fileData = $providerObject->getReport(...array_values($provider['parameters'])); + $stream = $directory->openFile($fileFullPath, 'w+'); + $stream->lock(); + $headers = []; + foreach ($fileData as $row) { + if (!$headers) { + $headers = array_keys($row); + $stream->writeCsv($headers); + } + $stream->writeCsv($row); + } + $stream->unlock(); + $stream->close(); + } + if ($errorsList) { + $errorStream = $directory->openFile($path . $this->errorsFileName, 'w+'); + foreach ($errorsList as $error) { + $errorStream->lock(); + $errorStream->writeCsv($error); + $errorStream->unlock(); + } + $errorStream->close(); + } + + return true; + } +} diff --git a/app/code/Magento/Analytics/Model/ReportWriterInterface.php b/app/code/Magento/Analytics/Model/ReportWriterInterface.php new file mode 100644 index 0000000000000..bb7f8dfbe26a6 --- /dev/null +++ b/app/code/Magento/Analytics/Model/ReportWriterInterface.php @@ -0,0 +1,30 @@ +moduleManager = $moduleManager; + } + + /** + * Returns module with module status + * + * @return array + * @since 2.2.0 + */ + public function current() + { + $current = parent::current(); + if (is_array($current) && isset($current['module_name'])) { + $current['status'] = + $this->moduleManager->isEnabled($current['module_name']) == 1 ? 'Enabled' : "Disabled"; + } + return $current; + } +} diff --git a/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php new file mode 100644 index 0000000000000..e070e2c669ccf --- /dev/null +++ b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php @@ -0,0 +1,109 @@ +scopeConfig = $scopeConfig; + $this->configPaths = $configPaths; + $this->storeManager = $storeManager; + } + + /** + * Generates report using config paths from di.xml + * For each website and store + * @return \IteratorIterator + * @since 2.2.0 + */ + public function getReport() + { + $configReport = $this->generateReportForScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0); + + /** @var WebsiteInterface $website */ + foreach ($this->storeManager->getWebsites() as $website) { + $configReport = array_merge( + $this->generateReportForScope(ScopeInterface::SCOPE_WEBSITES, $website->getId()), + $configReport + ); + } + + /** @var StoreInterface $store */ + foreach ($this->storeManager->getStores() as $store) { + $configReport = array_merge( + $this->generateReportForScope(ScopeInterface::SCOPE_STORES, $store->getId()), + $configReport + ); + } + return new \IteratorIterator(new \ArrayIterator($configReport)); + } + + /** + * Creates report from config for scope type and scope id. + * + * @param string $scope + * @param int $scopeId + * @return array + * @since 2.2.0 + */ + private function generateReportForScope($scope, $scopeId) + { + $report = []; + foreach ($this->configPaths as $configPath) { + $report[] = [ + "config_path" => $configPath, + "scope" => $scope, + "scope_id" => $scopeId, + "value" => $this->scopeConfig->getValue( + $configPath, + $scope, + $scopeId + ) + ]; + } + return $report; + } +} diff --git a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php new file mode 100644 index 0000000000000..478e0ae4ccd63 --- /dev/null +++ b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php @@ -0,0 +1,128 @@ +scopeConfig = $scopeConfig; + $this->analyticsToken = $analyticsToken; + $this->flagManager = $flagManager; + } + + /** + * Retrieve subscription status to Magento BI Advanced Reporting. + * + * Statuses: + * Enabled - if subscription is enabled and MA token was received; + * Pending - if subscription is enabled and MA token was not received; + * Disabled - if subscription is not enabled. + * Failed - if subscription is enabled and token was not received after attempts ended. + * + * @return string + * @since 2.2.0 + */ + public function getStatus() + { + $isSubscriptionEnabledInConfig = $this->scopeConfig->getValue('analytics/subscription/enabled'); + if ($isSubscriptionEnabledInConfig) { + return $this->getStatusForEnabledSubscription(); + } + + return $this->getStatusForDisabledSubscription(); + } + + /** + * Retrieve status for subscription that enabled in config. + * + * @return string + * @since 2.2.0 + */ + public function getStatusForEnabledSubscription() + { + $status = static::ENABLED; + if ($this->flagManager->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE)) { + $status = self::PENDING; + } + + if (!$this->analyticsToken->isTokenExist()) { + $status = static::PENDING; + if ($this->flagManager->getFlagData(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) === null) { + $status = static::FAILED; + } + } + + return $status; + } + + /** + * Retrieve status for subscription that disabled in config. + * + * @return string + * @since 2.2.0 + */ + public function getStatusForDisabledSubscription() + { + return static::DISABLED; + } +} diff --git a/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php new file mode 100644 index 0000000000000..688caedf8e864 --- /dev/null +++ b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php @@ -0,0 +1,88 @@ +subscriptionStatusProvider = $subscriptionStatusProvider; + $this->urlBuilder = $urlBuilder; + } + + /** + * @inheritdoc + * + * @codeCoverageIgnore + * @since 2.2.0 + */ + public function getIdentity() + { + return hash('sha256', 'ANALYTICS_NOTIFICATION'); + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function isDisplayed() + { + return $this->subscriptionStatusProvider->getStatus() === SubscriptionStatusProvider::FAILED; + } + + /** + * {@inheritdoc} + * @since 2.2.0 + */ + public function getText() + { + $messageDetails = ''; + + $messageDetails .= __('Failed to synchronize data to the Magento Business Intelligence service. '); + $messageDetails .= __( + 'Retry Synchronization', + $this->urlBuilder->getUrl('analytics/subscription/retry') + ); + + return $messageDetails; + } + + /** + * @inheritdoc + * + * @codeCoverageIgnore + * @since 2.2.0 + */ + public function getSeverity() + { + return self::SEVERITY_MAJOR; + } +} diff --git a/app/code/Magento/Analytics/README.md b/app/code/Magento/Analytics/README.md new file mode 100644 index 0000000000000..ee6d017a1f3ac --- /dev/null +++ b/app/code/Magento/Analytics/README.md @@ -0,0 +1,25 @@ +# Magento_Analytics module + +The Magento_Analytics module integrates your Magento instance with the [Magento Business Intelligence (MBI)](https://magento.com/products/business-intelligence) to use [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html) functionality. + +The module implements the following functionality: + +* enabling subscription to the MBI and automatic re-subscription +* changing the base URL with the same MBI account remained +* declaring the configuration schemas for report data collection +* collecting the Magento instance data as reports for the MBI +* introducing API that provides the collected data +* extending Magento configuration with the module parameters: + * subscription status (enabled/disabled) + * industry (a business area in which the instance website works) + * time of data collection (time of the day when the module collects data) + +## Structure + +Beyond the [usual module file structure](http://devdocs.magento.com/guides/v2.2/architecture/archi_perspectives/components/modules/mod_intro.html) the module contains a directory `ReportXml`. +[Report XML](http://devdocs.magento.com/guides/v2.2/advanced-reporting/report-xml.html) is a markup language used to build reports for Advanced Reporting. +The language declares SQL queries using XML declaration. + +## Extensibility + +We do not recommend to extend the Magento_Analytics module. It introduces an API that is purposed to transfer the collected data. Note that the API cannot be used for other needs. diff --git a/app/code/Magento/Analytics/ReportXml/Config.php b/app/code/Magento/Analytics/ReportXml/Config.php new file mode 100644 index 0000000000000..4176486fd0993 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Config.php @@ -0,0 +1,47 @@ +data = $data; + } + + /** + * Returns config value by name + * + * @param string $queryName + * @return array + * @since 2.2.0 + */ + public function get($queryName) + { + return $this->data->get($queryName); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php new file mode 100644 index 0000000000000..a479b70c91945 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php @@ -0,0 +1,64 @@ +hasAttributes()) { + $attrs = $source->attributes; + foreach ($attrs as $attr) { + $result[$attr->name] = $attr->value; + } + } + if ($source->hasChildNodes()) { + $children = $source->childNodes; + if ($children->length == 1) { + $child = $children->item(0); + if ($child->nodeType == XML_TEXT_NODE) { + $result['_value'] = $child->nodeValue; + return count($result) == 1 ? $result['_value'] : $result; + } + } + foreach ($children as $child) { + if ($child instanceof \DOMCharacterData) { + continue; + } + $result[$child->nodeName][] = $this->convertNode($child); + } + } + return $result; + } + + /** + * Converts XML document into corresponding array. + * + * @param \DOMDocument $source + * @return array + * @since 2.2.0 + */ + public function convert($source) + { + return $this->convertNode($source); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/Config/Mapper.php b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php new file mode 100644 index 0000000000000..8da73e257b825 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php @@ -0,0 +1,39 @@ +readers = $readers; + $this->mapper = $mapper; + } + + /** + * Reads configuration according to the given scope. + * + * @param string|null $scope + * @return array + * @since 2.2.0 + */ + public function read($scope = null) + { + $data = []; + foreach ($this->readers as $reader) { + $data = array_merge_recursive($data, $reader->read($scope)); + } + return $this->mapper->execute($data); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/ConfigInterface.php b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php new file mode 100644 index 0000000000000..b9271700f6758 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php @@ -0,0 +1,25 @@ +resourceConnection = $resourceConnection; + $this->objectManager = $objectManager; + } + + /** + * Creates one-time connection for export + * + * @param string $connectionName + * @return AdapterInterface + * @since 2.2.0 + */ + public function getConnection($connectionName) + { + $connection = $this->resourceConnection->getConnection($connectionName); + $connectionClassName = get_class($connection); + $configData = $connection->getConfig(); + $configData['use_buffered_query'] = false; + unset($configData['persistent']); + return $this->objectManager->create( + $connectionClassName, + [ + 'config' => $configData + ] + ); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php new file mode 100644 index 0000000000000..e8c35ad46e2e5 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php @@ -0,0 +1,29 @@ +conditionResolver = $conditionResolver; + $this->nameResolver = $nameResolver; + } + + /** + * Assembles WHERE conditions + * + * @param SelectBuilder $selectBuilder + * @param array $queryConfig + * @return SelectBuilder + * @since 2.2.0 + */ + public function assemble(SelectBuilder $selectBuilder, $queryConfig) + { + if (!isset($queryConfig['source']['filter'])) { + return $selectBuilder; + } + $filters = $this->conditionResolver->getFilter( + $selectBuilder, + $queryConfig['source']['filter'], + $this->nameResolver->getAlias($queryConfig['source']) + ); + $selectBuilder->setFilters(array_merge_recursive($selectBuilder->getFilters(), [$filters])); + return $selectBuilder; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php new file mode 100644 index 0000000000000..8b6f739e3ecdc --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php @@ -0,0 +1,75 @@ +nameResolver = $nameResolver; + $this->columnsResolver = $columnsResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Assembles FROM condition + * + * @param SelectBuilder $selectBuilder + * @param array $queryConfig + * @return SelectBuilder + * @since 2.2.0 + */ + public function assemble(SelectBuilder $selectBuilder, $queryConfig) + { + $selectBuilder->setFrom( + [ + $this->nameResolver->getAlias($queryConfig['source']) => + $this->resourceConnection + ->getTableName($this->nameResolver->getName($queryConfig['source'])), + ] + ); + $columns = $this->columnsResolver->getColumns($selectBuilder, $queryConfig['source']); + $selectBuilder->setColumns(array_merge($selectBuilder->getColumns(), $columns)); + return $selectBuilder; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php new file mode 100644 index 0000000000000..ec83019c39c31 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php @@ -0,0 +1,120 @@ +conditionResolver = $conditionResolver; + $this->nameResolver = $nameResolver; + $this->columnsResolver = $columnsResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Assembles JOIN conditions + * + * @param SelectBuilder $selectBuilder + * @param array $queryConfig + * @return SelectBuilder + * @since 2.2.0 + */ + public function assemble(SelectBuilder $selectBuilder, $queryConfig) + { + if (!isset($queryConfig['source']['link-source'])) { + return $selectBuilder; + } + $joins = []; + $filters = $selectBuilder->getFilters(); + + $sourceAlias = $this->nameResolver->getAlias($queryConfig['source']); + + foreach ($queryConfig['source']['link-source'] as $join) { + $joinAlias = $this->nameResolver->getAlias($join); + + $joins[$joinAlias] = [ + 'link-type' => isset($join['link-type']) ? $join['link-type'] : 'left', + 'table' => [ + $joinAlias => $this->resourceConnection + ->getTableName($this->nameResolver->getName($join)), + ], + 'condition' => $this->conditionResolver->getFilter( + $selectBuilder, + $join['using'], + $joinAlias, + $sourceAlias + ) + ]; + if (isset($join['filter'])) { + $filters = array_merge( + $filters, + [ + $this->conditionResolver->getFilter( + $selectBuilder, + $join['filter'], + $joinAlias, + $sourceAlias + ) + ] + ); + } + $columns = $this->columnsResolver->getColumns($selectBuilder, isset($join['attribute']) ? $join : []); + $selectBuilder->setColumns(array_merge($selectBuilder->getColumns(), $columns)); + } + $selectBuilder->setFilters($filters); + $selectBuilder->setJoins(array_merge($selectBuilder->getJoins(), $joins)); + return $selectBuilder; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php new file mode 100644 index 0000000000000..5b9279175b5ff --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php @@ -0,0 +1,107 @@ +nameResolver = $nameResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Returns connection + * + * @return \Magento\Framework\DB\Adapter\AdapterInterface + * @since 2.2.0 + */ + private function getConnection() + { + if (!$this->connection) { + $this->connection = $this->resourceConnection->getConnection(); + } + return $this->connection; + } + + /** + * Set columns list to SelectBuilder + * + * @param SelectBuilder $selectBuilder + * @param array $entityConfig + * @return array + * @since 2.2.0 + */ + public function getColumns(SelectBuilder $selectBuilder, $entityConfig) + { + if (!isset($entityConfig['attribute'])) { + return []; + } + $group = []; + $columns = $selectBuilder->getColumns(); + foreach ($entityConfig['attribute'] as $attributeData) { + $columnAlias = $this->nameResolver->getAlias($attributeData); + $tableAlias = $this->nameResolver->getAlias($entityConfig); + $columnName = $this->nameResolver->getName($attributeData); + if (isset($attributeData['function'])) { + $prefix = ''; + if (isset($attributeData['distinct']) && $attributeData['distinct'] == true) { + $prefix = ' DISTINCT '; + } + $expression = new ColumnValueExpression( + strtoupper($attributeData['function']) . '(' . $prefix + . $this->getConnection()->quoteIdentifier($tableAlias . '.' . $columnName) + . ')' + ); + } else { + $expression = $tableAlias . '.' . $columnName; + } + $columns[$columnAlias] = $expression; + if (isset($attributeData['group'])) { + $group[$columnAlias] = $expression; + } + } + $selectBuilder->setGroup(array_merge($selectBuilder->getGroup(), $group)); + return $columns; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php new file mode 100644 index 0000000000000..96a7b0b95cafd --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php @@ -0,0 +1,175 @@ + '%1$s = %2$s', + 'neq' => '%1$s != %2$s', + 'like' => '%1$s LIKE %2$s', + 'nlike' => '%1$s NOT LIKE %2$s', + 'in' => '%1$s IN(%2$s)', + 'nin' => '%1$s NOT IN(%2$s)', + 'notnull' => '%1$s IS NOT NULL', + 'null' => '%1$s IS NULL', + 'gt' => '%1$s > %2$s', + 'lt' => '%1$s < %2$s', + 'gteq' => '%1$s >= %2$s', + 'lteq' => '%1$s <= %2$s', + 'finset' => 'FIND_IN_SET(%2$s, %1$s)' + ]; + + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface + * @since 2.2.0 + */ + private $connection; + + /** + * @var ResourceConnection + * @since 2.2.0 + */ + private $resourceConnection; + + /** + * ConditionResolver constructor. + * @param ResourceConnection $resourceConnection + * @since 2.2.0 + */ + public function __construct( + ResourceConnection $resourceConnection + ) { + $this->resourceConnection = $resourceConnection; + } + + /** + * Returns connection + * + * @return \Magento\Framework\DB\Adapter\AdapterInterface + * @since 2.2.0 + */ + private function getConnection() + { + if (!$this->connection) { + $this->connection = $this->resourceConnection->getConnection(); + } + return $this->connection; + } + + /** + * Returns value for condition + * + * @param string $condition + * @param string $referencedEntity + * @return mixed|null|string|\Zend_Db_Expr + * @since 2.2.0 + */ + private function getValue($condition, $referencedEntity) + { + $value = null; + $argument = isset($condition['_value']) ? $condition['_value'] : null; + if (!isset($condition['type'])) { + $condition['type'] = 'value'; + } + + switch ($condition['type']) { + case "value": + $value = $this->getConnection()->quote($argument); + break; + case "variable": + $value = new Expression($argument); + break; + case "identifier": + $value = $this->getConnection()->quoteIdentifier( + $referencedEntity ? $referencedEntity . '.' . $argument : $argument + ); + break; + } + return $value; + } + + /** + * Returns condition for WHERE + * + * @param SelectBuilder $selectBuilder + * @param string $tableName + * @param array $condition + * @param null|string $referencedEntity + * @return string + * @since 2.2.0 + */ + private function getCondition(SelectBuilder $selectBuilder, $tableName, $condition, $referencedEntity = null) + { + $columns = $selectBuilder->getColumns(); + if (isset($columns[$condition['attribute']]) + && $columns[$condition['attribute']] instanceof Expression + ) { + $expression = $columns[$condition['attribute']]; + } else { + $expression = $this->getConnection()->quoteIdentifier($tableName . '.' . $condition['attribute']); + } + return sprintf( + $this->conditionMap[$condition['operator']], + $expression, + $this->getValue($condition, $referencedEntity) + ); + } + + /** + * Build WHERE condition + * + * @param SelectBuilder $selectBuilder + * @param array $filterConfig + * @param string $aliasName + * @param null|string $referencedAlias + * @return array + * @since 2.2.0 + */ + public function getFilter(SelectBuilder $selectBuilder, $filterConfig, $aliasName, $referencedAlias = null) + { + $filtersParts = []; + foreach ($filterConfig as $filter) { + $glue = $filter['glue']; + $parts = []; + foreach ($filter['condition'] as $condition) { + if (isset($condition['type']) && $condition['type'] == 'variable') { + $selectBuilder->setParams(array_merge($selectBuilder->getParams(), [$condition['_value']])); + } + $parts[] = $this->getCondition( + $selectBuilder, + $aliasName, + $condition, + $referencedAlias + ); + } + if (isset($filter['filter'])) { + $parts[] = '(' . $this->getFilter( + $selectBuilder, + $filter['filter'], + $aliasName, + $referencedAlias + ) . ')'; + } + $filtersParts[] = '(' . implode(' ' . strtoupper($glue) . ' ', $parts) . ')'; + } + return implode(' OR ', $filtersParts); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php new file mode 100644 index 0000000000000..fdea82ba25426 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php @@ -0,0 +1,43 @@ +getName($elementConfig); + if (isset($elementConfig['alias'])) { + $alias = $elementConfig['alias']; + } + return $alias; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php new file mode 100644 index 0000000000000..1092d5fd1e4fc --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php @@ -0,0 +1,69 @@ +connectionFactory = $connectionFactory; + $this->queryFactory = $queryFactory; + } + + /** + * Tries to do query for provided report with limit 0 and return error information if it failed + * + * @param string $name + * @param SearchCriteriaInterface $criteria + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function validate($name, SearchCriteriaInterface $criteria = null) + { + $query = $this->queryFactory->create($name); + $connection = $this->connectionFactory->getConnection($query->getConnectionName()); + $query->getSelect()->limit(0); + try { + $connection->query($query->getSelect()); + } catch (\Zend_Db_Statement_Exception $e) { + return [$name, $e->getMessage()]; + } + + return []; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php new file mode 100644 index 0000000000000..bb37af94c9419 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php @@ -0,0 +1,318 @@ +resourceConnection = $resourceConnection; + } + + /** + * Get join condition + * + * @return array + * @since 2.2.0 + */ + public function getJoins() + { + return $this->joins; + } + + /** + * Set joins conditions + * + * @param array $joins + * @return void + * @since 2.2.0 + */ + public function setJoins($joins) + { + $this->joins = $joins; + } + + /** + * Get connection name + * + * @return string + * @since 2.2.0 + */ + public function getConnectionName() + { + return $this->connectionName; + } + + /** + * Set connection name + * + * @param string $connectionName + * @return void + * @since 2.2.0 + */ + public function setConnectionName($connectionName) + { + $this->connectionName = $connectionName; + } + + /** + * Get columns + * + * @return array + * @since 2.2.0 + */ + public function getColumns() + { + return $this->columns; + } + + /** + * Set columns + * + * @param array $columns + * @return void + * @since 2.2.0 + */ + public function setColumns($columns) + { + $this->columns = $columns; + } + + /** + * Get filters + * + * @return array + * @since 2.2.0 + */ + public function getFilters() + { + return $this->filters; + } + + /** + * Set filters + * + * @param array $filters + * @return void + * @since 2.2.0 + */ + public function setFilters($filters) + { + $this->filters = $filters; + } + + /** + * Get from condition + * + * @return array + * @since 2.2.0 + */ + public function getFrom() + { + return $this->from; + } + + /** + * Set from condition + * + * @param array $from + * @return void + * @since 2.2.0 + */ + public function setFrom($from) + { + $this->from = $from; + } + + /** + * Process JOIN conditions + * + * @param Select $select + * @param array $joinConfig + * @return Select + * @since 2.2.0 + */ + private function processJoin(Select $select, $joinConfig) + { + switch ($joinConfig['link-type']) { + case 'left': + $select->joinLeft($joinConfig['table'], $joinConfig['condition'], []); + break; + case 'inner': + $select->joinInner($joinConfig['table'], $joinConfig['condition'], []); + break; + case 'right': + $select->joinRight($joinConfig['table'], $joinConfig['condition'], []); + break; + } + return $select; + } + + /** + * Creates Select object + * + * @return Select + * @since 2.2.0 + */ + public function create() + { + $connection = $this->resourceConnection->getConnection($this->getConnectionName()); + $select = $connection->select(); + $select->from($this->getFrom(), []); + $select->columns($this->getColumns()); + foreach ($this->getFilters() as $filter) { + $select->where($filter); + } + foreach ($this->getJoins() as $joinConfig) { + $select = $this->processJoin($select, $joinConfig); + } + if (!empty($this->getGroup())) { + $select->group(implode(', ', $this->getGroup())); + } + return $select; + } + + /** + * Returns group + * + * @return array + * @since 2.2.0 + */ + public function getGroup() + { + return $this->group; + } + + /** + * Set group + * + * @param array $group + * @return void + * @since 2.2.0 + */ + public function setGroup($group) + { + $this->group = $group; + } + + /** + * Get parameters + * + * @return array + * @since 2.2.0 + */ + public function getParams() + { + return $this->params; + } + + /** + * Set parameters + * + * @param array $params + * @return void + * @since 2.2.0 + */ + public function setParams($params) + { + $this->params = $params; + } + + /** + * Get having condition + * + * @return array + * @since 2.2.0 + */ + public function getHaving() + { + return $this->having; + } + + /** + * Set having condition + * + * @param array $having + * @return void + * @since 2.2.0 + */ + public function setHaving($having) + { + $this->having = $having; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php new file mode 100644 index 0000000000000..1866d9282c1e9 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php @@ -0,0 +1,47 @@ +objectManager = $objectManager; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return SelectBuilder + * @since 2.2.0 + */ + public function create(array $data = []) + { + return $this->objectManager->create(SelectBuilder::class, $data); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/IteratorFactory.php b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php new file mode 100644 index 0000000000000..195fad845623f --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php @@ -0,0 +1,66 @@ +objectManager = $objectManager; + $this->defaultIteratorName = $defaultIteratorName; + } + + /** + * Creates instance of the result iterator with the query result as an input + * Result iterator can be changed through report configuration + * + * < ... + * + * Uses IteratorIterator by default + * + * @param \Traversable $result + * @param string|null $iteratorName + * @return \IteratorIterator + * @since 2.2.0 + */ + public function create(\Traversable $result, $iteratorName = null) + { + return $this->objectManager->create( + $iteratorName ?: $this->defaultIteratorName, + [ + 'iterator' => $result + ] + ); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/Query.php b/app/code/Magento/Analytics/ReportXml/Query.php new file mode 100644 index 0000000000000..7e464a5ad46d1 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/Query.php @@ -0,0 +1,105 @@ +select = $select; + $this->connectionName = $connectionName; + $this->selectHydrator = $selectHydrator; + $this->config = $config; + } + + /** + * @return Select + * @since 2.2.0 + */ + public function getSelect() + { + return $this->select; + } + + /** + * @return string + * @since 2.2.0 + */ + public function getConnectionName() + { + return $this->connectionName; + } + + /** + * @return array + * @since 2.2.0 + */ + public function getConfig() + { + return $this->config; + } + + /** + * Specify data which should be serialized to JSON + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource. + * @since 5.4.0 + */ + public function jsonSerialize() + { + return [ + 'connectionName' => $this->getConnectionName(), + 'select_parts' => $this->selectHydrator->extract($this->getSelect()), + 'config' => $this->getConfig() + ]; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/QueryFactory.php b/app/code/Magento/Analytics/ReportXml/QueryFactory.php new file mode 100644 index 0000000000000..37e6609553023 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/QueryFactory.php @@ -0,0 +1,153 @@ +config = $config; + $this->selectBuilderFactory = $selectBuilderFactory; + $this->assemblers = $assemblers; + $this->queryCache = $queryCache; + $this->objectManager = $objectManager; + $this->selectHydrator = $selectHydrator; + } + + /** + * Returns query connection name according to configuration + * + * @param string $queryConfig + * @return string + * @since 2.2.0 + */ + private function getQueryConnectionName($queryConfig) + { + $connectionName = 'default'; + if (isset($queryConfig['connection'])) { + $connectionName = $queryConfig['connection']; + } + return $connectionName; + } + + /** + * Create query according to configuration settings + * + * @param string $queryName + * @return Query + * @since 2.2.0 + */ + private function constructQuery($queryName) + { + $queryConfig = $this->config->get($queryName); + $selectBuilder = $this->selectBuilderFactory->create(); + $selectBuilder->setConnectionName($this->getQueryConnectionName($queryConfig)); + foreach ($this->assemblers as $assembler) { + $selectBuilder = $assembler->assemble($selectBuilder, $queryConfig); + } + $select = $selectBuilder->create(); + return $this->objectManager->create( + Query::class, + [ + 'select' => $select, + 'selectHydrator' => $this->selectHydrator, + 'connectionName' => $selectBuilder->getConnectionName(), + 'config' => $queryConfig + ] + ); + } + + /** + * Creates query by name + * + * @param string $queryName + * @return Query + * @since 2.2.0 + */ + public function create($queryName) + { + $cached = $this->queryCache->load($queryName); + if ($cached) { + $queryData = json_decode($cached, true); + return $this->objectManager->create( + Query::class, + [ + 'select' => $this->selectHydrator->recreate($queryData['select_parts']), + 'selectHydrator' => $this->selectHydrator, + 'connectionName' => $queryData['connectionName'], + 'config' => $queryData['config'] + ] + ); + } + $query = $this->constructQuery($queryName); + $this->queryCache->save(json_encode($query), $queryName); + return $query; + } +} diff --git a/app/code/Magento/Analytics/ReportXml/ReportProvider.php b/app/code/Magento/Analytics/ReportXml/ReportProvider.php new file mode 100644 index 0000000000000..4edd1100c5325 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/ReportProvider.php @@ -0,0 +1,83 @@ +queryFactory = $queryFactory; + $this->connectionFactory = $connectionFactory; + $this->iteratorFactory = $iteratorFactory; + } + + /** + * Returns custom iterator name for report + * Null for default + * + * @param Query $query + * @return string|null + * @since 2.2.0 + */ + private function getIteratorName(Query $query) + { + $config = $query->getConfig(); + return isset($config['iterator']) ? $config['iterator'] : null; + } + + /** + * Returns report data by name and criteria + * + * @param string $name + * @return \IteratorIterator + * @since 2.2.0 + */ + public function getReport($name) + { + $query = $this->queryFactory->create($name); + $connection = $this->connectionFactory->getConnection($query->getConnectionName()); + $statement = $connection->query($query->getSelect()); + return $this->iteratorFactory->create($statement, $this->getIteratorName($query)); + } +} diff --git a/app/code/Magento/Analytics/ReportXml/SelectHydrator.php b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php new file mode 100644 index 0000000000000..9dd0f8327dd14 --- /dev/null +++ b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php @@ -0,0 +1,153 @@ +resourceConnection = $resourceConnection; + $this->objectManager = $objectManager; + $this->selectParts = $selectParts; + } + + /** + * @return array + * @since 2.2.0 + */ + private function getSelectParts() + { + return array_merge($this->predefinedSelectParts, $this->selectParts); + } + + /** + * Extracts Select metadata parts + * + * @param Select $select + * @return array + * @throws \Zend_Db_Select_Exception + * @since 2.2.0 + */ + public function extract(Select $select) + { + $parts = []; + foreach ($this->getSelectParts() as $partName) { + $parts[$partName] = $select->getPart($partName); + } + return $parts; + } + + /** + * @param array $selectParts + * @return Select + * @since 2.2.0 + */ + public function recreate(array $selectParts) + { + $select = $this->resourceConnection->getConnection()->select(); + + $select = $this->processColumns($select, $selectParts); + + foreach ($selectParts as $partName => $partValue) { + $select->setPart($partName, $partValue); + } + + return $select; + } + + /** + * Process COLUMNS part values and add this part into select. + * + * If each column contains information about select expression + * an object with the type of this expression going to be created and assigned to this column. + * + * @param Select $select + * @param array $selectParts + * @return Select + * @since 2.2.0 + */ + private function processColumns(Select $select, array &$selectParts) + { + if (!empty($selectParts[Select::COLUMNS]) && is_array($selectParts[Select::COLUMNS])) { + $part = []; + + foreach ($selectParts[Select::COLUMNS] as $columnEntry) { + list($correlationName, $column, $alias) = $columnEntry; + if (is_array($column) && !empty($column['class'])) { + $expression = $this->objectManager->create( + $column['class'], + isset($column['arguments']) ? $column['arguments'] : [] + ); + $part[] = [$correlationName, $expression, $alias]; + } else { + $part[] = $columnEntry; + } + } + + $select->setPart(Select::COLUMNS, $part); + unset($selectParts[Select::COLUMNS]); + } + + return $select; + } +} diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php new file mode 100644 index 0000000000000..302cf00f9091f --- /dev/null +++ b/app/code/Magento/Analytics/Setup/InstallData.php @@ -0,0 +1,47 @@ +notificationTime = $notificationTime; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @since 2.2.0 + */ + public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $this->notificationTime->storeLastTimeNotification(1); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php new file mode 100644 index 0000000000000..b94a295c86527 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php @@ -0,0 +1,76 @@ +abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment', 'getLabel']) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->additionalComment = new AdditionalComment($this->contextMock); + } + + /** + * @return void + */ + public function testRender() + { + $this->abstractElementMock->setForm($this->formMock); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('New comment'); + $this->abstractElementMock->expects($this->any()) + ->method('getLabel') + ->willReturn('Comment label'); + $html = $this->additionalComment->render($this->abstractElementMock); + $this->assertRegexp( + "/New comment/", + $html + ); + $this->assertRegexp( + "/Comment label/", + $html + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php new file mode 100644 index 0000000000000..d37daf9525119 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -0,0 +1,79 @@ +abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment']) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->setMethods(['getLocaleDate']) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + $this->timeZoneMock = $this->getMockBuilder(TimezoneInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock->expects($this->any()) + ->method('getLocaleDate') + ->willReturn($this->timeZoneMock); + $this->collectionTimeLabel = new CollectionTimeLabel($this->contextMock); + } + + /** + * @return void + */ + public function testRender() + { + $timeZone = "America/New_York"; + $this->abstractElementMock->setForm($this->formMock); + $this->timeZoneMock->expects($this->once()) + ->method('getConfigTimezone') + ->willReturn($timeZone); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('Eastern Standard Time (America/New_York)'); + $this->assertRegexp( + "/Eastern Standard Time \(America\/New_York\)/", + $this->collectionTimeLabel->render($this->abstractElementMock) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php new file mode 100644 index 0000000000000..e25e745317699 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php @@ -0,0 +1,86 @@ +subscriptionStatusProviderMock = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment']) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subscriptionStatusLabel = new SubscriptionStatusLabel( + $this->contextMock, + $this->subscriptionStatusProviderMock + ); + } + + /** + * @return void + */ + public function testRender() + { + $this->abstractElementMock->setForm($this->formMock); + $this->subscriptionStatusProviderMock->expects($this->once()) + ->method('getStatus') + ->willReturn('Enabled'); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('Subscription status: Enabled'); + $this->assertRegexp( + "/Subscription status: Enabled/", + $this->subscriptionStatusLabel->render($this->abstractElementMock) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php new file mode 100644 index 0000000000000..3a251f9a8685a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php @@ -0,0 +1,84 @@ +configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultRedirectFactoryMock = $this->getMockBuilder(RedirectFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->signUpController = $this->objectManagerHelper->getObject( + SignUp::class, + [ + 'config' => $this->configMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock + ] + ); + } + + /** + * @return void + */ + public function testExecute() + { + $urlBIEssentialsConfigPath = 'analytics/url/bi_essentials'; + $this->configMock->expects($this->once()) + ->method('getValue') + ->with($urlBIEssentialsConfigPath) + ->willReturn('value'); + $this->resultRedirectFactoryMock->expects($this->once())->method('create')->willReturn($this->redirectMock); + $this->redirectMock->expects($this->once())->method('setUrl')->with('value')->willReturnSelf(); + $this->assertEquals($this->redirectMock, $this->signUpController->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php new file mode 100644 index 0000000000000..99de92cc63905 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php @@ -0,0 +1,185 @@ +reportUrlProviderMock = $this->getMockBuilder(ReportUrlProvider::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->redirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->showController = $this->objectManagerHelper->getObject( + Show::class, + [ + 'reportUrlProvider' => $this->reportUrlProviderMock, + 'resultFactory' => $this->resultFactoryMock, + 'messageManager' => $this->messageManagerMock, + ] + ); + } + + /** + * @return void + */ + public function testExecute() + { + $otpUrl = 'http://example.com?otp=15vbjcfdvd15645'; + + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + $this->reportUrlProviderMock + ->expects($this->once()) + ->method('getUrl') + ->with() + ->willReturn($otpUrl); + $this->redirectMock + ->expects($this->once()) + ->method('setUrl') + ->with($otpUrl) + ->willReturnSelf(); + $this->assertSame($this->redirectMock, $this->showController->execute()); + } + + /** + * @dataProvider executeWithExceptionDataProvider + * + * @param \Exception $exception + */ + public function testExecuteWithException(\Exception $exception) + { + + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + $this->reportUrlProviderMock + ->expects($this->once()) + ->method('getUrl') + ->with() + ->willThrowException($exception); + if ($exception instanceof LocalizedException) { + $message = $exception->getMessage(); + } else { + $message = __('Sorry, there has been an error processing your request. Please try again later.'); + } + $this->messageManagerMock + ->expects($this->once()) + ->method('addExceptionMessage') + ->with($exception, $message) + ->willReturnSelf(); + $this->redirectMock + ->expects($this->once()) + ->method('setPath') + ->with('adminhtml') + ->willReturnSelf(); + $this->assertSame($this->redirectMock, $this->showController->execute()); + } + + /** + * @return array + */ + public function executeWithExceptionDataProvider() + { + return [ + 'ExecuteWithLocalizedException' => [new LocalizedException(__('TestMessage'))], + 'ExecuteWithException' => [new \Exception('TestMessage')], + ]; + } + + /** + * @return void + */ + public function testExecuteWithSubscriptionUpdateException() + { + $exception = new SubscriptionUpdateException(__('TestMessage')); + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->redirectMock); + $this->reportUrlProviderMock + ->expects($this->once()) + ->method('getUrl') + ->with() + ->willThrowException($exception); + $this->messageManagerMock + ->expects($this->once()) + ->method('addNoticeMessage') + ->with($exception->getMessage()) + ->willReturnSelf(); + $this->redirectMock + ->expects($this->once()) + ->method('setPath') + ->with('adminhtml') + ->willReturnSelf(); + $this->assertSame($this->redirectMock, $this->showController->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php new file mode 100644 index 0000000000000..9097349e9137c --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php @@ -0,0 +1,252 @@ +resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resultJsonMock = $this->getMockBuilder(Json::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->preparedValueFactoryMock = $this->getMockBuilder(PreparedValueFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configValueResourceMock = $this->getMockBuilder(AbstractDb::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->requestMock = $this->getMockBuilder(RequestInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->activateController = $this->objectManagerHelper->getObject( + Activate::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'preparedValueFactory' => $this->preparedValueFactoryMock, + 'configValueResource' => $this->configValueResourceMock, + 'logger' => $this->loggerMock, + 'notificationTime' => $this->notificationTimeMock, + '_request' => $this->requestMock, + 'subscriptionApprovedFiled' => $this->subscriptionApprovedField, + ] + ); + } + + /** + * @dataProvider executeDataProvider + * + * @param bool $isSubscriptionEnabled + * @return void + */ + public function testExecute($isSubscriptionEnabled) + { + $successResult = [ + 'success' => true, + 'error_message' => '', + ]; + + $this->requestMock + ->expects($this->once()) + ->method('getParam') + ->with($this->subscriptionApprovedField) + ->willReturn($isSubscriptionEnabled); + + if ($isSubscriptionEnabled) { + $configValue = $this->createConfigValueMock(); + $this->preparedValueFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($configValue); + $this->configValueResourceMock->expects($this->once())->method('save')->with($configValue); + } else { + $this->notificationTimeMock + ->expects($this->once()) + ->method('unsetLastTimeNotificationValue') + ->willReturn(true); + } + + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultJsonMock); + $this->resultJsonMock->expects($this->once()) + ->method('setData') + ->with($successResult) + ->willReturnSelf(); + $this->assertSame( + $this->resultJsonMock, + $this->activateController->execute() + ); + } + + /** + * @dataProvider executeExceptionsDataProvider + * + * @param \Exception $exception + */ + public function testExecuteWithException(\Exception $exception) + { + $this->requestMock + ->expects($this->once()) + ->method('getParam') + ->with($this->subscriptionApprovedField) + ->willReturn(true); + + $this->preparedValueFactoryMock + ->expects($this->once()) + ->method('create') + ->willThrowException($exception); + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultJsonMock); + + if ($exception instanceof LocalizedException) { + $this->resultJsonMock + ->expects($this->once()) + ->method('setData') + ->with([ + 'success' => false, + 'error_message' => $exception->getMessage(), + ]) + ->willReturnSelf(); + } else { + $this->resultJsonMock + ->expects($this->once()) + ->method('setData') + ->withAnyParameters() + ->willReturnSelf(); + } + + $this->assertSame( + $this->resultJsonMock, + $this->activateController->execute() + ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createConfigValueMock() + { + return $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @return array + */ + public function executeExceptionsDataProvider() + { + return [ + [new LocalizedException(__('TestMessage'))], + [new \Exception('TestMessage')], + ]; + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + [true], + [false], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php new file mode 100644 index 0000000000000..0f425291bf999 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php @@ -0,0 +1,168 @@ +dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->disableOriginalConstructor() + ->getMock(); + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->getMock(); + $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultMock = $this->getMockBuilder(Json::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON) + ->willReturn($this->resultMock); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->action = $objectManagerHelper->getObject( + Postpone::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock, + 'notificationTime' => $this->notificationTimeMock, + 'logger' => $this->loggerMock + ] + ); + } + + public function testExecuteSuccess() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willReturn(true); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => true, + 'error_message' => '' + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } + + public function testExecuteFailedWithLocalizedException() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willThrowException(new LocalizedException(__('Error message'))); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => false, + 'error_message' => 'Error message' + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } + + public function testExecuteFailedWithException() + { + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(100500); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotification') + ->with(100500) + ->willThrowException(new \Exception('Any message')); + $this->resultMock->expects($this->once()) + ->method('setData') + ->with( + [ + 'success' => false, + 'error_message' => __('Error occurred during postponement notification') + ], + false, + [] + )->willReturnSelf(); + $this->assertEquals($this->resultMock, $this->action->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php new file mode 100644 index 0000000000000..2c921e2260140 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php @@ -0,0 +1,159 @@ +resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resultRedirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subscriptionHandlerMock = $this->getMockBuilder(SubscriptionHandler::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->retryController = $this->objectManagerHelper->getObject( + Retry::class, + [ + 'resultFactory' => $this->resultFactoryMock, + 'subscriptionHandler' => $this->subscriptionHandlerMock, + 'messageManager' => $this->messageManagerMock, + ] + ); + } + + /** + * @return void + */ + public function testExecute() + { + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->resultRedirectMock); + $this->resultRedirectMock + ->expects($this->once()) + ->method('setPath') + ->with('adminhtml') + ->willReturnSelf(); + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willReturn(true); + $this->assertSame( + $this->resultRedirectMock, + $this->retryController->execute() + ); + } + + /** + * @dataProvider executeExceptionsDataProvider + * + * @param \Exception $exception + * @param Phrase $message + */ + public function testExecuteWithException(\Exception $exception, Phrase $message) + { + $this->resultFactoryMock + ->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_REDIRECT) + ->willReturn($this->resultRedirectMock); + $this->resultRedirectMock + ->expects($this->once()) + ->method('setPath') + ->with('adminhtml') + ->willReturnSelf(); + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willThrowException($exception); + $this->messageManagerMock + ->expects($this->once()) + ->method('addExceptionMessage') + ->with($exception, $message); + + $this->assertSame( + $this->resultRedirectMock, + $this->retryController->execute() + ); + } + + /** + * @return array + */ + public function executeExceptionsDataProvider() + { + return [ + [new LocalizedException(__('TestMessage')), __('TestMessage')], + [ + new \Exception('TestMessage'), + __('Sorry, there has been an error processing your request. Please try again later.') + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php new file mode 100644 index 0000000000000..ef071cdf3a911 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php @@ -0,0 +1,91 @@ +exportDataHandlerMock = $this->getMockBuilder(ExportDataHandlerInterface::class) + ->getMockForAbstractClass(); + + $this->subscriptionStatusMock = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->collectData = $this->objectManagerHelper->getObject( + CollectData::class, + [ + 'exportDataHandler' => $this->exportDataHandlerMock, + 'subscriptionStatus' => $this->subscriptionStatusMock, + ] + ); + } + + /** + * @param string $status + * @return void + * @dataProvider executeDataProvider + */ + public function testExecute($status) + { + $this->subscriptionStatusMock + ->expects($this->once()) + ->method('getStatus') + ->with() + ->willReturn($status); + $this->exportDataHandlerMock + ->expects(($status === SubscriptionStatusProvider::ENABLED) ? $this->once() : $this->never()) + ->method('prepareExportData') + ->with(); + + $this->assertTrue($this->collectData->execute()); + } + + /** + * @return array + */ + public function executeDataProvider() + { + return [ + 'Subscription is enabled' => [SubscriptionStatusProvider::ENABLED], + 'Subscription is disabled' => [SubscriptionStatusProvider::DISABLED], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php new file mode 100644 index 0000000000000..c8ab5a6f4649e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php @@ -0,0 +1,133 @@ +connectorMock = $this->getMockBuilder(Connector::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->signUp = new SignUp( + $this->connectorMock, + $this->configWriterMock, + $this->flagManagerMock, + $this->reinitableConfigMock + ); + } + + public function testExecute() + { + $attemptsCount = 10; + + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($attemptsCount); + + $attemptsCount -= 1; + $this->flagManagerMock->expects($this->once()) + ->method('saveFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $attemptsCount); + $this->connectorMock->expects($this->once()) + ->method('execute') + ->with('signUp') + ->willReturn(true); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->flagManagerMock->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + $this->assertTrue($this->signUp->execute()); + } + + public function testExecuteFlagNotExist() + { + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(null); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->assertFalse($this->signUp->execute()); + } + + public function testExecuteZeroAttempts() + { + $attemptsCount = 0; + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($attemptsCount); + $this->addDeleteAnalyticsCronExprAsserts(); + $this->flagManagerMock->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + $this->assertFalse($this->signUp->execute()); + } + + /** + * Add assertions for method deleteAnalyticsCronExpr. + * + * @return void + */ + private function addDeleteAnalyticsCronExprAsserts() + { + $this->configWriterMock + ->expects($this->once()) + ->method('delete') + ->with(SubscriptionHandler::CRON_STRING_PATH) + ->willReturn(true); + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->willReturnSelf(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php new file mode 100644 index 0000000000000..23ba59a90ce7b --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php @@ -0,0 +1,214 @@ +connectorMock = $this->getMockBuilder(Connector::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->update = new Update( + $this->connectorMock, + $this->configWriterMock, + $this->reinitableConfigMock, + $this->flagManagerMock, + $this->analyticsTokenMock + ); + } + + /** + * @return void + */ + public function testExecuteWithoutToken() + { + $this->flagManagerMock + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(10); + $this->connectorMock + ->expects($this->once()) + ->method('execute') + ->with('update') + ->willReturn(false); + $this->analyticsTokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->addFinalOutputAsserts(); + $this->assertFalse($this->update->execute()); + } + + /** + * @param bool $isExecuted + */ + private function addFinalOutputAsserts(bool $isExecuted = true) + { + $this->flagManagerMock + ->expects($this->exactly(2 * $isExecuted)) + ->method('deleteFlag') + ->withConsecutive( + [SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE], + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE] + ); + $this->configWriterMock + ->expects($this->exactly((int)$isExecuted)) + ->method('delete') + ->with(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH); + $this->reinitableConfigMock + ->expects($this->exactly((int)$isExecuted)) + ->method('reinit') + ->with(); + } + + /** + * @param $counterData + * @return void + * @dataProvider executeWithEmptyReverseCounterDataProvider + */ + public function testExecuteWithEmptyReverseCounter($counterData) + { + $this->flagManagerMock + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($counterData); + $this->connectorMock + ->expects($this->never()) + ->method('execute') + ->with('update') + ->willReturn(false); + $this->analyticsTokenMock + ->method('isTokenExist') + ->willReturn(true); + $this->addFinalOutputAsserts(); + $this->assertFalse($this->update->execute()); + } + + /** + * Provides empty states of the reverse counter. + * + * @return array + */ + public function executeWithEmptyReverseCounterDataProvider() + { + return [ + [null], + [0] + ]; + } + + /** + * @param int $reverseCount + * @param bool $commandResult + * @param bool $finalConditionsIsExpected + * @param bool $functionResult + * @return void + * @dataProvider executeRegularScenarioDataProvider + */ + public function testExecuteRegularScenario( + int $reverseCount, + bool $commandResult, + bool $finalConditionsIsExpected, + bool $functionResult + ) { + $this->flagManagerMock + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE) + ->willReturn($reverseCount); + $this->connectorMock + ->expects($this->once()) + ->method('execute') + ->with('update') + ->willReturn($commandResult); + $this->analyticsTokenMock + ->method('isTokenExist') + ->willReturn(true); + $this->addFinalOutputAsserts($finalConditionsIsExpected); + $this->assertSame($functionResult, $this->update->execute()); + } + + /** + * @return array + */ + public function executeRegularScenarioDataProvider() + { + return [ + 'The last attempt with command execution result False' => [ + 'Reverse count' => 1, + 'Command result' => false, + 'Executed final output conditions' => true, + 'Function result' => false, + ], + 'Not the last attempt with command execution result False' => [ + 'Reverse count' => 10, + 'Command result' => false, + 'Executed final output conditions' => false, + 'Function result' => false, + ], + 'Command execution result True' => [ + 'Reverse count' => 10, + 'Command result' => true, + 'Executed final output conditions' => true, + 'Function result' => true, + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php new file mode 100644 index 0000000000000..e078bbe99f93a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php @@ -0,0 +1,129 @@ +reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->tokenModel = $this->objectManagerHelper->getObject( + AnalyticsToken::class, + [ + 'reinitableConfig' => $this->reinitableConfigMock, + 'config' => $this->configMock, + 'configWriter' => $this->configWriterMock, + 'tokenPath' => $this->tokenPath, + ] + ); + } + + /** + * @return void + */ + public function testStoreToken() + { + $value = 'jjjj0000'; + + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with($this->tokenPath, $value); + + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->willReturnSelf(); + + $this->assertTrue($this->tokenModel->storeToken($value)); + } + + /** + * @return void + */ + public function testGetToken() + { + $value = 'jjjj0000'; + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->tokenPath) + ->willReturn($value); + + $this->assertSame($value, $this->tokenModel->getToken()); + } + + /** + * @return void + */ + public function testIsTokenExist() + { + $this->assertFalse($this->tokenModel->isTokenExist()); + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->tokenPath) + ->willReturn('0000'); + $this->assertTrue($this->tokenModel->isTokenExist()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php new file mode 100644 index 0000000000000..bfdc971efc79e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -0,0 +1,81 @@ +dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->getMock(); + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); + $this->canViewNotification = $objectManager->getObject( + CanViewNotification::class, + [ + 'notificationTime' => $this->notificationTimeMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock + ] + ); + } + + public function testValidate() + { + $this->notificationTimeMock->expects($this->once()) + ->method('getLastTimeNotification') + ->willReturn(1); + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(10005000); + $this->assertTrue($this->canViewNotification->isVisible([])); + } + + public function testValidateFlagRemoved() + { + $this->notificationTimeMock->expects($this->once()) + ->method('getLastTimeNotification') + ->willReturn(null); + $this->dateTimeFactoryMock->expects($this->never()) + ->method('create'); + $this->assertFalse($this->canViewNotification->isVisible([])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php new file mode 100644 index 0000000000000..865ad236fc057 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php @@ -0,0 +1,178 @@ +reinitableConfigMock = $this->getMockBuilder(ReinitableConfigInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->subscriptionUpdateHandler = $this->objectManagerHelper->getObject( + SubscriptionUpdateHandler::class, + [ + 'reinitableConfig' => $this->reinitableConfigMock, + 'analyticsToken' => $this->analyticsTokenMock, + 'flagManager' => $this->flagManagerMock, + 'configWriter' => $this->configWriterMock, + ] + ); + } + + /** + * @return void + */ + public function testTokenDoesNotExist() + { + $this->analyticsTokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->with() + ->willReturn(false); + $this->flagManagerMock + ->expects($this->never()) + ->method('saveFlag'); + $this->configWriterMock + ->expects($this->never()) + ->method('save'); + $this->assertTrue($this->subscriptionUpdateHandler->processUrlUpdate('http://store.com')); + } + + /** + * @return void + */ + public function testTokenAndPreviousBaseUrlExist() + { + $url = 'https://store.com'; + $this->analyticsTokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->with() + ->willReturn(true); + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE) + ->willReturn(true); + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->withConsecutive( + [SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue], + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, $url] + ); + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH, $this->cronExpression); + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->with(); + $this->assertTrue($this->subscriptionUpdateHandler->processUrlUpdate($url)); + } + + /** + * @return void + */ + public function testTokenExistAndWithoutPreviousBaseUrl() + { + $url = 'https://store.com'; + $this->analyticsTokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->with() + ->willReturn(true); + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE) + ->willReturn(false); + $this->flagManagerMock + ->expects($this->exactly(2)) + ->method('saveFlag') + ->withConsecutive( + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, $url], + [SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue] + ); + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH, $this->cronExpression); + $this->reinitableConfigMock + ->expects($this->once()) + ->method('reinit') + ->with(); + $this->assertTrue($this->subscriptionUpdateHandler->processUrlUpdate($url)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php new file mode 100644 index 0000000000000..555020ffd247f --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php @@ -0,0 +1,111 @@ +configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->collectionTime = $this->objectManagerHelper->getObject( + CollectionTime::class, + [ + 'configWriter' => $this->configWriterMock, + '_logger' => $this->loggerMock, + ] + ); + } + + /** + * @return void + */ + public function testAfterSave() + { + $this->collectionTime->setData('value', '05,04,03'); + + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(CollectionTime::CRON_SCHEDULE_PATH, join(' ', ['04', '05', '*', '*', '*'])); + + $this->assertInstanceOf( + Value::class, + $this->collectionTime->afterSave() + ); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testAfterSaveWrongValue() + { + $this->collectionTime->setData('value', '00,01'); + $this->collectionTime->afterSave(); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testAfterSaveWithLocalizedException() + { + $exception = new \Exception('Test message'); + $this->collectionTime->setData('value', '05,04,03'); + + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(CollectionTime::CRON_SCHEDULE_PATH, join(' ', ['04', '05', '*', '*', '*'])) + ->willThrowException($exception); + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + $this->collectionTime->afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php new file mode 100644 index 0000000000000..d01101bf5cc3b --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -0,0 +1,185 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configWriterMock = $this->getMockBuilder(WriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->tokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->subscriptionHandler = $this->objectManagerHelper->getObject( + SubscriptionHandler::class, + [ + 'flagManager' => $this->flagManagerMock, + 'configWriter' => $this->configWriterMock, + 'attemptsInitValue' => $this->attemptsInitValue, + 'analyticsToken' => $this->tokenMock, + 'notificationTime' => $this->notificationTimeMock, + ] + ); + } + + /** + * @return void + */ + public function testProcessEnabledTokenExist() + { + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->configWriterMock + ->expects($this->never()) + ->method('save'); + $this->flagManagerMock + ->expects($this->never()) + ->method('saveFlag'); + $this->notificationTimeMock + ->expects($this->never()) + ->method('unsetLastTimeNotificationValue'); + $this->assertTrue( + $this->subscriptionHandler->processEnabled() + ); + } + + /** + * @return void + */ + public function testProcessEnabledTokenDoesNotExist() + { + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->configWriterMock + ->expects($this->once()) + ->method('save') + ->with(SubscriptionHandler::CRON_STRING_PATH, "0 * * * *"); + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue) + ->willReturn(true); + $this->notificationTimeMock + ->expects($this->once()) + ->method('unsetLastTimeNotificationValue') + ->willReturn(true); + $this->assertTrue( + $this->subscriptionHandler->processEnabled() + ); + } + + /** + * @return void + */ + public function testProcessDisabledTokenDoesNotExist() + { + $this->configWriterMock + ->expects($this->once()) + ->method('delete') + ->with(CollectionTime::CRON_SCHEDULE_PATH); + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE) + ->willReturn(true); + $this->assertTrue( + $this->subscriptionHandler->processDisabled() + ); + } + + /** + * @return void + */ + public function testProcessDisabledTokenExists() + { + $this->configWriterMock + ->expects($this->once()) + ->method('delete') + ->with(CollectionTime::CRON_SCHEDULE_PATH); + $this->tokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->flagManagerMock + ->expects($this->never()) + ->method('deleteFlag'); + $this->assertTrue( + $this->subscriptionHandler->processDisabled() + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php new file mode 100644 index 0000000000000..d64827d2d18d2 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php @@ -0,0 +1,184 @@ +subscriptionHandlerMock = $this->getMockBuilder(SubscriptionHandler::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->enabledModel = $this->objectManagerHelper->getObject( + Enabled::class, + [ + 'subscriptionHandler' => $this->subscriptionHandlerMock, + '_logger' => $this->loggerMock, + 'config' => $this->configMock, + ] + ); + } + + /** + * @return void + */ + public function testAfterSaveSuccessEnabled() + { + $this->enabledModel->setData('value', $this->valueEnabled); + + $this->configMock + ->expects($this->any()) + ->method('getValue') + ->willReturn(!$this->valueEnabled); + + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willReturn(true); + + $this->assertInstanceOf( + Value::class, + $this->enabledModel->afterSave() + ); + } + + /** + * @return void + */ + public function testAfterSaveSuccessDisabled() + { + $this->enabledModel->setData('value', $this->valueDisabled); + + $this->configMock + ->expects($this->any()) + ->method('getValue') + ->willReturn(!$this->valueDisabled); + + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processDisabled') + ->with() + ->willReturn(true); + + $this->assertInstanceOf( + Value::class, + $this->enabledModel->afterSave() + ); + } + + /** + * @return void + */ + public function testAfterSaveSuccessValueNotChanged() + { + $this->enabledModel->setData('value', null); + + $this->configMock + ->expects($this->any()) + ->method('getValue') + ->willReturn(null); + + $this->subscriptionHandlerMock + ->expects($this->never()) + ->method('processEnabled') + ->with() + ->willReturn(true); + $this->subscriptionHandlerMock + ->expects($this->never()) + ->method('processDisabled') + ->with() + ->willReturn(true); + + $this->assertInstanceOf( + Value::class, + $this->enabledModel->afterSave() + ); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testExecuteAfterSaveFailedWithLocalizedException() + { + $exception = new \Exception('Message'); + $this->enabledModel->setData('value', $this->valueEnabled); + + $this->subscriptionHandlerMock + ->expects($this->once()) + ->method('processEnabled') + ->with() + ->willThrowException($exception); + + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($exception->getMessage()); + + $this->enabledModel->afterSave(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php new file mode 100644 index 0000000000000..d689f040c48b3 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php @@ -0,0 +1,59 @@ +objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\Model\Config\Backend\Vertical::class + ); + } + + /** + * @return void + */ + public function testBeforeSaveSuccess() + { + $this->subject->setValue('Apps and Games'); + + $this->assertInstanceOf( + \Magento\Analytics\Model\Config\Backend\Vertical::class, + $this->subject->beforeSave() + ); + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testBeforeSaveFailedWithLocalizedException() + { + $this->subject->setValue(''); + + $this->subject->beforeSave(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php new file mode 100644 index 0000000000000..7c94fb1b60a14 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php @@ -0,0 +1,142 @@ +objectManagerHelper = new ObjectManagerHelper($this); + + $this->mapper = $this->objectManagerHelper->getObject(Mapper::class); + } + + /** + * @param array $configData + * @param array $resultData + * @return void + * + * @dataProvider executingDataProvider + */ + public function testExecution($configData, $resultData) + { + $this->assertSame($resultData, $this->mapper->execute($configData)); + } + + /** + * @return array + */ + public function executingDataProvider() + { + return [ + 'wrongConfig' => [ + ['config' => ['files']], + [] + ], + 'validConfigWithFileNodes' => [ + [ + 'config' => [ + 0 => [ + 'file' => [ + 0 => [ + 'name' => 'fileName', + 'providers' => [[]] + ] + ] + ] + ] + ], + [ + 'fileName' => [ + 'name' => 'fileName', + 'providers' => [] + ] + ], + ], + 'validConfigWithProvidersNode' => [ + [ + 'config' => [ + 0 => [ + 'file' => [ + 0 => [ + 'name' => 'fileName', + 'providers' => [ + 0 => [ + 'reportProvider' => [0 => []] + ] + ] + ] + ] + ] + ] + ], + [ + 'fileName' => [ + 'name' => 'fileName', + 'providers' => [ + 'reportProvider' => ['parameters' => []] + ] + ] + ], + ], + 'validConfigWithParametersNode' => [ + [ + 'config' => [ + 0 => [ + 'file' => [ + 0 => [ + 'name' => 'fileName', + 'providers' => [ + 0 => [ + 'reportProvider' => [ + 0 => [ + 'parameters' => [ + 0 => ['name' => ['reportName']] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ], + [ + 'fileName' => [ + 'name' => 'fileName', + 'providers' => [ + 'reportProvider' => [ + 'parameters' => [ + 'name' => 'reportName' + ] + ] + ] + ] + ], + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php new file mode 100644 index 0000000000000..1eee74a1f93a0 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php @@ -0,0 +1,108 @@ +mapperMock = $this->getMockBuilder(Mapper::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->readerXmlMock = $this->getMockBuilder(ReaderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->readerDbMock = $this->getMockBuilder(ReaderInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reader = $this->objectManagerHelper->getObject( + Reader::class, + [ + 'mapper' => $this->mapperMock, + 'readers' => [ + $this->readerXmlMock, + $this->readerDbMock, + ], + ] + ); + } + + /** + * @return void + */ + public function testRead() + { + $scope = 'store'; + $xmlReaderResult = [ + 'config' => ['node1' => ['node2' => 'node4']] + ]; + $dbReaderResult = [ + 'config' => ['node1' => ['node2' => 'node3']] + ]; + $mapperResult = ['node2' => ['node3', 'node4']]; + + $this->readerXmlMock + ->expects($this->once()) + ->method('read') + ->with($scope) + ->willReturn($xmlReaderResult); + + $this->readerDbMock + ->expects($this->once()) + ->method('read') + ->with($scope) + ->willReturn($dbReaderResult); + + $this->mapperMock + ->expects($this->once()) + ->method('execute') + ->with(array_merge_recursive($xmlReaderResult, $dbReaderResult)) + ->willReturn($mapperResult); + + $this->assertSame($mapperResult, $this->reader->read($scope)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php new file mode 100644 index 0000000000000..b96f3543ff701 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php @@ -0,0 +1,60 @@ +objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\Model\Config\Source\Vertical::class, + [ + 'verticals' => [ + 'Apps and Games', + 'Athletic/Sporting Goods', + 'Art and Design' + ] + ] + ); + } + + /** + * @return void + */ + public function testToOptionArray() + { + $expectedOptionsArray = [ + ['value' => '', 'label' => __('--Please Select--')], + ['value' => 'Apps and Games', 'label' => __('Apps and Games')], + ['value' => 'Athletic/Sporting Goods', 'label' => __('Athletic/Sporting Goods')], + ['value' => 'Art and Design', 'label' => __('Art and Design')] + ]; + + $this->assertEquals( + $expectedOptionsArray, + $this->subject->toOptionArray() + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php new file mode 100644 index 0000000000000..8282b1ae52617 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php @@ -0,0 +1,68 @@ +dataInterfaceMock = $this->getMockBuilder(DataInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->config = $this->objectManagerHelper->getObject( + Config::class, + [ + 'data' => $this->dataInterfaceMock, + ] + ); + } + + /** + * @return void + */ + public function testGet() + { + $key = 'configKey'; + $defaultValue = 'mock'; + $configValue = 'emptyString'; + + $this->dataInterfaceMock + ->expects($this->once()) + ->method('get') + ->with($key, $defaultValue) + ->willReturn($configValue); + + $this->assertSame($configValue, $this->config->get($key, $defaultValue)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php new file mode 100644 index 0000000000000..6890fe200f9dc --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php @@ -0,0 +1,218 @@ +curlMock = $this->getMockBuilder( + \Magento\Framework\HTTP\Adapter\Curl::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder( + \Psr\Log\LoggerInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->curlFactoryMock = $this->getMockBuilder(CurlFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->curlFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->curlMock); + + $this->responseFactoryMock = $this->getMockBuilder( + \Magento\Analytics\Model\Connector\Http\ResponseFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->converterMock = $this->createJsonConverter(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\Model\Connector\Http\Client\Curl::class, + [ + 'curlFactory' => $this->curlFactoryMock, + 'responseFactory' => $this->responseFactoryMock, + 'converter' => $this->converterMock, + 'logger' => $this->loggerMock, + ] + ); + } + + /** + * Returns test parameters for request. + * + * @return array + */ + public function getTestData() + { + return [ + [ + 'data' => [ + 'version' => '1.1', + 'body'=> ['name' => 'value'], + 'url' => 'http://www.mystore.com', + 'headers' => [JsonConverter::CONTENT_TYPE_HEADER], + 'method' => \Magento\Framework\HTTP\ZendClient::POST, + ] + ] + ]; + } + + /** + * @return void + * @dataProvider getTestData + */ + public function testRequestSuccess(array $data) + { + $responseString = 'This is response.'; + $response = new \Zend_Http_Response(201, [], $responseString); + $this->curlMock->expects($this->once()) + ->method('write') + ->with( + $data['method'], + $data['url'], + $data['version'], + $data['headers'], + json_encode($data['body']) + ); + $this->curlMock->expects($this->once()) + ->method('read') + ->willReturn($responseString); + $this->curlMock->expects($this->any()) + ->method('getErrno') + ->willReturn(0); + + $this->responseFactoryMock->expects($this->any()) + ->method('create') + ->with($responseString) + ->willReturn($response); + + $this->assertEquals( + $response, + $this->subject->request( + $data['method'], + $data['url'], + $data['body'], + $data['headers'], + $data['version'] + ) + ); + } + + /** + * @return void + * @dataProvider getTestData + */ + public function testRequestError(array $data) + { + $response = new \Zend_Http_Response(0, []); + $this->curlMock->expects($this->once()) + ->method('write') + ->with( + $data['method'], + $data['url'], + $data['version'], + $data['headers'], + json_encode($data['body']) + ); + $this->curlMock->expects($this->once()) + ->method('read'); + $this->curlMock->expects($this->atLeastOnce()) + ->method('getErrno') + ->willReturn(1); + $this->curlMock->expects($this->atLeastOnce()) + ->method('getError') + ->willReturn('CURL error.'); + + $this->loggerMock->expects($this->once()) + ->method('critical') + ->with( + new \Exception( + 'MBI service CURL connection error #1: CURL error.' + ) + ); + + $this->assertEquals( + $response, + $this->subject->request( + $data['method'], + $data['url'], + $data['body'], + $data['headers'], + $data['version'] + ) + ); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createJsonConverter() + { + $converterMock = $this->getMockBuilder(ConverterInterface::class) + ->getMockForAbstractClass(); + $converterMock->expects($this->any())->method('toBody')->willReturnCallback(function ($value) { + return json_encode($value); + }); + $converterMock->expects($this->any()) + ->method('getContentTypeHeader') + ->willReturn(JsonConverter::CONTENT_TYPE_HEADER); + return $converterMock; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php new file mode 100644 index 0000000000000..7ac6f50ea24c4 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php @@ -0,0 +1,34 @@ +assertEquals(JsonConverter::CONTENT_TYPE_HEADER, $converter->getContentTypeHeader()); + } + + public function testConvertBody() + { + $body = '{"token": "secret-token"}'; + $converter = new JsonConverter(); + $this->assertEquals(json_decode($body, 1), $converter->fromBody($body)); + } + + public function testConvertData() + { + $data = ["token" => "secret-token"]; + $converter = new JsonConverter(); + $this->assertEquals(json_encode($data), $converter->toBody($data)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php new file mode 100644 index 0000000000000..5047e8a9dd391 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php @@ -0,0 +1,39 @@ + 'testValue']; + $response = new \Zend_Http_Response(201, [], json_encode($expectedBody)); + $responseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class) + ->getMockForAbstractClass(); + $responseHandlerMock->expects($this->once()) + ->method('handleResponse') + ->with($expectedBody) + ->willReturn(true); + $notFoundResponseHandlerMock = $this->getMockBuilder(ResponseHandlerInterface::class) + ->getMockForAbstractClass(); + $notFoundResponseHandlerMock->expects($this->never())->method('handleResponse'); + $responseResolver = new ResponseResolver( + new JsonConverter(), + [ + 201 => $responseHandlerMock, + 404 => $notFoundResponseHandlerMock, + ] + ); + $this->assertTrue($responseResolver->getResult($response)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php new file mode 100644 index 0000000000000..5b86dd6557d69 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php @@ -0,0 +1,107 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $successHandler = $this->getMockBuilder(\Magento\Analytics\Model\Connector\Http\ResponseHandlerInterface::class) + ->getMockForAbstractClass(); + $successHandler->method('handleResponse') + ->willReturn(true); + + $this->notifyDataChangedCommand = new NotifyDataChangedCommand( + $this->analyticsTokenMock, + $this->httpClientMock, + $this->configMock, + new ResponseResolver(new JsonConverter(), [201 => $successHandler]), + $this->loggerMock + ); + } + + public function testExecuteSuccess() + { + $configVal = "Config val"; + $token = "Secret token!"; + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($configVal); + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($token); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + ZendClient::POST, + $configVal, + ['access-token' => $token, 'url' => $configVal] + )->willReturn(new \Zend_Http_Response(201, [])); + $this->assertTrue($this->notifyDataChangedCommand->execute()); + } + + public function testExecuteWithoutToken() + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->httpClientMock->expects($this->never()) + ->method('request'); + $this->assertFalse($this->notifyDataChangedCommand->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php new file mode 100644 index 0000000000000..a33d7d0d7c1bf --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php @@ -0,0 +1,187 @@ +loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->responseResolverMock = $this->getMockBuilder(ResponseResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subject = new OTPRequest( + $this->analyticsTokenMock, + $this->httpClientMock, + $this->configMock, + $this->responseResolverMock, + $this->loggerMock + ); + } + + /** + * Returns test parameters for request. + * + * @return array + */ + private function getTestData() + { + return [ + 'otp' => 'thisisotp', + 'url' => 'http://www.mystore.com', + 'access-token' => 'thisisaccesstoken', + 'method' => \Magento\Framework\HTTP\ZendClient::POST, + 'body'=> ['access-token' => 'thisisaccesstoken','url' => 'http://www.mystore.com'], + ]; + } + + /** + * @return void + */ + public function testCallSuccess() + { + $data = $this->getTestData(); + + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($data['access-token']); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($data['url']); + + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + $data['method'], + $data['url'], + $data['body'] + ) + ->willReturn(new \Zend_Http_Response(201, [])); + $this->responseResolverMock->expects($this->once()) + ->method('getResult') + ->willReturn($data['otp']); + + $this->assertEquals( + $data['otp'], + $this->subject->call() + ); + } + + /** + * @return void + */ + public function testCallNoAccessToken() + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + + $this->httpClientMock->expects($this->never()) + ->method('request'); + + $this->assertFalse($this->subject->call()); + } + + /** + * @return void + */ + public function testCallNoOtp() + { + $data = $this->getTestData(); + + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($data['access-token']); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($data['url']); + + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + $data['method'], + $data['url'], + $data['body'] + ) + ->willReturn(new \Zend_Http_Response(0, [])); + + $this->responseResolverMock->expects($this->once()) + ->method('getResult') + ->willReturn(false); + + $this->loggerMock->expects($this->once()) + ->method('warning'); + + $this->assertFalse($this->subject->call()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php new file mode 100644 index 0000000000000..203eb57157e0e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php @@ -0,0 +1,22 @@ +assertFalse($OTPHandler->handleResponse([])); + $expectedOtp = 123; + $this->assertEquals($expectedOtp, $OTPHandler->handleResponse(['otp' => $expectedOtp])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php new file mode 100644 index 0000000000000..4c3dde7a92c3f --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php @@ -0,0 +1,36 @@ +getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + $analyticsToken->expects($this->once()) + ->method('storeToken') + ->with(null); + $subscriptionHandler = $this->getMockBuilder(SubscriptionHandler::class) + ->disableOriginalConstructor() + ->getMock(); + $subscriptionStatusProvider = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $subscriptionStatusProvider->method('getStatus')->willReturn(SubscriptionStatusProvider::ENABLED); + $reSignUpHandler = new ReSignUp($analyticsToken, $subscriptionHandler, $subscriptionStatusProvider); + $this->assertFalse($reSignUpHandler->handleResponse([])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php new file mode 100644 index 0000000000000..2bbd528638a19 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php @@ -0,0 +1,30 @@ +getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + $analyticsToken->expects($this->once()) + ->method('storeToken') + ->with($accessToken); + $signUpHandler = new SignUp($analyticsToken, new JsonConverter()); + $this->assertFalse($signUpHandler->handleResponse([])); + $this->assertEquals($accessToken, $signUpHandler->handleResponse(['access-token' => $accessToken])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php new file mode 100644 index 0000000000000..90102e2c3d868 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php @@ -0,0 +1,20 @@ +assertTrue($updateHandler->handleResponse([])); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php new file mode 100644 index 0000000000000..cc9eba99b3d48 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php @@ -0,0 +1,174 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + $this->integrationManagerMock = $this->getMockBuilder(IntegrationManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->integrationToken = $this->getMockBuilder(IntegrationToken::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->responseResolverMock = $this->getMockBuilder(ResponseResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->signUpCommand = new SignUpCommand( + $this->analyticsTokenMock, + $this->integrationManagerMock, + $this->configMock, + $this->httpClientMock, + $this->loggerMock, + $this->responseResolverMock + ); + } + + public function testExecuteSuccess() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn($this->integrationToken); + $this->integrationManagerMock->expects($this->once()) + ->method('activateIntegration') + ->willReturn(true); + $data = $this->getTestData(); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($data['url']); + $this->integrationToken->expects($this->any()) + ->method('getData') + ->with('token') + ->willReturn($data['integration-token']); + $httpResponse = new \Zend_Http_Response(201, [], '{"access-token": "' . $data['access-token'] . '"}'); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + $data['method'], + $data['url'], + $data['body'] + ) + ->willReturn($httpResponse); + $this->responseResolverMock->expects($this->any()) + ->method('getResult') + ->with($httpResponse) + ->willReturn(true); + $this->assertTrue($this->signUpCommand->execute()); + } + + public function testExecuteFailureCannotGenerateToken() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn(false); + $this->integrationManagerMock->expects($this->never()) + ->method('activateIntegration'); + $this->assertFalse($this->signUpCommand->execute()); + } + + public function testExecuteFailureResponseIsEmpty() + { + $this->integrationManagerMock->expects($this->once()) + ->method('generateToken') + ->willReturn($this->integrationToken); + $this->integrationManagerMock->expects($this->once()) + ->method('activateIntegration') + ->willReturn(true); + $httpResponse = new \Zend_Http_Response(0, []); + $this->httpClientMock->expects($this->once()) + ->method('request') + ->willReturn($httpResponse); + $this->responseResolverMock->expects($this->any()) + ->method('getResult') + ->willReturn(false); + $this->assertFalse($this->signUpCommand->execute()); + } + + /** + * Returns test parameters for request. + * + * @return array + */ + private function getTestData() + { + return [ + 'url' => 'http://www.mystore.com', + 'access-token' => 'thisisaccesstoken', + 'integration-token' => 'thisisintegrationtoken', + 'headers' => [JsonConverter::CONTENT_TYPE_HEADER], + 'method' => \Magento\Framework\HTTP\ZendClient::POST, + 'body'=> ['token' => 'thisisintegrationtoken','url' => 'http://www.mystore.com'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php new file mode 100644 index 0000000000000..eb22461d789c8 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php @@ -0,0 +1,143 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->httpClientMock = $this->getMockBuilder(ClientInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->responseResolverMock = $this->getMockBuilder(ResponseResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->updateCommand = new UpdateCommand( + $this->analyticsTokenMock, + $this->httpClientMock, + $this->configMock, + $this->loggerMock, + $this->flagManagerMock, + $this->responseResolverMock + ); + } + + public function testExecuteSuccess() + { + $url = "old.localhost.com"; + $configVal = "Config val"; + $token = "Secret token!"; + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn($configVal); + + $this->flagManagerMock->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE) + ->willReturn($url); + + $this->analyticsTokenMock->expects($this->once()) + ->method('getToken') + ->willReturn($token); + + $this->httpClientMock->expects($this->once()) + ->method('request') + ->with( + ZendClient::PUT, + $configVal, + [ + 'url' => $url, + 'new-url' => $configVal, + 'access-token' => $token + ] + )->willReturn(new \Zend_Http_Response(200, [])); + + $this->responseResolverMock->expects($this->once()) + ->method('getResult') + ->willReturn(true); + + $this->assertTrue($this->updateCommand->execute()); + } + + public function testExecuteWithoutToken() + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + + $this->assertFalse($this->updateCommand->execute()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php new file mode 100644 index 0000000000000..14d641a19729d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php @@ -0,0 +1,70 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->signUpCommandMock = $this->getMockBuilder(SignUpCommand::class) + ->disableOriginalConstructor() + ->getMock(); + $this->commands = ['signUp' => SignUpCommand::class]; + $this->connector = new Connector($this->commands, $this->objectManagerMock); + } + + public function testExecute() + { + $commandName = 'signUp'; + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with($this->commands[$commandName]) + ->willReturn($this->signUpCommandMock); + $this->signUpCommandMock->expects($this->once()) + ->method('execute') + ->willReturn(true); + $this->assertTrue($this->connector->execute($commandName)); + } + + /** + * @expectedException \Magento\Framework\Exception\NotFoundException + */ + public function testExecuteCommandNotFound() + { + $commandName = 'register'; + $this->connector->execute($commandName); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php new file mode 100644 index 0000000000000..3de718d843a1d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php @@ -0,0 +1,226 @@ +analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextFactoryMock = $this->getMockBuilder(EncodedContextFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextMock = $this->getMockBuilder(EncodedContext::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->key = ''; + $this->source = ''; + $this->initializationVectors = []; + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->cryptographer = $this->objectManagerHelper->getObject( + Cryptographer::class, + [ + 'analyticsToken' => $this->analyticsTokenMock, + 'encodedContextFactory' => $this->encodedContextFactoryMock, + 'cipherMethod' => $this->cipherMethod, + ] + ); + } + + /** + * @return void + */ + public function testEncode() + { + $token = 'some-token-value'; + $this->source = 'Some text'; + $this->key = hash('sha256', $token); + + $checkEncodedContext = function ($parameters) { + $emptyRequiredParameters = + array_diff(['content', 'initializationVector'], array_keys(array_filter($parameters))); + if ($emptyRequiredParameters) { + return false; + } + + $encryptedData = openssl_encrypt( + $this->source, + $this->cipherMethod, + $this->key, + OPENSSL_RAW_DATA, + $parameters['initializationVector'] + ); + + return ($encryptedData === $parameters['content']); + }; + + $this->analyticsTokenMock + ->expects($this->once()) + ->method('getToken') + ->with() + ->willReturn($token); + + $this->encodedContextFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->callback($checkEncodedContext)) + ->willReturn($this->encodedContextMock); + + $this->assertSame($this->encodedContextMock, $this->cryptographer->encode($this->source)); + } + + /** + * @return void + */ + public function testEncodeUniqueInitializationVector() + { + $this->source = 'Some text'; + $token = 'some-token-value'; + + $registerInitializationVector = function ($parameters) { + if (empty($parameters['initializationVector'])) { + return false; + } + + $this->initializationVectors[] = $parameters['initializationVector']; + + return true; + }; + + $this->analyticsTokenMock + ->expects($this->exactly(2)) + ->method('getToken') + ->with() + ->willReturn($token); + + $this->encodedContextFactoryMock + ->expects($this->exactly(2)) + ->method('create') + ->with($this->callback($registerInitializationVector)) + ->willReturn($this->encodedContextMock); + + $this->assertSame($this->encodedContextMock, $this->cryptographer->encode($this->source)); + $this->assertSame($this->encodedContextMock, $this->cryptographer->encode($this->source)); + $this->assertCount(2, array_unique($this->initializationVectors)); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @dataProvider encodeNotValidSourceDataProvider + */ + public function testEncodeNotValidSource($source) + { + $this->cryptographer->encode($source); + } + + /** + * @return array + */ + public function encodeNotValidSourceDataProvider() + { + return [ + 'Array' => [[]], + 'Empty string' => [''], + ]; + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testEncodeNotValidCipherMethod() + { + $source = 'Some string'; + $cryptographer = $this->objectManagerHelper->getObject( + Cryptographer::class, + [ + 'cipherMethod' => 'Wrong-method', + ] + ); + + $cryptographer->encode($source); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testEncodeTokenNotValid() + { + $source = 'Some string'; + + $this->analyticsTokenMock + ->expects($this->once()) + ->method('getToken') + ->with() + ->willReturn(null); + + $this->cryptographer->encode($source); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php new file mode 100644 index 0000000000000..283b13212919d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php @@ -0,0 +1,61 @@ +objectManagerHelper = new ObjectManagerHelper($this); + } + + /** + * @param string $content + * @param string|null $initializationVector + * @return void + * @dataProvider constructDataProvider + */ + public function testConstruct($content, $initializationVector) + { + $constructorArguments = [ + 'content' => $content, + 'initializationVector' => $initializationVector, + ]; + /** @var EncodedContext $encodedContext */ + $encodedContext = $this->objectManagerHelper->getObject( + EncodedContext::class, + array_filter($constructorArguments) + ); + + $this->assertSame($content, $encodedContext->getContent()); + $this->assertSame($initializationVector ?: '', $encodedContext->getInitializationVector()); + } + + /** + * @return array + */ + public function constructDataProvider() + { + return [ + 'Without Initialization Vector' => ['content text', null], + 'With Initialization Vector' => ['content text', 'c51sd3c4sd68c5sd'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php new file mode 100644 index 0000000000000..b3826c232ed0c --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php @@ -0,0 +1,74 @@ +objectManagerHelper = new ObjectManagerHelper($this); + } + + /** + * @return void + */ + public function testThatNotifyExecuted() + { + $expectedResult = true; + $notifyCommandName = 'notifyDataChanged'; + $exportDataHandlerMockObject = $this->createExportDataHandlerMock(); + $analyticsConnectorMockObject = $this->createAnalyticsConnectorMock(); + /** + * @var $exportDataHandlerNotification ExportDataHandlerNotification + */ + $exportDataHandlerNotification = $this->objectManagerHelper->getObject( + ExportDataHandlerNotification::class, + [ + 'exportDataHandler' => $exportDataHandlerMockObject, + 'connector' => $analyticsConnectorMockObject, + ] + ); + $exportDataHandlerMockObject->expects($this->once()) + ->method('prepareExportData') + ->willReturn($expectedResult); + $analyticsConnectorMockObject->expects($this->once()) + ->method('execute') + ->with($notifyCommandName); + $this->assertEquals($expectedResult, $exportDataHandlerNotification->prepareExportData()); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createExportDataHandlerMock() + { + return $this->getMockBuilder(ExportDataHandler::class)->disableOriginalConstructor()->getMock(); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createAnalyticsConnectorMock() + { + return $this->getMockBuilder(Connector::class)->disableOriginalConstructor()->getMock(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php new file mode 100644 index 0000000000000..7c181bea81aab --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php @@ -0,0 +1,270 @@ +filesystemMock = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->archiveMock = $this->getMockBuilder(Archive::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->reportWriterMock = $this->getMockBuilder(ReportWriterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->cryptographerMock = $this->getMockBuilder(Cryptographer::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileRecorderMock = $this->getMockBuilder(FileRecorder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->directoryMock = $this->getMockBuilder(WriteInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextMock = $this->getMockBuilder(EncodedContext::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->exportDataHandler = $this->objectManagerHelper->getObject( + ExportDataHandler::class, + [ + 'filesystem' => $this->filesystemMock, + 'archive' => $this->archiveMock, + 'reportWriter' => $this->reportWriterMock, + 'cryptographer' => $this->cryptographerMock, + 'fileRecorder' => $this->fileRecorderMock, + 'subdirectoryPath' => $this->subdirectoryPath, + 'archiveName' => $this->archiveName, + ] + ); + } + + /** + * @param bool $isArchiveSourceDirectory + * @dataProvider prepareExportDataDataProvider + */ + public function testPrepareExportData($isArchiveSourceDirectory) + { + $tmpFilesDirectoryPath = $this->subdirectoryPath . 'tmp/'; + $archiveRelativePath = $this->subdirectoryPath . $this->archiveName; + + $archiveSource = $isArchiveSourceDirectory ? (__DIR__) : '/tmp/' . $tmpFilesDirectoryPath; + $archiveAbsolutePath = '/tmp/' . $archiveRelativePath; + + $this->filesystemMock + ->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::SYS_TMP) + ->willReturn($this->directoryMock); + $this->directoryMock + ->expects($this->exactly(4)) + ->method('delete') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$archiveRelativePath] + ); + + $this->directoryMock + ->expects($this->exactly(4)) + ->method('getAbsolutePath') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$tmpFilesDirectoryPath], + [$archiveRelativePath], + [$archiveRelativePath] + ) + ->willReturnOnConsecutiveCalls( + $archiveSource, + $archiveSource, + $archiveAbsolutePath, + $archiveAbsolutePath + ); + + $this->reportWriterMock + ->expects($this->once()) + ->method('write') + ->with($this->directoryMock, $tmpFilesDirectoryPath); + + $this->directoryMock + ->expects($this->exactly(2)) + ->method('isExist') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$archiveRelativePath] + ) + ->willReturnOnConsecutiveCalls( + true, + true + ); + + $this->directoryMock + ->expects($this->once()) + ->method('create') + ->with(dirname($archiveRelativePath)); + + $this->archiveMock + ->expects($this->once()) + ->method('pack') + ->with( + $archiveSource, + $archiveAbsolutePath, + $isArchiveSourceDirectory ? true : false + ); + + $fileContent = 'Some text'; + $this->directoryMock + ->expects($this->once()) + ->method('readFile') + ->with($archiveRelativePath) + ->willReturn($fileContent); + + $this->cryptographerMock + ->expects($this->once()) + ->method('encode') + ->with($fileContent) + ->willReturn($this->encodedContextMock); + + $this->fileRecorderMock + ->expects($this->once()) + ->method('recordNewFile') + ->with($this->encodedContextMock); + + $this->assertTrue($this->exportDataHandler->prepareExportData()); + } + + /** + * @return array + */ + public function prepareExportDataDataProvider() + { + return [ + 'Data source for archive is directory' => [true], + 'Data source for archive doesn\'t directory' => [false], + ]; + } + + /** + * @return void + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testPrepareExportDataWithLocalizedException() + { + $tmpFilesDirectoryPath = $this->subdirectoryPath . 'tmp/'; + $archivePath = $this->subdirectoryPath . $this->archiveName; + + $this->filesystemMock + ->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::SYS_TMP) + ->willReturn($this->directoryMock); + $this->reportWriterMock + ->expects($this->once()) + ->method('write') + ->with($this->directoryMock, $tmpFilesDirectoryPath); + $this->directoryMock + ->expects($this->exactly(3)) + ->method('delete') + ->withConsecutive( + [$tmpFilesDirectoryPath], + [$tmpFilesDirectoryPath], + [$archivePath] + ); + $this->directoryMock + ->expects($this->exactly(2)) + ->method('getAbsolutePath') + ->with($tmpFilesDirectoryPath); + $this->directoryMock + ->expects($this->once()) + ->method('isExist') + ->with($tmpFilesDirectoryPath) + ->willReturn(false); + + $this->assertNull($this->exportDataHandler->prepareExportData()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php new file mode 100644 index 0000000000000..c8c07ae8240c3 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php @@ -0,0 +1,194 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoFactoryMock = $this->getMockBuilder(FileInfoFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoMock = $this->getMockBuilder(FileInfo::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->fileInfoManager = $this->objectManagerHelper->getObject( + FileInfoManager::class, + [ + 'flagManager' => $this->flagManagerMock, + 'fileInfoFactory' => $this->fileInfoFactoryMock, + 'flagCode' => $this->flagCode, + 'encodedParameters' => $this->encodedParameters, + ] + ); + } + + /** + * @return void + */ + public function testSave() + { + $path = 'path/to/file'; + $initializationVector = openssl_random_pseudo_bytes(16); + $parameters = [ + 'path' => $path, + 'initializationVector' => $initializationVector, + ]; + + $this->fileInfoMock + ->expects($this->once()) + ->method('getPath') + ->with() + ->willReturn($path); + $this->fileInfoMock + ->expects($this->once()) + ->method('getInitializationVector') + ->with() + ->willReturn($initializationVector); + + foreach ($this->encodedParameters as $encodedParameter) { + $parameters[$encodedParameter] = base64_encode($parameters[$encodedParameter]); + } + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with($this->flagCode, $parameters); + + $this->assertTrue($this->fileInfoManager->save($this->fileInfoMock)); + } + + /** + * @param string|null $path + * @param string|null $initializationVector + * @dataProvider saveWithLocalizedExceptionDataProvider + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testSaveWithLocalizedException($path, $initializationVector) + { + $this->fileInfoMock + ->expects($this->once()) + ->method('getPath') + ->with() + ->willReturn($path); + $this->fileInfoMock + ->expects($this->once()) + ->method('getInitializationVector') + ->with() + ->willReturn($initializationVector); + + $this->fileInfoManager->save($this->fileInfoMock); + } + + /** + * @return array + */ + public function saveWithLocalizedExceptionDataProvider() + { + return [ + 'Empty FileInfo' => [null, null], + 'FileInfo without IV' => ['path/to/file', null], + ]; + } + + /** + * @dataProvider loadDataProvider + * @param array|null $parameters + */ + public function testLoad($parameters) + { + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with($this->flagCode) + ->willReturn($parameters); + + $processedParameters = $parameters ?: []; + $encodedParameters = array_intersect($this->encodedParameters, array_keys($processedParameters)); + foreach ($encodedParameters as $encodedParameter) { + $processedParameters[$encodedParameter] = base64_decode($processedParameters[$encodedParameter]); + } + + $this->fileInfoFactoryMock + ->expects($this->once()) + ->method('create') + ->with($processedParameters) + ->willReturn($this->fileInfoMock); + + $this->assertSame($this->fileInfoMock, $this->fileInfoManager->load()); + } + + /** + * @return array + */ + public function loadDataProvider() + { + return [ + 'Empty flag data' => [null], + 'Correct flag data' => [[ + 'path' => 'path/to/file', + 'initializationVector' => 'xUJjl54MVke+FvMFSBpRSA==', + ]], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php new file mode 100644 index 0000000000000..73f6ed644721a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php @@ -0,0 +1,62 @@ +objectManagerHelper = new ObjectManagerHelper($this); + } + + /** + * @param string|null $path + * @param string|null $initializationVector + * @return void + * @dataProvider constructDataProvider + */ + public function testConstruct($path, $initializationVector) + { + $constructorArguments = [ + 'path' => $path, + 'initializationVector' => $initializationVector, + ]; + /** @var FileInfo $fileInfo */ + $fileInfo = $this->objectManagerHelper->getObject( + FileInfo::class, + array_filter($constructorArguments) + ); + + $this->assertSame($path ?: '', $fileInfo->getPath()); + $this->assertSame($initializationVector ?: '', $fileInfo->getInitializationVector()); + } + + /** + * @return array + */ + public function constructDataProvider() + { + return [ + 'Degenerate object' => [null, null], + 'Without Initialization Vector' => ['content text', null], + 'With Initialization Vector' => ['content text', 'c51sd3c4sd68c5sd'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php new file mode 100644 index 0000000000000..68ff00a433fd2 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php @@ -0,0 +1,209 @@ +fileInfoManagerMock = $this->getMockBuilder(FileInfoManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoFactoryMock = $this->getMockBuilder(FileInfoFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + + $this->filesystemMock = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileInfoMock = $this->getMockBuilder(FileInfo::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->directoryMock = $this->getMockBuilder(WriteInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->encodedContextMock = $this->getMockBuilder(EncodedContext::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->fileRecorder = $this->objectManagerHelper->getObject( + FileRecorder::class, + [ + 'fileInfoManager' => $this->fileInfoManagerMock, + 'fileInfoFactory' => $this->fileInfoFactoryMock, + 'filesystem' => $this->filesystemMock, + 'fileSubdirectoryPath' => $this->fileSubdirectoryPath, + 'encodedFileName' => $this->encodedFileName, + ] + ); + } + + /** + * @param string $pathToExistingFile + * @dataProvider recordNewFileDataProvider + */ + public function testRecordNewFile($pathToExistingFile) + { + $content = openssl_random_pseudo_bytes(200); + + $this->filesystemMock + ->expects($this->once()) + ->method('getDirectoryWrite') + ->with(DirectoryList::MEDIA) + ->willReturn($this->directoryMock); + + $this->encodedContextMock + ->expects($this->once()) + ->method('getContent') + ->with() + ->willReturn($content); + + $hashLength = 64; + $fileRelativePathPattern = '#' . preg_quote($this->fileSubdirectoryPath, '#') + . '.{' . $hashLength . '}/' . preg_quote($this->encodedFileName, '#') . '#'; + $this->directoryMock + ->expects($this->once()) + ->method('writeFile') + ->with($this->matchesRegularExpression($fileRelativePathPattern), $content) + ->willReturn($this->directoryMock); + + $this->fileInfoManagerMock + ->expects($this->once()) + ->method('load') + ->with() + ->willReturn($this->fileInfoMock); + + $this->encodedContextMock + ->expects($this->once()) + ->method('getInitializationVector') + ->with() + ->willReturn('init_vector***'); + + /** register file */ + $this->fileInfoFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->callback( + function ($parameters) { + return !empty($parameters['path']) && ('init_vector***' === $parameters['initializationVector']); + } + )) + ->willReturn($this->fileInfoMock); + $this->fileInfoManagerMock + ->expects($this->once()) + ->method('save') + ->with($this->fileInfoMock); + + /** remove old file */ + $this->fileInfoMock + ->expects($this->exactly($pathToExistingFile ? 3 : 1)) + ->method('getPath') + ->with() + ->willReturn($pathToExistingFile); + $directoryName = dirname($pathToExistingFile); + if ($directoryName === '.') { + $this->directoryMock + ->expects($this->once()) + ->method('delete') + ->with($pathToExistingFile); + } elseif ($directoryName) { + $this->directoryMock + ->expects($this->exactly(2)) + ->method('delete') + ->withConsecutive( + [$pathToExistingFile], + [$directoryName] + ); + } + + $this->assertTrue($this->fileRecorder->recordNewFile($this->encodedContextMock)); + } + + /** + * @return array + */ + public function recordNewFileDataProvider() + { + return [ + 'File doesn\'t exist' => [''], + 'Existing file into subdirectory' => ['dir_name/file.txt'], + 'Existing file doesn\'t into subdirectory' => ['file.txt'], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php new file mode 100644 index 0000000000000..31d5c77ce50b0 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php @@ -0,0 +1,228 @@ +integrationServiceMock = $this->getMockBuilder(IntegrationServiceInterface::class) + ->getMock(); + $this->configMock = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->oauthServiceMock = $this->getMockBuilder(OauthServiceInterface::class) + ->getMock(); + $this->integrationMock = $this->getMockBuilder(Integration::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getId', + 'getConsumerId' + ]) + ->getMock(); + $this->integrationManager = $objectManagerHelper->getObject( + IntegrationManager::class, + [ + 'integrationService' => $this->integrationServiceMock, + 'oauthService' => $this->oauthServiceMock, + 'config' => $this->configMock + ] + ); + } + + /** + * @param string $status + * + * @return array + */ + private function getIntegrationUserData($status) + { + return [ + 'name' => 'ma-integration-user', + 'status' => $status, + 'all_resources' => false, + 'resource' => [ + 'Magento_Analytics::analytics', + 'Magento_Analytics::analytics_api' + ], + ]; + } + + /** + * @return void + */ + public function testActivateIntegrationSuccess() + { + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->exactly(2)) + ->method('getId') + ->willReturn(100500); + $integrationData = $this->getIntegrationUserData(Integration::STATUS_ACTIVE); + $integrationData['integration_id'] = 100500; + $this->configMock->expects($this->exactly(2)) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('update') + ->with($integrationData); + $this->assertTrue($this->integrationManager->activateIntegration()); + } + + /** + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + */ + public function testActivateIntegrationFailureNoSuchEntity() + { + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn(null); + $this->configMock->expects($this->once()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->never()) + ->method('update'); + $this->integrationManager->activateIntegration(); + } + + /** + * @dataProvider integrationIdDataProvider + * + * @param int|null $integrationId If null integration is absent. + * @return void + */ + public function testGetTokenNewIntegration($integrationId) + { + $this->configMock->expects($this->atLeastOnce()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getConsumerId') + ->willReturn(100500); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn($integrationId); + if (!$integrationId) { + $this->integrationServiceMock + ->expects($this->once()) + ->method('create') + ->with($this->getIntegrationUserData(Integration::STATUS_INACTIVE)) + ->willReturn($this->integrationMock); + } + $this->oauthServiceMock->expects($this->at(0)) + ->method('getAccessToken') + ->with(100500) + ->willReturn(false); + $this->oauthServiceMock->expects($this->at(2)) + ->method('getAccessToken') + ->with(100500) + ->willReturn('IntegrationToken'); + $this->oauthServiceMock->expects($this->once()) + ->method('createAccessToken') + ->with(100500, true) + ->willReturn(true); + $this->assertEquals('IntegrationToken', $this->integrationManager->generateToken()); + } + + /** + * @dataProvider integrationIdDataProvider + * + * @param int|null $integrationId If null integration is absent. + * @return void + */ + public function testGetTokenExistingIntegration($integrationId) + { + $this->configMock->expects($this->atLeastOnce()) + ->method('getConfigDataValue') + ->with('analytics/integration_name', null, null) + ->willReturn('ma-integration-user'); + $this->integrationServiceMock->expects($this->once()) + ->method('findByName') + ->with('ma-integration-user') + ->willReturn($this->integrationMock); + $this->integrationMock->expects($this->once()) + ->method('getConsumerId') + ->willReturn(100500); + $this->integrationMock->expects($this->once()) + ->method('getId') + ->willReturn($integrationId); + if (!$integrationId) { + $this->integrationServiceMock + ->expects($this->once()) + ->method('create') + ->with($this->getIntegrationUserData(Integration::STATUS_INACTIVE)) + ->willReturn($this->integrationMock); + } + $this->oauthServiceMock->expects($this->once()) + ->method('getAccessToken') + ->with(100500) + ->willReturn('IntegrationToken'); + $this->oauthServiceMock->expects($this->never()) + ->method('createAccessToken'); + $this->assertEquals('IntegrationToken', $this->integrationManager->generateToken()); + } + + /** + * @return array + */ + public function integrationIdDataProvider() + { + return [ + [1], + [null], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php new file mode 100644 index 0000000000000..afda37962a3cb --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php @@ -0,0 +1,166 @@ +linkInterfaceFactoryMock = $this->getMockBuilder(LinkInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->fileInfoManagerMock = $this->getMockBuilder(FileInfoManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManagerInterfaceMock = $this->getMockBuilder(StoreManagerInterface::class) + ->getMockForAbstractClass(); + $this->linkInterfaceMock = $this->getMockBuilder(LinkInterface::class) + ->getMockForAbstractClass(); + $this->fileInfoMock = $this->getMockBuilder(FileInfo::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeMock = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->linkProvider = $this->objectManagerHelper->getObject( + LinkProvider::class, + [ + 'linkFactory' => $this->linkInterfaceFactoryMock, + 'fileInfoManager' => $this->fileInfoManagerMock, + 'storeManager' => $this->storeManagerInterfaceMock + ] + ); + } + + public function testGet() + { + $baseUrl = 'http://magento.local/pub/media/'; + $fileInfoPath = 'analytics/data.tgz'; + $fileInitializationVector = 'er312esq23eqq'; + $this->fileInfoManagerMock->expects($this->once()) + ->method('load') + ->willReturn($this->fileInfoMock); + $this->linkInterfaceFactoryMock->expects($this->once()) + ->method('create') + ->with( + [ + 'initializationVector' => base64_encode($fileInitializationVector), + 'url' => $baseUrl . $fileInfoPath + ] + ) + ->willReturn($this->linkInterfaceMock); + $this->storeManagerInterfaceMock->expects($this->once()) + ->method('getStore')->willReturn($this->storeMock); + $this->storeMock->expects($this->once()) + ->method('getBaseUrl') + ->with( + UrlInterface::URL_TYPE_MEDIA + ) + ->willReturn($baseUrl); + $this->fileInfoMock->expects($this->atLeastOnce()) + ->method('getPath') + ->willReturn($fileInfoPath); + $this->fileInfoMock->expects($this->atLeastOnce()) + ->method('getInitializationVector') + ->willReturn($fileInitializationVector); + $this->assertEquals($this->linkInterfaceMock, $this->linkProvider->get()); + } + + /** + * @param string|null $fileInfoPath + * @param string|null $fileInitializationVector + * + * @dataProvider fileNotReadyDataProvider + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + * @expectedExceptionMessage File is not ready yet. + */ + public function testFileNotReady($fileInfoPath, $fileInitializationVector) + { + $this->fileInfoManagerMock->expects($this->once()) + ->method('load') + ->willReturn($this->fileInfoMock); + $this->fileInfoMock->expects($this->once()) + ->method('getPath') + ->willReturn($fileInfoPath); + $this->fileInfoMock->expects($this->any()) + ->method('getInitializationVector') + ->willReturn($fileInitializationVector); + $this->linkProvider->get(); + } + + /** + * @return array + */ + public function fileNotReadyDataProvider() + { + return [ + [null, 'initVector'], + ['path', null], + ['', 'initVector'], + ['path', ''], + ['', ''], + [null, null] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php new file mode 100644 index 0000000000000..03fe7d968a7f5 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php @@ -0,0 +1,76 @@ +flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->notificationTime = $objectManagerHelper->getObject( + NotificationTime::class, + [ + 'flagManager' => $this->flagManagerMock, + ] + ); + } + + public function testStoreLastTimeNotification() + { + $value = 100500; + + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(NotificationTime::NOTIFICATION_TIME, $value) + ->willReturn(true); + $this->assertTrue($this->notificationTime->storeLastTimeNotification($value)); + } + + public function testGetLastTimeNotification() + { + $value = 100500; + + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(NotificationTime::NOTIFICATION_TIME) + ->willReturn(true); + $this->assertEquals($value, $this->notificationTime->getLastTimeNotification()); + } + + public function testUnsetLastTimeNotificationValue() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(NotificationTime::NOTIFICATION_TIME) + ->willReturn(true); + $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValue()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php new file mode 100644 index 0000000000000..38d073a4b4550 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php @@ -0,0 +1,147 @@ +subscriptionUpdateHandlerMock = $this->getMockBuilder(SubscriptionUpdateHandler::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configValueMock = $this->getMockBuilder(Value::class) + ->disableOriginalConstructor() + ->setMethods(['isValueChanged', 'getPath', 'getScope', 'getOldValue']) + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->plugin = $this->objectManagerHelper->getObject( + BaseUrlConfigPlugin::class, + [ + 'subscriptionUpdateHandler' => $this->subscriptionUpdateHandlerMock, + ] + ); + } + + /** + * @param array $configValueData + * @return void + * @dataProvider afterSavePluginIsNotApplicableDataProvider + */ + public function testAfterSavePluginIsNotApplicable( + array $configValueData + ) { + $this->configValueMock + ->method('isValueChanged') + ->willReturn($configValueData['isValueChanged']); + $this->configValueMock + ->method('getPath') + ->willReturn($configValueData['path']); + $this->configValueMock + ->method('getScope') + ->willReturn($configValueData['scope']); + $this->subscriptionUpdateHandlerMock + ->expects($this->never()) + ->method('processUrlUpdate'); + + $this->assertEquals( + $this->configValueMock, + $this->plugin->afterAfterSave($this->configValueMock, $this->configValueMock) + ); + } + + /** + * @return array + */ + public function afterSavePluginIsNotApplicableDataProvider() + { + return [ + 'Value has not been changed' => [ + 'Config Value Data' => [ + 'isValueChanged' => false, + 'path' => Store::XML_PATH_SECURE_BASE_URL, + 'scope' => ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ], + ], + 'Unsecure URL has been changed' => [ + 'Config Value Data' => [ + 'isValueChanged' => true, + 'path' => Store::XML_PATH_UNSECURE_BASE_URL, + 'scope' => ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ], + ], + 'Secure URL has been changed not in the Default scope' => [ + 'Config Value Data' => [ + 'isValueChanged' => true, + 'path' => Store::XML_PATH_SECURE_BASE_URL, + 'scope' => ScopeInterface::SCOPE_STORES + ], + ], + ]; + } + + /** + * @return void + */ + public function testAfterSavePluginIsApplicable() + { + $this->configValueMock + ->method('isValueChanged') + ->willReturn(true); + $this->configValueMock + ->method('getPath') + ->willReturn(Store::XML_PATH_SECURE_BASE_URL); + $this->configValueMock + ->method('getScope') + ->willReturn(ScopeConfigInterface::SCOPE_TYPE_DEFAULT); + $this->configValueMock + ->method('getOldValue') + ->willReturn('http://store.com'); + $this->subscriptionUpdateHandlerMock + ->expects($this->once()) + ->method('processUrlUpdate') + ->with('http://store.com'); + + $this->assertEquals( + $this->configValueMock, + $this->plugin->afterAfterSave($this->configValueMock, $this->configValueMock) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php new file mode 100644 index 0000000000000..ee507d88c68db --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php @@ -0,0 +1,153 @@ +configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->otpRequestMock = $this->getMockBuilder(OTPRequest::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reportUrlProvider = $this->objectManagerHelper->getObject( + ReportUrlProvider::class, + [ + 'config' => $this->configMock, + 'analyticsToken' => $this->analyticsTokenMock, + 'otpRequest' => $this->otpRequestMock, + 'flagManager' => $this->flagManagerMock, + 'urlReportConfigPath' => $this->urlReportConfigPath, + ] + ); + } + + /** + * @param bool $isTokenExist + * @param string|null $otp If null OTP was not received. + * + * @dataProvider getUrlDataProvider + */ + public function testGetUrl($isTokenExist, $otp) + { + $reportUrl = 'https://example.com/report'; + $url = ''; + + $this->configMock + ->expects($this->once()) + ->method('getValue') + ->with($this->urlReportConfigPath) + ->willReturn($reportUrl); + $this->analyticsTokenMock + ->expects($this->once()) + ->method('isTokenExist') + ->with() + ->willReturn($isTokenExist); + $this->otpRequestMock + ->expects($isTokenExist ? $this->once() : $this->never()) + ->method('call') + ->with() + ->willReturn($otp); + if ($isTokenExist && $otp) { + $url = $reportUrl . '?' . http_build_query(['otp' => $otp], '', '&'); + } + $this->assertSame($url ?: $reportUrl, $this->reportUrlProvider->getUrl()); + } + + /** + * @return array + */ + public function getUrlDataProvider() + { + return [ + 'TokenDoesNotExist' => [false, null], + 'TokenExistAndOtpEmpty' => [true, null], + 'TokenExistAndOtpValid' => [true, '249e6b658877bde2a77bc4ab'], + ]; + } + + /** + * @return void + */ + public function testGetUrlWhenSubscriptionUpdateRunning() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE) + ->willReturn('http://store.com'); + $this->setExpectedException( + SubscriptionUpdateException::class, + 'Your Base URL has been changed and your reports are being updated. ' + . 'Advanced Reporting will be available once this change has been processed. Please try again later.' + ); + $this->reportUrlProvider->getUrl(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php new file mode 100644 index 0000000000000..96ac1143ec5ec --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php @@ -0,0 +1,213 @@ +configInterfaceMock = $this->getMockBuilder(ConfigInterface::class)->getMockForAbstractClass(); + $this->reportValidatorMock = $this->getMockBuilder(ReportValidator::class) + ->disableOriginalConstructor()->getMock(); + $this->providerFactoryMock = $this->getMockBuilder(ProviderFactory::class) + ->disableOriginalConstructor()->getMock(); + $this->reportProviderMock = $this->getMockBuilder(ReportProvider::class) + ->disableOriginalConstructor()->getMock(); + $this->directoryMock = $this->getMockBuilder(WriteInterface::class)->getMockForAbstractClass(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reportWriter = $this->objectManagerHelper->getObject( + ReportWriter::class, + [ + 'config' => $this->configInterfaceMock, + 'reportValidator' => $this->reportValidatorMock, + 'providerFactory' => $this->providerFactoryMock + ] + ); + } + + /** + * @param array $configData + * @return void + * + * @dataProvider configDataProvider + */ + public function testWrite(array $configData) + { + $errors = []; + $fileData = [ + ['number' => 1, 'type' => 'Shoes Usual'] + ]; + $this->configInterfaceMock + ->expects($this->once()) + ->method('get') + ->with() + ->willReturn([$configData]); + $this->providerFactoryMock + ->expects($this->once()) + ->method('create') + ->with($this->providerClass) + ->willReturn($this->reportProviderMock); + $parameterName = isset(reset($configData)[0]['parameters']['name']) + ? reset($configData)[0]['parameters']['name'] + : ''; + $this->reportProviderMock->expects($this->once()) + ->method('getReport') + ->with($parameterName ?: null) + ->willReturn($fileData); + $errorStreamMock = $this->getMockBuilder( + \Magento\Framework\Filesystem\File\WriteInterface::class + )->getMockForAbstractClass(); + $errorStreamMock + ->expects($this->once()) + ->method('lock') + ->with(); + $errorStreamMock + ->expects($this->exactly(2)) + ->method('writeCsv') + ->withConsecutive( + [array_keys($fileData[0])], + [$fileData[0]] + ); + $errorStreamMock->expects($this->once())->method('unlock'); + $errorStreamMock->expects($this->once())->method('close'); + if ($parameterName) { + $this->reportValidatorMock + ->expects($this->once()) + ->method('validate') + ->with($parameterName) + ->willReturn($errors); + } + $this->directoryMock + ->expects($this->once()) + ->method('openFile') + ->with( + $this->stringContains('/var/tmp' . $parameterName ?: $this->reportName), + 'w+' + )->willReturn($errorStreamMock); + $this->assertTrue($this->reportWriter->write($this->directoryMock, '/var/tmp')); + } + + /** + * @param array $configData + * @return void + * + * @dataProvider configDataProvider + */ + public function testWriteErrorFile($configData) + { + $errors = ['orders', 'SQL Error: test']; + $this->configInterfaceMock->expects($this->once())->method('get')->willReturn([$configData]); + $errorStreamMock = $this->getMockBuilder( + \Magento\Framework\Filesystem\File\WriteInterface::class + )->getMockForAbstractClass(); + $errorStreamMock->expects($this->once())->method('lock'); + $errorStreamMock->expects($this->once())->method('writeCsv')->with($errors); + $errorStreamMock->expects($this->once())->method('unlock'); + $errorStreamMock->expects($this->once())->method('close'); + $this->reportValidatorMock->expects($this->once())->method('validate')->willReturn($errors); + $this->directoryMock->expects($this->once())->method('openFile')->with('/var/tmp' . 'errors.csv', 'w+') + ->willReturn($errorStreamMock); + $this->assertTrue($this->reportWriter->write($this->directoryMock, '/var/tmp')); + } + + /** + * @return void + */ + public function testWriteEmptyReports() + { + $this->configInterfaceMock->expects($this->once())->method('get')->willReturn([]); + $this->reportValidatorMock->expects($this->never())->method('validate'); + $this->directoryMock->expects($this->never())->method('openFile'); + $this->assertTrue($this->reportWriter->write($this->directoryMock, '/var/tmp')); + } + + /** + * @return array + */ + public function configDataProvider() + { + return [ + 'reportProvider' => [ + [ + 'providers' => [ + [ + 'name' => $this->providerName, + 'class' => $this->providerClass, + 'parameters' => [ + 'name' => $this->reportName + ], + ] + ] + ] + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php new file mode 100644 index 0000000000000..654fad74ef309 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php @@ -0,0 +1,50 @@ +moduleManagerMock = $this->getMockBuilder(ModuleManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->moduleIterator = $objectManagerHelper->getObject( + ModuleIterator::class, + [ + 'moduleManager' => $this->moduleManagerMock, + 'iterator' => new \ArrayIterator([0 => ['module_name' => 'Coco_Module']]) + ] + ); + } + + public function testCurrent() + { + $this->moduleManagerMock->expects($this->once()) + ->method('isEnabled') + ->with('Coco_Module') + ->willReturn(true); + foreach ($this->moduleIterator as $item) { + $this->assertEquals(['module_name' => 'Coco_Module', 'status' => 'Enabled'], $item); + } + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php new file mode 100644 index 0000000000000..a2f9be1461c15 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php @@ -0,0 +1,123 @@ +scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->websiteMock = $this->getMockBuilder(WebsiteInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeMock = $this->getMockBuilder(StoreInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configPaths = [ + 'web/unsecure/base_url', + 'currency/options/base', + 'general/locale/timezone' + ]; + + $this->storeConfigurationProvider = new StoreConfigurationProvider( + $this->scopeConfigMock, + $this->storeManagerMock, + $this->configPaths + ); + } + + public function testGetReport() + { + $map = [ + ['web/unsecure/base_url', 'default', 0, '127.0.0.1'], + ['currency/options/base', 'default', 0, 'USD'], + ['general/locale/timezone', 'default', 0, 'America/Dawson'], + ['web/unsecure/base_url', 'websites', 1, '127.0.0.2'], + ['currency/options/base', 'websites', 1, 'USD'], + ['general/locale/timezone', 'websites', 1, 'America/Belem'], + ['web/unsecure/base_url', 'stores', 2, '127.0.0.3'], + ['currency/options/base', 'stores', 2, 'USD'], + ['general/locale/timezone', 'stores', 2, 'America/Phoenix'], + ]; + + $this->scopeConfigMock + ->method('getValue') + ->will($this->returnValueMap($map)); + + $this->storeManagerMock->expects($this->once()) + ->method('getWebsites') + ->willReturn([$this->websiteMock]); + + $this->storeManagerMock->expects($this->once()) + ->method('getStores') + ->willReturn([$this->storeMock]); + + $this->websiteMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + + $this->storeMock->expects($this->once()) + ->method('getId') + ->willReturn(2); + $result = iterator_to_array($this->storeConfigurationProvider->getReport()); + $resultValues = []; + foreach ($result as $item) { + $resultValues[] = array_values($item); + } + array_multisort($resultValues); + array_multisort($map); + $this->assertEquals($resultValues, $map); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php new file mode 100644 index 0000000000000..2e52a13f90bbf --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php @@ -0,0 +1,196 @@ +scopeConfigMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->getMockForAbstractClass(); + + $this->analyticsTokenMock = $this->getMockBuilder(AnalyticsToken::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->statusProvider = $this->objectManagerHelper->getObject( + SubscriptionStatusProvider::class, + [ + 'scopeConfig' => $this->scopeConfigMock, + 'analyticsToken' => $this->analyticsTokenMock, + 'flagManager' => $this->flagManagerMock, + ] + ); + } + + /** + * @param array $flagManagerData + * @dataProvider getStatusShouldBeFailedDataProvider + */ + public function testGetStatusShouldBeFailed(array $flagManagerData) + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(false); + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(true); + + $this->expectFlagManagerReturn($flagManagerData); + $this->assertEquals(SubscriptionStatusProvider::FAILED, $this->statusProvider->getStatus()); + } + + /** + * @return array + */ + public function getStatusShouldBeFailedDataProvider() + { + return [ + 'Subscription update doesn\'t active' => [ + 'Flag Manager data mapping' => [ + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, null], + [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, null] + ], + ], + 'Subscription update is active' => [ + 'Flag Manager data mapping' => [ + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'http://store.com'], + [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, null] + ], + ], + ]; + } + + /** + * @param array $flagManagerData + * @param bool $isTokenExist + * @dataProvider getStatusShouldBePendingDataProvider + */ + public function testGetStatusShouldBePending(array $flagManagerData, bool $isTokenExist) + { + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn($isTokenExist); + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(true); + + $this->expectFlagManagerReturn($flagManagerData); + $this->assertEquals(SubscriptionStatusProvider::PENDING, $this->statusProvider->getStatus()); + } + + /** + * @return array + */ + public function getStatusShouldBePendingDataProvider() + { + return [ + 'Subscription update doesn\'t active and the token does not exist' => [ + 'Flag Manager data mapping' => [ + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, null], + [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, 45] + ], + 'isTokenExist' => false, + ], + 'Subscription update is active and the token does not exist' => [ + 'Flag Manager data mapping' => [ + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'http://store.com'], + [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, 45] + ], + 'isTokenExist' => false, + ], + 'Subscription update is active and token exist' => [ + 'Flag Manager data mapping' => [ + [SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'http://store.com'], + [SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, null] + ], + 'isTokenExist' => true, + ], + ]; + } + + public function testGetStatusShouldBeEnabled() + { + $this->flagManagerMock + ->method('getFlagData') + ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE) + ->willReturn(null); + $this->analyticsTokenMock->expects($this->once()) + ->method('isTokenExist') + ->willReturn(true); + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(true); + $this->assertEquals(SubscriptionStatusProvider::ENABLED, $this->statusProvider->getStatus()); + } + + public function testGetStatusShouldBeDisabled() + { + $this->scopeConfigMock->expects($this->once()) + ->method('getValue') + ->with('analytics/subscription/enabled') + ->willReturn(false); + $this->assertEquals(SubscriptionStatusProvider::DISABLED, $this->statusProvider->getStatus()); + } + + /** + * @param array $mapping + */ + private function expectFlagManagerReturn(array $mapping) + { + $this->flagManagerMock + ->method('getFlagData') + ->willReturnMap($mapping); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php new file mode 100644 index 0000000000000..536a7dbb5dfe9 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php @@ -0,0 +1,106 @@ +subscriptionStatusMock = $this->getMockBuilder(SubscriptionStatusProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $this->urlBuilderMock = $this->getMockBuilder(UrlInterface::class) + ->getMockForAbstractClass(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->notification = $this->objectManagerHelper->getObject( + NotificationAboutFailedSubscription::class, + [ + 'subscriptionStatusProvider' => $this->subscriptionStatusMock, + 'urlBuilder' => $this->urlBuilderMock + ] + ); + } + + public function testIsDisplayedWhenMessageShouldBeDisplayed() + { + $this->subscriptionStatusMock->expects($this->once()) + ->method('getStatus') + ->willReturn( + SubscriptionStatusProvider::FAILED + ); + $this->assertTrue($this->notification->isDisplayed()); + } + + /** + * @dataProvider notDisplayedNotificationStatuses + * + * @param $status + */ + public function testIsDisplayedWhenMessageShouldNotBeDisplayed($status) + { + $this->subscriptionStatusMock->expects($this->once()) + ->method('getStatus') + ->willReturn($status); + $this->assertFalse($this->notification->isDisplayed()); + } + + public function testGetTextShouldBuildMessage() + { + $retryUrl = 'http://magento.dev/retryUrl'; + $this->urlBuilderMock->expects($this->once()) + ->method('getUrl') + ->with('analytics/subscription/retry') + ->willReturn($retryUrl); + $messageDetails = 'Failed to synchronize data to the Magento Business Intelligence service. '; + $messageDetails .= sprintf('Retry Synchronization', $retryUrl); + $this->assertEquals($messageDetails, $this->notification->getText()); + } + + /** + * Provide statuses according to which message should not be displayed. + * + * @return array + */ + public function notDisplayedNotificationStatuses() + { + return [ + [SubscriptionStatusProvider::PENDING], + [SubscriptionStatusProvider::DISABLED], + [SubscriptionStatusProvider::ENABLED], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php new file mode 100644 index 0000000000000..325d3d4a85c7e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php @@ -0,0 +1,121 @@ +objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\Config\Converter\Xml::class + ); + } + + /** + * @return void + */ + public function testConvertNoElements() + { + $this->assertEmpty( + $this->subject->convert(new \DOMDocument()) + ); + } + + /** + * @return void + */ + public function testConvert() + { + $dom = new \DOMDocument(); + + $expectedArray = [ + 'config' => [ + [ + 'noNamespaceSchemaLocation' => 'urn:magento:module:Magento_Analytics:etc/reports.xsd', + 'report' => [ + [ + 'name' => 'test_report_1', + 'connection' => 'sales', + 'source' => [ + [ + 'name' => 'sales_order', + 'alias' => 'orders', + 'attribute' => [ + [ + 'name' => 'entity_id', + 'alias' => 'identifier', + ] + ], + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'entity_id', + 'operator' => 'gt', + '_value' => '10' + ] + ] + ] + ] + ] + ] + ], + [ + 'name' => 'test_report_2', + 'connection' => 'default', + 'source' => [ + [ + 'name' => 'customer_entity', + 'alias' => 'customers', + 'attribute' => [ + [ + 'name' => 'email' + ] + ], + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'dob', + 'operator' => 'null' + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + + $dom->loadXML(file_get_contents(__DIR__ . '/../_files/valid_reports.xml')); + + $this->assertEquals($expectedArray, $this->subject->convert($dom)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php new file mode 100644 index 0000000000000..f69b40118b935 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php @@ -0,0 +1,47 @@ +mapper = new Mapper(); + } + + public function testExecute() + { + $configData['config'][0]['report'] = [ + [ + 'source' => ['product'], + 'name' => 'Product', + ] + ]; + $expectedResult = [ + 'Product' => [ + 'source' => 'product', + 'name' => 'Product', + ] + ]; + $this->assertEquals($this->mapper->execute($configData), $expectedResult); + } + + public function testExecuteWithoutReports() + { + $configData = []; + $this->assertEquals($this->mapper->execute($configData), []); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml new file mode 100644 index 0000000000000..e04ee96163797 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/_files/valid_reports.xml @@ -0,0 +1,25 @@ + + + + + + + + 10 + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php new file mode 100644 index 0000000000000..1b89a0d3ad671 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php @@ -0,0 +1,64 @@ +dataMock = $this->getMockBuilder(DataInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->config = $this->objectManagerHelper->getObject( + Config::class, + [ + 'data' => $this->dataMock, + ] + ); + } + + public function testGet() + { + $queryName = 'query string'; + $queryResult = [ 'query' => 1 ]; + + $this->dataMock + ->expects($this->once()) + ->method('get') + ->with($queryName) + ->willReturn($queryResult); + + $this->assertSame($queryResult, $this->config->get($queryName)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php new file mode 100644 index 0000000000000..330f7f1a6707a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php @@ -0,0 +1,106 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(MysqlPdoAdapter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionNewMock = $this->getMockBuilder(MysqlPdoAdapter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->connectionFactory = $this->objectManagerHelper->getObject( + ConnectionFactory::class, + [ + 'resourceConnection' => $this->resourceConnectionMock, + 'objectManager' => $this->objectManagerMock, + ] + ); + } + + public function testGetConnection() + { + $connectionName = 'read'; + + $this->resourceConnectionMock + ->expects($this->once()) + ->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + + $this->connectionMock + ->expects($this->once()) + ->method('getConfig') + ->with() + ->willReturn(['persistent' => 1]); + + $this->objectManagerMock + ->expects($this->once()) + ->method('create') + ->with(get_class($this->connectionMock), ['config' => ['use_buffered_query' => false]]) + ->willReturn($this->connectionNewMock); + + $this->assertSame($this->connectionNewMock, $this->connectionFactory->getConnection($connectionName)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php new file mode 100644 index 0000000000000..6ebfd1ffa2da6 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php @@ -0,0 +1,143 @@ +nameResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\NameResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->selectBuilderMock->expects($this->any()) + ->method('getFilters') + ->willReturn([]); + + $this->conditionResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ConditionResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\DB\Assembler\FilterAssembler::class, + [ + 'conditionResolver' => $this->conditionResolverMock, + 'nameResolver' => $this->nameResolverMock + ] + ); + } + + /** + * @return void + */ + public function testAssembleEmpty() + { + $queryConfigMock = [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales' + ] + ]; + + $this->selectBuilderMock->expects($this->never()) + ->method('setFilters'); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } + + /** + * @return void + */ + public function testAssembleNotEmpty() + { + $queryConfigMock = [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'entity_id', + 'operator' => 'null' + ] + ] + ] + ] + ] + ]; + + $this->nameResolverMock->expects($this->any()) + ->method('getAlias') + ->with($queryConfigMock['source']) + ->willReturn($queryConfigMock['source']['alias']); + + $this->conditionResolverMock->expects($this->once()) + ->method('getFilter') + ->with( + $this->selectBuilderMock, + $queryConfigMock['source']['filter'], + $queryConfigMock['source']['alias'] + ) + ->willReturn('(sales.entity_id IS NULL)'); + + $this->selectBuilderMock->expects($this->once()) + ->method('setFilters') + ->with(['(sales.entity_id IS NULL)']); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php new file mode 100644 index 0000000000000..cbabac5613a8b --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php @@ -0,0 +1,167 @@ +nameResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\NameResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->selectBuilderMock->expects($this->any()) + ->method('getColumns') + ->willReturn([]); + + $this->columnsResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ColumnsResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceConnection = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\DB\Assembler\FromAssembler::class, + [ + 'nameResolver' => $this->nameResolverMock, + 'columnsResolver' => $this->columnsResolverMock, + 'resourceConnection' => $this->resourceConnection, + ] + ); + } + + /** + * @dataProvider assembleDataProvider + * @param array $queryConfig + * @param string $tableName + * @return void + */ + public function testAssemble(array $queryConfig, $tableName) + { + $this->nameResolverMock->expects($this->any()) + ->method('getAlias') + ->with($queryConfig['source']) + ->willReturn($queryConfig['source']['alias']); + + $this->nameResolverMock->expects($this->once()) + ->method('getName') + ->with($queryConfig['source']) + ->willReturn($queryConfig['source']['name']); + + $this->resourceConnection + ->expects($this->once()) + ->method('getTableName') + ->with($queryConfig['source']['name']) + ->willReturn($tableName); + + $this->selectBuilderMock->expects($this->once()) + ->method('setFrom') + ->with([$queryConfig['source']['alias'] => $tableName]); + + $this->columnsResolverMock->expects($this->once()) + ->method('getColumns') + ->with($this->selectBuilderMock, $queryConfig['source']) + ->willReturn(['entity_id' => 'sales.entity_id']); + + $this->selectBuilderMock->expects($this->once()) + ->method('setColumns') + ->with(['entity_id' => 'sales.entity_id']); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfig) + ); + } + + /** + * @return array + */ + public function assembleDataProvider() + { + return [ + 'Tables without prefixes' => [ + [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'attribute' => [ + [ + 'name' => 'entity_id' + ] + ], + ], + ], + 'sales_order', + ], + 'Tables with prefixes' => [ + [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'attribute' => [ + [ + 'name' => 'entity_id' + ] + ], + ], + ], + 'pref_sales_order', + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php new file mode 100644 index 0000000000000..b913689513ce5 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php @@ -0,0 +1,279 @@ +nameResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\NameResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->selectBuilderMock->expects($this->any()) + ->method('getFilters') + ->willReturn([]); + $this->selectBuilderMock->expects($this->any()) + ->method('getColumns') + ->willReturn([]); + $this->selectBuilderMock->expects($this->any()) + ->method('getJoins') + ->willReturn([]); + + $this->columnsResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ColumnsResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->conditionResolverMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\ConditionResolver::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceConnection = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\DB\Assembler\JoinAssembler::class, + [ + 'conditionResolver' => $this->conditionResolverMock, + 'nameResolver' => $this->nameResolverMock, + 'columnsResolver' => $this->columnsResolverMock, + 'resourceConnection' => $this->resourceConnection, + ] + ); + } + + /** + * @return void + */ + public function testAssembleEmpty() + { + $queryConfigMock = [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales' + ] + ]; + + $this->selectBuilderMock->expects($this->never()) + ->method('setColumns'); + $this->selectBuilderMock->expects($this->never()) + ->method('setFilters'); + $this->selectBuilderMock->expects($this->never()) + ->method('setJoins'); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } + + /** + * @param array $queryConfigMock + * @param array $joinsMock + * @param array $tablesMapping + * @return void + * @dataProvider assembleNotEmptyDataProvider + */ + public function testAssembleNotEmpty(array $queryConfigMock, array $joinsMock, array $tablesMapping) + { + $filtersMock = []; + + $this->nameResolverMock->expects($this->at(0)) + ->method('getAlias') + ->with($queryConfigMock['source']) + ->willReturn($queryConfigMock['source']['alias']); + $this->nameResolverMock->expects($this->at(1)) + ->method('getAlias') + ->with($queryConfigMock['source']['link-source'][0]) + ->willReturn($queryConfigMock['source']['link-source'][0]['alias']); + $this->nameResolverMock->expects($this->once()) + ->method('getName') + ->with($queryConfigMock['source']['link-source'][0]) + ->willReturn($queryConfigMock['source']['link-source'][0]['name']); + + $this->resourceConnection + ->expects($this->any()) + ->method('getTableName') + ->willReturnOnConsecutiveCalls(...array_values($tablesMapping)); + + $this->conditionResolverMock->expects($this->at(0)) + ->method('getFilter') + ->with( + $this->selectBuilderMock, + $queryConfigMock['source']['link-source'][0]['using'], + $queryConfigMock['source']['link-source'][0]['alias'], + $queryConfigMock['source']['alias'] + ) + ->willReturn('(billing.parent_id = `sales`.`entity_id`)'); + + if (isset($queryConfigMock['source']['link-source'][0]['filter'])) { + $filtersMock = ['(sales.entity_id IS NULL)']; + + $this->conditionResolverMock->expects($this->at(1)) + ->method('getFilter') + ->with( + $this->selectBuilderMock, + $queryConfigMock['source']['link-source'][0]['filter'], + $queryConfigMock['source']['link-source'][0]['alias'], + $queryConfigMock['source']['alias'] + ) + ->willReturn($filtersMock[0]); + + $this->columnsResolverMock->expects($this->once()) + ->method('getColumns') + ->with($this->selectBuilderMock, $queryConfigMock['source']['link-source'][0]) + ->willReturn( + [ + 'entity_id' => 'sales.entity_id', + 'billing_address_id' => 'billing.entity_id' + ] + ); + + $this->selectBuilderMock->expects($this->once()) + ->method('setColumns') + ->with( + [ + 'entity_id' => 'sales.entity_id', + 'billing_address_id' => 'billing.entity_id' + ] + ); + } + + $this->selectBuilderMock->expects($this->once()) + ->method('setFilters') + ->with($filtersMock); + $this->selectBuilderMock->expects($this->once()) + ->method('setJoins') + ->with($joinsMock); + + $this->assertEquals( + $this->selectBuilderMock, + $this->subject->assemble($this->selectBuilderMock, $queryConfigMock) + ); + } + + /** + * @return array + */ + public function assembleNotEmptyDataProvider() + { + return [ + [ + [ + 'source' => [ + 'name' => 'sales_order', + 'alias' => 'sales', + 'link-source' => [ + [ + 'name' => 'sales_order_address', + 'alias' => 'billing', + 'link-type' => 'left', + 'attribute' => [ + [ + 'alias' => 'billing_address_id', + 'name' => 'entity_id' + ] + ], + 'using' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'parent_id', + 'operator' => 'eq', + 'type' => 'identifier', + '_value' => 'entity_id' + ] + ] + ] + ], + 'filter' => [ + [ + 'glue' => 'and', + 'condition' => [ + [ + 'attribute' => 'entity_id', + 'operator' => 'null' + ] + ] + ] + ] + ] + ] + ] + ], + [ + 'billing' => [ + 'link-type' => 'left', + 'table' => [ + 'billing' => 'pref_sales_order_address' + ], + 'condition' => '(billing.parent_id = `sales`.`entity_id`)' + ] + ], + ['sales_order_address' => 'pref_sales_order_address'] + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php new file mode 100644 index 0000000000000..c8ab79625e9c3 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php @@ -0,0 +1,150 @@ +selectBuilderMock = $this->getMockBuilder(SelectBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new ObjectManagerHelper($this); + $this->columnsResolver = $objectManager->getObject( + ColumnsResolver::class, + [ + 'nameResolver' => new NameResolver(), + 'resourceConnection' => $this->resourceConnectionMock + ] + ); + } + + public function testGetColumnsWithoutAttributes() + { + $this->assertEquals($this->columnsResolver->getColumns($this->selectBuilderMock, []), []); + } + + /** + * @dataProvider getColumnsDataProvider + */ + public function testGetColumnsWithFunction($expectedColumns, $expectedGroup, $entityConfig) + { + $this->resourceConnectionMock->expects($this->any()) + ->method('getConnection') + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->any()) + ->method('quoteIdentifier') + ->with('cpe.name') + ->willReturn('`cpe`.`name`'); + $this->selectBuilderMock->expects($this->once()) + ->method('getColumns') + ->willReturn([]); + $this->selectBuilderMock->expects($this->once()) + ->method('getGroup') + ->willReturn([]); + $this->selectBuilderMock->expects($this->once()) + ->method('setGroup') + ->with($expectedGroup); + $this->assertEquals( + $expectedColumns, + $this->columnsResolver->getColumns( + $this->selectBuilderMock, + $entityConfig + ) + ); + } + + /** + * @return array + */ + public function getColumnsDataProvider() + { + return [ + 'COUNT( DISTINCT `cpe`.`name`) AS name' => [ + 'expectedColumns' => [ + 'name' => new ColumnValueExpression('COUNT( DISTINCT `cpe`.`name`)') + ], + 'expectedGroup' => [ + 'name' => new ColumnValueExpression('COUNT( DISTINCT `cpe`.`name`)') + ], + 'entityConfig' => + [ + 'name' => 'catalog_product_entity', + 'alias' => 'cpe', + 'attribute' => [ + [ + 'name' => 'name', + 'function' => 'COUNT', + 'distinct' => true, + 'group' => true + ] + ], + ], + ], + 'AVG(`cpe`.`name`) AS avg_name' => [ + 'expectedColumns' => [ + 'avg_name' => new ColumnValueExpression('AVG(`cpe`.`name`)') + ], + 'expectedGroup' => [], + 'entityConfig' => + [ + 'name' => 'catalog_product_entity', + 'alias' => 'cpe', + 'attribute' => [ + [ + 'name' => 'name', + 'alias' => 'avg_name', + 'function' => 'AVG', + ] + ], + ], + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php new file mode 100644 index 0000000000000..2a97e109543cf --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php @@ -0,0 +1,108 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderMock = $this->getMockBuilder(SelectBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->conditionResolver = new ConditionResolver($this->resourceConnectionMock); + } + + public function testGetFilter() + { + $condition = ["type" => "variable", "_value" => "1", "attribute" => "id", "operator" => "neq"]; + $valueCondition = ["type" => "value", "_value" => "2", "attribute" => "first_name", "operator" => "eq"]; + $identifierCondition = [ + "type" => "identifier", + "_value" => "other_field", + "attribute" => "last_name", + "operator" => "eq"]; + $filter = [["glue" => "AND", "condition" => [$valueCondition]]]; + $filterConfig = [ + ["glue" => "OR", "condition" => [$condition], 'filter' => $filter], + ["glue" => "OR", "condition" => [$identifierCondition]], + ]; + $aliasName = 'n'; + $this->selectBuilderMock->expects($this->any()) + ->method('setParams') + ->with(array_merge([], [$condition['_value']])); + + $this->selectBuilderMock->expects($this->once()) + ->method('getParams') + ->willReturn([]); + + $this->selectBuilderMock->expects($this->any()) + ->method('getColumns') + ->willReturn(['price' => new Expression("(n.price = 400)")]); + + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->willReturn($this->connectionMock); + + $this->connectionMock->expects($this->any()) + ->method('quote') + ->willReturn("'John'"); + $this->connectionMock->expects($this->exactly(4)) + ->method('quoteIdentifier') + ->willReturnMap([ + ['n.id', false, '`n`.`id`'], + ['n.first_name', false, '`n`.`first_name`'], + ['n.last_name', false, '`n`.`last_name`'], + ['other_field', false, '`other_field`'], + ]); + + $result = "(`n`.`id` != 1 OR ((`n`.`first_name` = 'John'))) OR (`n`.`last_name` = `other_field`)"; + $this->assertEquals( + $result, + $this->conditionResolver->getFilter($this->selectBuilderMock, $filterConfig, $aliasName) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php new file mode 100644 index 0000000000000..ef051feda0722 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php @@ -0,0 +1,90 @@ +nameResolverMock = $this->getMockBuilder(NameResolver::class) + ->disableOriginalConstructor() + ->setMethods(['getName']) + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->nameResolver = $this->objectManagerHelper->getObject(NameResolver::class); + } + + public function testGetName() + { + $elementConfigMock = [ + 'name' => 'sales_order', + 'alias' => 'sales', + ]; + + $this->assertSame('sales_order', $this->nameResolver->getName($elementConfigMock)); + } + + /** + * @param array $elementConfig + * @param string|null $elementAlias + * + * @dataProvider getAliasDataProvider + */ + public function testGetAlias($elementConfig, $elementAlias) + { + $elementName = 'elementName'; + + $this->nameResolverMock + ->expects($this->once()) + ->method('getName') + ->with($elementConfig) + ->willReturn($elementName); + + $this->assertSame($elementAlias ?: $elementName, $this->nameResolverMock->getAlias($elementConfig)); + } + + /** + * @return array + */ + public function getAliasDataProvider() + { + return [ + 'ElementConfigWithAliases' => [ + ['alias' => 'sales', 'name' => 'sales_order'], + 'sales', + ], + 'ElementConfigWithoutAliases' => [ + ['name' => 'sales_order'], + null, + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php new file mode 100644 index 0000000000000..fad0a80856b70 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php @@ -0,0 +1,125 @@ +connectionFactoryMock = $this->getMockBuilder(ConnectionFactory::class) + ->disableOriginalConstructor()->getMock(); + $this->queryFactoryMock = $this->getMockBuilder(QueryFactory::class) + ->disableOriginalConstructor()->getMock(); + $this->queryMock = $this->getMockBuilder(Query::class)->disableOriginalConstructor() + ->getMock(); + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class)->getMockForAbstractClass(); + $this->selectMock = $this->getMockBuilder(Select::class)->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->reportValidator = $this->objectManagerHelper->getObject( + ReportValidator::class, + [ + 'connectionFactory' => $this->connectionFactoryMock, + 'queryFactory' => $this->queryFactoryMock + ] + ); + } + + /** + * @dataProvider errorDataProvider + * @param string $reportName + * @param array $result + * @param \PHPUnit_Framework_MockObject_Stub $queryReturnStub + */ + public function testValidate($reportName, $result, \PHPUnit_Framework_MockObject_Stub $queryReturnStub) + { + $connectionName = 'testConnection'; + $this->queryFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->queryMock); + $this->queryMock->expects($this->once())->method('getConnectionName')->willReturn($connectionName); + $this->connectionFactoryMock->expects($this->once())->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + $this->queryMock->expects($this->atLeastOnce())->method('getSelect')->willReturn($this->selectMock); + $this->selectMock->expects($this->once())->method('limit')->with(0); + $this->connectionMock->expects($this->once())->method('query')->with($this->selectMock)->will($queryReturnStub); + $this->assertEquals($result, $this->reportValidator->validate($reportName)); + } + + /** + * Provide variations of the error returning + * + * @return array + */ + public function errorDataProvider() + { + $reportName = 'test'; + $errorMessage = 'SQL Error 42'; + return [ + [ + $reportName, + 'expectedResult' => [], + 'queryReturnStub' => $this->returnValue(null) + ], + [ + $reportName, + 'expectedResult' => [$reportName, $errorMessage], + 'queryReturnStub' => $this->throwException(new \Zend_Db_Statement_Exception($errorMessage)) + ] + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php new file mode 100644 index 0000000000000..fb8f5b4a1ff0e --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php @@ -0,0 +1,103 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilder = new SelectBuilder($this->resourceConnectionMock); + } + + public function testCreate() + { + $connectionName = 'MySql'; + $from = ['customer c']; + $columns = ['id', 'name', 'price']; + $filter = 'filter'; + $joins = [ + ['link-type' => 'left', 'table' => 'customer', 'condition' => 'in'], + ['link-type' => 'inner', 'table' => 'price', 'condition' => 'eq'], + ['link-type' => 'right', 'table' => 'attribute', 'condition' => 'neq'], + ]; + $groups = ['id', 'name']; + $this->selectBuilder->setConnectionName($connectionName); + $this->selectBuilder->setFrom($from); + $this->selectBuilder->setColumns($columns); + $this->selectBuilder->setFilters([$filter]); + $this->selectBuilder->setJoins($joins); + $this->selectBuilder->setGroup($groups); + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->once()) + ->method('select') + ->willReturn($this->selectMock); + $this->selectMock->expects($this->once()) + ->method('from') + ->with($from, []); + $this->selectMock->expects($this->once()) + ->method('columns') + ->with($columns); + $this->selectMock->expects($this->once()) + ->method('where') + ->with($filter); + $this->selectMock->expects($this->once()) + ->method('joinLeft') + ->with($joins[0]['table'], $joins[0]['condition'], []); + $this->selectMock->expects($this->once()) + ->method('joinInner') + ->with($joins[1]['table'], $joins[1]['condition'], []); + $this->selectMock->expects($this->once()) + ->method('joinRight') + ->with($joins[2]['table'], $joins[2]['condition'], []); + $this->selectBuilder->create(); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php new file mode 100644 index 0000000000000..38abc3683f81f --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php @@ -0,0 +1,59 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->iteratorIteratorMock = $this->getMockBuilder(\IteratorIterator::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->iteratorFactory = new IteratorFactory( + $this->objectManagerMock + ); + } + + public function testCreate() + { + $arrayObject = new \ArrayIterator([1, 2, 3, 4, 5]); + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with(\IteratorIterator::class, ['iterator' => $arrayObject]) + ->willReturn($this->iteratorIteratorMock); + + $this->assertEquals($this->iteratorFactory->create($arrayObject), $this->iteratorIteratorMock); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php new file mode 100644 index 0000000000000..e358bf00fe37a --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php @@ -0,0 +1,239 @@ +queryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\Query::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->configMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\Config::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectMock = $this->getMockBuilder( + \Magento\Framework\DB\Select::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->assemblerMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\Assembler\AssemblerInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->queryCacheMock = $this->getMockBuilder( + \Magento\Framework\App\CacheInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder( + \Magento\Framework\ObjectManagerInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectHydratorMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\SelectHydrator::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectBuilderFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilderFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\QueryFactory::class, + [ + 'config' => $this->configMock, + 'selectBuilderFactory' => $this->selectBuilderFactoryMock, + 'assemblers' => [$this->assemblerMock], + 'queryCache' => $this->queryCacheMock, + 'objectManager' => $this->objectManagerMock, + 'selectHydrator' => $this->selectHydratorMock + ] + ); + } + + /** + * @return void + */ + public function testCreateCached() + { + $queryName = 'test_query'; + + $this->queryCacheMock->expects($this->any()) + ->method('load') + ->with($queryName) + ->willReturn('{"connectionName":"sales","config":{},"select_parts":{}}'); + + $this->selectHydratorMock->expects($this->any()) + ->method('recreate') + ->with([]) + ->willReturn($this->selectMock); + + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with( + \Magento\Analytics\ReportXml\Query::class, + [ + 'select' => $this->selectMock, + 'selectHydrator' => $this->selectHydratorMock, + 'connectionName' => 'sales', + 'config' => [] + ] + ) + ->willReturn($this->queryMock); + + $this->queryCacheMock->expects($this->never()) + ->method('save'); + + $this->assertEquals( + $this->queryMock, + $this->subject->create($queryName) + ); + } + + /** + * @return void + */ + public function testCreateNotCached() + { + $queryName = 'test_query'; + + $queryConfigMock = [ + 'name' => 'test_query', + 'connection' => 'sales' + ]; + + $selectBuilderMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\DB\SelectBuilder::class + ) + ->disableOriginalConstructor() + ->getMock(); + $selectBuilderMock->expects($this->once()) + ->method('setConnectionName') + ->with($queryConfigMock['connection']); + $selectBuilderMock->expects($this->any()) + ->method('create') + ->willReturn($this->selectMock); + $selectBuilderMock->expects($this->any()) + ->method('getConnectionName') + ->willReturn($queryConfigMock['connection']); + + $this->queryCacheMock->expects($this->any()) + ->method('load') + ->with($queryName) + ->willReturn(null); + + $this->configMock->expects($this->any()) + ->method('get') + ->with($queryName) + ->willReturn($queryConfigMock); + + $this->selectBuilderFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($selectBuilderMock); + + $this->assemblerMock->expects($this->once()) + ->method('assemble') + ->with($selectBuilderMock, $queryConfigMock) + ->willReturn($selectBuilderMock); + + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with( + \Magento\Analytics\ReportXml\Query::class, + [ + 'select' => $this->selectMock, + 'selectHydrator' => $this->selectHydratorMock, + 'connectionName' => $queryConfigMock['connection'], + 'config' => $queryConfigMock + ] + ) + ->willReturn($this->queryMock); + + $this->queryCacheMock->expects($this->once()) + ->method('save') + ->with(json_encode($this->queryMock), $queryName); + + $this->assertEquals( + $this->queryMock, + $this->subject->create($queryName) + ); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php new file mode 100644 index 0000000000000..e288c668a54f7 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php @@ -0,0 +1,90 @@ +selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectHydratorMock = $this->getMockBuilder(selectHydrator::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->query = $this->objectManagerHelper->getObject( + Query::class, + [ + 'select' => $this->selectMock, + 'connectionName' => $this->connectionName, + 'selectHydrator' => $this->selectHydratorMock, + 'config' => [] + ] + ); + } + + /** + * @return void + */ + public function testJsonSerialize() + { + $selectParts = ['part' => 1]; + + $this->selectHydratorMock + ->expects($this->once()) + ->method('extract') + ->with($this->selectMock) + ->willReturn($selectParts); + + $expectedResult = [ + 'connectionName' => $this->connectionName, + 'select_parts' => $selectParts, + 'config' => [] + ]; + + $this->assertSame($expectedResult, $this->query->jsonSerialize()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php new file mode 100644 index 0000000000000..124d5f32078c8 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php @@ -0,0 +1,180 @@ +selectMock = $this->getMockBuilder( + \Magento\Framework\DB\Select::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->queryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\Query::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->queryMock->expects($this->any()) + ->method('getSelect') + ->willReturn($this->selectMock); + + $this->iteratorMock = $this->getMockBuilder( + \IteratorIterator::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->statementMock = $this->getMockBuilder( + \Magento\Framework\DB\Statement\Pdo\Mysql::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->statementMock->expects($this->any()) + ->method('getIterator') + ->willReturn($this->iteratorMock); + + $this->connectionMock = $this->getMockBuilder( + \Magento\Framework\DB\Adapter\AdapterInterface::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->queryFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\QueryFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->iteratorFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\IteratorFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->iteratorMock = $this->getMockBuilder( + \IteratorIterator::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = + new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->connectionFactoryMock = $this->getMockBuilder( + \Magento\Analytics\ReportXml\ConnectionFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->subject = $this->objectManagerHelper->getObject( + \Magento\Analytics\ReportXml\ReportProvider::class, + [ + 'queryFactory' => $this->queryFactoryMock, + 'connectionFactory' => $this->connectionFactoryMock, + 'iteratorFactory' => $this->iteratorFactoryMock + ] + ); + } + + /** + * @return void + */ + public function testGetReport() + { + $reportName = 'test_report'; + $connectionName = 'sales'; + + $this->queryFactoryMock->expects($this->once()) + ->method('create') + ->with($reportName) + ->willReturn($this->queryMock); + + $this->connectionFactoryMock->expects($this->once()) + ->method('getConnection') + ->with($connectionName) + ->willReturn($this->connectionMock); + + $this->queryMock->expects($this->once()) + ->method('getConnectionName') + ->willReturn($connectionName); + + $this->queryMock->expects($this->once()) + ->method('getConfig') + ->willReturn( + [ + 'connection' => $connectionName + ] + ); + + $this->connectionMock->expects($this->once()) + ->method('query') + ->with($this->selectMock) + ->willReturn($this->statementMock); + + $this->iteratorFactoryMock->expects($this->once()) + ->method('create') + ->with($this->statementMock, null) + ->willReturn($this->iteratorMock); + $this->assertEquals($this->iteratorMock, $this->subject->getReport($reportName)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php new file mode 100644 index 0000000000000..dce8089a787dc --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php @@ -0,0 +1,257 @@ +resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->selectMock = $this->getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->selectHydrator = $this->objectManagerHelper->getObject( + SelectHydrator::class, + [ + 'resourceConnection' => $this->resourceConnectionMock, + 'objectManager' => $this->objectManagerMock, + ] + ); + } + + public function testExtract() + { + $selectParts = + [ + Select::DISTINCT, + Select::COLUMNS, + Select::UNION, + Select::FROM, + Select::WHERE, + Select::GROUP, + Select::HAVING, + Select::ORDER, + Select::LIMIT_COUNT, + Select::LIMIT_OFFSET, + Select::FOR_UPDATE + ]; + + $result = []; + foreach ($selectParts as $part) { + $result[$part] = "Part"; + } + $this->selectMock->expects($this->any()) + ->method('getPart') + ->willReturn("Part"); + $this->assertEquals($this->selectHydrator->extract($this->selectMock), $result); + } + + /** + * @dataProvider recreateWithoutExpressionDataProvider + * @param array $selectParts + * @param array $parts + * @param array $partValues + */ + public function testRecreateWithoutExpression($selectParts, $parts, $partValues) + { + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->once()) + ->method('select') + ->willReturn($this->selectMock); + foreach ($parts as $key => $part) { + $this->selectMock->expects($this->at($key)) + ->method('setPart') + ->with($part, $partValues[$key]); + } + + $this->assertSame($this->selectMock, $this->selectHydrator->recreate($selectParts)); + } + + /** + * @return array + */ + public function recreateWithoutExpressionDataProvider() + { + return [ + 'Select without expressions' => [ + [ + Select::COLUMNS => [ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + 'field_name_2', + 'alias_2', + ], + ] + ], + [Select::COLUMNS], + [[ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + 'field_name_2', + 'alias_2', + ], + ]], + ], + ]; + } + + /** + * @dataProvider recreateWithExpressionDataProvider + * @param array $selectParts + * @param array $expectedParts + * @param \PHPUnit_Framework_MockObject_MockObject[] $expressionMocks + */ + public function testRecreateWithExpression( + array $selectParts, + array $expectedParts, + array $expressionMocks + ) { + $this->objectManagerMock + ->expects($this->exactly(count($expressionMocks))) + ->method('create') + ->with($this->isType('string'), $this->isType('array')) + ->willReturnOnConsecutiveCalls(...$expressionMocks); + $this->resourceConnectionMock + ->expects($this->once()) + ->method('getConnection') + ->with() + ->willReturn($this->connectionMock); + $this->connectionMock + ->expects($this->once()) + ->method('select') + ->with() + ->willReturn($this->selectMock); + foreach (array_keys($selectParts) as $key => $partName) { + $this->selectMock + ->expects($this->at($key)) + ->method('setPart') + ->with($partName, $expectedParts[$partName]); + } + + $this->assertSame($this->selectMock, $this->selectHydrator->recreate($selectParts)); + } + + /** + * @return array + */ + public function recreateWithExpressionDataProvider() + { + $expressionMock = $this->getMockBuilder(JsonSerializableExpression::class) + ->disableOriginalConstructor() + ->getMock(); + + return [ + 'Select without expressions' => [ + 'Parts' => [ + Select::COLUMNS => [ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + [ + 'class' => 'Some_class', + 'arguments' => [ + 'expression' => ['some(expression)'] + ] + ], + 'alias_2', + ], + ] + ], + 'expectedParts' => [ + Select::COLUMNS => [ + [ + 'table_name', + 'field_name', + 'alias', + ], + [ + 'table_name', + $expressionMock, + 'alias_2', + ], + ] + ], + 'expectedExpressions' => [ + $expressionMock + ] + ], + ]; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php new file mode 100644 index 0000000000000..94f6ed1845c40 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php @@ -0,0 +1,228 @@ + 'value']; + + /** + * @return void + */ + protected function setUp() + { + $this->searchResultMock = $this->getMockBuilder(SearchResultInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->searchCriteriaMock = $this->getMockBuilder(SearchCriteriaInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->dataCollectionMock = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->filterMock = $this->getMockBuilder(Filter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->dummyDataProvider = $this->objectManagerHelper->getObject( + DummyDataProvider::class, + [ + 'name' => $this->providerName, + 'searchResult' => $this->searchResultMock, + 'searchCriteria' => $this->searchCriteriaMock, + 'collection' => $this->dataCollectionMock, + 'data' => ['config' => $this->configData], + ] + ); + } + + /** + * @return void + */ + public function testGetName() + { + $this->assertSame($this->providerName, $this->dummyDataProvider->getName()); + } + + /** + * @return void + */ + public function testGetConfigData() + { + $this->assertSame($this->configData, $this->dummyDataProvider->getConfigData()); + $dataProvider = $this->objectManagerHelper + ->getObject( + DummyDataProvider::class, + [] + ); + $this->assertSame([], $dataProvider->getConfigData()); + } + + /** + * @return void + */ + public function testSetConfigData() + { + $configValue = ['key' => 'value']; + + $this->assertTrue($this->dummyDataProvider->setConfigData($configValue)); + $this->assertSame($configValue, $this->dummyDataProvider->getConfigData()); + } + + /** + * @return void + */ + public function testGetMeta() + { + $this->assertSame([], $this->dummyDataProvider->getMeta()); + } + + /** + * @return void + */ + public function testGetFieldMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldMetaInfo('', '')); + } + + /** + * @return void + */ + public function testGetFieldSetMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldSetMetaInfo('')); + } + + /** + * @return void + */ + public function testGetFieldsMetaInfo() + { + $this->assertSame([], $this->dummyDataProvider->getFieldsMetaInfo('')); + } + + /** + * @return void + */ + public function testGetPrimaryFieldName() + { + $this->assertSame('', $this->dummyDataProvider->getPrimaryFieldName()); + } + + /** + * @return void + */ + public function testGetRequestFieldName() + { + $this->assertSame('', $this->dummyDataProvider->getRequestFieldName()); + } + + /** + * @return void + */ + public function testGetData() + { + $this->dataCollectionMock + ->expects($this->once()) + ->method('toArray') + ->willReturn([]); + $this->assertSame([], $this->dummyDataProvider->getData()); + } + + /** + * @return void + */ + public function testAddFilter() + { + $this->assertNull($this->dummyDataProvider->addFilter($this->filterMock)); + } + + /** + * @return void + */ + public function testAddOrder() + { + $this->assertNull($this->dummyDataProvider->addOrder('', '')); + } + + /** + * @return void + */ + public function testSetLimit() + { + $this->assertNull($this->dummyDataProvider->setLimit(1, 1)); + } + + /** + * @return void + */ + public function testGetSearchCriteria() + { + $this->assertSame($this->searchCriteriaMock, $this->dummyDataProvider->getSearchCriteria()); + } + + /** + * @return void + */ + public function testGetSearchResult() + { + $this->assertSame($this->searchResultMock, $this->dummyDataProvider->getSearchResult()); + } +} diff --git a/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php new file mode 100644 index 0000000000000..eada5011a933f --- /dev/null +++ b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php @@ -0,0 +1,259 @@ +name = $name; + $this->searchResult = $searchResult; + $this->searchCriteria = $searchCriteria; + $this->collection = $collection; + $this->data = $data; + } + + /** + * Get Data Provider name + * + * @return string + * @since 2.2.0 + */ + public function getName() + { + return $this->name; + } + + /** + * Get config data + * + * @return mixed + * @since 2.2.0 + */ + public function getConfigData() + { + return isset($this->data['config']) ? $this->data['config'] : []; + } + + /** + * Set config data + * + * @param mixed $config + * + * @return bool + * @since 2.2.0 + */ + public function setConfigData($config) + { + $this->data['config'] = $config; + + return true; + } + + /** + * @return array + * @since 2.2.0 + */ + public function getMeta() + { + return []; + } + + /** + * @param string $fieldSetName + * @param string $fieldName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function getFieldMetaInfo($fieldSetName, $fieldName) + { + return []; + } + + /** + * Get field set meta info + * + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function getFieldSetMetaInfo($fieldSetName) + { + return []; + } + + /** + * @param string $fieldSetName + * + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function getFieldsMetaInfo($fieldSetName) + { + return []; + } + + /** + * Get primary field name + * + * @return string + * @since 2.2.0 + */ + public function getPrimaryFieldName() + { + return ''; + } + + /** + * Get field name in request + * + * @return string + * @since 2.2.0 + */ + public function getRequestFieldName() + { + return ''; + } + + /** + * Get data + * + * @return mixed + * @since 2.2.0 + */ + public function getData() + { + return $this->collection->toArray(); + } + + /** + * Add field filter to collection + * + * @param \Magento\Framework\Api\Filter $filter + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function addFilter(\Magento\Framework\Api\Filter $filter) + { + } + + /** + * Add ORDER BY to the end or to the beginning + * + * @param string $field + * @param string $direction + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function addOrder($field, $direction) + { + } + + /** + * Set Query limit + * + * @param int $offset + * @param int $size + * + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 2.2.0 + */ + public function setLimit($offset, $size) + { + } + + /** + * Returns search criteria + * + * @return SearchCriteriaInterface + * @since 2.2.0 + */ + public function getSearchCriteria() + { + return $this->searchCriteria; + } + + /** + * @return SearchResultInterface + * @since 2.2.0 + */ + public function getSearchResult() + { + return $this->searchResult; + } +} diff --git a/app/code/Magento/Analytics/composer.json b/app/code/Magento/Analytics/composer.json new file mode 100644 index 0000000000000..edc3443e487b6 --- /dev/null +++ b/app/code/Magento/Analytics/composer.json @@ -0,0 +1,26 @@ +{ + "name": "magento/module-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/module-backend": "100.2.*", + "magento/module-config": "100.2.*", + "magento/module-integration": "100.2.*", + "magento/module-store": "100.2.*", + "magento/framework": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\Analytics\\": "" + } + } +} diff --git a/app/code/Magento/Analytics/docs/images/M2_MA_signup.png b/app/code/Magento/Analytics/docs/images/M2_MA_signup.png new file mode 100644 index 0000000000000000000000000000000000000000..78ed8fad92881ddc1eae7f474f3d4dd88daf2cc7 GIT binary patch literal 11422 zcmbt)1yoh-*6vail@z2~P!W(8kX9)b1O%i*8fhd20h4YOq@^3AJCtte*mO#F*PZ+O z&bZ@0=iD>yfB!oi4rK4`UhjI>ob##ITV7TQ7mET5K@i->kHi%auc)V8 z=71lVdeTzj$Qk<2_sW#d2ttQE7Js1R6tyz?T1m+`0&_j30PEh{rgZaLCE{}Tr-nDg z>uv@-)0DqEGWPfaCg zynUNO04r}ze!YV>JUv^Q__@S0`5ITZ`QG5Nz4GzBF%8KSS5u#VX#iSuf!^8;mQu^>tN<95%4Fi4OiwS~YQ;v17M?C-fF}eE1#l;_P zC(dOKN}0|WZMK3=(J zzo?XNq5XQ6*c?^V?lgW^e%NeykUN=WF}}mw*ok?knK4!sR}dMjausw~8?&fjr*EKq zW?WaJm_{w=K<4hY)2Cvy)X&=6+dI+nmBq{3n=>0#@j4$noxzk6N9b#r^G^E4Jif?2 zLO?)Z?daGz@$*BjVJpdWSzDXTbZ5J;in6ArpM)>TbqRvl-n^MuTJpV!P4Yc8HMLJ) zp7BQFlj{9?_6u*3pus`agT;)T#N_0LMP85Hg<$~m%oZkq{O;C zG%-n4bLkOzA}u{RJ&iFjU))?$S{h!s)}Ix*G2hT2nLm%e<1B0^5S?owCiY?I-o=X- zFXP}`KwvBIuV258yp0idp)g~#e=!mK%+*!+^mMOU|KxDz-m96*$V6@L5N7@~?N z6fJwHQX79_o{x+2S4ws^-sOLV?0swt|7KFM%e85V1Hv; zHf^g*ik9cJ!g}%{m4Myl`uh6R%uI1-X8~>3o#)esO-+w{UB6+@mfFtyiAqUH2_{J{ zife9vx9UG8-^oJd z8TxA3pAU)_bW~r?uo|y=wa|UDxw$#`&mWWN&8LyP{6{|&E;ZID=DME@xEE5;EKvPi&f6vj`_q9*ad8j2ib{Vl-?{T8Ovg>_ zjjL;tac4{(>;MxJ6KB!R=4RfIXO=zu!eudh_sW$k1n>m{(X!5atE@IQHhJ!6ZW4n$ zD=h5naxt&x$Tv1OLuzX7zn=EzODrfT;PLbqV5)i|Z2@g{Uf6jXLAKY%Y5ASNvMRag*;Budk(gy-RchCs5t6D_+6}pVA~9 z)^^Wvm5S!|Ot3?ykFk>hIYyv5+{C#^UWV1g4 ze0{|pJ@OiIuG9|f%TUo@pZK}HzJA}@nnT-p;pWWTT#@}jZ$K2M3JxQ zc6N3pW#yvhL%RfvMCwQK=QzfaWur}VpK5AG#cL`0lCUad@{PQI|9+-FOM^B2)3CBx zKrZ*3&(CbFa-tQ0krivLMQT(&A!WYpe7_F)>!z zDgDNPE6D53X2#jg*;WM&4HoFGJfn7sb9A=z9Tvr|*HKXfP5~Xnii*iH1V~6w5FK)Z zjjdy{OlHZ}38fq;yYfrz-QJWhI~KxkGxbsLWMjJV;@h@JzRsx|0sj8P$g90ot@_RQ zc=~g6P~hmbhH{_p>?+j@ij8Gg&r){Y{&W4)r%&ApQutk_g(0!AYt|MXhg9|R>qc@qiob$FFGM1&D@dJR%}FGQE_@%p}C$ang#O`9@SgzoW{0r z?#Z>a!2NxvKReDhZr&_>`qSaXM4DgLV{=ujoJc;a^9YU0GAE;w6!l}X`4*U|2(mTT zu6S&wx=NTOP@L${Gwg|VD~u*CE-t>$G$}JvMqC_bwnRqX6M6X{H4P27lO-K&sDZ*jgLG{N@0C_8$QX9o@ zOSFWd#E|6y=wuQEYi#M1;omXjcNdtJ*u$_my2X*?EiAky4*ow(3m#{gI&I z=Vr9b-!z>K3=OX!-hO^W1i>&V&(Vd4hZ|Y2Hn+Eb1q6E{F8*;SqiDDPp+yEyV@aXy z?5|JQB;z?l+YT_j9LD)#CewZ=1d8~4|4s*AGzmr0)Y9@kCx<;gA;H4ZWp#wVuA$*! zO3!sx*7oJ+8jI>w;Vio`m8Da8q3==@JfuUQ$-mA+?YRq{@mY1 zSpj3|>Nixl^gE=qdvMU}=tE!?I8X8*P+WH`wz*+umpf{vcuO!O# zWM?32x72Av4_R?n%Q!e=JeT&N$K+xuj0*3Ri*m)+anPk-+o*=V_=l(sg_$mnP!bwYA7CREu~0yNn% z)ks;T#K^Jz^W=Kh*WILq#g@hro}&h7_5W9<`cDJucUc*dM=NR@p#FZVo=TL)hp23` z5$hT1kBqHHSi%2@3IEgg|5147xHcwSKK$}-gpt**If_IN!;{q0i=QIQ$;`y*6xzZ8@Z@yaHUAP8Mmg~EE`|A61vv&L&fCaH%8<{W zSH>(y%k0T`&B>67<)M5sVduLQm6Ze(6h6QNC{W?2W*ItWK0ZDi`VBby`}=gzbub}G zP+97QSS%{p<~yfrCijDK0a9d zZ}xw{C@3$MmXY~#eEf!h;PrNw)GS;;K}(AjRb=rQs!&2hvH#G*l9C{pZ~ToSulXR| z?Cflw1&SAq`EA2iBPGwqoR?V38}p0K7$p6IfK~Hqd|q&kmSyzz_KqJ|nuRXmdQpRT z223Ap%^TKv5jare)0+wOM7^|0($&>f(A2y`PtVWK?-T91Kk12Hs<`;()>e{Ewc8oh z<)EXzHI`Muyy&#DG64zEr}!0xZjmTS@f-B?4`KVn#S>wW{;I7dUMaR3XXE7LgoZcS zbL!t69~e-9@fw-cynUMZ__INSA9+Yb1oPLgU-1HUV21!SNCG`0EJZ{_x^r|y!}+XY zKuA4J&&X&GxS}?YgdvyG&8do)@pzC*B=5 zx*vNAoox4X7hCCMyfe-kpDW@tHy)I#)Xup_i9rVpipzT9eyQtG(de`q$~{Zj42N06 zVry&55JvaZ+}tf~ZS9cYVBNj_03iCJcLb||Yx(Iac? zA7ay_L`07Oq}m-!ZKvw4T*1dT{!@70ID(titxK;zQ*AKM5WA(N<%ek>bA8!DPYMGI z3pVim{h7~l955iu56zn$RI)XHj+EMR8nuySs^v@O%BJ)%jrq=-2rH(@)&sqeS5xyA z^TZ3U6oq$mPmd2uoOhVHxVbfip&l;e<>wQhFfuYGq^D!K@7K~2StP{A2YvZ+0p!Hn zw+ImliNIYqSy?=Kdiv#bxu<{&8w1s+#6V~sN=SUlXuWQ1_VS^K)B61ee@aG}jd_l1 z+VzIdbams}qWBe|GY$9GCtvL>KA$d277HJ|P$)OkBqCgN^d-_coz;9Apgp_%_4F1zXe z!9jEK(?}u%g}W&_z@p+QmhLcJyn-AQ?%P*uXZnCz1Id(!!6 zM4i@=;NW0TdsY^!>BDfr_0{sVDVQfKymQlmq5=4#$5#_1{T1%4$ym`_NE>%V{S;iQ z_|TIgS6=o7FNeE5oJ6O4cXgCf$Nhu{N;?-A7~pD=gjPD?wQC=svVGkTev@!AASN`;zQTqF;8{ zrBx^0e3cBWJs~dcXP;rvHO~JbMK4r!b}q}1rh9c6bioZ_VQP?&*7oEp@gNZZ5gqNx zXT(7VXn>}JM=-a@HT=}Zh7(k@rWPhY0Y>1m-sST2bY_*XZZ@E>^4i(~P)z9iuB%~) z>?LtPtWS?$i%Ut>wzs$UC85{Z#LVMCjVz;z@qygg!uK1fga1Pvre4d&&3z4YQ;FR| zNQU%v#%XdIwZ#4(f;LkZ;L;w@N;N1Hs&6*vGbo(4RHkKU80)iBS2UXkNeZq*9dyAu zv`ksqT~mzXelCUICU>*h; zP@^rJoO~H;dc`+*fo*=YqBO7+(B5|TOyaWjH4MIF&b`E(>#1ru!i%P4P6otcfn|i4 zG(&a26SCjGlXB4g^Gu~?Z!-9O)}9i%2!3FX2aZ6`(Ylj|6f2k8u~TAFQfV0uz2`bk zAdx`NS${7lRA?>te{{Q^c~1FtPMc*1hHghkMEEc%Cf^QCN=&?;&_#FiX1(6H2N2EC z-}%OJ6~~*cPB3)Dri(wujsFAKpEmqq1~)|EkBk+kiLC9>?+{l?xcMT>QJ*+5Pl~Ym z#>NDd9PQh;Z`Y9OywNRO%gf_h2DBW1vxSRCb?^7ohQ_boRz^m*&^jLW_ns?`OT!ut z+)QsBOs7fMyvyaZ?#BeAY??LTB7MXrWus$f?=+? z;_tE4ci_blGIjhnAf6WJX|4M8>!Hjyj&ndiAIZolWdfBOta#0hi9?3)@$ubYWGqg_ z^q2f#fhzjh*mwzqhlHD3mCY#V)Qu6_PNre2(K6yr(KFy3LLBa=Z_G!_`sT=-E5|0; z&zm|QpzOv6vNSw(Ydyj(_<+7c@pZ;=!X%;|&Q>I#zqZ186U?0(w{H1p=Y&D0wY)ut zaVMY}*yT`(O~RKiUz*t652Wh_kUZ$(wA9of=y6}!l>Acsr^W7I6~KcL2f4?XQ?cn| zGwMaaFat!Q;RtjkaA1ak938;GrGXsjSP@t8oB=*TBQ>>f^au~Vqo$Y7rctP#F3idK z3?RF`KU&mXThfnAckkZQ#z)f9wkG8r@moqyR^o+kt^G3yw+GO|UHF*DD7uZLS4?2w(Eora^H!4NkPem<~s@>w}H7S=D2ug}1#0IxElN*J})EdJ#wN$qi3nl5`w;dO;Qd0`t=h5gXHZ{Vj?00dGh4RRVpfT%~fzp z;r5Xl;EqAz;ocDu6iuCsm#-2isi;iD!zyvv%O17oZ`sab#cZ#vhX;BA=uH+y4xlA0 zbSb2B0eXK_LPFv?6Vny-ED{iux4~B%wESoAEW#%=+(4Z+dxMHZV5E*gvTE0iqe zCBYOtUH23ntkn7&oz;ci!f=I2V|5iS_0T9zZ7=k288lr5g&yCtFta{cOVa2LT0kyAD^9`%;tBBaGO;-tf+77?uLeQ8#Bk`yUa&B z8mtT#0_nWT%=`rA>z!4p$B(_mB_*LV9RGy$5A%AE>OoByz@|9pbmVB2D~Gb{SmuY$ zEt)y!&u(bArr{4K4uGg& zVYQzh&fU9rU-YIvlU*rh(Hh&7Ykd@#bvpLBH-$mcx4-YAd}9v*BXgm!+1b!*XJ>kt znXBy9i>YTen_wqpa(x^Hy{V=3Bm;0WRZWX&8G+1!Cn4h#bq%Bq*kyWy=OBqNjnDA- z>xFAt{L4rceqh8O8QOuT9Z6j#K>!#$%gfQU)b=z0M_x#c(V+cBp<0Gd0f(a8_Bik_ z`o$annpOO*&}41V!VFb5HT}T@pEf|)Wmi?R*k#WWhgM|7{PmM3Sa&IKL4pjI31tW@ zHnQ6DzR|#9Dwtcj@ZiCN2CMUCtu|D!0*+TRkHFvmH83zxQc+Su2D+sdgn65(Phg-_ zj&`NIy!>1Cs{MGar4=v0g7`Dzg{2FE5n#V8k5y{qn(wWSe&e@IRzv;!9M7q2N#y-i z!;r$E`6^u7nV6VZ7s&tm#>NB49ejL!SuM+fsAg)Gb~{!7o0MZ|82XpV-SP3`h5Q`l zkurN0LPEl}VbFE|by!F0G=GbV!htytS_+3+fQV5probf@1}b`DPXr%8V8FQM(%`c+lv;0y#<}95%3Lf)c#+r@}yGD^Yn(i|dY2+DrD=8_FRk!@s_Tcoy zqh=m=-HZ0}iV}8Fre|PiUmRH4=}wWOEpgvRs zJ3GVB*8{F7A&zdE27P^XRJ?@m4JM|?K$y@!&{oL6z5d1gu*%@BX9-FA$`Wk)X7R~M zNj#|J1@w$yVrC{J2nLJ>-Jnu1TIE^}S=S?d{RF*oPg*zC#ib<)@f)I|I)^(;DTAv3 ziVg#2X;t9ww3_8q-lC_^soagII6FNua;4^fB@P`$jB0FXXbEPJidb>)PJGM-68iDe zr(auIo_OvqEag;(s^uGbdo{siWd#;wRQSomBVxy@6TL`MjKDG?vuix8tWSl6g;(%| zAfB2g57y36iSj=e1W%g$p7r;UDp!=b;I}vI>5-8d`TF+=oxsCE8;R)spb>U%Iy+rE zi`d}-hun9(O8^Z4N1gCiu70CWWMm{HLXRaSJw}fVE}twengW1@!oUV47z|W1e;BZO z$enQ451zUUOl9epmhllD(UtE=A;c1@MGL>NN*9*l{=UBEj%dNzPo&!N=A?j?_V)G; z{*#X;ypNAR^`TRO>tY_?vO2+U`|*P#EiLVtxemy7P}HyHJE$|J0UAK=YuvbZZ?Giu z=Fwe<3txlnG@F(ZlQ)X($iZ^1*2tC zoY=>D(-d>f2H3zgo&saw8<(Mv+7amZ>BYVbpsaVmtFVyJ4}<0qBb^E_A0M=LU!cx<{``4)RaFzsfe_aS0efbV z(|!HA`g%1@T3Xt`f`Yr~XtL%VhF3s9kr|cQPMSx?wJ?FuWX1S}aO%vc$(uKBc%`JI zY`8sm@D5VG=M@zd2Aea@3i9$VY@%QxExIglEbT^Bc1%? zB}&k7)k`uV7_3|7{-qsfZy%o!C{kZnU`&q;3=-=}*})h3SH&hWI|H#;sl!S{Juk4A zO>k>{i;IhKD0yYrv@1;h(Fu*^36j|3PBK`@R%C?^MvX5MWZz74+CSdaZXmS3^_OD6 zuMNmtXmcNEl~z~y)Al)hI3}s&Pik0BC~)jH;M+q&wM%!dMKuw{)-rHUHwH?1Q|l_L1Qlggp>q`JOw6=T0IbXh&y;Ww^K79$kRge{dHHT#1~7#&leUJzH#WD z9}j&f8NJ}@BvhL~LN4ki)ZN_;GALLKcrjM=g1gxw8CVOG>lPxdm z>zk8S4CtVBbGpyi{rq8k#u=9bk(OcA-M)x}+W#LbQPDdn=qfyOT?jP5pZhU*3nV6s za^`&qz#l$**oJ;Enc9^UKx;jKT)hAAVWV4`{W>3CaaL=J!;D|4p8T_C=K{Qj;Mf3; z6#6UxL>wk}DWC`Ape(amiUQ?ReuMG;c7qo>z}I4GYKmwjLcPEwSg&%Dgox+{2ocj~ zti46*wtmr&l{l;nCz+t(%yWq=t8>yqLs*~?+xX&`7{2fg2sRZ|R8mxRR8$zjwjrdT zFts716?Bk6nm)^kFhMLC3W}PEjV+YNtp73+F6d}kzJfh8=T`&n`?m<_9RxjM&e1`V zhBsiS9$Skla<(%i?ZB!49rFxn^1jAMv=m4y%7z$>RlFu)v;nG%1eH6kF^7^86JJ3# zwzkaBYyCSq`2e0B5GV9tVuCym29uX^##eaJ(~P@!{)B->WI4H?(Pn@6T}G&OiXDOSVb5Z za)#zl^=h46Mk`)lL)HiN1Nq|w79Xh#s_ZTgVIbeYJ)6?0eHCWXS9-HBvR_1rqjdW+ zE-o?9WkW+ldU^$Qb!G@FN3Vkfy3Xk463Pj6bN~Q4s?7Oum7lW!SII7yfk^4mBy8Z0J#f#U$7K0*@R8}Sd z@0fs^+QJqE7rf5PO9JWl%a<>Wa)uQKrkXT!_me{hG^>TIt4G19fx~}3p#vWiTUtEd|0cf8G z;Eh76aqsnJqMnACD<3bf-fYX)%a<>sb6`X%Y$$I6J9}(6xrza z@Lf>f*c0>Yf;55-nLWezxOkD};X-UEffCz!JgDvW?=UXu!MP%zDx=OAf6!=qCGKY; zF|NC6#{=#sVK!P1AD#z02tDGCcZ;j*S#m1$G>tRX(55L34GoB9Hh{n%F!4#KbzDrx zp-}>8gs~t_$GC(?cm4X$63f2y=ilzx&_mF$KIXEf`}6%phrQ@;-@E{{Mqm&Eu=?nC zE5UVc$;J4AN0RXUI|6?CdAFSm9r6JZ??;2V-42jH@X zDzQiq*keHJU$jT?sQ!3y4*gM7u@!8XS)i_Bf51?g{nEtzyeCwI5SYOL9O%;$)alL4 zad=GNx}bFd0fE|&7w=#wh{d?9^22W>)^TVH>7@k~xrVp_s7#P!@q-R8C1zisb3p1`b+ZoXDU9c; zI+*mNjp}a*&Xo{{iFxtu)ZFBx?((I#U%q}NUju3YBb;;WY_pa9;#+WOTV2*F837qe zI+VxZ0RvVWSLmp!4#wByr|b?74;vNlt*^`Xnzbm8gCXQI?Cax`+3&X4%XF~ke&+ak zwRAoaLMNXc07gg~^(%DL)lK_Vz|v9k?>{sz!$n@2n-{3Y7B>EXQf?a^)#5aQH;1Nm zt)BLyyB#Jl09X*M+x`QzvZAL)lkweUwJW%|_NLJ6Bm@iKj{`C1E5}C?^YTD{78NN& z_&{vIrc-rC$93l`D5EBnRkelVIE-VT`{}8vKPV_*w)zFdHg9x zr}_$5UtiB*U^dOQN6x|lg;z(r7WId4^k5jLBH4Ur$c|EDFY@n=hx2ws@08&j1|Xkp zN%9=5_Xl{Ptq{xmhkfo8Im&E{5!L{K8#M;o?TJfy3#L^2?z#I_N2`Lj|Rt*03+>j_iR>$2Pat^#a3jzfg{6MQiF=g&W(+qKU!T`G`fe=gDrPL6y4 z;C}%Dmd_3}{VkE>bum!o6JQ9a7MX{)4_oXE5%$y6CTCLT!|6#~0EX1`boAjl2;;n= z1Nb#n@|S%iUU@?>#?%pl-v4~Yp6EVF@q_9_VH7<7CM&lsN~pA}R#sNwocbQe)3j&u z+k5k(XKJ9RAfr;e^)w>UDgNN!+%<(#*uDDXEI8)+-il>e1Q{;i}3x!L!a2# z*c&%)-0slSQ25MqypAk#0fkr`FK_`z*pGq-3xZt-dnRf^_LtrQxuA6+{<;K%2l&EI zG`@XRg7v<%G z2t53+G7`J*Sw*J=g{2*1}%w1_Jb@(6^GG73@i=|A_99}l05Ok&fs zCZs&#)E-QstLQZ};wDcjFQ>P-Jfh~LygAGNi_2}^q=5m`sewu(CnqQTQop;H=a)-9 zYqO0L6BGFSMiPnCv9>(d)z`NygY6i?AQ54ro*$OGh`#BQlXfQ6z9vyFOVcKwK7O>S z58X#x@Q{&_q2IX^gCvH)c3hgS>v;1fr)&U!W@);AS1%=*vZhSO$fB4;WTY*a#U4Sd2j;y1v)A!fByda@15PEQfGvYHF%#YF&Tb6J3}~rg-;$P(UFLSWeVwYip-QM@M5KDMU28q>IY-?c1Z$ z3JQddnpGK>ISz8pho(GysA)>ncb^%E;qh5t9*vXrsfde@7sJn6nN+yoqDs7%uUcHX zlvP%yZ(?E+`sbe-wzj#=$yj1touZ8QSB}Zt?SeqG2C^6Sc%2!{XSpc z2h&8ZHcQQn2@{rYWSqVCVNyUqpu>@{YBV|=5P*aUvL8HS=bFR^$MVYt+R3X++ZG2OJ1aYnHtQ-VT>mgUoJeM1V4!(FHaV$d zVv?wO=FC1Oru!8Y6>^v(0s?G%{R<04d}ixe;*MPmDkkRTolQ?qZ*C-GdQ0u&LqkJp zWhveHM$H2LEDB=AkcGo%lRRRD%?h^f+CMf(Suf)mhnNft&9BLR9oqJ&wA5zp>uiPB zQUTt}OV`+VGQhkgNruMp2+Q8RR)CxdKw*|56mv|g7I;yYm=+PsXO3T@K zP9QKPI~&J*`0N!^Cw3XUPFq{s#P~R%RY?c{K0WOa6BA=S(V0yJ_&yGf{6X@xd-KdY z?8+GTX(c6oK!}w4w2S=bu{Q2cqoV>sLg%clt@#B7JBJ%158=+l3bwssODaL@9k1Vbkcr8A3W*Ma$Lo5ukGqGjq(nd)cswxIGwz$W%B5R9#HdJ07Ar$)SbUFbe)lQQS8KtoTpFU^{uZjRY#5u z2h<2{{+nM|m~pWK#qTS22@1>sB^2tKJ&MM>x5tc-Pgom1SnJCww=WFs;_m)>c=m|6 z_)_>m+o60u)5}9sIb`4J3l}a7e6?kygW6PX9x&AV@ZzhcCS4DYazjJIfw70ChmhMG zPq+2;WwVJpJZmJ`rSnef^tqr_?zQfaI&!ui0FlOt6?SO%7I@LAg;q zdsgS%xrpg^kGZYKjLaA}3TFqV{OYIBhOl2#OG{5A%6RErY>eo-PRGb2!&p1kmYS%) zGnnz9o}ON;kXcn8!0BY!gRFuAy~~#~(rVDgHWk9THkQ#Z~+5_#y*p;s*}?y?b)k@}}k z2d0hkS`m9l>~pK+(D3k>`8A;wU0vNbCDyl#ii@G>@Gz`*X~1I6C7iq;8@s>0t}cs6 zbbNu<(b2K$%Fz|}NmA%v!Iv}9)`;ja+>@DgadA0v{J0Ji6Vn%bCH&Cu+NFKzQd-56 zCv^Sn1(e~AOm#RntDXWAN!N+!h=bVagf+ULl+seY8!W=zK@4m<1_pfApS_S|Ojcf= z4s2r0oUOgRtE_KdJ~5aLgZPCTd0AbWZZ~@?#MJfnEosu$(NW*ZD$B;kCg>MAPtV7( zLMHs<%k(K?w%sR*dv^q-m$D*I*lHC5hen#>U%hzInrBda+-uP;CN`EILR3$Z_8iZ-zd-7- z?JKgNSv7rXvT(z3zrL<6-?3ww02#v)t6R*06jwM0ML37@2=k978r^Me_W@X9;^K6x z*-!UVVR~z?|H=wJFfefYTHC#YtecN+`JoXa5$N7PG$P1}g9cN`0I^@}LVvsAMh4WJ zfQ$)4qiNrwVe<>Pxsat)_Tomm{r%$ihq3Z0lpQd^^Ydbg-)>NwBW?{u`j%+_n#-Gi znIGt3+MGv^f$7_X@|z=mA81&TR^FVAy7+Zw#(0zXosd{O^5&$=wBIz0UwHu0kg z21UIv(U!wuDx!uQ0ubmPrkei0E1AuQTzU+(@INkjggZCV4@L9t=n)KRv45@C-~En) z5o`?hPN~CTH0_C0=G}|*i)$Bm4YXKjC?KRnIB(vigB=kGo%O4ehTZei45RB|Qu%8e z?AL*Mk3t)j3!J?{=$a!9*U?)~(X=6+)F@I9FcxtCn*n%6sMRR!f;87LM%YmEy~DMx z$USq^vrsz5na3LSeNL_)PXkVEO+-Tda{!vH8Mjt(h2z@Rl5>MLKccFxt`E4Bl$1=c zPhp7+uN$_oun6!=K9dXa#3UsZ93+n^vx++;6f?|!czDZWEfY)Td#$|uxP*Qq_WyQf zx901RnZU7UfDn4>LYNm`o2_f<6HUp@Ew*-cI`Z=V*DOzZe+#`&oKaFrO3dklA_q_r z5LpL&cHt#&vem0-KK$ZjA7#y0{xd-VRpW6g%4crq{qx|J*+@bjD4vt6R01?H$!~5x zXE_LYCFVSGcG+82E&hZWuX+;uUVm=oh$AvGCfV89apI0iLZ(l%8Y2%12n(z8@$rGO z(Z%6H+Gb{+Y@Fe#B4dG!F>yhwX{$g?TeBmkeWZ4)V zU44B4QBhGY{)Gz|*HY>3MLVX$-5pA3F?I*?*N{XZ^Ni zUZZmA>XC7Aar5Ju$u`Xi5^xBNSX9`-g_o2L=ZVNJ#Yc zNpnWBvatboqzCR|u~}W5s&Jb!EUc=(^VA&B<< zOIa)k2ng^)+r2GSJAL{zO{5d4`{=^LLUwVnwyUcv|Iwqmii!cCV1p=ZUZ*#(cXKkH zjM8yg$iKO^I?+Fg;_ zW$b#YawNZ`q+znp;yt~*^Y6VY{rzb{H^2StE^&M#BUAt-!qsb9&Le-deVrX%xShPF z2r^=YWJZ}_ulAhF04;mmwp*|%NyZ4&5slvWGd&rK4&^#-^uZ8;3O=9H!Z@-MNBln+iR#ivf!Ev17*^*B%95 z59dYPZImwDg*mXJF@i(e!J**U^XG|oVu&PN`PPn()SEZayvW4F#0sb31~#Am_s@1B zHnP(o`5VA>0 zoVa$Na~(4??ASgz0t!%m1VL6=}5(EumHvGz<)~KYaM$H`?>&&4f35m}}FT>bD~s@^Trf zp;1ee6dNjZTPoR^*ih!%{ngnkwkK#-_>!yFnk)4hRa9o+P*#xx+Z|VC+5^u$PF*l4i>KZLrNLuy;jOnFOuN;nMYjD#Je?rP*EIkU zM#mGL=UG!UO#u>X*tSVW{7_Iq9kxTgP2A)Tqf)!JV#}5tQ|`>ZLR0c6a~(j_Z`|C} zGJf*yDPc~wkVY24^Pk(_iayziy#uQUBK24gHbBwL)g0caIPInOZ|8%tYnWbj?yS3X z-(LB_wg2Rs*)`7Nf(I=)djmFDS65++IDewZA6)!13;uJkAGG-sQJZ(&+#*iQ7JdK3 z#m358#QkFcD({vbM%uaAUnw(h!Iln@jrULmMYEoWC`@-CJ=FI#ws3eX}FQ z|6hdOzq5c2G`N0Orn(A?fhk}XJaL=Sva`#3_UzgGfY(fRTAHH0y*-h97phDgmQV#s zqPo#iQW|=^1DHZ#B-QVD_t?3sz5O>F{`1f^-?{ifE9jQ+&_LVDTn0LZ5{#-vfNaFv zoTRT^o*NbW;~BEQnm}lM*jH>x>QKkV@IZUXkHOSRbocgVef)R{*A8_Tx*2MHPe@=l zsl@C4uwN4N_bW%RYXbhYw6(u zi;p6!zt#(z;wOhAv3jPaNon^L3cs5k$xBqzqdol$4JIoqO9T4WsN1&_n}%n{pg-rx zn3?PX|F5BMuRpZl)>KQueI|)#yqZELRxOXP$#^ZE{q@&h-&A^m|1dw^5gHlkE=#OMHW~ZE#fypJ zH;jyo#C+F0`YXNkD=RDcg@p93UM;FxnGjG*lI~mX(txV|;K75={{DQ;RHf|7N|UJ0 z&d#)*%!kL`JhF{S+f*0Oxz;Xcm;u_MA*!iDLq*R45&(v1rK(Oqh&A|ZV328nFq<3n znQv1L4GYr&)68x9-S|@jZ{PyZi}j6-w$N5L$JcCm7i+n>xp2e@tqD@@&1>STd#LRZ z6@=zTrlzJ=zPuK`PCg#QvC%k%Cv zzuFKf_SubDSoHIW&L0|P8wO!+EFynpviI1hkr94r>35I&=Slb&^e;~tTrDj#9p07C zDw(;Lqv61}b0hou`rec|CU+N@v(ya_s~CO%ykC^@&^Hbu*9f7P)JC~tCug^KwI$OA`fl=QcFuKIxa2;qyskv z8XNHK6s~-FwJ-cvQ6)%SNw3Ach6s*ausK!moc?X8%2LEVyAR6d<>d*QRCych+Ar7& z{lFoaY8l0!O^e3ImaYG@uE|bGITh8})s_C~^&Jv8GSAm%HXO_i7N+XqS<>6C6Hr29yBcZVR2ASsP>OGqo--5r8-OG!$Hq%_hc;9cka-uusu znVZfyb2zd0T6?ekJil6z>Z)>>XryRxaB!Fk^3s}caPXMme*_8=c;}5{lLZ_cHJpO9 zgtjOAu^(z8!N6<)Jff6Um?ct}j`| z1ma66E=g%Fnv7Bj*K>H9Z3~S>$RZ7{C8|&#H~L>rj4QF`!uyI7uNsq^!|eIhKaU5Q zH@0o=f2w{}eK66v($wMK&3pj|PYnlQrBR=yp%@B;!+}FUfak}=fPgpcU%-`^p|j&4 zf^U=ralt_X1KA+!Q2U-|=HSzHC?^v5e(guN%rLeVaSTWxTqe>W>;PYJ0%vNU5k&;S zffwDxa0uevga}TgU)K@1z^6{6#E9Z>C<~I*!-VeS&-KbQ>8rgz?qX+U@T?7n;^LNA z&~0QP!5`pD7ihGPeE(}2M_+x${W3cB8<%XYFjxL3VQ`RQlx~~U-VjAFj%e_b7*~Q4 z1rA;d3`%)Jf*yQ97QBp(pvDGcW&)=yKFxg&zCa6J%1Xy0gAw6_S!#Kzqk=Esf|s;3 zLtvVwpTK08gi9gd3lZQYF77s%1g8v~Y9BtOHUjv9G)%oM!oA7Ota!&j|>TZlYa^0x0(;oP8LX?FbuDj#2F;QL@zlY09Eg1a1 zNbVawN2SONW<*xF`2EAnz<{*N_pTmGZKR~Q_`I@`)d8*)!lGA=zw=?m8TnV81u_R4 z+m4KkjPJqEvV7l#S~KQvHcK`p%4rPhMR?>{vB(6!S5^$UkixJin9c7moJlh;RYt;Q zaQ>_(I4#8OP~Q!3_`kqt^Efu3_yXn~alX+P9<^ZIn3+kg;lDTe!lpU(u{tjd2I0 zB#A}ufPchyB3s0Lhr0os=InQEu}a1W4ektSa&M7RirdZ*1To0^d&tphzDyMHvHQ;M zZbNi5hR2_dn@A>VzxZf#bynx%j7T2C=#&h?}US_|lsv8~NF{ z#&e@C7Qz8fz8X;9TPGvd(U?oFAEQii`Gcw@b}oX7w^NTPQPaG!1^BHMw&<-XKX>9^ zaxlNX;AiO46G+&UW951^?9=#K*};`WB-ownP(z53s=yAu_Mk`R;M3#Zf%_)Q(d6j4 zn)mG@O9Sk|Ntlp)3hZen3^HD21{HQ4VUzr!|IX{c&27Hg$ozhx)6WN{8J1gr)jGmU{6xnFz^}rB^#)YbrwgdSO&)fUMnt{{=-`)XfA{D1; zJ|^rGL!;JhX858VXBJ8sTQRGpwp3n!k$JXX>4C0rgy3#DVQYeSvP(2AOS5pDQs(qRMN#l_|IZ250a4&(OJ ztGy|y717T3tAfc{S;vOBPN&ZhJO=w_EA$rs{^{blT>Iu)(t@w{clRKCgo)L#B_6kf zsK*!Tlc&*bIpTg4PUX+&O@pk`^4?*!HEC+8Nx#9${_cFI(zwHWLtcYY9C8#L4wi8( ztz2yF$!c5FZoH&>O19d;TvbLctv3fkX4q)ysDvh%7yqa)Ki7olUse_t77L%76U+Vm zeeyuX>*DjK3D=~!oJqWU8CefG~( zrHvxjcB|QP9XwBBo3i+mYZhi^?g6E9UV3w7e$tA@1W$UG zjxSthjdinU>IMeP$t6%->#qsmahrppB`IBk#Km#J*h)8Yd2vqBU}K99H>AcP2WR~;dNn^Iq>73>hO=lCbmogDef25evyHtLcxLuxSG&v$Zyfr3W zow_9l`Ngk-?NFOe=DVI=1spfc-!3-1d)8(0c%VlrF!dvqDx-CXyk0UC85T-O|$Xp{jXp)8c#VYs1+8GR9=;xPMYU#zwo5s~5Z95n^MuaC&QLd3LcoA$PKpT~RNWntLpsE!%#ok%Sx=?MbdDCvP$nj(uN2_~YqI*ryLBbF1qyU3Usl&p zieh@Fr!^f=^E`GyyR`p3mS%rASGCy?@XueRvpgzYcUjAzszSfvrBJ|=aD{FaDGLY3 zJF)wzxP_h36dAnyHt#E2d69@*@2i8O-jC=s#k_7ZvgQ)LW!T(9q8i3YRO}RN;6}+m zMn4o~52jug#DD(Wo6M@;>wiC!L#iP8d)EIW-Kp7&YpAa^eg*R@+n@3`AzI5awXj0vto=KD3GVUUsf5r{ykV0qL7UtD=N719MjrRk%C|3= zWW3R!352L*3F;8aQS9#Q)O~Z^MGHThlB22vNM*GB{NiGuGMv0Okx9$#`2OnfyT|bo zeda)hVW&BVo=V8i?s z|G&peMOHjGW1eYEQ92aK40V#EF3+FC?{ikJHRD3!*P+3t^n1kekj*Kx_!po~3XtbD z{=$vW3x_Y+xJf{MM2Hj@7Q*0<5yw(sJbnk+Ts7;qx%Ik~XzqRykAf8v9sCz+4uytz z?wUmBMxt}QHSxw8I%1BT!bC(}cbb|F6dsXqoaf2-2<&!-l?EDro&n_ zt)FzrOOYA291*s$dlQ5s>#({=yJ20rV)HNaE8oly4tL$Z)=A?P{$^gA1m~hj8Q{0~ z`1jqV&q_9EweB_ovz)gExxCpZvWV*aAH69A@fcL!g2G8o`&|+l0W1)OpQH1{Bd_Np zxMbhe+W+b_%KX9Ywx@2TbgXb<^kH=%mQrM752q9r@8zDS^kxmM?4SUGaZX-5 z<2h}XqeM8eTz=#;-AJbsTUI9w`o40%s_BoPaih48Z1`{5lKE4sv~0p8{;gcL{&o8I zH953JJP{1C6;4Z=b!;$jWRf{+>1DDFtD1SF2a0}qABqOWMZUD)hgZMX2P4J#F|jfC z`NAdC>6X4#P^OEu#F&FXW!W>{%W&3#FFB#W|%w;7{fXdl}Rh z@nS)gK&Bxg7a5G^ZI350D_1b{`+-mc?|VO{=Oe_aHldP5pGWp~8qWQrooFO6E1en{ zkr9lk14Uwp^Hpn_P3qsG7F=-Q1d6MJULH}mv(9gh!QcNa7NCm5cv&ly@3bFFo zyT{ohe&4`7#W^Gfe|*Q0oq&s_^*)-M7J|WnK4bZ?tpC9pvhLJOmRlZ2X{qoeUQxYZC@CsYYrEG zm~8iv3?=9ZGab~je)<^G_bIz@*ndu~e|3tOv^eE0s$V-~{W596L*t)G8!XB3XBNh+ zYIAXQmGa37Oqte+iX!6RUW$mG7e!i;E^M{>OW51t-}Rn6Q743f1tuWL<%oJf171s9eKTu6IP@E= zPSWD%7bp@>z+MsjwX{}2k%!y7J^2Y{I%I{>K5WREa~+I@(rVi){y zLQW><5Lb8`K@jPOsI4`y3Lao}&F$A5`dm`g!mO57QX2a`2RYZ2R!%HzE?oy8GeW zPLu8I=H1=h1E3Ll3ernxS=(Lqi`;8vS`68lnPWn3d)+Cl`kFx|jn4qhpSsc*Nql(g z-y4eR`*?q~M88*(?fuDdrA1@Ap`n3Z0KkuW#tczE!GNn-J(>F?J>#hZ`Ys}4&mazy zPQ#zg?^jzTJ6Pi{<3#TnO&Y9Xa=V`H4=vq4dQKNA1X~S8lcf8vwz_YriQW}5<_Nl% zTVIrjJt}PHcy6L5V9&=g7h!2G>`fKOERLn|+zI_@r=6YC}p(^9+$fcCzWL;~H zLrcUoF_-O#mtssz3c7j`%Z)a)o`i&i2M6E|zZmhkK4Kbib#ak?YM2nkyK_1&)jXgk z`3k^Lq6QTVI!;#^G<}{W*lYTvDBo?PjZljFy0uj}4Qlh8g_RYb%nKQt^6h2btNYz{Cbe(Ujz43%hhmWsZ987IyvRX&!3+=>nFXWZDa_JCq`*GfU0H*(yQCe6vu=a zgW<^-%xTCL(@rV81bS480-(ig({gc?vm+0QEuc(%6m(0W@naOeUa&~kseIF1oy*3~ z{&hu`-gi9+S=s}}J1!=~h%&O=wn#q$P!@R$yF<>##@P}3qm@~*Zfq}>f28q*SLrv% z4z=9<&WL$C^qmF4YLuwWhZJ-?+{48zp%1q9Oe%JpK$o$#)ZO1U@LvAvV6g1i^{9Ia zdkl4d)0w%eNsYt{ejJ?QT(_fS$%t2n}AGpF_GNLXd18GU;BbW-{Imvq)5nfq|-Xaj2sh9_R6+Dj#8wY$t+3rYe|4{T5$_lWWGSnA?>opbNeWD zP9f&sZc2MGb$)3llum(Tb*}g`Q^1v3W%ji>N{NPz6~^eotO({(!9t@A9vP=89E@uz zDJkLEEY*R+QunpDL6L!MlJp^r>^)9~2e{}~mzNGH>_%_hwYiL@5`ey6P>L9Q z|L*CURL%V%+OBxrvX6GnYT>Lsvy&bmmvUzUL;sVA9 zIgH8csC4%ua4|i+Axl-%6oY)feEWvXCffw|-z%Zz-EW7jWV~-JoA!J&^#^E|xQHRO=0-PwViI=O{oSfN=A+ zqCr-~0msM0??FVN!vUHF>RWp^0+f~@03XO0gOPFMsR258KD4mMjN^m|a08z@1e-cu z9LN`R@pV%=)ayv#NAGh{D8;FRfYu;SZBbAm-i--#Xo1GzU>w!Nn*U!1 zjmuG!C(X>a#dEZnkWEzhF{tEgt!y}={Bp@DKwb1*T)5l7bsH$L`jKuA@C3o0Iviy4 z8T>>hQkJWt917I-X9QrrQsl=B5+bg@G033SI0dw5`~0B|?%>fZNRRY6_)48*){aizOchU5$1;$#3H$k#suoFcITu>d4sbbQ=5lwtIfj z%wib^JW4+sf?1r#W+vH$z^j6$H*&k*2nh%xt=zUZvAgD}S^#+tPDx6N#K;Ps1N1pY zWQqVEfA5^zq9n^+>I`sP_j4Vi(zR$u&^raPj9*GQJJ<1VY5%rV7RKAx0>#~|88Gn+ zARAl&Or^+Z7~|ZVUg2b5{(Dh&FA|U8HE2SiJnyFqBgdI$W}^;fE9@*AF*Kw?kT8E% zCdd9%rHqiqwDy9!{#O3#eyDpkl^QCadRAnCtEs8ks0-Re>rSHXSqOt>gL76fJ;e`v z8xnb?mUr1+VI6-@+7{?y5i5MY3g=lMz?6c}@39m!68c^Kejaz{mUY^>mXbC$W!0jF zFExeSbMgcJJyjMKhE8!??oStOy#D0E)7kh(()TSRPzOPwBiBY zfPZaHHmfVv(DZ-*$5q5o4f^beHW164_{- z1EuDjTeYI*^uMaap-ADsM-9I z14JgLZ{B~CnYsC$;rN@3*M9Px+ib-!X(y5p$V1t`ybr6Y-O0%EswHgF65jE|z|;mH zgV%u@{b>jO(E^#v?a!JKYXQ*0#`d&~jmKL(j!FBg`=xi;jaq919uG~-CzxL%yy$m_ zJUObY3);Dc1>B9AEWk7(z}T3tS%KVQvDW>)$xWPhRZ+F4MQqEWNkk*2I&?~hr`1~~ zV*{l}s+*@o;)C}z10{k;r7RW14rOw-C_kTuAJfk1E_S40C-P5xpd^=6F5n90Bt$$x zINQvi##HyBT8UFX!AMR3SwXmXw+^T=h9B|90>vL_f$aK^R~9=cumaSW7Bq%b_@G-k zpm#nwL{lQb>wzCR5vXz^BAmqmDfeNSSOkJl4cw{?=1fy0$R-sihPTaJ-Y5`5n6ah9 z--ChDF9yyjT7L%Cw_hQqHatQeOe&308dDlJn-t)T#M#TDy__VK!DHIYu*IpzLdBdmdyQL-;WtqAICv3W47kGv9{y9XPui6@bS#Ald?nAlf%yFuKWZ{?iX*L24E@Hnzc1smu%%)8dVn>A0TspZjtf4AIfh`s=WO z9`_D9nkw{xy=^O2h$c7GwhMOYq|o)hVM~cP@`javWB)YnQqClDXav z#X}C=?OT@%U|A z9y4ztd_LCaPxw7-XSUrl^_)Y0RIkvQN62kbZM0vut{)S_+Y1YYO}Znc+O%NV`0^w+ zl!4aN0KjqmOO^E66chh6mEYZs9&m6}L$EABws0DFeBzowa{~-Z8F6DIiN*eCp)Nnx z8j!7_YU7UbStWlK-AdCR>96pP0pepmnAOinFCMwO*lidaQ}$SOpWolMiLRj^85voa zQ4?eHoG;gjy4s%!r{H%AY;suE9YgE-dm<$9&FAKQLWv97#*&dmMHG-YzsrKgObWH8 z=FAg$aqwXU$=j7k@-3uTIjz@5U-11(OKrdQzrN|KfASuG)_x!ZogXlcQM=jlfs2ca zyPIDD{{kTMn!0;*|3Ixh1H|NPd;9HLo)mKD+u_e>5BW?evvN#Y=U?uC+I4z$I3M+- zxu~TkG5{bw*CNh)#<=#|2Of7%N`mlz(5BjmJu3qjubM=|#h3d3yN9HNFol*u53Ly^4RR}jP z59#q_o|G^xtrQuwUX+LD3ze{^y4`yK>%sYpW8VRGc?%5ASN>BkC1Emvu;tUwGOY)2 z*U~8yIapZm?#gv46kTBUsfNd9KdQ01I`uT@)iVb={zXMa1WTjdi{iiI$OZC;)f5#0 z>D}aYSVGDE`0-gGiN}f)FTLtaSZbMb0J!q?#L3Dx zE!raJ)GLQ2Z5F`j?tq@BV)ysB`4^f$CMk4sBwr=;pdgXSYw5@T0abphXV&4kE#|l; zoDIA^0JK?_h!11DV$PZ%!&E$07=S2psVOOK`Q2Y`fKTz7fEB!}Q?5PbmfJy3GPXow znVgt-3S98il9Cd1qk!v%oHGzKP}C(2s1jGe;b;!l;Ap-jy=y6{OK{EHk$TLHHiD8m z0ODxg4Kon_V{kL6xWx&dN6f7-XKkzf?}_vOOn`(!Lc(8?&9@IsS-6*3a0j^nT@QHcDUdFEX5TAcLa7=d$oV<+$zo>0CNj41Qa}J z|KZ~0DM>|{)?W8b6hE*~c)aLsfeD#ZTuu_Ey{pUlWh)tDGejgt(a>g^asX7@g+O@3 z*I9z@uMG^+Fw5EwNv2;c0f0G26gH$^ zR8S0EXm(g83|4ZJ+2-6nUIGlrv_LLyj`-uj7hRI|eo(G0^8JK2!_#Dy!(szI%7>r* z;QPhtLJX|B=gsf_>RDL-{vU6>Tk6hl*PaH-!DqZx89j}=|ue07?sl$44Nawl?*3zxt7e@14l)u&E;rX z>~d0Sp|2L*Ab4iWVVf5zu-%vN$9d?I?96zWH#H_T!uwcshOHSaw*{1@5JGE^g)#;4 zEy#c3TL6j>8d4)6078vu0SCfWZve7c2uAM*pLW}rV!(m46gt2~Z=8aN!KeI~(eVE_ zGi47_%GeAa@8vOf`jis&X6i+?E6*zon#w(E_Cv5mOS49wm&dGf^B9dC9F3G=+;4r4 z(=$~<*4zF4`%_2}Qx*!m+P9_Jdh(xB!c~e61vW&gB0>+9)1>=giO^#4-vbgdyjPny zf+c&G#5TbmAXt>W=20951dYg!$Lr<%y_Bv8`sH@71_KJNW2>AH^-Hl#i*eBi z5>X+04_e+zH`7H*h#yfp{=Nl)o$5nYwcan$^ED58rMf%*``Nck4lzV$~y%1IU6yaWx?VvXa2ZdEgQW2UB1@%I7`eNMiGCxm>v zS@UV)(W+@X5&Zh$kFkUl*A7#u_f%Z%hd*oPBv7Agdkv1Ru}kOy_3}_E)_k!V|E|Ql zk?G}mnEGTjmYO%ilxbMj9IZe|!Q=JI??$1{{(mL$qQ-at^fy;7ioL`%y|O4`0oE11 z7~_4<8bF6j`V4tXpQQlbd7|;huoZbM7`af3q@pNPem8s#++CGaPKkKX^YjYxnnZVE zg4V2L#f+C&aswP*Nl$CdN;t^b?6dX?#ECs@VB4>E2if18tR7X=bWXp*X3$f;vs8}R zdm!~15#HIS^Jb3vyZ(Dv>1=#-7*%&Fvk&t;1P2;1+o5>!+D|fzG-1 zKO}!x4a8x*fckM4@HiiE1}@@(H5wXPqpybtF9%SE?|9ygTfh6s{^o1+&7WT;i7*S7 z0}zQq9iu(p*}ib>C>KF1&8n!vlJXE!)AK9PRS!I87Qcbio5rxtz|X2TDKiQV-1tO9 zQ5S}mYl@ZEi)bArF^yRyF=XzIHo>O2@C>qbLi|H!g@uKCNNwd-bpEy->8h%#bL5Cg zGYPTWrEc|O#CSgdjB7IA{ID}ZkWkVBOm-T-vrQS*?`p=aZVKd`z8k&IG^$7B6%{uD zv?1JaTdy}DQcx>HY)YW&k-wwC@VPpm7fnnKa!V9kPGa#=SH4$5R`ycVO3TWBYVsEK70_|uKAj|bJn+NK< zGr-M1(NboK#{*CN_jncy`5?e;bSL`p52dl!(vrvTa8&&LMKc6kizh9CS5==Dk+nxM zt}hSYcykU~E9yJB-Inqm<@ewL8+eK;oERUUNOVU+(03_u61`>iW8(YkW|C;Rek?*~72}qwabCe5uozqQ>j&8Yq_5&7> zv@vhOUwq(}by+5;A|1nT|NiZ=WbwMuI-z>JEIYj$CsM0KHIiNlDAXpvHG8jM_VUBt zWS;pjqdpJ<(!0(_Sh!iHyB?1no7$5?an)EHdZ%zW`0hR?;Z-B-5a2qQC&~|E>~hjH zRg}^z9#M;{a`5oXsN%(3M{#tnH?O!vC3gWG{SGJ;jo<(o*Y4b+ReQ`fwZdmThV}I+ zbfSCtHQKoyiT{-^>dUlB>N7JlOD_-CI@(?vOc~`~GJ#+RxZ*LN^x{c3LSMyIJqyS6 zL7WsF1#$)Z3ETc$6&XMysy`Jc%e+9TBsz}yORK?ibq0u&Tq&mA5ScU0s=bU`g0+05jvyIxFw_*KMF6QXR;>ib ztat-oq7fMZ6_#=fCLv#ahM)@5OFmIAAqGKUDYqVs*b@Z!5-?bP8Jy!F@nD#wYl`%t zqODPj>VWocG|P9S!bYEp`K#j1*>|d_Eu3%+lINc=N0>?A4PBbxYsr5mu$MeHq9c87 zmoy&siHo+WpiRf1!VP3&aF8`;xUdtkTxyrzvG~y$<5xzDusrlm0i{^#rSvzQg4Yx% zy8Du)n_dYNt5wsjD!T&mg!tgg=#`BmMwUXDtZJ375usmkbE%|CaZUm)Y1x``UfB`C zoS#&c$3^O$1*c>?{=EgqKvvD-xz?eZw(|Kr{<74R z_`F)LQabl#q}vI zOod0r4*#An@@tg}fdnNrgrE zFw+L%Eo&(nvEZKP7y)n@UKO1gF}D^HHB7uF!=xcpz)_1 z8>mZoVF^f>*^ZH+>f868WO##=LKL)~rZIIbUh%AJ$ZgK2dRA-u*cIIFuD#1KT){h$ zc<8xoIP&6PAkQcF_PBAJg26!WE++|5=%~TjQLWwFNKp7CKt)6Kwnm3M#{u(zKm}Vd zAepdvKtvj!A)taS2eJsH6h=r0s$lR=!IVn~K@hOxfEGR`mK_nE0alYFupNTL5rCST z5GX5`5)_CBPMMkeo!Ac0yu;;Y4l*%+VE|fP<=<nR38M8|v#D;d7r?8h+DE{N?G-Se|F< zRvVUWFnfO9RsHsPzp@vbzqK?RJu(dS;r$~XNT%27fdNh*|8J-pAjA@`RM`cc^RcXVI_P&>A5q`m|zvY;t< z`rowuLcQ;Lx~h4pea~FtH|46dl8HyILk6~p056Bd-lWD@#33&FdJqgs`VQFW`Mj}T zIu-JOM7fu5gDR;t02zPO|Jw`uFA!(cwHG?%W1lt!Ff^iP}(f zd2u21J@?#b@txNz;PZICduZHT0_IbW;zw=eeIrS=5s(Ccm8|Z>VEjz!{e)~ zOm`0v$^r>Ch=^GJ>H60>=>tsAO-vrM_Kq3rujN5|J%I1 zNOI^#YZEXLW$osHw_68Ohyi2xNGsz7hg-`-36^nREV)2$>xVz=*-~h;M&6=jKno3y z-RnScB4saNM^*syT4%l3=!dy(m6esz$E$5AMI|LsF=|T>+F~0^`78fW67w+(ps@}G^(6M67TaG>1qZcnW%!PLEZ0Cz_WavJ^eawQ5LpM18>r( zS6^RW@;d;X8PlX`;6d63*-6ttd7Q`RZCun3(?lFs5%0)X_sEhNjAK=YkPzTuH7`&$ zWJJ7M36!^XX{!1laX6SGl{=NojdS`Os0kcX;r7%xu!4(V4K2lhw1eODDP6uGLxI3* zD;y~%Ga@_(%&vOw_y72i)Wb>}{s}5^=(KR~1n|+Q1ekt;8^22O!Vv|4mO=9(a7TeI zR2{a-3^+HK6y!rd^uR#{rqw z#d)*VT3?Qf!cKhm!(5qG_|EU&^VDJH2uw@eAmkZim6~AJfNQSA(*LA@Ou4y3Ew?}sNZzAAH3m%z=%ofd1 zDb)-(0Z?ZvtbMP8pG>X^Fjn#-XoqZcGwOxau(NdIPQ{OMbvF5B|{AbETW zf(2^Zprn{RT`xPjHd{xx=x-=F0CRgJDk{qT2cY<+JNsilV8Qj-bLr(GB_cKxkU4k) z!AV=MSGbWkn0zbUFf-zn{#W}nelcyrP{BW1Y*GC=*8i?*0u(%GbeCs(76v<&Hs#wL zfpwa70=5rEm$q&D?N8Gi7kz3O6~|Ag1if*{HmJFrp{VQMlTVeXcJI)arK9C$wRla6 zo!P#2ohK_^=m>XTCAjhrAQ@`#B{&#iEnfzm%~6h_DnTI_%P_L7)^%5vJs=Pkwg)R( zz;UUuY;PCDK)=Jxs}ryWguxoXq`*)a)E0w<78f+`z;=tq2e3!b6a1*@LG0-ad+IBo z@4lP;k(mdU5&aq4hMm6ppD#dbM>nnyd`lK$Ko}`D1vbGPye>Uf=q#^MB#!(57NY76 z*aV}s3R`$jV>}ZPVliM>;=VNq_6t1LS~4;*P0fB82RlgW4WfQ{k}j)10r%YC4FT-V zVOGY@V!W7pWbV*jROKcote(&|1~_!$FltJ+K(~ZLPU_)FFfEObmr#hbFd#+H${@k%w z_E94T0IuFR8H>Sh#PJ8Fas4JmNxnb159B~gsGJ^1@FdF$OFMxU*v}MW!WiSPS~Eo0 zLMu3Y2cC5rLCh?d%qabG61AqBpS+r)nV2yyKR64-@Mf9f9e@^HUKddqQfF*O{1P`s zHROJ&#zah23HKW-33$4wKrjuYC`*w(zJZeV*`c!d3Vk>k1B#oeefiFCd^m${Z z^=fNVvL4=>ul7@zi&J6qAHX-bzp$eVEfxn?S?-f++= zb*g^0ML2IU93#Pvb8ggQW3y!ir3jOJDZcOri=bHs!T`8#s9%uJTNP*_j3&BoXI^x= zt^WaAM*4pfIJm8P?Pj474GzXqjK+fW-*}GLg!N1{P+JZB!m%h8V7o_oNo`8nL2EWJ zqFaNBK8s|I?L8o}I$C-RoXn!8BFI^Omfw99ECF={wk9=Ii#`vaaE=(OHS1e|rMY>X zZN4N{=MLdS-oVtE>T3|4kg#Vbbx-kStk$VWURW>uv02mgl>YdzE2dW=(`BudYF`WX z^aM4>QcJ&lK7pgsOPIDexiEy$piv+jS*MyhxeI`$1z7St^-dgA;~9{S%(<*>iJh)j z1BrTkdn@@bDzzOQK60o`e2*bxNY;Q}75-QPR)lRWUKih*r_|4x#E0s(lWB+2Dv+I- z3A57Fd=7To3YxTg*3I!gcccMZRs;d`$A$Sxu#CEDz^06_%_k7+eDef!#JvOBGrhWa z#WKsrBj6s#zy2^YW)4iV&&sTC#++XC0vzvh|GmU=4j{DZ8I>d{9^@rDx(AdBSVysr zoChV@Q&tuUIDJL02LZ#7nvvO|N2fi5e&rg?Sd8B;bD%Zj^*DN6rjU+{#5)&~NGa^8n(Kpp!7#o&9MKu!(g5V-UB1-;um|^b3D8S?ewWf}1Nb z8?McrCQvN*Ub41QA@z`hzU}I(PWByTanQBv)Ml_0AhA|Kfp|9sz#=O>xQ2n^z0{}w;8T<_ V90=AE=Hb9U1sPT8YDv@J{{?EqC*uGB literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/docs/images/definition.png b/app/code/Magento/Analytics/docs/images/definition.png new file mode 100644 index 0000000000000000000000000000000000000000..16acc576320b0173e0078192f4c1b4bd3f1938fc GIT binary patch literal 7138 zcmd6sc{r5szsDbB30bleQp%QnooszamdY+9%MjTjOIczNjf5;Ei5Zl&LdceFY{^ct zW$al7Gng3rcJ6-P>-^67=X7AWq2CPl|>(ws9VWL-th=im~IK>P*#)s$|L;>3)TACAMp>>ibmp}Yt^gzx#vF{ zW@B#>2*hRJZ*go6F3%*u3-TklCDrF$u7nCZ%13O85j-LL$n3n)M|MqZ<5l zM7XXV{2vZtlp=L>bbOxaG!UV?HtLO?9>r*$8-05uV0V#kd@qZqGV&d(=T#faC*r50 z$p81-d{HJ{PM4CDl$4e(uBpK-yjxyguB)pnFIPx6Y`dQ?Dz2%idGX@6wl>{@At?lQ z+*P5bLJwtgmyS!VsG#6Ru4#vpT=MmyiHVhOr#tK!9YSz*k2X96uHU#ZTj(&~nXJS? zLrtxypzx(q289u7rZ$q0l5!T16ch77yts2hzxvi z_ZHDA@31>n9x8F_IE|h)($_!nn3h>UM$*&M6PjLITf;T8_&%+b4!mtw=LEpb+PhswzOY@*urL21#QWMX>VHJ_fIj!KM=XR5XlU}yho7v5L9hGl>+cvf~c z#q{1L0Trg_rN9f$ZEk594ItXy`g@4NHkZxAJ?!d(hUT?n*aP8u#>OlVa-&BXn#SWt zrlyPnDZ_Tx=SxaT-oF=(nyTXQb)bW_OmH2Hc{NC~?2M1wq;QE%1}rTJ8H9#vK*AR< z#`Cn)6JlawP^c3{7Qr*kktC9Lf2US^#Th#i6%`d2=M#@{xZCJk!^6XrSKQo|8XF(q zD>yApBG;yAMKMtv@2B1y`E=LCCF9n-$#Q@&3m5DJQm!M@-+(TeUAEt7QMUgbEUxS_Xt z_oI11tZa@L6Klqpi+1A@%=Rh5mhwe~>Dta_Xa*mZ)yI z;Gjo9K{`9H&v;5mNPs!ZC3#!;K;(OOw$lFIN%M`%KEJNIyDyJdKQO|m$o}+2Bpx;t-Qa9VJm1dIFJ5E$?{@EO{lpPReAIyNSTKG)RB z#6+m12>$N<`}ZZcE@}NtL8~2-2Sz^G*7~pD28=Y-=L~mxPl`Z+3#l%kyHj6RR#tv6 z%g1@V$;ik^N=kb1LU!)s)mf6;X&AKtBfk)MfQ*Tv9w~8gad!Ghh8w=y@&TZ@zI;&$ zf@x?R{c4TXBIr(IygwbZX&(8s#q;ZTZLN%r6eId3Nli~^gX*zWRm#G`bNg!zg161H zd=?U0KYTr3TP7>_lw4F))Ten|XHhUw{Xj$>A`pqlrQDQ*g9FY>w@5p`9d~>@zA3}4 zOYHwbATs60)YjJSP5>L4C*k#Q6O(?>`^4GVvWH8iTWKCCQnoR%v1SEBO-)VvTPxXo z1{VjKBN@!ahXy~G6%-Uu^R8r`#mZkq@_I65Zj3s3OxEqzZ%?v`KHhkgV{UHllM&_6 zX4c?FQ$a8c-tG zUZ(O;H&W$#-)44%}G#Ws!S`hN_h&IWRI@L~B zXIGp*Wj`)nyk*UVPD*y`>%%6;)MH!3w{u zs;UKtpV&*4cQFhK+KXlrsj01nCE)t{inFty*a1m7IyzF4IHQ47k&uXGd6|}0bAO@+ zpBa|HBIh+(cV0K1Zg3Qb>kJ5e^9@wnh+S|T%R25}u_vxPx_lCik7)bFYQmSVPx`mSDH+Z!8%x$D&Oc$+xb?-`;p){BWk43}qprVw zv2pU3nj@3Z`F)w)4E`rgEF2tuYm@3TlqY%x>hnxLs6ATG2|0z_eCFl!$AA=m_z=zF z3l4DBs<-p1xJ_MCF-jfGeX(xE=p<54kM5B7M}NO8kgq87O;8ZHiW>z(I6*%k@HcKS z)Q^vkpJ8WrYA`f4{qb7T+SJsPP6+t6M~@zn33V-(S0qZ^kXxfJ2;}cpw}HIUu{fP< zyJBT@4{>iZ=-tiD z=C{_?{y6%`h>Zs$ot>R`yIvdC!(ub+u)*8+0|UPtUVeb@&81?7z?hCzdX`OzO~F{5Ww@CHH9W#< zSBt79?=sG5rGrNf{ZT%Y$NgW!B{U&;dsG5nxe)H=}1_(g0pY{xi6I zPj~mtf}zsV(y5Sb{s~tZ?pN0@lrhj8@~937;VWg@Ed$XZ{R}-lJsS%>W*=^X)_dN+ z&$);PqBxLekkmD=R3RI>T|4DDQIl*3G=QMGR_EBj6k?6WHu=vqQ$t@u4{PN8PU{wv zw%4XoI-LCc{Pb0|P0aH2mx#pj(XUQ&+Pb=9<2CzZQ%6dV)}89@j`KASqnFC+>qEdA z;$9K-?Kw~PpN4hhxxjO-L(0Y{4)j&Nn0XDPO%bCG|KcVg(TuhC!`BCM=Pii+y#>ysbC&P69A zRNcA+j3@XU9v;fO^pYQHyRtl8`Z)5ORmE5{32{vy zgyvt*z3e+jcgPdd`1B5qgA?NtE3eODd0&S5*g)igCa@efUV(Z1fKsZ*OAJ(jA@D7l z!T2{eo}YuasI5R}w;xi_#hn&UUXGQ<>KPhtJrshII0S^axRvjZlZ;e>;RB~$F*oNx z;3B2{UOagmuG?P!)O^}U?;lXePHn5q!kc&SShKA=3h$lYjAqVUA}3nUwE6z>Sx)W<&n_M`rF?%*Y-m9M**<;0UjTnDU1 z=S<0d!Y3FwR8^jGBWtw1qhoja33E_Tkgu=r8x9?CeD+K4&a1uCB@72(ZE1_+6Y-V( zRg!QDU+0Q+dFo}Su&?NMnO{A&Y{Tq#DVLf``s905xCjcbVw9;-bW>biWz}0^|EG6v z?6-g&CYK_|_Icl+G+})HFSht{QnnPv(CcP%BU`f{#-%UA{KL(Rkn9-?OsSCnM%HhB zY>O3vJE(rrRpB&zb*iDSQ083T0ADhA(x@(j+CP&uH`gy9Ah?Fb#0T6!nFF&?HhkCF zIdr{4gfsSnre>zw8PC55!(?i)WNt>6}hgNs{W?+ahb#o55R8(fmv7lT09P2u}(UHjOH~zw`E%-Gi zHJ+UmL};q?N(=sk5ZTOQ{7b*{*VWNtk>GW8wL|);p`p9SqSz?i>|__JwT^Al$&)8R zWdqwGP)H$k?KjClwOb8-XZ?W7OJ;*E`rAf0?Vo)f&VPMpaZ82MK1QKX*}4fhWE-at zC`VBel!(C`v~nSy^C|ZZM4nZ+{OG8bymew>UduHnX_d>1G^VH*k+a{*he~Y!1K#b^ zl$jXJr3b8#x4ET$6kYXe2I;`9$mMvAbcO2+LfrqaD0_Z#$(&XZeZVrD50;9)g?E6` zdwDHB*|?cG7#kaFX+8N*WGw&n>&`;|%a^COImC3PTbi2(-7ALN@8XIq3a;k@4XuP7 z6=V14A?LmfTQf7q(p$hPGtkpRXH`|lDk6pE7y}Tb=YxYcAsKE)DDm~{1?;(2x&w*g zI!Xu>;$2)H21W(lczvl9cJ%e@RVa`&O)>Cec$fwP#^jSEqmav&{fK;EK|AJs5s0bb zVG9HTQEf9hI5?MguJwzX^1b0p&|5^k8`;;?^kq*P8AgBdq{HpSM`GR1WpsY$=1%t_ zNadeD%f)2L$;(qwQp(B6iN=UaO9z;FW-zKvNELqi!~|soEsIr|M}mZ|@QtsWl=|81?Ys!}j_0w{OpG(IY2Awr!yuVp*Tf zpGbjaCZf2wm==oD(Q3d~-7cb_pn$x$S8W5>#eU#PfKS-9fvKhVqhZ=6$QHgz3Cm9& zW0jH@F3b;EBK(4*>8j&5xDLXpXrZ$b5;xu%LyzI_+B-Y%;A{7b=I1{J z0n`vV&H3e z+RV1ol_DJ#83}wo>;T)7_$N?U#ZFI!?t6we;ujWb>hykNZx}JVt#52loCVz5&An=C zdGn^Qu&`?dj)6-G6%`e0Aprk0Pl^!a=2i(LorMO6hjCv&S5|UDAmah<(8fABFg$;1 z=*;DZbURahHnskeAU9A@AOrKx8>dr_WATMWaUB3J%ge_%J3H%m=Z=R!OmuW~Z0tP` zkDP|mS@<1VY(sC4GqVME`4xU74N{NfvS1CutUGz9?PQJ)c3zw zu1!|YFTR!YlBcAi8pGj0X?HmBs`?l9&_gUNEZ-+5dqr9nWFY8y;XjD z!3luAu_so)PFplCIMEwEXX*x_?3PuDx=j zrh)EDxlXAaR?px_628Iqnj$)Cf1T3gBOM~-0V4h3|7 zvQ8|i{f;w7*76O}+FG_>*B1_EwKu2tIb8~ZZa&C2qWR@iS0$>lq4j9bJ{z0n#)=0yVqNwO1F!!Kl zrhzX8;m1$irhw}_m?)TxOo>AaO}b(JO>r|*)8{(bNwu@6a4vH=ym_?Dg<|?(cLSg+ z;7!PTp*uAvC+D5|oD&{0wy`N3a$lQjKv-Mzad4R5y!qARi+xkX_Egw$f3|Kcr{vyZ zcEY00lO|&e3uh%Xm^jDise`BY=Lk+v@vMb=fofTT!T zR|ajm*MtD41X^$i6xk?4Z5NpC&&pzeDvFDxrKC82o`DQ8Dn4LXz~lti90%zrU_oN` zv|6qQCTbV2c|1Bb)qurfffbRI^aRG#a5Wyiku>-=^FBDstL`_AkW*_6$I{YLESK~} z)ZE-0I|s+96(JE-5mYw@HsB;DD*>4FJLoOomxD%~&v#AUzVT`}91cAM47|11oUXRfEw3+2z8a5d{od^?f7pQi!9P4S z)ZdkFn107A5Z}wc@9C)&C5R7HLia$8`mycgmPgk|RhS=iz7hilo4gJd;fn@ob91XI z4%6D^*48%=DM=zm8Ud>|fS`otz+>*Nj8#Q#B_^e_!2y&0Y*-9IA{UFG#~I%+EO3)S zpcYH>;3|}jpbnKieqJ$QpJ*Qe#+F&V9wwAiQ8DB&O&wEu>(Ulse`iNVQD*0|iFmTU zEZ_i4D@HTyh&gPh1vvXmRtP@s2Mo98J}jZgU;-GBirJtfb*h+Qlt@i zDL~@Fw#qU`3%%z%ITm<-5rk!BU%2J3@yn#k6UJ-&x*Rl-;R*5ap$9vqJ)OvOwe9f- z%z_&1qRxOSy5Agw^z|+-Y_|*Xa&l4Gl=Pe_10Ea)PGKt z&KRhcUJw>$=i+K>ZKb$kV>1q7z|`orr+gwv-s}qh~Eg&>k2be$VfeqSR z{*iklbxZNyF!5(;Hb}2P+O4ddQp}C*;s2$U%f$QuMCPrnt>9en0dW^v?a}9r;JLG; zE~vU?cLP7u#x(@iQ7VGc(074zg@|R!g3ayiV(Tiy?Ed#d%OIfx3LZYX1sXo=s&GBm zw-*EJuFnM1)ex;@AeAD)4q|Ki8ACcDfbS#j6_?XLm6yNzke`(We`oxhNB*L?_%dmx zMZflnEb&3>!Ow|_!yh-K0ZDhik)6d=++&Ir6BT`<;*+J5JzDBW`?H=hQ$5%p%sg-_ zT)7(=@8A8DFjCA+NB8X6Gtojr5$c#9Jj7WSm6@%dk8 zR^!=@elz;kv&vpTm*^%4^k85~p|Kii(}@D_j&nx{0Cv5U&>->yy3Hwhdu}PlhM6ki z`?0u~7^sY+(_oS1;82v2A`d7MG=UAG?5>QN)=E##1N4dAP_`40s;a8LR5NJDM1KC zN9hT|R(nBGoihJP!d|0oP67@3$)vaqtTbI>a^@qkXyfBOUzBQrA-6TNmM z{c{i#FEig6b;FbVH}A7Z2MB09&Uno#WAv_5&}Nh@d%^8d3>&+Uu!yLboVjp& z+Bz36=^9@(F*P%{xOVII9a}ql2S;}gPcLsDU%$Yh;E+&6Soo9JxcG#`q~y%3=h->A zFY@x=6ql5il~+_&y>Do2YR0sDXzl9m!T0uk>i;}8J~2s{`Z_&BBrSbkUitBJb&ayK z`)hCi0QmjquU-rw#(!6f{`~KX{ZD%F()BvQL^mnRU%ePkgwlnPmx=j|`bj>+n=JPO z_@y--vkDkxynffoCUe1tEa>)VlwC+xlPE{|tJ=S5_J2>YnE#Y!|4p&~L$4VSCnE#B z^B8$S5YW-BH_5y8d_XRqrbvk#=|(5$y!AD^7B5OQB(ZIFjP9#lmRGX0PvhOnKkuO; zZzJI2P@Fq-2PBnZ5@ttLEVNlV$j9_;Cu4St8c==?Gv2i68ArSbmFMO$h@FF0ZHITI zDjtIlok8KXg3GStSGct%Ub zteijP7QZt;e|9mu<%EM{kjRRG<*Dt?B9$?0FfsBnKL6Y|GiXKk3ah`{&JWDPYyF)4 zRKDJ|Pd~%#OeHHA{gM@5ok&(Hq8x+Lu}b9buG}asN-1?e+~j!<#Zp=5*4$^0B99nZ z^Lu7FroNu3S4oFbPZnbryPSgT=3<7qhT5f({-{< z@vHoSigtrK=R0n^6(|3*cx9Td(_g)6VU??xT)PmV{J6#g?NjgOx+SVc{0ARTdfa#v zTdf2NcxLz$s@6NNO`ht;aeV_Y_^BO-)tvW+9Q}ed7!A#a!DrnP0YO5=cIGI z9)d2t;+j#)dkdr!CCz$540z-Bw^ZD1FcaGSf}bQ}-XChKk6dL%hzIZ|ijzy1D$_oAOu3&y~oZZqD0THtUZL6=Y)c z`ZukMtJj6X#i z)lPolu;t0QxU$zU{h=o{p%44cHOw}g4t5Zbczy2kM+py}aIq9?g7V(wTGQc4Rf3i3 zcgMS;8!K^Q#sZI46f%qk3p`zmH2PaKydUXSFs~_b+@WCN8(jr`T-YYmzB|KvGUkTL zX8NGYW#+Ya#KI&quJt6X^t63HS6Z6NpuAQd^6$+*SKC`%=IGK{_H9jwGVk1{+`K<@ zn*Vyn=B_CJ_C@FQmyD?cMQ;j<{RsK{8SZuVa$`<@LX?)SIl)oeWCm#db^)w(iA87hBpv*KztU93^vA^cD%CWYndj}31+6u z4(6Xur@cxBMGD3(!Nn0!;zIlu(uuVGTlv?3!|Ay1$poi7F^3iN`)Lt(3`hd-X%B}(v)0>UV^i@_D8;18_lb!D$zKUkv+fpxv4stXxwQ zwk=8x0=yUXgR$y$>tav;G-?k-1bUYEg#Kx44%skwsIwgwwZg)h-tKJPYI=*%WLUU) zw>gDk{836~Qd3{1o2Jk>QKx5Fd>4^m0ksWH`KXtEZEe8Btl2^@<($ZDOn$6zPC8?kW9zEhCw3urNe+<9o8(&U^0L{5S>I5x zxJElnl57rP(9OT%5=?UC18{gLwGTibd1aqV zarH(wBvH>$A2VZs|KWl6h4OakkDGGFm3%fz<YHad&B|P zq`Z0I81!IM#qDVnt0Lp1PyM-LP#p6y=uS1Mo+f}gs!IoMxb8W2&@U6sjzKd&|Fd-x z$Simi)0ID%7z5??C{-VWK;kh-s5YxJP=rO@I1COKAYc2&pj@lV83>k(W~myr@8G2P zXD`)rtj;Ts+LA6in}W|92MXuvx5e0+ds#2$=-8SWe{Ma$>2&+w4MI1H-7~6KNRD;N z%&40x92s1ZCm|s*OZOX012+X5jmh;c_3{8O`!_?1##}##T6)uS+2BrIb`W(Na6L3Z zK7hOzY9g200EMK2g+v#n2~FtsDIorbZA;dz1hWoI=E|1&4=)W8L#dx-i_Sp1u7}-N zxbGk}M~pBbjBk)_3xWdz8LtuS+-~fc+wyRJ!U!{n8ddOh z+x-{@eq7sEvLD)@uobc)Unq+?Q)s@)nvQ{=RF_ez>NM+ zCtaEj{YSzya9swF-vfbAikf5o4~LY0B2)}k(J8{GZi!nmwQ<+TYI#)rZJW$pX1UxD zmJ5`K{i_t$*v$u69kO><6oew-O&pwOhWSnP&Uij<#n?V`bXdz7>l8XfWSX3a@a7kA zRmtwy4aX!v+>TC8br~@61KW55VM;Lw3?G@&^26E8r%9Jjt z0>?|-V?<9v{5Q>Rx2J()(aipO_hCBSO7J97L~4}2W}nBdl>}i&$q2~StKlleypvhJ zqjqs0C&o%lbp=`#CCztD`E3fFi%#4z%#S&$noF(`!`u$zT1Rf`~Yc_ z+C2tw4lF`|YfWI`V-O6Hy&Vhz)pu9M{)zd9>iOW2X??N(oM!zaN87=)4Q|o9--}$P z_Q8NLTs8jv8tv?d_hWh>9G9B1eEXA)Kf{Ty_vOCY8;4cx2=f_@@^o4oCW9Kt4g2{N z;S>W|9~`HF98v+!>{oP-+)r^$n3oLDx>#2$_{@S6@AkC&Va!#xXkGV<$fuI<=+O7R z1e)&Xvz4*#KH8a`+(VoX7WzS*-bQ~9NGgQry@6XCiJMo&P(~^66slA0YO6E=w`irv zzZUEt`}MIi6?;OlSmL?W*u^l`8yriQ%E`BA1|71fug9S3W6}#`` zD%VUhEfXie>d&lHC0-nuyi~(cIVlFYVdQZAM+^28gAWxBkrnIj*7-!6e6;NQbwb`7 z7e4!x>3=8wyfjC{fH-^BTF?!amAQjHS6)ZJ7%x0824q!r!b#wmc|}5PohSOz8uvbY9QH0vFqbVX9Y61 zT}NH}gxtDqKHxHcZ=Df4ne!?oPqZjVJ#lG5eQ18C>gJ+H(wk6ke zG2I0VQov=BLf^K?EKuH!V-K>jymB6qzr#?0D09$?&sa?II6*QiJY&Ae8jR>F&*{>d z-G`*m#C>Txlv9supfg)_e^3c^OB1iZEFo;WR`%uRn0t;vZM%hUkh*I5GN&r=9Op8; zuakw+OOZwtmY#x$g5C+LS?OxN)xU%Xz99V(Z%W zdqyAZEyU(K7j8^Z=zAgCk0&P|?6GYu{Gf2fn*De@+OhG}45Abp-2F!5@MQa|RTqUZ ze@&G~6W_kh#W@gnC7F^%w8w5gX?&(}Ax7hrp>(4n<08zi7c2m3r9fhXC9Q8$;?YFw z)SIgp%(sIBMKF}$r#F-hpX8{Uh}8td-DC23ZO#ClIR<$aqU;FNJEV+qVB2I0t0t6J z))+#Nx;TM#gax0Nl7bc-4%o+t%JBL(*}03RI(fL=Z2P&U$k<2YK?9ai%2Zn*{}`ml z>u1}+Hui0omRe>y^3bgOPw?`F_tdAmzd#7JUh7n0UE$u#M|RgJ{-q`T#QH=jv9aKb z!C>)kS5z94yxyhl2Y(?w*;ts~6da75pR;JWW?vosuFn-lAE#nKXiq<+mzkWpjd!-j zhepXx?Gw&JQ&3+F##7d;pc5<*x~XwuZXQyo0i ztIb%7YocZ(bkVGP2=&iY6Nl1=TJhTy(Rlk!RZQ^-paCQN>XBfRh{*k{^be}UOcDW# z@Lz7qw4WA2#N;MsM6XF`Wa_4VHZ?n)rc?lgl6S8Gfh8`!`?@)$Rr7wiyMC>8)s_9? z^L{#+%(nTr#ANTqnlIhCdi8dy;BDp;(FPtsK_xIiOi!hHFV3;_MX6_Xrs1P;^QRpNbC#?jC5DdXlk6)cQ?&+Sz<94KTccY1f-usKgyQa} zNN-(IE2c=!?aW}P(yi6~aL;P>3+6Q}!!{(-)RJJ^M55gWyCNfLA-)xzjy0x$jmQ<0 zsT8$0ky8hm#>F5MdzPn_zI1JXto=jI#8 z2c(4*EjTZv6V1CugIs_f+!}bjKI%BD$0suVX>2QpxHWn&(PXEZif&~_8Tq{8PB)NQ zGdKtMQj{FXb_rAzX|?fpIp9>K-ZAB0=joKPAT;ESlnIk~@urCNrWDicDIHL>`bqF9 zs@sHY3jkd_OOy3WB@MWybf`B`xRU3F0>Vzc%mC6XFV?+bYA{|-QHW7sc6LkbWqsZF zpH_T*9RPW-klZ?zpoJ521k79rjSKt;>&}Pkx_VqomkZA-w9Ex76nd69e*9tU$;0qa zRlNV|ZIP#<5=X`KEy=eY$a0vF12QPySAYVNQ}&k*Rm5d0GBqUXOpC7FzVojr3I1M{ zF>7grSNe^Y)V0qX+v(5?7w#iMdk6;7Kp{Eang=)rIpBbJoDlVDku>>exL)te>NC7& zU7w#p&!Bt5O;GIBPf0&y8nP6W4Sv3fHh6IK3Ta7fzr3^^qsg6!7HFzJ3FsblM#;8e zp%C70KMA|e_|Q^iE@g7RsOg;?Si(cu=3(RKaQ>{N^mILSvMWjX7{uRkX5A5z+=PzK zH!UV6Zq>^*VOu78#6AxNLwU~G{6xL#zm#fRzBRoc#}wHVx~L+xOESo&7&#SmR;`N3 zzkX%N-g;D6yRFbzWa~NG(gGEUdG--B^2~xc+!6G9d{M$c^4-xJ1Fe}Ml6WtLYi=tG zb*dn^?%QXNw~=7$g-1D=*KWLOSrEy-wcPhyM3L=oNK-XX--DAVBb$t*QEz#dxF8?o zn&pUdd96$wgS^$E`F_pF^b(7c>KJlaZzs4*XQT2vuy3LvdQEf(18i7nMpENgpFcaP z=difViM&6isgyghRj-Ooh4g6K5_)=vyViU*zby^g`AR8rZ2K%JP0|q#o4aedG)dqr zB@6F}d#n}=NgxD5bLP*rPIxp;)FX{l>QBe~v5@Sx@EOg!cj}Htp2;pNyrtq5cM8?p zlLWogA-6{NF1W!CRz!G;0VlcWX(b8Tmpo;S#gI4K$28$GvMVMXg(=r%rHwr9UcRhO zsuu?{`W2}H_p5-uo^Im?01Yqm#kAsjINGJ>XQrv@-W6K4Ta8`Np1AUS+a%uD)H7-N zr1PJmzR`vh@x50TLW$G@WF!cxG7`9U`((#c8qqmh0pmjsfw)mv(tH zc$))H;!fa_Y)VMeQWGk0z5=`%9|}Z;L3xa2-Bbuw8}91W51wAr36>Jh?aAz01Pi*- zJ(1G6zLX9XV7Bv5Hnu~y{ZM_3mwHtilP35~7RLJyB}~_8^VkXqZo0g&urxpB?IyKlevi-@Ft5Kj!2u)#uOz~!|XMxr7ZvKH`9AI zcRlUT@|}pHV+jxlR{cH^#SI*OJU9jkQmtyJm&hIMB~**4pgkI)<%?Xy+jfc&I?$78 z{3@j%)~e%h)oJR-Sy7hfswt$EnWCL|*tn$ltw*w${!G4R5ZNJX*&F zd?MIb!UPN=djjC83`j=4>_gfIeMaJN-Ydj02oL6iH0@a)+2OSbLKjrVjla)0I^@l; zp0-~y640OQ&RqVMXRv>w0`&WqB?Xgs%Y2NEK*$5toUUx!NR(VzY3)xJt%)YVu?^Fw zJ95=Pj8E+fG<1T=bdP`dRMz6wtSJBI)OS=6zijn)!V+}RywNMD|GF~HR#}-Bf9_8 zuH;p&&Yzmxs@Z<*=S-zs-nhiT*+0Ct`g)o2YI`liqFH(7`ymkExn-kEPUe4a`c%y^*{h01o~AvJP-7xf(Fs zva!c6Hb9O2?q0Ggg69Ml7K8?3ByO+_%y@5d&T|3d;B-BcT11W-qc6I_G?<%yS(uVPs5yMgxiIdQ&j)cLBAl;;ATuhlos_09h?X*L%0pt5HwFxPUQ!2i#kDx z?xuz+wTtnZ+PT-{YzPDGuJ-=$RfiL9GVK-SU%pGw`!e5<&!wyHk4+U)lk(HVvU zmNLZKVGV3@AA70%&$#c3~4u<*uawlNj)VRQs8w@0TcHKI9L#g}TchvOZ8BJ>= zI)*`#3z6Gt4g3KzjzR9U`eRUI^-S$BjHJ-2w)2Wj@l7)5uPA+vVtBZ~C$Ix%WW$;8-OJl*W6cj}5J=nmz{Io1G&jvYiz!Ws z$Q`!_=RllSON0>?90*PNmOWzGt%GtxQ#uEkb4@MJK(ai)yLc9nU8f_yFv4h3$l&v) zW}AYK-_a*_tm(-3(OMQwaG?+W=VCpz@xd_&sM_Oz0|zNbc-kEm5IrEJgiBla72x{Y zhu%`kZB$nquz3tJ6Fdgxq@w9dkxRA7ziR!<68{<#|NovHSJB+GOL%chg-x-lM2-t! z*6C=_TGSqLj|7j$i9~6ve?eps>)NXj z;Df2z=QmhlX`dW*lBt&$7estqE>TcaIo+e&)IIwqF87VI-uu%5yt{hO<=j8XJl@-O z*>tfeSrZHGf+QO#zNMIS+54b*gQ1b$W)oWyaupM)rR^_g0@cOcGdczYC?_xF)ydx$ zO?FqeN zr^e%FyMF$;)7^!6%Mb$T3h0^f4_4#HyR475T}olcASnu}1@}2x?%$%G^vGw`Oio_e zx?^N-R*moe6hSB8MV(5Wn}b_6_nn}7#*9Br&(Sf|B|F@E+{YAO4qphzuUd_-J1W1> z8eL3(O#DARAq!ro4S|_iSUTy9fG3wnXqR1<=uUYk^@4S$^&ftxW6;T5G&Lk0@IuF+ zf5~HLTxt+tGa^-hfw({(f-pmVTEVGeE-1x6?fQm z86I2y*MQjnv#$(JHshLeQ0tbl;8cT|KfPNQ1o2ISmdZA-*Xo|K-iu_#he>X4)RU!W zjApF6j+Cx9>!n0048DDAkm2IR?eIG#aq5&t0DmqWMOg{zQ$vu70N$+gx z{d(XZ^PoAt&(K4R^EJu~6Fy;B@$mB7i;~04k=%E;(~$gS^d0?L)0d`#>K7ZQCpMZc z5o0TaO$k9o7d<{*N*oaIoN#|sd26TP1OvH#<28A}bOL#kRL?^7B7YnAb1Yn*uPu{V zn|jb}(?uzz6^Qb2&pC;1P~S&+@ta%E)tAxz?frYx0(!4((gTmYc;!R}celm9B{-;~CEp9(Svv+`92dV)z;>zO^ zzgy+m+OJ{vMcT3wl6Fzb)t-xbH8 z{To{8N2M;cF1N@mG(X7Eb1wH|kgr|!|3wD~{&10_sHISEk`B=ckW=t`V`0+9I@R4nOG7h*&Z%r#`&r#_!j%bLQ^aJQXQXKdg1pQA|L4O1bQh6EI z=2?M;THwR0-y;cB$7XBh!Fv*TuH|;@txlzfOz#_ist+P_Bp06OIh7*TyZ(fxXx?c_ zo4T1W$ny=qJmSBYohh0H$fZtZeA%gcdilo5NdY?Y4MCh*UlQ(9QF8#YUsFBW$gqU{ z{n}C>!nA2rSxtGUDQ<%hMPHxMye-+wne%2!oMdLRJ1nQ)ZPKBij_yv{SqyoleGw%r zk5;WM_faF=yw4eaV?ymZ6fU;?!dkj9%LJS!U~{$ZP_$cVv$GM9p-0<^fnx};*= z>$^0>>Bo;iTTs06D%PU-EjMj?SGp|iER93=V+rm%Fk_F@bwJjPD@mZWMPG{u!pY_6n=aO6EUVMt;Ex8YsckiI~AXcb^=)kvA9 zsKqyNr@)92U;%A3Oq3!|CwZ|h&#i;!df(~fM)0PLVC*MpLw(E#;VjW8uWD4nygGRv zQvy_-c?}rB`BTMBQY?ApN{im2K-BH*OLfFsI@ge>es-)mebXMWO@-e7y>j;4FMTAhNK~kX<^pbxmxo^oXR&&nL z+0L4*g^AU(BGvQE%^LbD2d1dK>l5&oC`hgFx8HnhjBRiNIWTqlLm^FO@p|ge3WXE{ zDa3*);ep)fZ67bnY zA@vR-%v{Jd&zwGTewgrjo9&-z^wl=5k!ole(>iiUns6qFPda6~- zdMqM|VbW;pFJi-l%PQh`#L_d*K=Yi2imX2GNlNo5%FL%h&#t zr!+lTi~w^}uTBJ`H!pMCeCV&~9R7JIgu|oXJT~{HQB~-tRMBU8*mMt|mV7`H3XQ8p zY8}-d73{+zjHmRr8-CB?8k#Ocx0U>t`||eTY9Ue1hi|{mAoCCRFO4=0>26=8usmIE z9pC(a*#Q^ZML#2b3c=3!@a$fHW4LG&=S9_1WxGC zJT$1RU3U>34`#dfK5gc}ZaivwWxCgDm^`ek%K1pQ#*D%7D(o|MFLxsyDjXl|%-aM$ z@$*18t(-VZ)QLkf!itS5OZ}cLWM}Ys=Qzlpk5wKI^WAxWmG$0{YVP6XW02RX3+Fh5 zczzc`1-Wh{Ry>bq#DIVNlD-JW4K*3)>^ZbrBG$BJr&!$9_&qf_GTGZ$n<8|Jc{gS)1PG)Rb zs1Rrue3CW};aAfOBf4@!r9>yNW)VUeOIB)kN2wQl{g}6Ei=jf=&*?1g^)3}dTVa#Em^buoxX|T?ZF@7e4ckJe z#~R!(nnU{uioXmp`8p4KP5azxmZ*gmqMpl~y-E8>9*M(pl&;PY+Fpyof+g)N+b7lJ zykb1fx6i;EyX1J$%1LvAlh3n3`%ezd5uW$7xfZtt(uKGpXuR);;B(`LH|sn4_P@NQ zQ;c2JHqafrbe~<#M<(PLlvx3uVeHXy6~HnsIzeJP&NehtoXeWD-)LQqfJPJ=Sc-1C z$!>k%khR=T-IO(W)Qa`uR~Qz)aP279lT1UG`b7y(A;H8EAs>S?S+3)CjcQDW<*RHf z4*D;1#_UbbXZp;Xm313=0637r?xZE8QXB7Vu4 z3ek%m+-k?my&f(S@llnD2IG}J?~H(tsHX?qlKO+?v@g1n&8Kyx%J@1P;I`SRhmjE zPM6?yZj)*TeZHCoRs%h2-keW6?q#s=JW*=1UQ*aNDy4c8q}vHt!vJ?LJ(+rht+~qL z$-8S8?5|-g&OA^unn9eocHV7Cmbp9dPyNO$2_gc;k@M)V8R?rV+7 zZ1u&h9WBZ8ir12m&G(f**Sy@X*8CwiRQRDUc)Jdqo2zl2%X3?Op&J9Hp{~QBZnh59JBu8dJFQ_EDDy zX~PruusZ=C0#?Grbv!ob+PG572b&)-r9G_BZeM-0zQBqe*lfhgRj8O~>IAs=EXH~ z62=quig$49g)k2!R~IioZ8+TxTai9`PSxwsBd4c$O-aKb-7cceC)X{WSj3D;8X*?j zV#MF7?3*x{H|d)oTS&9CjLsV`6h78Z!_5J?YWsNyOw7s?v$22D-L>-;Bdm08wOsFI znwt8&b-@21ovHV25W_u4F3KC>VW_ao@&@sHj=n5Q_R>Y?y{F>sbPw9kEEfPNX} zh`x15bNex}ORak{Fxz&JHzP9+@rG|~%5=86Qst$*snRZxDZRiIl=sr6>x^2p&UC;E zwa9h9S#Pj;TV_l381(D}dSi$(NmE2Z$jtG@S_g^9o1u%f3XT-hYAB4|;p_ZeM`Ojb zN2P)axe?}Xdt$5Zzc8&8^)Dyo_8#dF)v;Itm5p>{Y%->~JlRwTw|*b{)i)<@`g*3` zSnpUiZyPpbT{$uOf+AQ9ez?YwxS(`FsFXwt8J^*-@?U9BDjULY?rToq6{~YXQ6_CDlf#gQ;-E zH!v3!Rz<#1~e#cRAQ<0D*%j)XL z(|CakzQyJXC$5gan^p2?F|;yYqozD=UgZ8Y>nYHCG-YmrIOM|#C2P9Ag!kK#LJ+q+)2S! zrp{6$R{0T050=LWAgjIFuBykO+D7NHGO|9_q_a_@rt}mlfhR;%kCM~22rzJ!;)sBo zi%FL7d|My2ER!!47|iS!#HvZQnajJaO8tD)vMZ?c4nUI|`lJ+rq(!=KjpC+;z6MaY z$YljJzA&M8#MLHyRX1FOycdVya<%EF2X-uhj99Yz$R+rp=9-xAIM%rgd3D!7dIre( zf!B$Wp3uzDZ`vE&m+v)~8ouPN8ap~#{jWG4htIkZIq3nb@~c%F<0B$0jW$;85&{ z)*n5O(N;S{_;;i7qcs~iLSYPt8Ai%`2>UV0WML=Td*txus@0MTH(uDTH78-Q!1W|B zWkV6lLwWLInP?fXEf#p#3h?raKz|PV?(u3;0-U@>^Qtb1la2C370F3 ze@#C>eb3PzUlY!m%F^Vq;-21;jV&*bNM2sHRy^a2Z2VoFj5|vE)$Zd*n3+mbm2H^Z zpa%F#JAGv>O#~9`FcUdf17)}fLl1a7&7VE%IW5jPuX6MPdxyeu=z5oe!*glSj~@9? z#k6AKEb;S_ay3DReQnwpTlvkRWmVaXp6(G7PgcR(Cqx*F)Aw`9-w2})vw$#u40z+p zH$=QZypud|XraYgga7sT<+l_=u^A1kmB`}zb~o4_38Bd>B)cSJ7`e@b(u{#s`03=# zD^l*%7N$6L!h-jmtQ@z*os3FKpwf7O0MDiJ%x*xj;v$f_$sF8#df(oy3 z3u01&zTP80O!=p&C{iwHcGexrH4#xef02afYPAqAbFskiMY=Cebsgg3T-aL4Wv@v& z6z0h-Obs+}jmt~rY37>n_*{#6{QaHAnf||XoaOJ&l;z&CUT89uR~p-qYXAqMAnMA?R5O~;E>C~YuXnY-xSue{3n4X zMd1{)ZK|0EBFrfgwo{=(`n~#!U;I{kqt>klP`26 z(e3v!=<6S~?m3wu+NW81Te{RL`y*G}hc8EsuY^TBLe}^X=FMn!fNA|M5lD zm8R9nVCPfEAlG=$tB1O?GuBY1`oHPevziHu_RU>C}tf zqSLvySjpn)f8Nah%uXWb#++FXcU%!2Y)Pj=DB#W_ zoo4b@b&0Q7&f|dnLWRv${nU--_n+KP_+TqXH{P5*v&-Z8#B@nym&YqdaCVQgf};lYZ8~D%6;i z7{3N&dUbPZD^%aft)#=CesImiUu~V<$OFSVChvh3>GN-~^=DSJ9I2JNoQ>4t$T-iKWGYcJ`|OQqE-GBt3y)b zA3{}IllI#_j3K!K>J+A%oNxPCLYJMaR-C@|ZrF&yLC2KaA_`a~Da{hzJcbmJkFRjAyRI4f=;McYo zqTu!iN)>Qz#JaiR?Fpsr4c1`mb8{FxE$#ldUW>2qhh(F(<8IelpG5LZX~DndnjIA( zt-_9;R4-63CUi~hh8g|X5a#nGv7P$3Cc878&hQb2<$Xyg#B5OZQArt86S{|i3(Z~X zqu{^P*zlY2?U-*^yoCW6-!huJ4LO4LuW5HJPSM&iN2lPDzPVBA|{g zrM|q_bo;SAm})2NQ_7%so@ddTY#PgbCG)n>!uU2+DukbEO$1LD^x}l|^ogmrtfqqM z*<9(_T9MR{-j&Zmm{8L~JwjsQr&B*AlWyN*)E1!Vpx=2vK^oW2_!(#s;@`pU2QOVd zG#~5RI1sW6->T-KhT4uNaTx2DXMW0591xz@!@>;GNh9%6(v*dd`l!VpDSCmDEA=EW z=R6Ry-gCAz5u=4~>)y}ulj~iSxNxqu`uxSOtn3WEKV2JF63SL}i*oA#yS`AzgjlaJ zETm#?ZpL@szqro1+vAIasmcnk{$Ttcjak9dMzV4l+CpP3N99y4s8(4jBpT_VXB9}g zMbshxj2Wu0-D524ujrAC8=0n7s*pZ^ZqPWf6n5pkfPeAfC6%o_5^#@_MF#*6Qh#kr zu7*Cb=4|!c%&tRo-o$!Y|4RJ2`a7Ui!zSd$?TYXe^P|FGRw}#{d5xl$_G$uY!Sa+l zMeCAE&=V;1k+5;g*qO!{`6AQDe3u`e^$K%%d2#XLR|fA+bmMj$)w>3Pvb1JI^qD90 zgg3t?4nU9oAxx@}2oExeTaCZ<+7hyc47~#n@urWTUavl@XItO5AOxVVl2=lRY9J_h zI!cW)jDZr5q<%T|JtP=ntU^PipJ_m{yqO21&!2O?Atlxjls7Pp zo9GP39~Pp( z`|x(0da2r%*LkKdEI`v*Wj(Ak8$A$n@yi2dhUf7H_d$$(bU%Ez=MhpEupp^;lVXtC z9g|eAB7Vy7TlDl#Wq(+0FjL1e zgtsL@j}2Z14AuPltz%uWPI2^ee3(OE-BdN2X@qrL>^9r45&9;Oe(l{+wkCudQ8s+o z8IDg#K&q7^2qV3ODDk(WHcC*Z7r#Dis7l9{B)=<}_qg@&g`LGI@gccLZqjx)8gMM) zaAie3KzS}Xj0U3`Bhe#t*E^~l7P-9n4YzJEw7fMkfC~{9H)rww?_xRsnfQs|GUNnm zEZ91^wGq9(O*`!x);G1W9}<#5yXj;KVc+xHK}SP&>EVNoS5WZbwP<}uY{PyfAsBUv zHb`fg1aEV%Ve-Ao%Mm*EtqtuBg|CZdJQ_1H&A%IoO4^?g;V}dy@9D14WC4D2pqPBv zgX6*)28O}Q5arieN4Mn~f-RQfN%E;P+QFWu1k>1TMSBfbuYhx1`Efq=sc7;iG3%~E z9a3oW1KJtD+J*o}8j{2#9ZCBCz=S@}UoLR)D73dsqUV8@kruT3Bo?QfDc)Ad(CBQ;#=L%!6$>BX>1$}3Zhzj35k&V zYB5DJ1-&|5(!wKqLEN{k*c_1 z)P6H=dw;LJ%s%mbhf~bA@Pk*}l?+TLbj2KZd<>+K!8{*?eocZf7zy!)kCzC2yc7`cvQ~>wPYo=U@@U*MuHhT3Gupc6vG4tU-N#yA<)bZ zQ8g6_eEE3wKXS+aJF1M`bLt6VhwRxkgVTP$rSf<({_vp0=sTyC!j16`Ug}MXNkXzJ zU-wlYrP^s-*P#3%QN^?brn0dzo|iZ)k-BeRo~S-J6rk~H@G1|t(|@HK{e7+H1@E3utu9MW+d-_k5}w{Gru*Y*@201MREA7#^+oXnjp0M}CAoW2Zr$?qH_}&S~#+A7(GM`{YJkn{ahUH3!FU$89`BtWArTNv{8Dd^Ef>RIF@h> z>MW%v-AdL6youJU?_6Lp5JVc_a_z{j-9wD#6Xn+DU`8`t>Y?XQ!9QdM12*iZ;LJ7S lEq9EB+ju|L&L}bn8dcona|z2lT5gQ&OtO67`nJ}6eGjzy;?K2=$dNM*Du8ck%)EX8L@4C>GR zNl#s2R}m(6Gg9Eg2ZIH7@3;vobN_&z&NGg>@)oOd$8U#wq1H97TWQwCt{G`bCZF$N zt*${HnT@C3fk4Q}6lfriu6E)>J}@I85NbA3$h#m*Jcv#-91=(pdljPbR~ZDt^KULX zNr1=3##$D4sS#W;7uHV~K)elQUBgY4M|Ym+Pgxj?2-5Wsw%RH}*&H7K4~F|UbN&)V zULhpR&CM+~sjDh08?e;2vRW9ee6FpnO+Y|^Ss-h%w6>O)m-qGYu@g#WSH=$g{5dMD z0MR#Zvz&2rbK{CvN>a(y;gOJ#*q~z>gX#?}^(5YHvDCJ+`)EVPt6wY>F38M0{XI>h z>N?q1yc2gr!@I}_$H&KKKZAnsPp__oSyIx_dF z3VeW<8U+S;6%lber1RUi?Y%u^b#-gH-0bXDwNkPBNT-DXhlyHQV()_y>kXPafut*2 zmfUbS+mxxN)1?c$heaMQO@kDUjf+cxKcTv^vJ^fxI?9vKO@NP&riOd(^@?7DLH+h) z>xE$|V{oJ)zu(!9Dk&*H8`n(-S$v{Xr4LKL*JC#6w{P>Y=(Op+J zzBkxSqs$yB!ps~)yPAIj&lcMPwx1%G*x0n1qCNpswsC{TU!+Bi(HnN@4*W&aZ59S(;YuG z?BwL+`RO4Q;$uO9YOb5RyD%*K!-o&m)wn86F@B_z=My4wMrQ0*6TeCA+oYu1^z=Ua z%bJyj8=rnbjFmFtaxybBi;MZeOI&=^QX9bi#fujvCU*|)`59c?%9dAFU|4A(|HBE- zy1KgOc6KN~zapb3%4zN&OO`WC77b^+-I=}mMTWBL+eu-5IPnDzu>iCAt*xo?@j|V9 zH}Q#R*kctQ3dGsjnW3SfOkM2cR-l2-O~Mp#*!yt+_BKMvu*V@o!^7TQUWuMLxV7M* zAOo!5{&I}X)wQ73=5LULd(3Le@YiGzk&yo}v-~R+>|Tg`&A>w59SZf*T3?WC1Rh;A zh2Un!xr4_j{x^K}ucQ7UH7j#YQliV!z&@!{6^=MRPz4-!oyNzr2O5*~0+%(-z=H>_t{!!Z~P2j=S4t5lq7Y-kiH1a59_DJiLoiworh{^1oj zAqjVyaLPGU#^w0RU>;P$qi1zdtwsEe>!AY%P{l%bLS9}TDJe$2e{{6=X-CvmQkq0Z z7yf{N0Ogc)-_05@O26B{(hLQHLp6D5V4yicNK~|=wbkkR(ZPY~r|W z$PZ5Up|rG~p!_bXTsChDn>#%2>gpPwn4l(UJKC93&yeb+-c1NnRaKQfUr`sP?>*QU zJ4Pg_U{g{geD-ZTJrB#u?!|F5R?3NeK#`bmr@Jph z8p^;>pp_pK6m+mT(M`STRx9SZ$Q9p}n3&krr4)|n!YkFWaXC6;23wz(lXIOx1THCA zpOe#;z1tqiFy()09}bb}YXNr$nB2LfyStl@EHA?ON#-hU66^?A{Ou4ir|GZD{aLC$ z29~ zLi;Db*WlfzjsB8CLT@eT_Q(PMy12OfEJU(82cn|^wSrbr4nG}zUSd+?l2cdbyYxK` zi9{M>z-U_&b^3XOe1;VYbnm@?W%lL}b)mPJS_iC#F2pMmycfRzlmKnJt-*n}pS|}uy2}8V=p)-vTcPB4 zloS-E15^|g9=I)2Okw917e!p=zftq*Ra93iGrkl2sF@|_?&(<$H!?H3?783PgkhC? zy}Z0^jywRnIA9SWlEB181&Xw&sAz!osZPeQm#Q4^!jZBHj))0nTj801`lRtW_o*j;oVi0l^8U7o7!V*@(wL6ZfuPA zPT(@#s++i(nOVb+?(PTlh8S^ixIfTc| zWaX&P2n!1X68Qc5H~5@F?L{g+4sLokYzLJ>ag9EH`g9I@u^kEk4H_Nsr7MO?D>K^v zkql|?8_X6~q7I!$1d}NkmXnj4toPLyhxEVP*xbZ+FQ8xv0#Q(DesOrFrr2blB28*> zadDc2=dR-g>IUe0<2kz%b)MXDvX37Je~R{fHuCEi9X-8W*&wLR>1p$NQvov82M>2pPc^t7}IfNkr(bY%InBq2Z|z8jS| zv?G0bdiwL9g)v?|infbAN%|$G!gOR39_wL|kqacWa03k;ouSD|{)aUEpJY=a$loH~ zQ=HE}^78UhRgG-rFU%UY14L}IYqK|Xd2u*i<62%`9heEpj2f+@X4u;*9lQ@}$iv;8Y>nwpwq zEeed7Wey7qpvdLqLX>inA2`nfHPlP(;pS#jIXcr4>e`85dC|X^Nsu#aSO4WpPw?@E zV?dqlAje7!Wu)=RkIjiX&bUq>McLs{VLP3SrAg_Foi}%%wqGG4x?B(lnBfIIvnT1k ze2$iCqTtH_MqWb&Y357}qM7o!jZNa+ry*MTsZxGE0F<3gOp-osqZPI{@xr3Ua#d3% zz2>erXei8{H2>WYt6E}6OEyy(!c~7se7XdcC-7xEi2AyIv9ax*Ibr-#M!-dcK*O|Y zN+ZUoi}t&uCQ*-lSVau0Jd>D9c0mCzCnqNi)-*ChM(6D8Oc?y~G96#C-%$~g^9MEQ z>78+$Mjxk>4_Vbr8-5_`2iff+-!1E5O8LnZzc5Jy3&dN)%~+eE;CRr{LO9m zuR5RP!61)_f!fdTKe5%)iY+II3F0M%a59LyeOR+5ncWw#n(?K9EG#Tw?_u^Cowvyl zWe_J5{&=_(1O9(+@|u&fX^9rXi%VCN*K1|C9?(jOyK^L|h}aHf1C;`lfD=0(AD?!v zN`7%MO_Yj{&q)|1D?L5E)bTtOr>qh$P|T-u)7WY0db90*?z6`I{e9q~E;<0T0DLSk zL^qgpbal_c@fQHKT~Ofa6?ooK!hAy=%0|k$=IX4GEUZV=ck}(UO4J2u6aG!#JmVAR zcdUMVIwq`xOmZ!AuPtEE2_b6eIRBAUCEUDEa!`%eSv-$MeF;=h=Y zs5-~e$CBQ=*$D|aW-&1Zvxs1&!cra~FD&t$7t!#BiRzK}>EiB6`8wj~7vC(7T5g#z z>i9(JzHcg*SvH^3>TJd^Ii*Yai3wxpIte&g>L!`B$_6#5lcxjWh^_H$7_1g`_~t&duF`O1;>vcZ4`y zEslp1!xR-20XkNGynmc_hZuqiRX%eF6ARCIf=9@=tL8+R3w=(_pVxdv!yC)Gcq zI47W!g_~RPnFN|*?0|4u>xG1wWmWpUW(V8-EgFTzkLtJok2(8|y7mYEFMRzB4dcMt zZ}KpzuPY#1$ou>`(IOF4m9#V{Gq(^6B_*ZxTPgSBuIlq|0I7+Nw$AYT>Clh&Ir>5k z+uV%U-Eb#56wrS{>+z2{1~obF;%#Ka&|L;3kxR`(X68o*O|ha=s5pw@82ZDo-RAAkew+QhJy!I1gWnj_U*gNYG~walWG!zK5~vVe-QBlCO5Kp` zZXo2~Gpb_aS|K5${JvNAJ? zfn+gz#y1rLf*&~<8FXkUsr2nq3v&qhkCMT%#<-l1AC;b%>g(zPV-6<6T7mR}7-r^w z%nk!J25eYpWi*`M_%j6!4bAP_BTJs8h2$UzDpaO{Pgr`N|HiS$%IfK1K_)Q172=ej zH8L`Sjz*)eh>Gr*Bw(@a9UaewlFP08LPA3&;140V{w2$mjg5)M0BKluZSAO~lD@t^ z72?&aS3bVJ_6+fJu~$7gJ*L0nJvnAt2cbt&QqueP@8#bx=@tx=M_m7!voD6^;o(_b zU7eks&CJSD6_J&f?`UuTIXvt<0-r0o#9cPIWN+Zb#gXOYr-?LNzQY17q)LY-DUW$t=%xVPOWVqfZeg)v>%>@W% zEB@Gf^QZqN9sI9u`(JZLmMuquGuvwrAN4`hZAc@66jBVS2L0?muL}H~p3C5(d4?zT zTV9Ev6aSr~SA~2uoG==wd`Z+%G=ja zWNtofND&bSm2`&Cy)wjgdE9&w+2t`;O5ii%nCJu& z5(Kl36Scagrr)7a(Ru}GQhwmCI0kxpQ`AnIzNt5ccdFj^Fqr5DFqa-@M>`-~Ax@cJ zT>LpSG{3Z@EX0WhGJSoqH$_ZLtQ*T$=dm#gTn9!TCZ3JR46X6rduC=fm7JX1-rhbm zGz9ilV^fWBq04I8ZLHcc;PMxXH;QLi@!O&f#(#pelW#GsXJWP>pp;g+ zvNx=6mV|rr>ebDk37eJ!*@`H^@yyoDCZ~NL$-}(T8gj7ewt6Y&S@fqFVB~wplEG2{ zQ>O5;p|_RKcF)7e^P`t7qV7mky?_7G_Z);K0M445YPVwB0yRxcdea7N#rN< zru%&lTM~HVmFi9V>K*LusYTW|H)%EvD{4N`!?HmfY1x?hn1{_Lk%@^3RXs5=(Oeok zna0HyftOWXtzV=!_1T#fBotO7)6>&?OMR}-I}QHe4{HUgs;;)S=P?V~&BMc`$SM{xF3+rujmI7R_ZU{xhU|o;J0--$WtOZxJw-3GWCSy%KkD!}SXjW6(}?3R zHiF*X-dXZ*zW4T?&qfGrPS$rP0HHIkRYq~(m|ycLIS04+_x*uPX)Z3P$=u1+HESwO zj4k4&C9r4R2?9%i7eV9$($^xrQ$G<+4=Iag^ysMJ9tS#_l$PJAWNmfTe>)hOsPoxt zhb7#@?^7XA#v{Fv{vfWJjhDkD(_}Toom@~gF zkbSfzT+VY!&+xA!u?y)JVRBaaV(07Be;>J8>H|$LhS`~!{;7#;Gk8mnZUTpwkpU7Y zW#aJ2NJ+14=0=L#KL|Cew9^Gf8$8hfrVO~@fP?akouaa`GC&ZQ?j9as?Gj>QNxc6U z*=sF=m6eqw7({KHC~!K#H>7MF9ZQOe&L_6~I}Qu~HnRrUdf@gz&pdVsHd>`=w#g!R~Idh&}yf>N>E*VDWL? z3nZA#iVB@tDy&tt!^Fpa8+-zSh*z(Uyp)ucsYx&?DMpr-^G(4-f0l-R+IIPCWJJt! z(-=$v5<}x!xBNbHKu>Z}jQM&6)%Ig@J(I`kY2v~j>jnY>C16*aGm3VvgP?P1X^EDS zGA1QuZF7^KK0aqLyQJEuAC@E5Q&V>TwF(B+gHInKxB-KopwlH s^p8-EOa?a26F@q?#{c_=ZMy;H!h|M|sE(|`vqXrZteQ+Q!aV3d0Mn7{E&u=k literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/docs/images/update.png b/app/code/Magento/Analytics/docs/images/update.png new file mode 100644 index 0000000000000000000000000000000000000000..149f5b5d3f9bd4f2ff6c320f07fc4361b0e45557 GIT binary patch literal 7534 zcmdsccT`hfx9tH0se%wdDN;m16cA}5C4zK>7>XcO2@(Y9Jqblcq=V9>Nf1!!A|Qk! zBA_BAgkGgdFGA?;ZGPYTux|1Mo&;qpPU~9UcF@sm+UnAl~!ZYAQy)X-gwmBR2FQd=()? zA*4d}0A6iDlyvr9b@=HJen)b23FM>&27I|vv zT0T%X5tkRJps!u~st7~=s zn~S_8@Z;m-f?3x{r&RqTV)H~&=gfuXduPPXBs#{t`s1C1v|5c30MEme-oU_sl8S0+X=!A5m_x##HNY9mfq6RGE>p7i|{<_ z@F%5Vd}2z<55?4kgoky4VyBUOe0(Xlb4hc_-s$?n2|7xOisXu;7kmLw&?Up%_{2nq z^1NDW(CAxKC_2)b!x6u%SxNllGY%WTRY9;j;UIiLBA8Iaej-%}ALD0|$ zmGsWem8UEd3sSgH? z^GNav3RE{AKFpC1|I|6A-uU&aNVuqo2o&`6DP=f5GF`P~q}t1|BSY!*>C?K2S0u4v z_V=ay!_UD3c%X^N$qTG>ke1M^?QP%O+P-@t_(e9l!!lfRoG`)$g*w>Z2Wuc~} z1kD-7M}yrKB-xC5Sdy4Ok0{+_>(%~xu(w6Q&(9yk!pgz|L6t6J7n>2D2|78MnVH4K z5_|K`68{Phabm(ILzG?H?Qv za4o7a47Uyvs`6%qGjU(ph*MKjRuWzAE5sZGH^@DRUs~F;lYiNGW_tR0aPa4cQPFMU1Qef;Fh~8qpnwtjSXQQ>pn$CuZB>s~?t}ZS37vtrN?f|6 zefu_fb5j|+S)iI#V(LWugwBxMm7{BHY~0Y$@Z`x841$`5hK8CN3=miRX4Mm;?KL$| zo;mU$C5o934h>xv6-`S^!{C@1gE6_SmvpRIc4xC=u5(&fxnD>guP*XinN!t_kl*ok zb3?v2x|VXg@a|B5|Ew1Tfh5`8#k6N__YDazPd&Nv1!riK-&0*xHPGL0WNbVzFmU!% z4$)pwQIS@l*s6A7v9nC@Z-wqV>p3bAQnC*P8{Y-m$L}aA2e=R8w0ry$9sJu&2 z@Oog{Ylq@{7@KfcWu0y7&!4Zay9pAe2`hDMVQORkTb4fgA8W(|6%H0}W#K{-Oz-#X z=exSO&Gp)^)U4}kYlqD(h+VqmHp4@mW|{Na0A(k+J)Arj{CI zW0NRheU6)ZX!66A+}5$^3wcHCC{^0I4ozf0d3kxRPo4MD>-6-I?Z1XQb z`--hs0vk4z;442$g4l%hf2GRB)F+P+d=SZ3pVS)Ra5!)8iqSjgHKUD0 z6QDb0W}>WNMV15_XnJ}Y40d0Rti>-bKIY`)G&djG-^aCE#>d9SzI@rRpZxOW%h=d2 z%itf$z(X7syGPByQG)$=c3A|vliyQ@?numrhaxAt2-#`P@cSWQ;0PuFE55i-oRyr9R_n1_Gv(IYU)KI_2rw6w>j(B73kQ^~!}C9pLQ&CLbJ zO4RRnH8hMzNYwEMzs=1pvZ^(6xw&c9TVy%Z)%7YVN%*B!5tgVjUa&d79$1}E!4RaFJbT`?++fE0YWI8+&f ze+Muynn(Us9?>!mKZt#FE1}=XJ^lB0%0$LQ-W3?At50ozjMwr?d%z4oG%uu zAOKck_bv2v2=({rwU7{+Lz@rz`5Rn44&`xiaie$g^wYy*VuXX$G&G$1OUC8ucbEi( zZrs=<&yl|Qsx8dVGY)P1)Y8`8S#4yd6W|Nj9Q6^xD)Vx2{UkFpG3A(`8L^sv zzP_J6eVX<9{TKwDl&cpJ7AEhr%tL^qv&T7zIDda*QFej1rKQBy)`&UR+0Lxrzkj#4 z>mO2H50oLJPM$nzXb^sS$qKzG)ay_l%o2`IKH_b%Db>$AA8cQ4mWy_BTAIlW1Yr6Y z4u`ih_74n5=COm!3ZVvlb=RlEkWtDcxp{NbyVSHm&IpB?}4sm^3F8B|+vEV?5@Qt6he>Z`c8jx_o8-wjmljJ_C5 zSA%SGQ&UbwMPmJ#b_c*=m^2v}7=}twnrdn%1cVe7aUkKyrSbb8Ls?Zvu`9JHQs`)I zx#*E1BT*$KB^fRzQhi}z8;P_&P=>}#x-N^jxU5uE$kt}0MJWXaue&^s)JzA8DOTAqiS7U@mnu4gT?B+yM1Xt8WK!y%)MVD%{k6g!)XNQL^K+x}q z%+JsJaz!}>czSx;+1cspw#tp+8b^@;dm5fnZvoWs-;+g9SUNa4MTLb`xsE>#I}mF# zJCgHs>>)Gw3k&A~x2EK){t&9-Rre9V9wg{F4@4uX=&yNV+OJ?-}wd3~W z3wL(A+I#X%D1L7)4Pjb8wodY-MLoi8E~aP+iAqSI2QP(lDPcTOsO(Wehw>Zz{5Mzd zr)Q!+6c=YIVJmK5OuhPm(xWZ13?!u$!P{y0vztw+DG1W^^k3Fe|lNMb`Ds z(U?vNwD0F@i3STApIp*r%`9DAOYY`BJcR7S@pwF_6z#Z+DaE4QgcF!%$HF6S=zeRW zSnnt%nC$20rY13CE4>A9t0Lhv z?*Ifcz%!wsKu&ckBNde=rMNYOJ_EuMe0}!>J5rJOZ`6$gM+l#%O@G1lOHWK0a- zHQP|tEYr`f&ezKxsVopO9PWASPtfKpBV&Mm2-i^#FPaEVGI%5DI%!CJ?rRF=QL!r%dNK3mq>zbLFSz7W2h>tD)`YZ2dXzJF(asRUyMl3D0V=S+*Q14>g z-vXn;yRFmis#>nDt3bodHvjyovrF|eEednE`T`E);P_}R60W1CCsTl48Lc(1be_JH zimgunV>tH=w;XL@=%#cyJ^CfUcB>PyLk#^upk#{y&rz?{*5Jtyyo zs3<)vs|+hS#Q?KcEMpoS>+J=~Z+%>X2D-aFe}8!bIDdvR==}^FS0Jd|Oe{fXP6La@ zCg?mYKq7#kun_NaymIN%gQMicMDN9Z$z5mUcghn!FfkF4(CFw2Z}!?RtBdbW&bF${ z%F4Rb?fe1krhja#Ft57$xHYB9I^j(U3{7u3U0wO2lYpfIx5YwiN(LyGBf*f4jg1q<)^l_CZ3p~bl>@JM;@?pLzc z{V+9mK#aT=dJo7Xgk3*BIgs`O9`GcfhQ-9hdd1(y0PH=KLbs>I$HTm*a`n?+1F~ps zT}-qG>M0MA=?reWyRiUfh?{BWExeoG*$(d^ep+pFUt^_}2^e)^3bA`vN?(A?bIC08^4 zSo%13-@X+>qtU{`!n+bhiW@wNzOGH-?3Nq@Gpj3p3>}DtK&$xm?MHHu03q)GEPjbqv-A%bdRf7$a&2)_zKrststI(1x+t!tI}}uZz{^vh6)Q%ErsK z&0usdyv{qc_2C5s1jYi7l#cfFPjme)z*W&2hO@vI>b)qyJM)4j>}n3}S>e!7%3PSh z`CwKgL`z2}@9`&cRDl9qe*y*un3<0@hg?oFpL@Kd%EC&&P_Nl{=V-f^y4!_uxKjN0 z9^0MFtFB|!K`isE$Ck;0m0DwCqu!CS7pdNNWV#ViR)pt&!&3P-sz%C1ZDeF58;_TD9yT>Hdb?$WL=u~$xWPy=R+j`SR9l;l zk?~VyrH_Y)d5v$W!Fy@Pm-hS%4X_*;IXT@NgO^%D2|8`qg%anHs89b(Es$B4x?X!} zj(2QKrnv~DnZEuhb)=h{TYGzZX=y1;efrOz*Y9N=HR7FTOsuRs!VE-||YyA+j#llE)t_f80WYizuAg+oqOmQ|IDi|dH&L{RUZ)oDidaW=MDq`Sb?dZRd{}% z0E#z52`eZln0V!$%_b}Hi`_0vDPaFP^sS{uSBMpg)e`#q_wQ|NaoHWU0b$mC^iHHO zBI8?g^X|?LScCV1F4O6G3gGeZHhuf1mfKV_Q=QA_O27tPEQkx<+ghQzdGjVDAjHoP zLC#}!dXbs4q6s>H1Y28MZ}yB>U18iX`ICWfYHCt^Bq}bxydfwCL#l>?r9l7(PC`@e ze!x|bWF@A`x$JIl1G?(76aD-g=Rdv{5uv;jER6s0<43L4+v(A4-AviHZ{I>U?d@mZ zs0`<~x3)6S(YXPe2D1U0RdLhLTkl#g4Gs+WO?;z+L@r+@F&NytcNVfmqkX)+H=T_W zBSid*0@tRruLdMq8yLJwPM%#_^50y%_gwWs=^zUwTkdR*ZqkPjAD%vYMny%nkwMSM z$Vg8Q2JmC+oe@`fiP6!gt{%?hikVk{>^CtoIyTX^&z+&&xSeDeU&l`-YVx^>*SSyY zTy6BSTpuMpkLK`LTbh`_8@#u@mSR>|0VKu(1c4;k*w{$B^|!bZG5mw-UeHeNySw>b z0Aor^-+%Z3EE_2voou47uP=+LRV}7zAPcQN;goczzDwASa@3nH>ktr>|E6#H{}=hU z5laYO9d@E9Q;(>;`hz!^=Gy;5OFpg4p^M8ICAs@oD!XB4kU|!|StqXIExD9&+kjP2 z0JVP-i2lH%Jw8YzLC4y9EJNwx#Ba|Rh31vj;6)&~^p`xri`X@UhlhhuW!-wAp`nqO znAr7SmG*6PyUGm(1^C{g)N|EwkY`ihPoqwXZ^ooehN|JoWKWPnzzqDCzOS~-?-94E zF})ZUbyh0GKL*pTA`)&^?vOwr5c2ZSckd>S5Ap$5kCPLaVh_=1P8OC`(3j%o%AAH| zflI*0mkG#oStY)tq_eF}Oi?in?eaS`hfX^$4S?& z%axUtd943w1D@}xQ>TD`2-MZL9=ETd-U32GQ)|<$kn8kM_Lo|o8}r7{XU{nUQ&ZE9 zjB9SL(Dz@zJUu+HAgS)%OR299)X<-&!%M0;t# z70fCgpB=G(99xUs0&N~1c(@PR8Q|sf?(kJuTzdL(h5}2~-F=pDm+A{3=fGnDvhfd~ zZQ_xloyNUVFDThrPR3z~0%D@#+{SM4SU_gOcY0}=S!})>0|Fa{i-`{G-bvwwA z&6`91T;R#=Rsg#|Dg@Fw-8Dxkrb7#pj@4-fZNQc~W?T}bBh3$Ma% z6+JitK8APTp~@(*$#T!^CTgZNbxLzF9WY_YLBJ6rPcm?dmvG|tw@b%AVj>zle0bij zNVW~%3_bheU(=r@W`nKJgBKMQodZA`mOmMMdPx;PgHoJE6qm87>Fo5hI<4P&n;f4K zrn@ZfHcuLhU{dSAQ3{9$NtXih=f15ondqR!o`b+dt*m{BLH;{EXQ#^+qTy- zn$bLuoScBSaEWjxBs+T&5MLQCJvX<%PpKJ_H^CYK1Fx*A+W8SD4BB3ExMYQI(siFl zNvTyfP2pe}z5l#`+=%9q`AL>>{~acQx2$rf4p4R-sqteo<fUC4ah-t(3_u$2z)(duEdGm5XI7=v*3$!h$iv5{qrKg3{zq$T zoR$#Kq-$GSaIkfxc0)$2wIsaa(xNyOeqs(Kb{Xt{MC0ICsv8N5l zWdM?3n%=IiXXKoD4ouG4H2|e3ub{BEvja@jp}|4-yAL0`&CZuJSLx~v`~rHQ%3^tH z3OKo6cxDI|yuvtcCCb_Jm8#<=05>0X3GL?C1wIw7e#g8{CWE*oYh(jCtN=bJ_!O02 zp7%e4?0)g^;lqQC;y^FZ?zgs978my?A|whdkt+-9d2+NHF21mTqrgEkJ%FQ7x|uo+ S500OvLfY#3YDKE|pZ*_Yk)@^p literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/docs/images/update_request.png b/app/code/Magento/Analytics/docs/images/update_request.png new file mode 100644 index 0000000000000000000000000000000000000000..7181251e3634efcc49ddfe412c3c8d3509c93665 GIT binary patch literal 13059 zcmeI2cTkhtxA(Dws9-|{5fDTH0TBV|h_rx6Z=tD3CqYU8sd}UcNS7LVClHX31PzcV zC`gyk6Cff2(h_=y+$Wy%JNGU3&fGulJMSO&FvAS9d9w5Dwbx#It?y?=>Oa&xd7Se& z6BE-(kd~Su6VpKm6Vm}E=A*#Kc;vkjCMI4cklHEZ0EV;h4xHb!xBvxF+pZop+E!?bA`=0rLY=>)}$xuS;1X4ZfvaP5GR7L)b~> z6`sDG71CwBGSxZa`+R5Q*haSdfajJUtqU(nQSzFu+j(p8S$6Qp(1XKZu!_^cuU+gf zm=5!PTRqHS@id`Wxy3&xml?~;&D~O=!AyuE#_} zUI)R>SUcJ9OyXV=7Tc z9LA=&s;}$O9LGbMg(>gN=#73&;17CZpK6Wm-w9sr(WK7Tbo(5;;+Jdrd@@-?xvGwe zlj6>?DP)^I&9CtuQad^Tss6%|oU^k!V|0-};NjLpy25jm{9Hv%W)~m5HiND7tZmw) zjB>{;?Df`2Dh30#HLIGakb+8L>EP~$1lz&VL3RGynj|-i`y{vB3=NXEQKpn@%7t1o zw63!gF4K*~41lTl9jcdO_VeO7Vv&w+AxZ|>awVXm_-^f(ziav68jV7U)=xk;Y>Wj^ zzw*beK6yXl*=`b?&2wODv59Texg=}qq3qOw?>p@&i7=;2MNWc18afd_~yd(+Bv57&z7 z@PPGU$I)gkcdN4OvW!AP#PN~2DgrfDdEala#!+u$e}@)ufK$@p&4o&3`c^mc$La#P zRv#5LMtdXK^~@6bp{VZrAFLxJ*Qy1v`bE{+F1fk)c5#XW)_|R%1u@c|z-;*5&fPg% zIDb4{dEt=WOhpvD@6j4BB{I&+<-8a--ICD^WAO zx;)y&3H9w}r2WMR<@aax6ngf6nLPKl*Sz$U_q^fS@bwuz>pm>1&73v+Ok6Sx1cqh(kl?1>NPnC;0EPqY5FnSz@%XR z`s+D?sA2|jFbVlyy92fO$qjM2$}5WgcNh3$E!`V1jsesU)BYMRgtl5z zedWvfl72w2qm4Cm zp47QMG^VQ~BMXxW-l(I%Lblp%M;6DMSj(Sc@&|T=rX*S}Ppp$%#l;nm3D^L7>|CH?KmiW6l&l*{5mIWYQ(_Ju4ZrI!2PSX+C<>3ir7$udk zJ4y7Sk}$4EhFf?-=Hm?9yvJlHfi+2=xq~;y_X)QhFqwqVdVWicbpC{>o!8DntvoD@ z+y7S{v@w*03T*Bg5mD)5VuP{8A52%>NzF{gq^Bu-L8bV7g7s9-()B3UUF(Cch(`pKcH zTZ(irS#$HMflqAzQ2p9~rOmJ8Zjs9OjUcNprpcO-IGp1et&ctwC>2Fb%$+z z5aS%jXu(BwwBRweO*(M3aYyBybn>&NlR+k$$%VTEHbs2QF@@Js(DrsIAWfeK@L1V8 zz2S?=z`peQMwX$jS)5eXgG(d(L;slHA09fBH2?V(YNeBIb6yby$K|4`rJ##IBtRN> z3wX@tC#8)7?t_=RfV*FFS-^W%sSBFdF4>*`hEhkvTl#ldq~C!P~$;GNyhhxW1(6qzlblKui&mb`mX!!A6BZj;xe;j4 z592T#aOseZNhp~W6g&wxD{z`*i%LNjo0Ox0ODAO6Zu9Lc@!+LsDYI}nu(Jq4a7yHv zeSd3L3f9Fkkrw=6J}FI_B|c>+-YO7?XX|z^ypt^TiN#U5YM_bu#_riM z7CZY!bBvHtG1{V1t)&9-V*|gTNUvS2X^!i^T?~o5ma;fnNru!~+s|7Lr(wZ`y0mha zoK4sI3|!a+OE(GM)@!MEJ3TvNosBjezgLQp`D5=kp5(mqRlN7M#}73M1_1@PYGJhP zA7R^s%lqyW>$a3u+Z;N2VsRQN0Xd`19f#{9aUB~PCYr`{0@v~a!P`jzE~vQsOH+Ay zv?GMRLkSAg?I-W1sP0smet6SbW9mGCQz2a)$$;NJOyuB0b}n}E$=_9uQ=7}!`*DG= zsG4U1&jxc5r;<=?<-sZe4(@s)TS1zwJ`cVKC(^ZPs`sI5jX%Rnr zbfCg4viWxV&562?t6mog$vGaSmDT4>&GU3q-TksYtB<-Nh@g6OShdTRSQ|>4Y=&Px zulz|hv6$t^F>depy2%tv1gTOU9vglH{puwLrrlLXUX97ev%?*L5!2`r`ytP(VI?J|3IKz#52_8 zgSNft>bXwN@N=XPjI`b4a01k;GJ1e$ItM#F?qj;a-uaABAzvu${sOI@OF0p9tL`DZ ztE2~e(Qbxg%4?wTfG$EGinh|?pDN|RpAkTwEM0m&+{%ubhcCNkH0-5Lrp)CpfrBJR z#4iZI3Plg@IXHz5U%%?~F0cU7>DNm{an45J>H9l-L|*Wwd9tDj3mn!vZ_^oXB2_z3 z^6ZXC^pvEG$Pq-ALg%+>>x8cbHe{gm_tVJIIFEw zzYC^2E@XGYl+f#Mml1}5wW8WXp4tj{^n1zNcN0y|2c7aCt4P`S7Q7IXV|1ePdw++C zqNr;19sb$|>>@3MP9~(r8q_#6b(nG6`e9v>EfVfy^=${gfE8qSMuyhK+_?!UIz5do zV4{Yl=7+bUs#e}7{HbLQcCG`66r-LF2Sq5d!KdW9YbkfAZcUKXQ4IJB;!8)4tHI83 znn_Ac>~hrr6!Xg)3t6A-FJJEC=zMERZmnt0(HYW=v+3Oq-NKw(8C1n{|Dw_AS7LcI z5%y0|gKGN?*r6w^1a_}|&abxJ{s$ulBKk-#xPwA110ep7>GDK}c6Oq}L}~>ZB(VAz z$!6BM-h0fn$CKssqQ*&sxxTG+X!c5gK4!U%@X$36lO!8~PzyEcyjr6k1!n4#qcGdWVXdhC#vc%yj zMMtIw<;okPC=%k2f0we@xM$kkNi@Dz78(hwZn5Z>&n(@SfE#1nI*kv7K zH|(%Oc7j9TjNtaiLu~J@eTKhOX;;C%wgu#ZDH6E|GNhbP$YBPUB>yPtF2ct%4pugiZLcfabFa3pJqTB(}ovvTSfCyR5}2)|A2 z$)CHY*YM5%<#;*@Z1k|-R?$PvBWf7~;@=b;YM5knu=n_34W12BEs$RmK~o2$+9};uYjCzuHkB%WmWTqoaXqYR4iA zq4|$<@+WRYr`py&?DjO71dUu$_TI&nMNBu&T1BO$dKl~&z&Ru_y^G!_U`=yD z(Ur$q6P9^d48ufs*kP0JZrZv8fCDXBZpw}T<)Co%Wk<4s5*r44ATn@RLdP8a(Z`@` z8FIJXR#v3WMwKk&QagOPR58K_F<1X4D?9#-P3owo-iI4@h_-ZugZcumZC)RtzX&NV zy*Bo?pdMLmw<0-}u^5N#sR=NEgARpKw{oLWU1Q_yRj#&PC`Fj2QH zN3(EBggbhoIc5b_s2z%9fxQX=Qs&*EbEBnF*QlfjWva1{DVHQ2Hm^%+y)b@! zoLDUOkh|A^4mpVM&qY|TH?IKM#q-EyKdnrY$Lw^M=?dXwX;A2xsK9kY}LR-Pr!M_0;v$i zU(J=X?{Kf1w#tP|EAK$;w+sXNH-)W@&RBu+@i%8Ec|qqV@1YD_xtMRRv{Xbr!DNQ* zE$_NI%d0P7ACUUS+J@}OUN)q*E@k;jDaxs0UHH^W*?O5~b);SC!Re|jlxyxUoT+8% z(5y}vDZqtc;k&;ryccKda|?z4Fx#YWU6Ln%-!6MKuau4OE;;4^k=CD_FskZX++6FV z|L(A^H7HR?(G+CaLxZiP1Ueg?*S>w`iqsmlj<#KGKK_0=j@+ZGUA^`g85N0dHItWa z&>WUjw$pRbA&M#B=5&)J?E3qs zan~tDm0UHXkbQss4coN(yc`pcp0rz$n9s`Oa74_fzSI*zp!j)*W0>icTyZ&ji5keG zUR@dFgI_mr;q9Ir*;WS4ga)ipAGEzt_t1X(&`h+pMG=ytc+2Nog0^LLgK*N8Za3S& z1@k4tTBxQn*VPdmhZZB-=LWL<`=tFAJxZyGZ2SYzz#XWj2suLA(%?vb#qB(om%?l$ zvr$cZvhw~Cn{xOAp1usxOIQ?Tj<#at%*wNR<}^z--kwp&7qtwGt#HW``<9cjS7W0@ zh7&%zI9Oxr1TDGaAC=uM5Oa>1X!W^Xwq1}JhS0^fKb*GFQS!b#yw{g(lHv=4m&1jO z4f~P8kx4gFxHT;l8fb5YjOxvGI%*(!6*2Z+2D&7KN6*qv5zKaN?2CXzIuDi z2N9YIvJ`!=vY_(e8zx_z{Yegz)8(kI!G_a5=Zy?Lgv3Xgk!P=Xl= zt1{*CJ|W-%4|H3)(xQ-aCy&h_hHOw9+l+Ba`2nQ0(=F&S{{raE(TeEcs!Ktyj-Fhe z$hu>yOQ~ENuZRk5<`Kd-N0-5ktuIL*-yco$ewCc*%qo+etr)O9 zwB6uvI_iUY`IBM^P5bGJO7~XNUy1#lT1#JaWq#(@&t1fP4s$4*RgU30VaFl$y@BL$ z?n`fVnJ9?VcP(SI(XT#`>uk-fVnhboWFp^3?2FCRj*2uKiGn_8;N z;4_P^RdpmM9fjrJw_m`fPJ|Hzi0MCSq21bh-AT zL)=ve$ASv!=IVZ}IFaMPRleUmLH0n9kil98j8uw-q09Io+}Bcv*_@;QDo8RiUkFx~ zvSwYs$_wF!%xYO`w(>zve?9$YRbqHmC7~$=0*K7rG~NHOhyfnn{Oe&N?+f(sGNZEj z?;Ff`^@1a6fWMn@!8M*$CAmG<0JP$GEb}h&fddS@(s@rMj!G<`ol@F-L@#_>U(fe{ zbCN0ETt`-0pkCTf@AaS06?XR*u!)x`>`Y;(=YT0b#{E^BDI89*aJaPb=@`%Ev8K5M z>of0p-M3}f-q8Fi6R@#0<@4zwH=c*a|H)(kRCDA2EM4rw&qOG7VkBNjjdXQUopkkY`lE2bA#Ok>3_w44 z;P>@k_$U1OM>)uvE*~(*zwfL{?hFe9Au)uTe-P3?r0gF`_&=MFir;c(=x`%hzGE|3 zN^n5!4z-RkP}!N@k*!D`1td8J1AvuedPZ3~X2C|Lb3&-W020BmioO4+o2@X+pc29K zUOnYeB&tnVnv;73t}%4)+5FMpp%!$ybb8OT?X3{CL$cdDXlETJPphx7^y-u%zuWtn zq*s6cLFU~a28v+dBGQ;$5 z*0s>l*^KTZf{=-pINzoSHeZ0#{V5;nfAx8BmIv zs3YbPw7u%#HRa@!F2%%j2G8gP=V7~q5OxjhJXvl2m8v5M!$c071T2gs1B=F5=I?5(#B6I zEUMH39ILJ*Czzz0cIy*>#azPfjD^sHXkx#C;P;ouGV3*V`n@c3iGss&-(MUWVHL0c z)~s*e#IG5<+UNs_Mt;so-?=?LpB~G$C&>9h-0@q*a})xB>yA@AJ;c#{%`G%5NUWac zcN2h0uFc`u=Y$i);`}av;EjtBc0FrgNWlZ24k=zecjWi6APfUCgUMGtLL@j{hLPK4d2XHDn8CwIVUtV@M+) zg)Anc-!aHAHCCRwm@JvhbH515+!#P>n6}q#uJCmD&)!YinJ7Tnd;XO#0*xqa0Gw^? zI$#%(+KE_sYywta)(AuWRS>ssjdZVH(s*3!$gb>RNTYPhQ04;;0z=KF`4{062UDeC z&Ncw!#22O^6K8zOD{+VbfKmi)I7&Igm4a|&uWrSlH3)zoVmnJm{Qxs9;AO>scSQg< zF!M|QG4WUEGV;o>V-AcbWVf2@_EW8*<)XGB29w2a_g8I0`vNyg_baJg46Y18wF-*S zX*Yj-=XT5q!d88rq+3^c-+bnr^k(KM&-0(B-9PGxeJJcb9O~62+mb3M_2^v&T1ZIP z3lA8Yn&DdMAyV;9wZS~O8R^JBznV0Dk`HLw01^?{RsHTAdsEUKkb$D#@z*F~4q&tVq<1K*&|Dhm0#`Wid*^^WhX{paIC0SW}d^wM2FBFCg3OYTH-JL_g zUQN|0GAIpANPRRn?{-Nf`&vf)yKh>S?9$2C9lJ7TVr8c;+J0&?BdyAa25$U_7MEKS zatBm239?bdlm431KEGZJvHbZx@7T`(@$a^{9r)CI?yFPF{ZdG+yeImDmDXe}OAN~~ z)r&Yq8bHwrewBhs;VjJ0KXZ;@fN13px@jr=IWZ+ngJi7O%jqWf_!0uAiLoz&0R0Wi zuC+5lEVCR7{pG2XBLxeV-5M7ccv%krb}4rAkBlhLp<|h5^$bAlwTY$kbE|5HMOT#} zq&t*}k}LS#;>cJ|T+#KrGp#!QSt;iX`o#!Ao8u99I3{3&3QK1!7XHxc(0;c6tdKGp zhyzz3g}U!SkR2)u9X=L7bWETA6maja=m=u$V1BiWKZ*zd$w8N^_ts%x zw5?*G|M5RA=Q}0sg68ksGc+t=VFm}*&M%oJ%9*UqO7J~?2?BOU-La(-I2`j{<9mz> z1UMXPS3m9%H8}oBRR3w|`lp@kpH{yA@4bx++T{7+n$e{e9$F=C7QswYWB%Q%`9fvl zj0(x^1EV2LyGR%11KhnhpplLQn<0J)+FfcnJr?<=R>1VK`5GX1ct!wn2XL#ll7L34 zKzpFg3|i?rSV;vMC47KXHg56Z-(rE-0YGt(XY}h`h1587BEDv*>C!ny01*$DF6pS@ zcR`iWEea$yoNy*Uw~h!f_n-zz^{zvl29wTT zpAtR@Fu*JZ11v+^PsYFiQ9|&qmQ)4CtE)0z-P$>tJ^No4C}s#g#Ml3=g3td85$V4& zXZ{j%JK5F~L&tDmI4moccb>0IeQ>R67_j#4QKtgg zulLS;O`QC6rq{@FyEx5u1!(KLtEfR83!uS(wvcB{;U~S?Z`M4pr>CTF$N()QAsr=I zKH!OKfAEK^ygChdCkw+ne@kFJeurHWu+L2GtNJO?`=+aP0IehcPWoT-$3BC*p+HB5 zCgPN-SAZ1McPiZx$LJ=F;go6v{R}_FJxf=9`jx%5M}zA_!#b%w=87T-HaF1Oo};w6 z>I<3zK=w2vJrd7w1G*1_Sb(+~Jm4KXfCk0G#~G*Mr~_v%^Q@i9aNRy`J1qTt`KdS* zSbi2<(lNGbDCVL>W0|20Y}VNK(~%4BJtmqz0Ihv~kpc9*jZtk8hZUQ;=K1?_E_r64)U~ zGnx+)Gf2Jrqxm``^!$DB0N=fNlej)xUbTHqQ2;V~rW2YIxD4taF3_@^z{tnGUjjA{ zd->|W!mg9TLDpzAqurGHuIZHP5&gN3&Y2m4JoP|{6TJKh5SEV*I`_uDadxd=Z#gaV zci{S8q|*4KjF9ku=%@b-{$r58#q@ui;XibS=_vGY<2zp+9ai?gY9sbiRTbhV2mZwn YyR-G-9GoM?Ou!FF{h?Z=>Z3pY4PTYIk^lez literal 0 HcmV?d00001 diff --git a/app/code/Magento/Analytics/etc/acl.xml b/app/code/Magento/Analytics/etc/acl.xml new file mode 100644 index 0000000000000..bf2251895f929 --- /dev/null +++ b/app/code/Magento/Analytics/etc/acl.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/di.xml b/app/code/Magento/Analytics/etc/adminhtml/di.xml new file mode 100644 index 0000000000000..5e305e70e5ad3 --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/di.xml @@ -0,0 +1,16 @@ + + + + + + + Magento\Analytics\Model\System\Message\NotificationAboutFailedSubscription + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/menu.xml b/app/code/Magento/Analytics/etc/adminhtml/menu.xml new file mode 100644 index 0000000000000..915211c4bb85e --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/menu.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/routes.xml b/app/code/Magento/Analytics/etc/adminhtml/routes.xml new file mode 100644 index 0000000000000..0ae2762dacc5f --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/routes.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml new file mode 100644 index 0000000000000..32d493451ca61 --- /dev/null +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -0,0 +1,47 @@ + + + + +
+ + general + Magento_Analytics::analytics_settings + + + For more information, view details or see our + terms and conditions.]]> + + + Magento\Config\Model\Config\Source\Enabledisable + Magento\Analytics\Model\Config\Backend\Enabled + Magento\Analytics\Block\Adminhtml\System\Config\SubscriptionStatusLabel + analytics/subscription/enabled + + + + Magento\Analytics\Model\Config\Source\Vertical + Magento\Analytics\Model\Config\Backend\Vertical + + + + Magento\Analytics\Block\Adminhtml\System\Config\CollectionTimeLabel + Magento\Analytics\Model\Config\Backend\CollectionTime + + + + Learn more about BI Essentials tier.]]> + Magento\Analytics\Block\Adminhtml\System\Config\AdditionalComment + + +
+
+
diff --git a/app/code/Magento/Analytics/etc/analytics.xml b/app/code/Magento/Analytics/etc/analytics.xml new file mode 100644 index 0000000000000..77ebe751a31cf --- /dev/null +++ b/app/code/Magento/Analytics/etc/analytics.xml @@ -0,0 +1,50 @@ + + + + + + + + modules + + + + + + + + + + + + + + stores + + + + + + + + + websites + + + + + + + + + groups + + + + + diff --git a/app/code/Magento/Analytics/etc/analytics.xsd b/app/code/Magento/Analytics/etc/analytics.xsd new file mode 100644 index 0000000000000..2506e3d6a6a9a --- /dev/null +++ b/app/code/Magento/Analytics/etc/analytics.xsd @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + File name attribute can has only [a-zA-Z0-9/_]. + + + + + + + + + + Value is required. + + + + + + + diff --git a/app/code/Magento/Analytics/etc/config.xml b/app/code/Magento/Analytics/etc/config.xml new file mode 100644 index 0000000000000..b6194ba12993f --- /dev/null +++ b/app/code/Magento/Analytics/etc/config.xml @@ -0,0 +1,25 @@ + + + + + + + https://advancedreporting.rjmetrics.com/signup + https://advancedreporting.rjmetrics.com/update + https://dashboard.rjmetrics.com/v2/magento/signup + https://advancedreporting.rjmetrics.com/otp + https://advancedreporting.rjmetrics.com/report + https://advancedreporting.rjmetrics.com/report + + Magento Analytics user + + 02,00,00 + + + + diff --git a/app/code/Magento/Analytics/etc/crontab.xml b/app/code/Magento/Analytics/etc/crontab.xml new file mode 100644 index 0000000000000..a4beef0359540 --- /dev/null +++ b/app/code/Magento/Analytics/etc/crontab.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/di.xml b/app/code/Magento/Analytics/etc/di.xml new file mode 100644 index 0000000000000..09efd7c36ad83 --- /dev/null +++ b/app/code/Magento/Analytics/etc/di.xml @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + Magento\Analytics\Model\Connector\SignUpCommand + Magento\Analytics\Model\Connector\UpdateCommand + Magento\Analytics\Model\Connector\NotifyDataChangedCommand + + + + + + Magento\Config\Model\ResourceModel\Config\Data + + + + + + Magento\Analytics\ReportXml\Config\Data + + + + + Magento\Analytics\ReportXml\Config\Reader + Magento_Analytics_ReportXml_CacheId + + + + + urn:magento:module:Magento_Analytics:etc/reports.xsd + + + + + Magento\Analytics\ReportXml\Config\Converter\Xml + Magento\Analytics\ReportXml\Config\SchemaLocator + reports.xml + + name + + name + alias + + name + name + + glue + + attribute + operator + + + glue + + attribute + operator + + + glue + + attribute + operator + + glue + + attribute + operator + + + + + + + + Magento\Analytics\ReportXml\Config\Reader\Xml + + + + + + + Magento\Analytics\Model\Config\Data + + + + + Magento\Analytics\Model\Config\Reader + Magento_Analytics_CacheId + + + + + urn:magento:module:Magento_Analytics:etc/analytics.xsd + + + + + Magento\Analytics\ReportXml\Config\Converter\Xml + Magento\Analytics\Model\Config\SchemaLocator + analytics.xml + + name + + + + + + + + Magento\Analytics\ReportXml\DB\Assembler\FromAssembler + Magento\Analytics\ReportXml\DB\Assembler\FilterAssembler + Magento\Analytics\ReportXml\DB\Assembler\JoinAssembler + + + + + + + Magento\Analytics\Model\Config\Reader\Xml + + + + + + + web/unsecure/base_url + currency/options/base + general/locale/timezone + general/country/default + carriers/dhl/title + carriers/dhl/active + carriers/fedex/title + carriers/fedex/active + carriers/flatrate/title + carriers/flatrate/active + carriers/tablerate/title + carriers/tablerate/active + carriers/freeshipping/title + carriers/freeshipping/active + carriers/ups/title + carriers/ups/active + carriers/usps/title + carriers/usps/active + payment/free/title + payment/free/active + payment/checkmo/title + payment/checkmo/active + payment/purchaseorder/title + payment/purchaseorder/active + payment/banktransfer/title + payment/banktransfer/active + payment/cashondelivery/title + payment/cashondelivery/active + payment/authorizenet_directpost/title + payment/authorizenet_directpost/active + payment/paypal_billing_agreement/title + payment/paypal_billing_agreement/active + payment/braintree/title + payment/braintree/active + payment/braintree_paypal/title + payment/braintree_paypal/active + analytics/general/vertical + + + + + + + Apps and Games + Athletic/Sporting Goods + Art and Design + Auto Parts + Baby/Children’s Apparel, Gear and Toys + Beauty and Cosmetics + Books, Music and Magazines + Crafts and Stationery + Consumer Electronics + Deal Site + Fashion Apparel and Accessories + Food, Beverage and Grocery + Home Goods and Furniture + Home Improvement + Jewelry and Watches + Mass Merchant + Office Supplies + Outdoor and Camping Gear + Pet Goods + Pharma and Medical Devices + Technology B2B + Other + + + + + + + + + + \Magento\Analytics\Model\Connector\ResponseHandler\SignUp + + + + + + + Magento\Analytics\Model\Connector\ResponseHandler\Update + Magento\Analytics\Model\Connector\ResponseHandler\ReSignUp + + + + + + + Magento\Analytics\Model\Connector\ResponseHandler\OTP + Magento\Analytics\Model\Connector\ResponseHandler\ReSignUp + + + + + + + Magento\Analytics\Model\Connector\ResponseHandler\ReSignUp + + + + + + SignUpResponseResolver + + + + + UpdateResponseResolver + + + + + OtpResponseResolver + + + + + NotifyDataChangedResponseResolver + + + diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml new file mode 100644 index 0000000000000..32ee5d23a4d86 --- /dev/null +++ b/app/code/Magento/Analytics/etc/module.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/reports.xml b/app/code/Magento/Analytics/etc/reports.xml new file mode 100644 index 0000000000000..8a43658670293 --- /dev/null +++ b/app/code/Magento/Analytics/etc/reports.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Analytics/etc/reports.xsd b/app/code/Magento/Analytics/etc/reports.xsd new file mode 100644 index 0000000000000..d0ba4068244fe --- /dev/null +++ b/app/code/Magento/Analytics/etc/reports.xsd @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/etc/webapi.xml b/app/code/Magento/Analytics/etc/webapi.xml new file mode 100644 index 0000000000000..8252d039f1d03 --- /dev/null +++ b/app/code/Magento/Analytics/etc/webapi.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/app/code/Magento/Analytics/i18n/en_US.csv b/app/code/Magento/Analytics/i18n/en_US.csv new file mode 100644 index 0000000000000..090534923e450 --- /dev/null +++ b/app/code/Magento/Analytics/i18n/en_US.csv @@ -0,0 +1,103 @@ +"Subscription status","Subscription status" +"Sorry, there has been an error processing your request. Please try again later.","Sorry, there has been an error processing your request. Please try again later." +"Sorry, there was an error processing your registration request to Magento Analytics. Please try again later.","Sorry, there was an error processing your registration request to Magento Analytics. Please try again later." +"Error occurred during postponement notification","Error occurred during postponement notification" +"Time value has an unsupported format","Time value has an unsupported format" +"Cron settings can't be saved","Cron settings can't be saved" +"There was an error save new configuration value.","There was an error save new configuration value." +"Please select a vertical.","Please select a vertical." +"--Please Select--","--Please Select--" +"Command was not found.","Command was not found." +"Input data must be string or convertible into string.","Input data must be string or convertible into string." +"Input data must be non-empty string.","Input data must be non-empty string." +"Not valid cipher method.","Not valid cipher method." +"Encryption key can't be empty.","Encryption key can't be empty." +"Source ""%1"" is not exist","Source ""%1"" is not exist" +"These arguments can't be empty ""%1""","These arguments can't be empty ""%1""" +"Cannot find predefined integration user!","Cannot find predefined integration user!" +"File is not ready yet.","File is not ready yet." +"Your Base URL has been changed and your reports are being updated. Advanced Reporting will be available once this change has been processed. Please try again later.","Your Base URL has been changed and your reports are being updated. Advanced Reporting will be available once this change has been processed. Please try again later." +"Failed to synchronize data to the Magento Business Intelligence service. ","Failed to synchronize data to the Magento Business Intelligence service. " +"Retry Synchronization","Retry Synchronization" +TestMessage,TestMessage +"Error message","Error message" +"Apps and Games","Apps and Games" +"Athletic/Sporting Goods","Athletic/Sporting Goods" +"Art and Design","Art and Design" +"Advanced Reporting","Advanced Reporting" +"Gain new insights and take command of your business' performance, using our dynamic product, order, and customer reports tailored to your customer data.","Gain new insights and take command of your business' performance, using our dynamic product, order, and customer reports tailored to your customer data." +"View details","View details" +"Go to Advanced Reporting","Go to Advanced Reporting" +"An error occurred while subscription process.","An error occurred while subscription process." +Analytics,Analytics +API,API +Configuration,Configuration +"Business Intelligence","Business Intelligence" +"BI Essentials","BI Essentials" +"This service provides a suite of dynamic reports based on your product, order and + customer data. All reports are accessed securely on a personalized dashboard dedicated to your reports - + separate from your Admin Panel.
For more information, view details or see our + terms and conditions.","This service provides a suite of dynamic reports based on your product, order and + customer data. All reports are accessed securely on a personalized dashboard dedicated to your reports - + separate from your Admin Panel.
For more information, view details or see our + terms and conditions." +"Advanced Reporting Service","Advanced Reporting Service" +Industry,Industry +"Time of day to send data","Time of day to send data" +"Get more insights from Magento Business Intelligence","Get more insights from Magento Business Intelligence" +"Magento Business Intelligence provides you with a simple and clear path to + becoming more data driven.
Learn more about BI Essentials tier.","Magento Business Intelligence provides you with a simple and clear path to + becoming more data driven.
Learn more about BI Essentials tier." +"Auto Parts","Auto Parts" +"Baby/Children’s Apparel, Gear and Toys","Baby/Children’s Apparel, Gear and Toys" +"Beauty and Cosmetics","Beauty and Cosmetics" +"Books, Music and Magazines","Books, Music and Magazines" +"Crafts and Stationery","Crafts and Stationery" +"Consumer Electronics","Consumer Electronics" +"Deal Site","Deal Site" +"Fashion Apparel and Accessories","Fashion Apparel and Accessories" +"Food, Beverage and Grocery","Food, Beverage and Grocery" +"Home Goods and Furniture","Home Goods and Furniture" +"Home Improvement","Home Improvement" +"Jewelry and Watches","Jewelry and Watches" +"Mass Merchant","Mass Merchant" +"Office Supplies","Office Supplies" +"Outdoor and Camping Gear","Outdoor and Camping Gear" +"Pet Goods","Pet Goods" +"Pharma and Medical Devices","Pharma and Medical Devices" +"Technology B2B","Technology B2B" +"Analytics Subscription","Analytics Subscription" +"powered by Magento Business Intelligence","powered by Magento Business Intelligence" +"

When you turn on Advanced + Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example + of the new data and trend reports, listed by category, include:

    +
  • Order: Number of orders, total revenue, and AOV
  • Customer: + New registered accounts, unique customers, number of orders, AOV, revenue by email +
  • Product: Quantity sold, bestsellers by volume/revenue

A + personalized dashboard includes all reports - separate from your Admin Panel, yet still at your + fingertips.

We're excited to offer these valuable tools that can help your business become + more data-driven. For more information, view details or see our + terms and conditions.

+ ","

When you turn on Advanced + Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example + of the new data and trend reports, listed by category, include:

    +
  • Order: Number of orders, total revenue, and AOV
  • Customer: + New registered accounts, unique customers, number of orders, AOV, revenue by email +
  • Product: Quantity sold, bestsellers by volume/revenue

A + personalized dashboard includes all reports - separate from your Admin Panel, yet still at your + fingertips.

We're excited to offer these valuable tools that can help your business become + more data-driven. For more information, view details or see our + terms and conditions.

+ " +"Are you sure you want to opt out?","Are you sure you want to opt out?" +Cancel,Cancel +"Opt out","Opt out" +"

Advanced Reporting in included, + free of charge, in your Magento software. When you opt out, we collect no product, order, and + customer data to generate our dynamic reports.

To opt in later: You can always turn on Advanced + Reporting in you Admin Panel.

","

Advanced Reporting in included, + free of charge, in your Magento software. When you opt out, we collect no product, order, and + customer data to generate our dynamic reports.

To opt in later: You can always turn on Advanced + Reporting in you Admin Panel.

" diff --git a/app/code/Magento/Analytics/registration.php b/app/code/Magento/Analytics/registration.php new file mode 100644 index 0000000000000..58d3688b7491d --- /dev/null +++ b/app/code/Magento/Analytics/registration.php @@ -0,0 +1,11 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml b/app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml new file mode 100644 index 0000000000000..a22c603b2a8b3 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/templates/dashboard/section.phtml @@ -0,0 +1,28 @@ + + +
+
+
+ escapeHtml(__('Advanced Reporting')) ?> +
+
+ escapeHtml(__('Gain new insights and take command of your business\' performance,' . + ' using our dynamic product, order, and customer reports tailored to your customer data.')) ?> +
+
+ +
diff --git a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml new file mode 100644 index 0000000000000..b44974b32cffa --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml @@ -0,0 +1,247 @@ + + +
+ + + analytics_subscription_form.analytics_subscription_form_data_source + + Analytics Subscription + templates/form/collapsible + + + analytics_subscription_form + true + simple + data + + analytics_subscription_form.analytics_subscription_form_data_source + + + + + + + + + + + + + Magento_Ui/js/form/provider + + + + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + + +
+ + + + + + + advanced-reports-subscription-text + When you turn on Advanced + Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example + of the new data and trend reports, listed by category, include:

    +
  • Order: Number of orders, total revenue, and AOV
  • Customer: + New registered accounts, unique customers, number of orders, AOV, revenue by email +
  • Product: Quantity sold, bestsellers by volume/revenue

A + personalized dashboard includes all reports - separate from your Admin Panel, yet still at your + fingertips.

We're excited to offer these valuable tools that can help your business become + more data-driven. For more information, view details or see our + terms and conditions.

]]> +
+
+
+
+ + + + + + + + + + + + + 1 + + + + + true + + analytics_subscription_checkbox + + + + + + Learn more.]]> + + 1 + 0 + + + + + + +
+
+ + + actionCancel + + + + + + + + + + + + + + + advanced-reports-subscription-text + Advanced Reporting in included, + free of charge, in your Magento software. When you opt out, we collect no product, order, and + customer data to generate our dynamic reports.

To opt in later: You can always turn on Advanced + Reporting in you Admin Panel.

]]>
+
+
+
+
+
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js new file mode 100644 index 0000000000000..9dee8d0c8e9ce --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js @@ -0,0 +1,66 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'Magento_Ui/js/modal/modal-component', + 'Magento_Ui/js/modal/alert', + 'mage/translate' +], function ($, Modal, alert, $t) { + 'use strict'; + + return Modal.extend({ + defaults: { + postponeOptions: {}, + imports: { + postponeUrl: '${ $.provider }:postpone_url' + }, + modules: { + form: '${ $.parentName }' + } + }, + + /** + * Send request to postpone modal appearance for a certain time. + * + * @param {Object} options - additional request options. + */ + sendPostponeRequest: function (options) { + var self = this, + data = $.extend(this.form().source.data, options); + + $.ajax({ + type: 'POST', + url: this.postponeUrl, + data: data, + showLoader: true + }).done(function (xhr) { + if (xhr.error) { + self.onError(xhr); + } + }).fail(this.onError); + }, + + /** + * Error handler. + * + * @param {Object} xhr - request result. + */ + onError: function (xhr) { + if (xhr.statusText === 'abort') { + return; + } + + alert({ + content: xhr.message || $t('An error occurred while subscription process.') + }); + }, + + /** @inheritdoc */ + actionCancel: function () { + this.sendPostponeRequest(this.postponeOptions); + this.closeModal(); + } + }); +}); diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html b/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html new file mode 100644 index 0000000000000..784e16d72c3f5 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html @@ -0,0 +1,13 @@ + +
+ + +
+ +
+
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html b/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html new file mode 100644 index 0000000000000..297867c60c1e4 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html @@ -0,0 +1,17 @@ + +
+ + +
diff --git a/app/code/Magento/CatalogAnalytics/LICENSE.txt b/app/code/Magento/CatalogAnalytics/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt b/app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/CatalogAnalytics/README.md b/app/code/Magento/CatalogAnalytics/README.md new file mode 100644 index 0000000000000..df125446117a3 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_CatalogAnalytics module + +The Magento_CatalogAnalytics module configures data definitions for a data collection related to the Catalog module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/CatalogAnalytics/composer.json b/app/code/Magento/CatalogAnalytics/composer.json new file mode 100644 index 0000000000000..6cda52197f80a --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-catalog-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-catalog": "101.1.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\CatalogAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/CatalogAnalytics/etc/analytics.xml b/app/code/Magento/CatalogAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..22d1f2c7d7776 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/etc/analytics.xml @@ -0,0 +1,18 @@ + + + + + + + + products + + + + + diff --git a/app/code/Magento/CatalogAnalytics/etc/module.xml b/app/code/Magento/CatalogAnalytics/etc/module.xml new file mode 100644 index 0000000000000..7974598e17a59 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/CatalogAnalytics/etc/reports.xml b/app/code/Magento/CatalogAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..5dae3ef90d7b2 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/etc/reports.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/CatalogAnalytics/registration.php b/app/code/Magento/CatalogAnalytics/registration.php new file mode 100644 index 0000000000000..77d6ce154b658 --- /dev/null +++ b/app/code/Magento/CatalogAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt b/app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/CustomerAnalytics/README.md b/app/code/Magento/CustomerAnalytics/README.md new file mode 100644 index 0000000000000..8c64ce97629da --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_CustomerAnalytics module + +The Magento_CustomerAnalytics module configures data definitions for a data collection related to the Customer module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/CustomerAnalytics/composer.json b/app/code/Magento/CustomerAnalytics/composer.json new file mode 100644 index 0000000000000..36e7492decc50 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-customer-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-customer": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\CustomerAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/CustomerAnalytics/etc/analytics.xml b/app/code/Magento/CustomerAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..5e47040c2f3bd --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/etc/analytics.xml @@ -0,0 +1,18 @@ + + + + + + + + customers + + + + + diff --git a/app/code/Magento/CustomerAnalytics/etc/module.xml b/app/code/Magento/CustomerAnalytics/etc/module.xml new file mode 100644 index 0000000000000..adc4f8dd849c2 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/CustomerAnalytics/etc/reports.xml b/app/code/Magento/CustomerAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..b3300b0127709 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/etc/reports.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/CustomerAnalytics/registration.php b/app/code/Magento/CustomerAnalytics/registration.php new file mode 100644 index 0000000000000..e4c3348182877 --- /dev/null +++ b/app/code/Magento/CustomerAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt b/app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/QuoteAnalytics/README.md b/app/code/Magento/QuoteAnalytics/README.md new file mode 100644 index 0000000000000..d4adcc9313229 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_QuoteAnalytics + +The Magento_QuoteAnalytics module configures data definitions for a data collection related to the Quote module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/QuoteAnalytics/composer.json b/app/code/Magento/QuoteAnalytics/composer.json new file mode 100644 index 0000000000000..7f38e489ab0b0 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-quote-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-quote": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\QuoteAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/QuoteAnalytics/etc/analytics.xml b/app/code/Magento/QuoteAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..cc4dfb6364904 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/etc/analytics.xml @@ -0,0 +1,18 @@ + + + + + + + + quotes + + + + + diff --git a/app/code/Magento/QuoteAnalytics/etc/module.xml b/app/code/Magento/QuoteAnalytics/etc/module.xml new file mode 100644 index 0000000000000..d72e36b748748 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/QuoteAnalytics/etc/reports.xml b/app/code/Magento/QuoteAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..f57012df23389 --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/etc/reports.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/QuoteAnalytics/registration.php b/app/code/Magento/QuoteAnalytics/registration.php new file mode 100644 index 0000000000000..19718c3cf2adf --- /dev/null +++ b/app/code/Magento/QuoteAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt b/app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/ReviewAnalytics/README.md b/app/code/Magento/ReviewAnalytics/README.md new file mode 100644 index 0000000000000..b078083dfb7dc --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_ReviewAnalytics module + +The Magento_ReviewAnalytics module configures data definitions for a data collection related to the Review module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/ReviewAnalytics/composer.json b/app/code/Magento/ReviewAnalytics/composer.json new file mode 100644 index 0000000000000..b31c420e181bf --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-review-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-review": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\ReviewAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/ReviewAnalytics/etc/analytics.xml b/app/code/Magento/ReviewAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..cd5d1b2c1af4c --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/etc/analytics.xml @@ -0,0 +1,27 @@ + + + + + + + + reviews + + + + + + + + + rating_option_votes + + + + + diff --git a/app/code/Magento/ReviewAnalytics/etc/module.xml b/app/code/Magento/ReviewAnalytics/etc/module.xml new file mode 100644 index 0000000000000..65df87bac4af1 --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/ReviewAnalytics/etc/reports.xml b/app/code/Magento/ReviewAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..8dd508983aced --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/etc/reports.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/ReviewAnalytics/registration.php b/app/code/Magento/ReviewAnalytics/registration.php new file mode 100644 index 0000000000000..6b795ca04c61b --- /dev/null +++ b/app/code/Magento/ReviewAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/SalesAnalytics/LICENSE_AFL.txt b/app/code/Magento/SalesAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/SalesAnalytics/README.md b/app/code/Magento/SalesAnalytics/README.md new file mode 100644 index 0000000000000..70f456c97d4b3 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_SalesAnalytics module + +The Magento_SalesAnalytics module configures data definitions for a data collection related to the Sales module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/SalesAnalytics/composer.json b/app/code/Magento/SalesAnalytics/composer.json new file mode 100644 index 0000000000000..7c9270a503b0d --- /dev/null +++ b/app/code/Magento/SalesAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-sales-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-sales": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\SalesAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/SalesAnalytics/etc/analytics.xml b/app/code/Magento/SalesAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..be6c4dfde9b19 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/etc/analytics.xml @@ -0,0 +1,36 @@ + + + + + + + + orders + + + + + + + + + order_items + + + + + + + + + order_addresses + + + + + diff --git a/app/code/Magento/SalesAnalytics/etc/module.xml b/app/code/Magento/SalesAnalytics/etc/module.xml new file mode 100644 index 0000000000000..7a15075a4bc21 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/SalesAnalytics/etc/reports.xml b/app/code/Magento/SalesAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..bb6bdb800e9bf --- /dev/null +++ b/app/code/Magento/SalesAnalytics/etc/reports.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/SalesAnalytics/registration.php b/app/code/Magento/SalesAnalytics/registration.php new file mode 100644 index 0000000000000..eff2c5b1a2c05 --- /dev/null +++ b/app/code/Magento/SalesAnalytics/registration.php @@ -0,0 +1,11 @@ +" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt b/app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/WishlistAnalytics/README.md b/app/code/Magento/WishlistAnalytics/README.md new file mode 100644 index 0000000000000..999fc835626da --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/README.md @@ -0,0 +1,3 @@ +# Magento_WishlistAnalytics module + +The Magento_WishlistAnalytics module configures data definitions for a data collection related to the Wishlist module entities to be used in [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html). diff --git a/app/code/Magento/WishlistAnalytics/composer.json b/app/code/Magento/WishlistAnalytics/composer.json new file mode 100644 index 0000000000000..20f414c00c320 --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/composer.json @@ -0,0 +1,23 @@ +{ + "name": "magento/module-wishlist-analytics", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.2.*", + "magento/module-wishlist": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\WishlistAnalytics\\": "" + } + } +} diff --git a/app/code/Magento/WishlistAnalytics/etc/analytics.xml b/app/code/Magento/WishlistAnalytics/etc/analytics.xml new file mode 100644 index 0000000000000..0b2531fe0df67 --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/etc/analytics.xml @@ -0,0 +1,27 @@ + + + + + + + + wishlists + + + + + + + + + wishlist_items + + + + + diff --git a/app/code/Magento/WishlistAnalytics/etc/module.xml b/app/code/Magento/WishlistAnalytics/etc/module.xml new file mode 100644 index 0000000000000..159ed86ee171a --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/WishlistAnalytics/etc/reports.xml b/app/code/Magento/WishlistAnalytics/etc/reports.xml new file mode 100644 index 0000000000000..0125fa93f815a --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/etc/reports.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/WishlistAnalytics/registration.php b/app/code/Magento/WishlistAnalytics/registration.php new file mode 100644 index 0000000000000..eacf1e0d78bcb --- /dev/null +++ b/app/code/Magento/WishlistAnalytics/registration.php @@ -0,0 +1,11 @@ +objectManager = Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Analytics/_files/create_link.php + */ + public function testGetAll() + { + $objectManager = Bootstrap::getObjectManager(); + + /** + * @var $fileInfoManager FileInfoManager + */ + $fileInfoManager = $objectManager->create(FileInfoManager::class); + + $storeManager = $objectManager->create(StoreManagerInterface::class); + + $fileInfo = $fileInfoManager->load(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => static::RESOURCE_PATH, + 'httpMethod' => Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => static::SERVICE_NAME, + 'serviceVersion' => static::SERVICE_VERSION, + 'operation' => static::SERVICE_NAME . 'Get', + ], + ]; + if (!$this->isTestBaseUrlSecure()) { + try { + $this->_webApiCall($serviceInfo); + } catch (\Exception $e) { + $this->assertContains( + 'Operation allowed only in HTTPS', + $e->getMessage() + ); + return; + } + $this->fail("Exception 'Operation allowed only in HTTPS' should be thrown"); + } else { + $response = $this->_webApiCall($serviceInfo); + $this->assertEquals(2, count($response)); + $this->assertEquals( + base64_encode($fileInfo->getInitializationVector()), + $response['initialization_vector'] + ); + $this->assertEquals( + $storeManager->getStore()->getBaseUrl( + UrlInterface::URL_TYPE_MEDIA + ) . $fileInfo->getPath(), + $response['url'] + ); + } + } + + /** + * @return bool + */ + private function isTestBaseUrlSecure() + { + return strpos('https://', TESTS_BASE_URL) !== false; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php new file mode 100644 index 0000000000000..81724e735f269 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php @@ -0,0 +1,55 @@ +configuration = $configuration; + } + + /** + * Cancel subscription for functional tests + * + * @param AbstractState $state + * @return bool + * @throws \Exception + */ + public function execute(AbstractState $state) + { + $url = $_ENV['app_backend_url'] . 'analytics/subscription/postpone'; + $curl = new BackendDecorator(new CurlTransport(), $this->configuration); + $curl->write($url, []); + $response = $curl->read(); + $curl->close(); + if (isset($response['success'])) { + return $response['success']; + } + return false; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php new file mode 100644 index 0000000000000..1c7edaaac86f0 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/ReportsSectionBlock.php @@ -0,0 +1,31 @@ +_rootElement->find($this->advancedReportingButton)->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php new file mode 100644 index 0000000000000..0cbb853167f30 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php @@ -0,0 +1,99 @@ +_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('Yes'); + } + + /** + * Disable checkbox in modal window. + * + * @return void + */ + public function disableCheckbox() + { + $this->_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('No'); + } + + /** + * Enable Advanced Reporting on a subscription popup. + * + * @return void + */ + public function acceptAdvancedReporting() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->acceptReportingButton)->click(); + $this->waitForElementNotVisible($this->loadingMask); + } + + /** + * Disable Advanced Reporting on a subscription popup. + * + * @return void + */ + public function declineAdvancedReporting() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->declineReportingButton)->click(); + $this->waitForElementNotVisible($this->loadingMask); + } + + /** + * Skip subscription popup. + * + * @return void + */ + public function skipAdvancedReporting() + { + $this->waitModalAnimationFinished(); + $this->_rootElement->find($this->skipReportingButton)->click(); + $this->waitForElementNotVisible($this->loadingMask); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php new file mode 100644 index 0000000000000..07b62a9518ae4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/System/Config/AnalyticsForm.php @@ -0,0 +1,158 @@ + td.value > p > span'; + + /** + * @var string + */ + private $submitButton = '#save'; + + /** + * @var string + */ + private $analyticsVertical = '#analytics_general_vertical'; + + /** + * @var string + */ + private $analyticsVerticalScope = '#row_analytics_general_vertical span[data-config-scope="[WEBSITE]"]'; + + /** + * @var string + */ + private $sendDataTimeHh = '#row_analytics_general_collection_time > td.value > select:nth-child(2)'; + + /** + * @var string + */ + private $sendDataTimeMm = '#row_analytics_general_collection_time > td.value > select:nth-child(3)'; + + /** + * @var string + */ + private $sendDataTimeSs = '#row_analytics_general_collection_time > td.value > select:nth-child(4)'; + + /** + * @var string + */ + private $timeZone = + '#row_analytics_general_collection_time > td.value > p > span'; + + /** + * @return array|string + */ + public function isAnalyticsEnabled() + { + return $this->_rootElement->find($this->analyticsStatus, Locator::SELECTOR_CSS)->getValue(); + } + + /** + * @param string $state + * @return array|string + */ + public function analyticsToggle($state = 'Enable') + { + return $this->_rootElement->find($this->analyticsStatus, Locator::SELECTOR_CSS, 'select')->setValue($state); + } + + /** + * @return array|string + */ + public function saveConfig() + { + return $this->browser->find($this->submitButton)->click(); + } + + /** + * @return array|string + */ + public function getAnalyticsStatus() + { + return $this->_rootElement->find($this->analyticsStatusLabel, Locator::SELECTOR_CSS)->getText(); + } + + /** + * @param string $vertical + * @return array|string + */ + public function setAnalyticsVertical($vertical) + { + return $this->_rootElement->find($this->analyticsVertical, Locator::SELECTOR_CSS, 'select') + ->setValue($vertical); + } + + /** + * @param string $hh + * @param string $mm + * @return $this + */ + public function setTimeOfDayToSendData($hh, $mm) + { + $this->_rootElement->find($this->sendDataTimeHh, Locator::SELECTOR_CSS, 'select') + ->setValue($hh); + $this->_rootElement->find($this->sendDataTimeMm, Locator::SELECTOR_CSS, 'select') + ->setValue($mm); + return $this; + } + + /** + * @return string + */ + public function getTimeOfDayToSendDate() + { + $hh = $this->_rootElement->find($this->sendDataTimeHh, Locator::SELECTOR_CSS, 'select') + ->getValue(); + $mm = $this->_rootElement->find($this->sendDataTimeMm, Locator::SELECTOR_CSS, 'select') + ->getValue(); + $ss = $this->_rootElement->find($this->sendDataTimeSs, Locator::SELECTOR_CSS, 'select') + ->getValue(); + return sprintf('%s, %s, %s', $hh, $mm, $ss); + } + + /** + * @return mixed + */ + public function getTimeZone() + { + return $this->_rootElement->find($this->timeZone, Locator::SELECTOR_CSS) + ->getText(); + } + + /** + * @return array|string + */ + public function getAnalyticsVertical() + { + return $this->_rootElement->find($this->analyticsVertical, Locator::SELECTOR_CSS)->getValue(); + } + + /** + * @return array|string + */ + public function getAnalyticsVerticalScope() + { + return $this->_rootElement->find($this->analyticsVerticalScope, Locator::SELECTOR_CSS)->isVisible(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php new file mode 100644 index 0000000000000..de379aea85fa7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php @@ -0,0 +1,53 @@ +browser = $browser; + $this->browser->selectWindow(); + \PHPUnit_Framework_Assert::assertTrue( + $this->browser->waitUntil( + function () use ($advancedReportingLink) { + return ($this->browser->getUrl() === $advancedReportingLink) ? true : null; + } + ), + 'Advanced Reporting Sign Up page was not opened by link.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting Sign Up page is opened by link'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php new file mode 100644 index 0000000000000..010d9c446819d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php @@ -0,0 +1,87 @@ +browser = $browser; + $count = 0; + $isVisible = false; + do { + try { + $this->browser->selectWindow(); + $isVisible = $this->browser->waitUntil(function () use ($businessIntelligenceLink) { + return ($this->browser->getUrl() === $businessIntelligenceLink) ?: null; + }); + break; + } catch (\Throwable $e) { + $dashboard->open(); + $dashboard->getMenuBlock()->navigate($menuItem, $waitMenuItemNotVisible); + $count++; + } + } while ($count < self::MAX_TRY_COUNT); + + \PHPUnit_Framework_Assert::assertTrue( + $isVisible, + "BI Essentials Sign Up page was not opened by link.\n + Actual link is '{$this->browser->getUrl()}'\n + Expected link is '$businessIntelligenceLink'" + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'BI Essentials Sign Up page is opened by link'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php new file mode 100644 index 0000000000000..daeed6a66cfa4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -0,0 +1,49 @@ +Configuration>General>Analytics->General menu. + */ +class AssertConfigAnalyticsDisabled extends AbstractConstraint +{ + /** + * Assert Analytics is disabled in Stores > Configuration > General > Analytics menu. + * + * @param ConfigAnalytics $configAnalytics + * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsConfigStep $openAnalyticsConfigStep) + { + $openAnalyticsConfigStep->run(); + + \PHPUnit_Framework_Assert::assertFalse( + (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), + 'Magento Analytics is not disabled.' + ); + \PHPUnit_Framework_Assert::assertEquals( + $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), + 'Subscription status: Disabled', + 'Magento Analytics status is not disabled.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics is disabled in Stores > Configuration > General > Analytics > General menu' + . ' and has Disabled status.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php new file mode 100644 index 0000000000000..eb699105e1906 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -0,0 +1,50 @@ + Configuration > General > Analytics > General menu. + */ +class AssertConfigAnalyticsEnabled extends AbstractConstraint +{ + /** + * Assert Analytics is enabled in Stores > Configuration > General > Analytics menu. + * + * @param ConfigAnalytics $configAnalytics + * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsConfigStep $openAnalyticsConfigStep) + { + $openAnalyticsConfigStep->run(); + + \PHPUnit_Framework_Assert::assertTrue( + (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), + 'Magento Analytics is not enabled.' + ); + + \PHPUnit_Framework_Assert::assertEquals( + $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), + 'Subscription status: Pending', + 'Magento Analytics status is not pending.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics is enabled and has Pending status in' + . ' Stores > Configuration > General > Analytics > General menu.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php new file mode 100644 index 0000000000000..e624b49ff38dc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php @@ -0,0 +1,54 @@ +run(); + + $configAnalytics->getAnalyticsForm()->analyticsToggle(); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->saveConfig(); + + \PHPUnit_Framework_Assert::assertTrue( + $systemConfigPage->getMessagesBlock()->assertSuccessMessage(), + 'Sending data to the Analytics is not saved.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Sending data to the Analytics is saved.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php new file mode 100644 index 0000000000000..1de9405e61f21 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsSendingTimeAndZone.php @@ -0,0 +1,52 @@ +run(); + + \PHPUnit_Framework_Assert::assertEquals( + 'Eastern European Standard Time (Europe/Kiev)', + $configAnalytics->getAnalyticsForm()->getTimeZone() + ); + + \PHPUnit_Framework_Assert::assertEquals( + sprintf('%s, %s, 00', $hh, $mm), + $configAnalytics->getAnalyticsForm()->getTimeOfDayToSendDate() + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Time and TimeZone are correct!'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php new file mode 100644 index 0000000000000..3793292653cbf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php @@ -0,0 +1,39 @@ + Configuration > General > Analytics > General menu. + */ +class AssertConfigAnalyticsVerticalScope extends AbstractConstraint +{ + /** + * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics menu. + * + * @param ConfigAnalytics $configAnalytics + */ + public function processAssert(ConfigAnalytics $configAnalytics) + { + \PHPUnit_Framework_Assert::assertEquals( + true, + $configAnalytics->getAnalyticsForm()->getAnalyticsVerticalScope(), + 'Magento Analytics vertical scope is not website' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Magento Analytics vertical scope is website'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php new file mode 100644 index 0000000000000..de1facb47230b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php @@ -0,0 +1,49 @@ +open(); + $dashboard->getSubscriptionBlock()->enableCheckbox(); + $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); + $dashboard->getModalBlock()->dismissWarning(); + $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getSubscriptionBlock()->isVisible(), + 'Advanced Reporting was not disabled' + ); + $dashboard->getModalBlock()->acceptWarning(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getModalBlock()->isVisible(), + 'Advanced Reporting disabling was not confirmed' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting was disabled'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php new file mode 100644 index 0000000000000..3cf503047e6ea --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php @@ -0,0 +1,42 @@ + Configuration > General > Analytics > General menu. + */ +class AssertEmptyVerticalCanNotBeSaved extends AbstractConstraint +{ + /** + * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * + * @param ConfigAnalytics $configAnalytics + * @param string $errorMessage + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) + { + \PHPUnit_Framework_Assert::assertEquals( + $errorMessage, + $configAnalytics->getMessages()->getErrorMessage(), + 'There is no error message when saving empty vertical in configuration' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return + 'Empty Magento Analytics vertical can not be saved'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php new file mode 100644 index 0000000000000..9205ee89f0913 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php @@ -0,0 +1,42 @@ +open(); + $dashboard->getSubscriptionBlock()->enableCheckbox(); + $dashboard->getSubscriptionBlock()->acceptAdvancedReporting(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getSubscriptionBlock()->isVisible(), + 'Advanced Reporting was not enabled' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting was enabled'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php new file mode 100644 index 0000000000000..ddb3593537ad8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php @@ -0,0 +1,42 @@ +open(); + $dashboard->getSubscriptionBlock()->disableCheckbox(); + $dashboard->getSubscriptionBlock()->skipAdvancedReporting(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getSubscriptionBlock()->isVisible(), + 'Advanced Reporting was not skipped' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting was skipped'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php new file mode 100644 index 0000000000000..c2bb48f4bb2ec --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php @@ -0,0 +1,39 @@ +getSubscriptionBlock()->isVisible(), + "Subscription form is visible on dashboard." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Subscription form is absent on dashboard."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php new file mode 100644 index 0000000000000..514c83a30ff51 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php @@ -0,0 +1,42 @@ + Configuration > General > Analytics > General menu. + */ +class AssertVerticalIsSet extends AbstractConstraint +{ + /** + * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * + * @param ConfigAnalytics $configAnalytics + * @param string $vertical + * @return void + */ + public function processAssert(ConfigAnalytics $configAnalytics, $vertical) + { + \PHPUnit_Framework_Assert::assertEquals( + $vertical, + $configAnalytics->getAnalyticsForm()->getAnalyticsVertical(), + $vertical . 'vertical is not selected' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return + 'Proper Magento Analytics vertical is selected'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml new file mode 100644 index 0000000000000..d4a96e588261f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/ConfigAnalytics.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml new file mode 100644 index 0000000000000..bc94ef7862ca7 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml new file mode 100644 index 0000000000000..80d142f8abd60 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/DefaultTimeZone.xml @@ -0,0 +1,35 @@ + + + + + + + 0 + Timezone + Europe/Kiev + + + 0 + Time of day to send data + 01,00,00 + + + + + 0 + Timezone + UTC + + + 0 + Time of day to send data + 02,00,00 + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml new file mode 100644 index 0000000000000..0b4f80512f197 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Integration.xml @@ -0,0 +1,16 @@ + + + + + + + Analytics + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml new file mode 100644 index 0000000000000..6d067a691d59d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml @@ -0,0 +1,19 @@ + + + + + + RoleName%isolation% + Custom + %current_password% + + Magento_Backend::dashboard + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml new file mode 100644 index 0000000000000..13bbb4d1306c5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/User.xml @@ -0,0 +1,24 @@ + + + + + + AdminUser%isolation% + FirstName%isolation% + LastName%isolation% + email%isolation%@example.com + 123123q + 123123q + + role::role_without_subscription_permissions + + %current_password% + Active + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php new file mode 100644 index 0000000000000..970ce59ceb5bf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.php @@ -0,0 +1,36 @@ +open(); + $dashboard->getReportsSectionBlock()->click(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml new file mode 100644 index 0000000000000..a975d19ef8879 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AdvancedReportingButtonTest.xml @@ -0,0 +1,15 @@ + + + + + + https://advancedreporting.rjmetrics.com/report + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php new file mode 100644 index 0000000000000..2fe656081d162 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php @@ -0,0 +1,37 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml new file mode 100644 index 0000000000000..f3ed3736e2ea2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml @@ -0,0 +1,15 @@ + + + + + + custom_admin_with_role_without_subscription_permissions + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php new file mode 100644 index 0000000000000..b52fa92ad6743 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.php @@ -0,0 +1,42 @@ +Configuration>General>Advanced Reporting->General + * 3. Set Option "Advanced Reporting Service" + * 4. Click "Save Config" + * 5. Perform assertions + * + * @ZephyrId MAGETWO-66465 + */ +class EnableDisableTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * @param ConfigAnalytics $configAnalytics + * @param string $vertical + * @param string $state + * @return void + */ + public function test(ConfigAnalytics $configAnalytics, $vertical, $state) + { + $configAnalytics->open(); + $configAnalytics->getAnalyticsForm()->analyticsToggle($state); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->saveConfig(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml new file mode 100644 index 0000000000000..fdc92ed814a90 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/EnableDisableTest.xml @@ -0,0 +1,21 @@ + + + + + + Apps and Games + Disable + + + + Apps and Games + Enable + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml new file mode 100644 index 0000000000000..8e19e1116da19 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml @@ -0,0 +1,28 @@ + + + + + + severity:S1 + Apps and Games + + + + + + severity:S1 + + + + + severity:S1 + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml new file mode 100644 index 0000000000000..9c19f80e91d39 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml @@ -0,0 +1,23 @@ + + + + + + Reports > BI Essentials + false + https://dashboard.rjmetrics.com/v2/magento/signup + + + + Reports > Advanced Reporting + false + https://advancedreporting.rjmetrics.com/report + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php new file mode 100644 index 0000000000000..e05804c2bfcfb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.php @@ -0,0 +1,75 @@ +Configuration>General>Advanced Reporting->General + * 3. Set Option "Time of day to send data" + * 4. Click "Save Config" + * 5. Perform assertions + * + * @ZephyrId MAGETWO-66464 + */ +class SetTimeToSendDataTest extends Injectable +{ + /* tags */ + const MVP = 'no'; + const SEVERITY = 'S1'; + /* end tags */ + + /** + * @var array + */ + private $configData; + + /** + * @param ConfigAnalytics $configAnalytics + * @param TestStepFactory $testStepFactory + * @param string $hh + * @param string $mm + * @param string $vertical + * @param string $configData + * @return void + */ + public function test( + ConfigAnalytics $configAnalytics, + TestStepFactory $testStepFactory, + $hh, + $mm, + $vertical, + $configData + ) { + $this->configData = $configData; + $testStepFactory->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData] + )->run(); + + $configAnalytics->open(); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->setTimeOfDayToSendData($hh, $mm); + $configAnalytics->getAnalyticsForm()->saveConfig(); + } + + /** + * Clean data after running test. + * + * @return void + */ + public function tearDown() + { + $this->objectManager->create( + \Magento\Config\Test\TestStep\SetupConfigurationStep::class, + ['configData' => $this->configData, 'rollback' => true] + )->run(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml new file mode 100644 index 0000000000000..21cc1f732c1f8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetTimeToSendDataTest.xml @@ -0,0 +1,18 @@ + + + + + + Apps and Games + 11 + 11 + change_default_timezone + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php new file mode 100644 index 0000000000000..a721774f4d22c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php @@ -0,0 +1,40 @@ +open(); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->saveConfig(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml new file mode 100644 index 0000000000000..1db31781ccc2f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml @@ -0,0 +1,21 @@ + + + + + + Apps and Games + + + + + --Please Select-- + Please select a vertical. + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php new file mode 100644 index 0000000000000..1f0a8ff4804a3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestStep/OpenAnalyticsConfigStep.php @@ -0,0 +1,54 @@ +Configuration->General->Analytics->General menu. + */ +class OpenAnalyticsConfigStep implements TestStepInterface +{ + /** + * Dashboard page. + * + * @var Dashboard + */ + private $dashboard; + + /** + * System Config page. + * + * @var SystemConfigEdit + */ + private $systemConfigPage; + + /** + * @param Dashboard $dashboard + * @param SystemConfigEdit $systemConfigPage + */ + public function __construct(Dashboard $dashboard, SystemConfigEdit $systemConfigPage) + { + $this->dashboard = $dashboard; + $this->systemConfigPage = $systemConfigPage; + } + + /** + * Navigate to Stores->Configuration->General->Analytics->General menu. + * + * @return void + */ + public function run() + { + $this->dashboard->open(); + $this->dashboard->getMenuBlock()->navigate('Stores > Configuration'); + $this->systemConfigPage->getForm()->getGroup('analytics', 'general'); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml new file mode 100644 index 0000000000000..74b10cca43c1f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -0,0 +1,51 @@ + + + + + + + Magento\Analytics\Mtf\App\State\NotificationTimeHandler + + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + + + S1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml new file mode 100644 index 0000000000000..2de77423c0a74 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php index 04ac3eee83245..395fa4cd4d81f 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php @@ -31,18 +31,31 @@ class UpgradeSystemTest extends Injectable protected $adminDashboard; /** - * Injection data. - * + * @var \Magento\Analytics\Mtf\App\State\NotificationTimeHandler + */ + private $analyticsNotificationHandler; + + /** + * @var \Magento\Mtf\Util\Iterator\ApplicationState + */ + private $applicationStateIterator; + + /** * @param Dashboard $adminDashboard * @param SetupWizard $setupWizard - * @return void + * @param \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler + * @param \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator */ public function __inject( Dashboard $adminDashboard, - SetupWizard $setupWizard + SetupWizard $setupWizard, + \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler, + \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator ) { $this->adminDashboard = $adminDashboard; $this->setupWizard = $setupWizard; + $this->analyticsNotificationHandler = $analyticsNotificationHandler; + $this->applicationStateIterator = $applicationStateIterator; } /** @@ -128,6 +141,11 @@ public function test( $assertSuccessMessage->processAssert($this->setupWizard, $upgrade['package']); + // Disable promotion popup for Analytics module + $appStateMetadata = $this->applicationStateIterator->current(); + $appState = \Magento\Mtf\ObjectManager::getInstance()->get($appStateMetadata['class']); + $this->analyticsNotificationHandler->execute($appState); + // Check application version $this->adminDashboard->open(); $assertApplicationVersion->processAssert($this->adminDashboard, $version); diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml index 716a6dd89a61f..7fd5c9cb5eda8 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml @@ -11,6 +11,7 @@ + diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php new file mode 100644 index 0000000000000..4578286a5d071 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php @@ -0,0 +1,177 @@ +otpResponseResolver = $objectManager->get( + 'OtpResponseResolver' + ); + $this->updateResponseResolver = $objectManager->get( + 'UpdateResponseResolver' + ); + $this->notifyDataChangedResponseResolver = $objectManager->get( + 'NotifyDataChangedResponseResolver' + ); + $this->converter = $objectManager->get(ConverterInterface::class); + $this->flagManager = $objectManager->get(FlagManager::class); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnOtp() + { + $body = $this->converter->toBody(['test' => '42']); + $retryResponse = new \Zend_Http_Response(401, [$this->converter->getContentTypeHeader()], $body); + $this->otpResponseResolver->getResult($retryResponse); + $this->assertCronWasSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignOnOtpWasNotCalled() + { + $body = $this->converter->toBody(['test' => '42']); + $successResponse = new \Zend_Http_Response(201, [$this->converter->getContentTypeHeader()], $body); + $this->otpResponseResolver->getResult($successResponse); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnUpdateWasCalled() + { + $body = $this->converter->toBody(['test' => '42']); + $retryResponse = new \Zend_Http_Response(401, [$this->converter->getContentTypeHeader()], $body); + $this->updateResponseResolver->getResult($retryResponse); + $this->assertCronWasSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnUpdateWasNotCalled() + { + $body = $this->converter->toBody(['test' => '42']); + $successResponse = new \Zend_Http_Response(201, [$this->converter->getContentTypeHeader()], $body); + $this->updateResponseResolver->getResult($successResponse); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDataFixture Magento/Analytics/_files/enabled_subscription_with_invalid_token.php + * @magentoDbIsolation enabled + */ + public function testReSignUpOnNotifyDataChangedWasNotCalledWhenSubscriptionUpdateIsRunning() + { + $this->flagManager + ->saveFlag( + SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, + 'https://previous.example.com/' + ); + $body = $this->converter->toBody(['test' => '42']); + $retryResponse = new \Zend_Http_Response(401, [$this->converter->getContentTypeHeader()], $body); + $this->notifyDataChangedResponseResolver->getResult($retryResponse); + $this->assertCronWasNotSet(); + } + + /** + * @return string|null + */ + private function getSubscribeSchedule() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** + * @var $scopeConfig ScopeConfigInterface + */ + $scopeConfig = $objectManager->get(ScopeConfigInterface::class); + + return $scopeConfig->getValue( + SubscriptionHandler::CRON_STRING_PATH, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + 0 + ); + } + + /** + * @return int|null + */ + private function getAttemptFlag() + { + $objectManager = Bootstrap::getObjectManager(); + /** + * @var $flagManager FlagManager + */ + $flagManager = $objectManager->get(FlagManager::class); + + return $flagManager->getFlagData(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); + } + + /** + * @return void + */ + private function assertCronWasSet() + { + $this->assertEquals('0 * * * *', $this->getSubscribeSchedule()); + $this->assertGreaterThan(1, $this->getAttemptFlag()); + } + + /** + * @return void + */ + private function assertCronWasNotSet() + { + $this->assertNull($this->getSubscribeSchedule()); + $this->assertNull($this->getAttemptFlag()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php new file mode 100644 index 0000000000000..6082712cfabff --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php @@ -0,0 +1,207 @@ +objectManager = Bootstrap::getObjectManager(); + $this->preparedValueFactory = $this->objectManager->get(PreparedValueFactory::class); + $this->configValueResourceModel = $this->objectManager->get(ConfigData::class); + $this->scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $this->flagManager = $this->objectManager->get(FlagManager::class); + } + + /** + * @magentoDbIsolation enabled + */ + public function testAfterSaveNotSecureUrl() + { + $this->saveConfigValue( + Store::XML_PATH_UNSECURE_BASE_URL, + 'http://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDbIsolation enabled + */ + public function testAfterSaveSecureUrlNotInDefaultScope() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeInterface::SCOPE_STORES + ); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDbIsolation enabled + * @magentoAdminConfigFixture web/secure/base_url https://previous.example.com/ + */ + public function testAfterSaveSecureUrlInDefaultScopeOnDoesNotRegisteredInstance() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasNotSet(); + } + + /** + * @magentoDbIsolation enabled + * @magentoAdminConfigFixture web/secure/base_url https://previous.example.com/ + * @magentoAdminConfigFixture analytics/general/token MBI_token + */ + public function testAfterSaveSecureUrlInDefaultScopeOnRegisteredInstance() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasSet(); + } + + /** + * @magentoDbIsolation enabled + * @magentoAdminConfigFixture web/secure/base_url https://previous.example.com/ + * @magentoAdminConfigFixture analytics/general/token MBI_token + */ + public function testAfterSaveMultipleBaseUrlChanges() + { + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + + $this->saveConfigValue( + Store::XML_PATH_SECURE_BASE_URL, + 'https://store10.com/', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + $this->assertCronWasSet(); + } + + /** + * @param string $path The configuration path in format section/group/field_name + * @param string $value The configuration value + * @param string $scope The configuration scope (default, website, or store) + * @return void + */ + private function saveConfigValue(string $path, string $value, string $scope) + { + $value = $this->preparedValueFactory->create( + $path, + $value, + $scope + ); + $this->configValueResourceModel->save($value); + } + + /** + * @return void + */ + private function assertCronWasNotSet() + { + $this->assertNull($this->getSubscriptionUpdateSchedule()); + $this->assertNull($this->getPreviousUpdateUrl()); + $this->assertNull($this->getUpdateReverseCounter()); + } + + /** + * @return void + */ + private function assertCronWasSet() + { + $this->assertSame( + '0 * * * *', + $this->getSubscriptionUpdateSchedule(), + 'Subscription update schedule has not been set' + ); + $this->assertSame( + 'https://previous.example.com/', + $this->getPreviousUpdateUrl(), + 'The previous URL stored for update is not correct' + ); + $this->assertSame(48, $this->getUpdateReverseCounter()); + } + + /** + * @return mixed + */ + private function getSubscriptionUpdateSchedule() + { + return $this->scopeConfig->getValue( + SubscriptionUpdateHandler::UPDATE_CRON_STRING_PATH, + ScopeConfigInterface::SCOPE_TYPE_DEFAULT + ); + } + + /** + * @return mixed + */ + private function getPreviousUpdateUrl() + { + return $this->flagManager->getFlagData(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE); + } + + /** + * @return mixed + */ + private function getUpdateReverseCounter() + { + return $this->flagManager + ->getFlagData(SubscriptionUpdateHandler::SUBSCRIPTION_UPDATE_REVERSE_COUNTER_FLAG_CODE); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php new file mode 100644 index 0000000000000..97d9b7cab0675 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php @@ -0,0 +1,56 @@ +reportUrlProvider = $objectManager->get(ReportUrlProvider::class); + $this->flagManager = $objectManager->get(FlagManager::class); + } + + /** + * @magentoDbIsolation enabled + */ + public function testGetUrlWhenSubscriptionUpdateIsRunning() + { + $this->flagManager + ->saveFlag( + SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, + 'https://previous.example.com/' + ); + $this->setExpectedException( + SubscriptionUpdateException::class, + 'Your Base URL has been changed and your reports are being updated. ' + . 'Advanced Reporting will be available once this change has been processed. Please try again later.' + ); + $this->reportUrlProvider->getUrl(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php b/dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php new file mode 100644 index 0000000000000..928bb6fb36a06 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/_files/create_link.php @@ -0,0 +1,21 @@ +create(\Magento\Analytics\Model\FileInfoManager::class); + +/** + * @var $fileInfo \Magento\Analytics\Model\FileInfo + */ +$fileInfo = $objectManager->create( + \Magento\Analytics\Model\FileInfo::class, + ['path' => 'analytics/jsldjsfdkldf/data.tgz', 'initializationVector' => 'binaryDataisdodssds8iui'] +); + +$fileInfoManager->save($fileInfo); diff --git a/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php new file mode 100644 index 0000000000000..0106bf6f1bdac --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token.php @@ -0,0 +1,29 @@ +get(\Magento\Framework\App\Config\Storage\WriterInterface::class); + +$configWriter->delete(SubscriptionHandler::CRON_STRING_PATH); +$configWriter->save('analytics/subscription/enabled', 1); + +/** + * @var $analyticsToken \Magento\Analytics\Model\AnalyticsToken + */ +$analyticsToken = $objectManager->get(\Magento\Analytics\Model\AnalyticsToken::class); +$analyticsToken->storeToken('42'); + +/** + * @var $flagManager \Magento\Framework\FlagManager + */ +$flagManager = $objectManager->get(\Magento\Framework\FlagManager::class); + +$flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); diff --git a/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php new file mode 100644 index 0000000000000..3fd3e21e282e0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/_files/enabled_subscription_with_invalid_token_rollback.php @@ -0,0 +1,29 @@ +get(\Magento\Framework\App\Config\Storage\WriterInterface::class); + +$configWriter->delete(SubscriptionHandler::CRON_STRING_PATH); +$configWriter->save('analytics/subscription/enabled', 0); + +/** + * @var $analyticsToken \Magento\Analytics\Model\AnalyticsToken + */ +$analyticsToken = $objectManager->get(\Magento\Analytics\Model\AnalyticsToken::class); +$analyticsToken->storeToken(null); + +/** + * @var $flagManager \Magento\Framework\FlagManager + */ +$flagManager = $objectManager->get(\Magento\Framework\FlagManager::class); + +$flagManager->deleteFlag(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js new file mode 100644 index 0000000000000..9f691c8dc2d05 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js @@ -0,0 +1,126 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/* global jQuery */ +/* eslint-disable max-nested-callbacks */ +define([ + 'jquery', + 'squire' +], function ($, Squire) { + 'use strict'; + + var injector = new Squire(), + mocks = { + 'Magento_Ui/js/modal/alert': jasmine.createSpy(), + 'uiRegistry': jasmine.createSpy() + }, + obj; + + describe('Magento_Analytics/js/modal/modal-component', function () { + beforeEach(function (done) { + injector.mock(mocks); + injector.require(['Magento_Analytics/js/modal/modal-component'], function (Constr) { + obj = new Constr({ + provider: 'provName', + name: '', + index: '', + links: '', + listens: '', + + /** + * @return {Object} source - mock for form data + */ + form: function () { + return { + source: { + data: {} + } + }; + } + }); + done(); + }); + }); + describe('"sendPostponeRequest" method', function () { + it('should send a ajax request', function () { + jQuery.ajax = jasmine.createSpy().and.callFake(function () { + var d = $.Deferred(); + + d.resolve({ + 'success': true + }); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + }); + + it('should call "onError" method if ajax received error', function () { + spyOn(obj, 'onError'); + jQuery.ajax = jasmine.createSpy().and.callFake(function () { + var d = $.Deferred(); + + d.resolve({ + 'error': true + }); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + expect(obj.onError).toHaveBeenCalled(); + }); + + it('should call "onError" method if request failed', function () { + spyOn(obj, 'onError'); + jQuery.ajax = jasmine.createSpy().and.callFake(function () { + var d = $.Deferred(); + + d.reject(); + + return d.promise(); + }); + + obj.sendPostponeRequest({}); + + expect(jQuery.ajax).toHaveBeenCalled(); + expect(obj.onError).toHaveBeenCalled(); + }); + }); + + describe('"onError" method', function () { + var abortRequest = { + statusText: 'abort' + }, + errorRequest = { + error: true, + message: 'Error text' + }; + + it('should do nothing if request aborted', function () { + expect(obj.onError(abortRequest)).toBeUndefined(); + }); + + it('should show alert with error', function () { + obj.onError(errorRequest); + expect(mocks['Magento_Ui/js/modal/alert']).toHaveBeenCalled(); + }); + }); + + describe('"actionCancel" method', function () { + it('should call "sendPostponeRequest" and "closeModal" methods', function () { + spyOn(obj, 'sendPostponeRequest'); + spyOn(obj, 'closeModal'); + obj.actionCancel(); + expect(obj.sendPostponeRequest).toHaveBeenCalledWith(obj.postponeOptions); + expect(obj.closeModal).toHaveBeenCalled(); + }); + }); + }); +}); From dc61daa5dfbcb1774f4cf30dcb2c9d5a8bc985f5 Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 15 Sep 2017 14:15:20 -0500 Subject: [PATCH 004/528] MAGETWO-80488: Apply AR code from previous development - update tests to PHPUnit version 6 --- .../Adminhtml/System/Config/AdditionalCommentTest.php | 2 +- .../Adminhtml/System/Config/CollectionTimeLabelTest.php | 2 +- .../System/Config/SubscriptionStatusLabelTest.php | 2 +- .../Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php | 2 +- .../Test/Unit/Controller/Adminhtml/Reports/ShowTest.php | 2 +- .../Controller/Adminhtml/Subscription/ActivateTest.php | 2 +- .../Controller/Adminhtml/Subscription/PostponeTest.php | 2 +- .../Unit/Controller/Adminhtml/Subscription/RetryTest.php | 2 +- .../Magento/Analytics/Test/Unit/Cron/CollectDataTest.php | 2 +- app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php | 2 +- app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php | 2 +- .../Analytics/Test/Unit/Model/AnalyticsTokenTest.php | 2 +- .../Test/Unit/Model/Condition/CanViewNotificationTest.php | 2 +- .../Backend/Baseurl/SubscriptionUpdateHandlerTest.php | 2 +- .../Test/Unit/Model/Config/Backend/CollectionTimeTest.php | 2 +- .../Config/Backend/Enabled/SubscriptionHandlerTest.php | 2 +- .../Test/Unit/Model/Config/Backend/EnabledTest.php | 2 +- .../Test/Unit/Model/Config/Backend/VerticalTest.php | 2 +- .../Analytics/Test/Unit/Model/Config/MapperTest.php | 2 +- .../Analytics/Test/Unit/Model/Config/ReaderTest.php | 2 +- .../Test/Unit/Model/Config/Source/VerticalTest.php | 2 +- app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php | 2 +- .../Test/Unit/Model/Connector/Http/Client/CurlTest.php | 2 +- .../Test/Unit/Model/Connector/Http/JsonConverterTest.php | 2 +- .../Unit/Model/Connector/Http/ResponseResolverTest.php | 2 +- .../Unit/Model/Connector/NotifyDataChangedCommandTest.php | 2 +- .../Test/Unit/Model/Connector/OTPRequestTest.php | 2 +- .../Test/Unit/Model/Connector/ResponseHandler/OTPTest.php | 2 +- .../Unit/Model/Connector/ResponseHandler/ReSignUpTest.php | 2 +- .../Unit/Model/Connector/ResponseHandler/SignUpTest.php | 2 +- .../Unit/Model/Connector/ResponseHandler/UpdateTest.php | 2 +- .../Test/Unit/Model/Connector/SignUpCommandTest.php | 2 +- .../Test/Unit/Model/Connector/UpdateCommandTest.php | 2 +- .../Magento/Analytics/Test/Unit/Model/ConnectorTest.php | 2 +- .../Analytics/Test/Unit/Model/CryptographerTest.php | 2 +- .../Analytics/Test/Unit/Model/EncodedContextTest.php | 2 +- .../Test/Unit/Model/ExportDataHandlerNotificationTest.php | 2 +- .../Analytics/Test/Unit/Model/ExportDataHandlerTest.php | 2 +- .../Analytics/Test/Unit/Model/FileInfoManagerTest.php | 2 +- .../Magento/Analytics/Test/Unit/Model/FileInfoTest.php | 2 +- .../Analytics/Test/Unit/Model/FileRecorderTest.php | 2 +- .../Analytics/Test/Unit/Model/IntegrationManagerTest.php | 2 +- .../Analytics/Test/Unit/Model/LinkProviderTest.php | 2 +- .../Analytics/Test/Unit/Model/NotificationTimeTest.php | 2 +- .../Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php | 2 +- .../Analytics/Test/Unit/Model/ReportUrlProviderTest.php | 8 ++------ .../Analytics/Test/Unit/Model/ReportWriterTest.php | 2 +- .../Test/Unit/Model/ReportXml/ModuleIteratorTest.php | 2 +- .../Test/Unit/Model/StoreConfigurationProviderTest.php | 2 +- .../Test/Unit/Model/SubscriptionStatusProviderTest.php | 2 +- .../Message/NotificationAboutFailedSubscriptionTest.php | 2 +- .../Test/Unit/ReportXml/Config/Converter/XmlTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/Config/MapperTest.php | 2 +- .../Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php | 2 +- .../Test/Unit/ReportXml/ConnectionFactoryTest.php | 2 +- .../Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php | 2 +- .../Unit/ReportXml/DB/Assembler/FromAssemblerTest.php | 2 +- .../Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php | 2 +- .../Test/Unit/ReportXml/DB/ColumnsResolverTest.php | 2 +- .../Test/Unit/ReportXml/DB/ConditionResolverTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php | 2 +- .../Test/Unit/ReportXml/DB/ReportValidatorTest.php | 2 +- .../Test/Unit/ReportXml/DB/SelectBuilderTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/QueryFactoryTest.php | 2 +- .../Magento/Analytics/Test/Unit/ReportXml/QueryTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/ReportProviderTest.php | 2 +- .../Analytics/Test/Unit/ReportXml/SelectHydratorTest.php | 2 +- .../Test/Unit/Ui/DataProvider/DummyDataProviderTest.php | 2 +- .../Model/Connector/Http/ReSignUpResponseResolverTest.php | 2 +- .../Analytics/Model/Plugin/BaseUrlConfigPluginTest.php | 2 +- .../Magento/Analytics/Model/ReportUrlProviderTest.php | 8 ++------ 72 files changed, 74 insertions(+), 82 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php index b94a295c86527..744ba7466e593 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php @@ -10,7 +10,7 @@ use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; -class AdditionalCommentTest extends \PHPUnit_Framework_TestCase +class AdditionalCommentTest extends \PHPUnit\Framework\TestCase { /** * @var AdditionalComment diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php index d37daf9525119..74fbbf2e78a40 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -11,7 +11,7 @@ use Magento\Framework\Data\Form\Element\AbstractElement; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; -class CollectionTimeLabelTest extends \PHPUnit_Framework_TestCase +class CollectionTimeLabelTest extends \PHPUnit\Framework\TestCase { /** * @var CollectionTimeLabel diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php index e25e745317699..04728c403a861 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php @@ -14,7 +14,7 @@ /** * Class SignupTest */ -class SubscriptionStatusLabelTest extends \PHPUnit_Framework_TestCase +class SubscriptionStatusLabelTest extends \PHPUnit\Framework\TestCase { /** * @var SubscriptionStatusLabel diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php index 3a251f9a8685a..6f613cdc4d639 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/BIEssentials/SignUpTest.php @@ -14,7 +14,7 @@ /** * Class SignupTest */ -class SignUpTest extends \PHPUnit_Framework_TestCase +class SignUpTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php index 99de92cc63905..4f54ce5059965 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Reports/ShowTest.php @@ -17,7 +17,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ShowTest extends \PHPUnit_Framework_TestCase +class ShowTest extends \PHPUnit\Framework\TestCase { /** * @var ReportUrlProvider|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php index 9097349e9137c..66c7ae4fac448 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php @@ -20,7 +20,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ActivateTest extends \PHPUnit_Framework_TestCase +class ActivateTest extends \PHPUnit\Framework\TestCase { /** * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php index 0f425291bf999..1fb7126146767 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php @@ -19,7 +19,7 @@ /** * Class PostponeTest */ -class PostponeTest extends \PHPUnit_Framework_TestCase +class PostponeTest extends \PHPUnit\Framework\TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject|DateTimeFactory diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php index 2c921e2260140..17c485a8df230 100644 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/RetryTest.php @@ -18,7 +18,7 @@ /** * Class RetryTest */ -class RetryTest extends \PHPUnit_Framework_TestCase +class RetryTest extends \PHPUnit\Framework\TestCase { /** * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php index ef071cdf3a911..81c57d79033c8 100644 --- a/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Cron/CollectDataTest.php @@ -13,7 +13,7 @@ /** * Class CollectDataTest */ -class CollectDataTest extends \PHPUnit_Framework_TestCase +class CollectDataTest extends \PHPUnit\Framework\TestCase { /** * @var ExportDataHandlerInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php index c8ab5a6f4649e..959a11f9e1058 100644 --- a/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Cron/SignUpTest.php @@ -15,7 +15,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class SignUpTest extends \PHPUnit_Framework_TestCase +class SignUpTest extends \PHPUnit\Framework\TestCase { /** * @var Connector|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php index 23ba59a90ce7b..ede53d8783a7a 100644 --- a/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Cron/UpdateTest.php @@ -16,7 +16,7 @@ /** * Class Update */ -class UpdateTest extends \PHPUnit_Framework_TestCase +class UpdateTest extends \PHPUnit\Framework\TestCase { /** * @var Connector|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php index e078bbe99f93a..57315543bc32d 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/AnalyticsTokenTest.php @@ -14,7 +14,7 @@ /** * Class AnalyticsTokenTest */ -class AnalyticsTokenTest extends \PHPUnit_Framework_TestCase +class AnalyticsTokenTest extends \PHPUnit\Framework\TestCase { /** * @var ReinitableConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index bfdc971efc79e..755db7e0b3ab1 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -14,7 +14,7 @@ /** * Class CanViewNotificationTest */ -class CanViewNotificationTest extends \PHPUnit_Framework_TestCase +class CanViewNotificationTest extends \PHPUnit\Framework\TestCase { /** * @var NotificationTime|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php index 865ad236fc057..f5f721c038c57 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Baseurl/SubscriptionUpdateHandlerTest.php @@ -13,7 +13,7 @@ use Magento\Framework\FlagManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -class SubscriptionUpdateHandlerTest extends \PHPUnit_Framework_TestCase +class SubscriptionUpdateHandlerTest extends \PHPUnit\Framework\TestCase { /** * @var AnalyticsToken|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php index 555020ffd247f..071b96111ac8b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/CollectionTimeTest.php @@ -14,7 +14,7 @@ /** * Class CollectionTimeTest */ -class CollectionTimeTest extends \PHPUnit_Framework_TestCase +class CollectionTimeTest extends \PHPUnit\Framework\TestCase { /** * @var WriterInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php index d01101bf5cc3b..e5ec3f80322a9 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -17,7 +17,7 @@ /** * Class SubscriptionHandlerTest */ -class SubscriptionHandlerTest extends \PHPUnit_Framework_TestCase +class SubscriptionHandlerTest extends \PHPUnit\Framework\TestCase { /** * @var FlagManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php index d64827d2d18d2..eea3193258bc6 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/EnabledTest.php @@ -16,7 +16,7 @@ /** * Class EnabledTest */ -class EnabledTest extends \PHPUnit_Framework_TestCase +class EnabledTest extends \PHPUnit\Framework\TestCase { /** * @var SubscriptionHandler|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php index d689f040c48b3..6fe7d0aa93998 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/VerticalTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the backend model for verticals configuration. */ -class VerticalTest extends \PHPUnit_Framework_TestCase +class VerticalTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\Model\Config\Backend\Vertical diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php index 7c94fb1b60a14..0b7f4870dbac8 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/MapperTest.php @@ -11,7 +11,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class MapperTest extends \PHPUnit_Framework_TestCase +class MapperTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php index 1eee74a1f93a0..6aa9c7ef3106c 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/ReaderTest.php @@ -13,7 +13,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ReaderTest extends \PHPUnit_Framework_TestCase +class ReaderTest extends \PHPUnit\Framework\TestCase { /** * @var Mapper|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php index b96f3543ff701..c13205d34f25b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Source/VerticalTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the source model for verticals configuration. */ -class VerticalTest extends \PHPUnit_Framework_TestCase +class VerticalTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\Model\Config\Source\Vertical diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php index 8282b1ae52617..8739219ebdf09 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConfigTest.php @@ -12,7 +12,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ConfigTest extends \PHPUnit_Framework_TestCase +class ConfigTest extends \PHPUnit\Framework\TestCase { /** * @var DataInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php index 6890fe200f9dc..f8f3919b2489e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/Client/CurlTest.php @@ -12,7 +12,7 @@ /** * A unit test for testing of the CURL HTTP client. */ -class CurlTest extends \PHPUnit_Framework_TestCase +class CurlTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\Model\Connector\Http\Client\Curl diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php index 7ac6f50ea24c4..60a19f3d5079e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/JsonConverterTest.php @@ -10,7 +10,7 @@ /** * Class JsonConverterTest */ -class JsonConverterTest extends \PHPUnit_Framework_TestCase +class JsonConverterTest extends \PHPUnit\Framework\TestCase { public function testConverterContainsHeader() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php index 5047e8a9dd391..7c3c484843285 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/Http/ResponseResolverTest.php @@ -12,7 +12,7 @@ /** * Class ResponseResolverTest */ -class ResponseResolverTest extends \PHPUnit_Framework_TestCase +class ResponseResolverTest extends \PHPUnit\Framework\TestCase { public function testGetResultHandleResponseSuccess() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php index 5b86dd6557d69..cee3877631c2e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/NotifyDataChangedCommandTest.php @@ -14,7 +14,7 @@ use Magento\Analytics\Model\Connector\NotifyDataChangedCommand; use Magento\Analytics\Model\Connector\Http\ClientInterface; -class NotifyDataChangedCommandTest extends \PHPUnit_Framework_TestCase +class NotifyDataChangedCommandTest extends \PHPUnit\Framework\TestCase { /** * @var NotifyDataChangedCommand diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php index a33d7d0d7c1bf..8a3f4efb15cf4 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/OTPRequestTest.php @@ -15,7 +15,7 @@ /** * A unit test for testing of the representation of a 'OTP' request. */ -class OTPRequestTest extends \PHPUnit_Framework_TestCase +class OTPRequestTest extends \PHPUnit\Framework\TestCase { /** * @var OTPRequest diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php index 203eb57157e0e..0ff36cca5db2d 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/OTPTest.php @@ -10,7 +10,7 @@ /** * Class OTPTest */ -class OTPTest extends \PHPUnit_Framework_TestCase +class OTPTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php index 4c3dde7a92c3f..707003149bcfd 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/ReSignUpTest.php @@ -13,7 +13,7 @@ /** * Class ReSignUpTest */ -class ReSignUpTest extends \PHPUnit_Framework_TestCase +class ReSignUpTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php index 2bbd528638a19..81711cfc56950 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/SignUpTest.php @@ -12,7 +12,7 @@ /** * Class SignUpTest */ -class SignUpTest extends \PHPUnit_Framework_TestCase +class SignUpTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php index 90102e2c3d868..7779357e8bea7 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/ResponseHandler/UpdateTest.php @@ -10,7 +10,7 @@ /** * Class UpdateTest */ -class UpdateTest extends \PHPUnit_Framework_TestCase +class UpdateTest extends \PHPUnit\Framework\TestCase { public function testHandleResult() { diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php index cc9eba99b3d48..5593496a957b7 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/SignUpCommandTest.php @@ -18,7 +18,7 @@ /** * Class SignUpCommandTest */ -class SignUpCommandTest extends \PHPUnit_Framework_TestCase +class SignUpCommandTest extends \PHPUnit\Framework\TestCase { /** * @var SignUpCommand diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php index eb22461d789c8..47253a13530e5 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Connector/UpdateCommandTest.php @@ -18,7 +18,7 @@ /** * Class SignUpCommandTest */ -class UpdateCommandTest extends \PHPUnit_Framework_TestCase +class UpdateCommandTest extends \PHPUnit\Framework\TestCase { /** * @var UpdateCommand diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php index 14d641a19729d..4414b81cbc183 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ConnectorTest.php @@ -12,7 +12,7 @@ /** * Class SignUpCommandTest */ -class ConnectorTest extends \PHPUnit_Framework_TestCase +class ConnectorTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php index 3de718d843a1d..a896c309b4007 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php @@ -14,7 +14,7 @@ /** * Class CryptographerTest */ -class CryptographerTest extends \PHPUnit_Framework_TestCase +class CryptographerTest extends \PHPUnit\Framework\TestCase { /** * @var AnalyticsToken|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php index 283b13212919d..a1a7c54510681 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/EncodedContextTest.php @@ -11,7 +11,7 @@ /** * Class EncodedContextTest */ -class EncodedContextTest extends \PHPUnit_Framework_TestCase +class EncodedContextTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php index b3826c232ed0c..1582c241bf45d 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerNotificationTest.php @@ -13,7 +13,7 @@ /** * Class ExportDataHandlerNotificationTest */ -class ExportDataHandlerNotificationTest extends \PHPUnit_Framework_TestCase +class ExportDataHandlerNotificationTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php index 7c181bea81aab..6ffb61d088567 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ExportDataHandlerTest.php @@ -19,7 +19,7 @@ /** * Class ExportDataHandlerTest */ -class ExportDataHandlerTest extends \PHPUnit_Framework_TestCase +class ExportDataHandlerTest extends \PHPUnit\Framework\TestCase { /** * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php index c8c07ae8240c3..da5f6af3ca4e1 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoManagerTest.php @@ -14,7 +14,7 @@ /** * Class FileInfoManagerTest */ -class FileInfoManagerTest extends \PHPUnit_Framework_TestCase +class FileInfoManagerTest extends \PHPUnit\Framework\TestCase { /** * @var FlagManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php index 73f6ed644721a..43ce833f1f03f 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileInfoTest.php @@ -11,7 +11,7 @@ /** * Class FileInfoTest */ -class FileInfoTest extends \PHPUnit_Framework_TestCase +class FileInfoTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php index 68ff00a433fd2..3c9520bdd995b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/FileRecorderTest.php @@ -18,7 +18,7 @@ /** * Class FileRecorderTest */ -class FileRecorderTest extends \PHPUnit_Framework_TestCase +class FileRecorderTest extends \PHPUnit\Framework\TestCase { /** * @var FileInfoManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php index 31d5c77ce50b0..3076a22c85be4 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/IntegrationManagerTest.php @@ -16,7 +16,7 @@ /** * Class IntegrationManagerTest */ -class IntegrationManagerTest extends \PHPUnit_Framework_TestCase +class IntegrationManagerTest extends \PHPUnit\Framework\TestCase { /** * @var IntegrationServiceInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php index afda37962a3cb..c7aa2219d1eee 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/LinkProviderTest.php @@ -18,7 +18,7 @@ /** * Class LinkProviderTest */ -class LinkProviderTest extends \PHPUnit_Framework_TestCase +class LinkProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ObjectManagerHelper diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php index 03fe7d968a7f5..581cb1171d318 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php @@ -13,7 +13,7 @@ /** * Class NotificationTimeTest */ -class NotificationTimeTest extends \PHPUnit_Framework_TestCase +class NotificationTimeTest extends \PHPUnit\Framework\TestCase { /** * @var FlagManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php index 38d073a4b4550..a89e06562383b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Plugin/BaseUrlConfigPluginTest.php @@ -17,7 +17,7 @@ /** * Class BaseUrlConfigPluginTest */ -class BaseUrlConfigPluginTest extends \PHPUnit_Framework_TestCase +class BaseUrlConfigPluginTest extends \PHPUnit\Framework\TestCase { /** * @var SubscriptionUpdateHandler | \PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php index ee507d88c68db..0607a977e5b68 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportUrlProviderTest.php @@ -17,7 +17,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ReportUrlProviderTest extends \PHPUnit_Framework_TestCase +class ReportUrlProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject @@ -143,11 +143,7 @@ public function testGetUrlWhenSubscriptionUpdateRunning() ->method('getFlagData') ->with(SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE) ->willReturn('http://store.com'); - $this->setExpectedException( - SubscriptionUpdateException::class, - 'Your Base URL has been changed and your reports are being updated. ' - . 'Advanced Reporting will be available once this change has been processed. Please try again later.' - ); + $this->expectException(SubscriptionUpdateException::class); $this->reportUrlProvider->getUrl(); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php index 96ac1143ec5ec..d9b030b84d639 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportWriterTest.php @@ -16,7 +16,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ReportWriterTest extends \PHPUnit_Framework_TestCase +class ReportWriterTest extends \PHPUnit\Framework\TestCase { /** * @var ConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php index 654fad74ef309..f314d77f32b41 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/ReportXml/ModuleIteratorTest.php @@ -10,7 +10,7 @@ use Magento\Framework\Module\Manager as ModuleManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -class ModuleIteratorTest extends \PHPUnit_Framework_TestCase +class ModuleIteratorTest extends \PHPUnit\Framework\TestCase { /** * @var ModuleManager|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php index a2f9be1461c15..cc46d175543ad 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/StoreConfigurationProviderTest.php @@ -12,7 +12,7 @@ use Magento\Store\Api\Data\WebsiteInterface; use Magento\Store\Model\StoreManagerInterface; -class StoreConfigurationProviderTest extends \PHPUnit_Framework_TestCase +class StoreConfigurationProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php index 2e52a13f90bbf..d6b041ce03178 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/SubscriptionStatusProviderTest.php @@ -16,7 +16,7 @@ /** * Class SubscriptionStatusProviderTest. */ -class SubscriptionStatusProviderTest extends \PHPUnit_Framework_TestCase +class SubscriptionStatusProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php index 536a7dbb5dfe9..ad1d87488d751 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/System/Message/NotificationAboutFailedSubscriptionTest.php @@ -13,7 +13,7 @@ /** * Class NotificationAboutFailedSubscriptionTest */ -class NotificationAboutFailedSubscriptionTest extends \PHPUnit_Framework_TestCase +class NotificationAboutFailedSubscriptionTest extends \PHPUnit\Framework\TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject|SubscriptionStatusProvider diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php index 325d3d4a85c7e..3f1ed9a5cf4c0 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/Converter/XmlTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the reports configuration converter (XML to PHP array). */ -class XmlTest extends \PHPUnit_Framework_TestCase +class XmlTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\Config\Converter\Xml diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php index f69b40118b935..85343b6b301d6 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/Config/MapperTest.php @@ -10,7 +10,7 @@ /** * Class MapperTest */ -class MapperTest extends \PHPUnit_Framework_TestCase +class MapperTest extends \PHPUnit\Framework\TestCase { /** * @var Mapper diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php index 1b89a0d3ad671..cbc9aa129d874 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConfigTest.php @@ -12,7 +12,7 @@ /** * Class ConfigTest */ -class ConfigTest extends \PHPUnit_Framework_TestCase +class ConfigTest extends \PHPUnit\Framework\TestCase { /** * @var DataInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php index 330f7f1a6707a..1e4ae9142c13d 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ConnectionFactoryTest.php @@ -15,7 +15,7 @@ /** * Class ConnectionFactoryTest */ -class ConnectionFactoryTest extends \PHPUnit_Framework_TestCase +class ConnectionFactoryTest extends \PHPUnit\Framework\TestCase { /** * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php index 6ebfd1ffa2da6..3b01105a8873b 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FilterAssemblerTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the 'filter' assembler. */ -class FilterAssemblerTest extends \PHPUnit_Framework_TestCase +class FilterAssemblerTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\DB\Assembler\FilterAssembler diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php index cbabac5613a8b..575db94a7b7e1 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/FromAssemblerTest.php @@ -10,7 +10,7 @@ /** * A unit test for testing of the 'from' assembler. */ -class FromAssemblerTest extends \PHPUnit_Framework_TestCase +class FromAssemblerTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\DB\Assembler\FromAssembler diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php index b913689513ce5..aaafd731552a0 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/Assembler/JoinAssemblerTest.php @@ -10,7 +10,7 @@ /** * A unit test for testing of the 'join' assembler. */ -class JoinAssemblerTest extends \PHPUnit_Framework_TestCase +class JoinAssemblerTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\DB\Assembler\JoinAssembler diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php index c8ab79625e9c3..bdbe3d1d22c22 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ColumnsResolverTest.php @@ -16,7 +16,7 @@ /** * Class ColumnsResolverTest */ -class ColumnsResolverTest extends \PHPUnit_Framework_TestCase +class ColumnsResolverTest extends \PHPUnit\Framework\TestCase { /** * @var SelectBuilder|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php index 2a97e109543cf..c8182d068fba5 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ConditionResolverTest.php @@ -14,7 +14,7 @@ /** * Class ConditionResolverTest */ -class ConditionResolverTest extends \PHPUnit_Framework_TestCase +class ConditionResolverTest extends \PHPUnit\Framework\TestCase { /** * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php index ef051feda0722..4accd03aef3ea 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/NameResolverTest.php @@ -11,7 +11,7 @@ /** * Class NameResolverTest */ -class NameResolverTest extends \PHPUnit_Framework_TestCase +class NameResolverTest extends \PHPUnit\Framework\TestCase { /** * @var NameResolver|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php index fad0a80856b70..bbb9ca4b511b6 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/ReportValidatorTest.php @@ -16,7 +16,7 @@ /** * Class ReportValidatorTest */ -class ReportValidatorTest extends \PHPUnit_Framework_TestCase +class ReportValidatorTest extends \PHPUnit\Framework\TestCase { /** * @var ConnectionFactory|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php index fb8f5b4a1ff0e..a82a187cdb3f8 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/DB/SelectBuilderTest.php @@ -13,7 +13,7 @@ /** * Class SelectBuilderTest */ -class SelectBuilderTest extends \PHPUnit_Framework_TestCase +class SelectBuilderTest extends \PHPUnit\Framework\TestCase { /** * @var SelectBuilder diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php index 38abc3683f81f..1d3f293ed676a 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/IteratorFactoryTest.php @@ -11,7 +11,7 @@ /** * Class IteratorFactoryTest */ -class IteratorFactoryTest extends \PHPUnit_Framework_TestCase +class IteratorFactoryTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php index e358bf00fe37a..9a3805a50f167 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryFactoryTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the query factory. */ -class QueryFactoryTest extends \PHPUnit_Framework_TestCase +class QueryFactoryTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\QueryFactory diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php index e288c668a54f7..a4b08a9ce5e0a 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/QueryTest.php @@ -13,7 +13,7 @@ /** * Class QueryTest */ -class QueryTest extends \PHPUnit_Framework_TestCase +class QueryTest extends \PHPUnit\Framework\TestCase { /** * @var Select|\PHPUnit_Framework_MockObject_MockObject diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php index 124d5f32078c8..5f329993dd291 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/ReportProviderTest.php @@ -8,7 +8,7 @@ /** * A unit test for testing of the reports provider. */ -class ReportProviderTest extends \PHPUnit_Framework_TestCase +class ReportProviderTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Analytics\ReportXml\ReportProvider diff --git a/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php index dce8089a787dc..ce57a1eca3689 100644 --- a/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php +++ b/app/code/Magento/Analytics/Test/Unit/ReportXml/SelectHydratorTest.php @@ -16,7 +16,7 @@ /** * Class SelectHydratorTest */ -class SelectHydratorTest extends \PHPUnit_Framework_TestCase +class SelectHydratorTest extends \PHPUnit\Framework\TestCase { /** * @var SelectHydrator diff --git a/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php index 94f6ed1845c40..a58b050a9d928 100644 --- a/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Ui/DataProvider/DummyDataProviderTest.php @@ -16,7 +16,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class DummyDataProviderTest extends \PHPUnit_Framework_TestCase +class DummyDataProviderTest extends \PHPUnit\Framework\TestCase { /** * @var SearchResultInterface|\PHPUnit_Framework_MockObject_MockObject diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php index 4578286a5d071..91f2455c61d87 100644 --- a/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Connector/Http/ReSignUpResponseResolverTest.php @@ -14,7 +14,7 @@ /** * Checks that cron job was set if error handler was set and appropriate http error code was returned. */ -class ReSignUpResponseResolverTest extends \PHPUnit_Framework_TestCase +class ReSignUpResponseResolverTest extends \PHPUnit\Framework\TestCase { /** * @var ResponseResolver diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php index 6082712cfabff..b8933cb5ed3d2 100644 --- a/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/Plugin/BaseUrlConfigPluginTest.php @@ -18,7 +18,7 @@ /** * @magentoAppArea adminhtml */ -class BaseUrlConfigPluginTest extends \PHPUnit_Framework_TestCase +class BaseUrlConfigPluginTest extends \PHPUnit\Framework\TestCase { /** * @var PreparedValueFactory diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php index 97d9b7cab0675..0e2f8c4cc96a2 100644 --- a/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php +++ b/dev/tests/integration/testsuite/Magento/Analytics/Model/ReportUrlProviderTest.php @@ -14,7 +14,7 @@ /** * @magentoAppArea adminhtml */ -class ReportUrlProviderTest extends \PHPUnit_Framework_TestCase +class ReportUrlProviderTest extends \PHPUnit\Framework\TestCase { /** * @var ReportUrlProvider @@ -46,11 +46,7 @@ public function testGetUrlWhenSubscriptionUpdateIsRunning() SubscriptionUpdateHandler::PREVIOUS_BASE_URL_FLAG_CODE, 'https://previous.example.com/' ); - $this->setExpectedException( - SubscriptionUpdateException::class, - 'Your Base URL has been changed and your reports are being updated. ' - . 'Advanced Reporting will be available once this change has been processed. Please try again later.' - ); + $this->expectException(SubscriptionUpdateException::class); $this->reportUrlProvider->getUrl(); } } From cee7a4c3a87ce095c3c2f1530f2f23e272f8c4c5 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 18 Sep 2017 10:00:31 -0500 Subject: [PATCH 005/528] MAGETWO-80488: Apply AR code from previous development - update test to suppress warnings of PHPMD.UnusedFormalParameter --- .../Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php index 81724e735f269..0ea32df272729 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php @@ -39,6 +39,7 @@ public function __construct( * @param AbstractState $state * @return bool * @throws \Exception + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute(AbstractState $state) { From c543259baf3a12d6a3a6c28c77f7142388d5e819 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 18 Sep 2017 10:40:19 -0500 Subject: [PATCH 006/528] MAGETWO-80488: Apply AR code from previous development - update composer.lock file --- composer.lock | 227 +++++++++++++++++++++++++------------------------- 1 file changed, 114 insertions(+), 113 deletions(-) diff --git a/composer.lock b/composer.lock index cd3ddf4d46cd2..2d4f578422dd5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "51eec653c09ff25e77e5f04058539975", + "hash": "9638b9ba14682bca16191207441a0c38", + "content-hash": "97eff12e92f191fc7f80f6e2ff9c278c", "packages": [ { "name": "braintree/braintree_php", @@ -51,7 +52,7 @@ } ], "description": "Braintree PHP Client Library", - "time": "2017-02-16T19:59:04+00:00" + "time": "2017-02-16 19:59:04" }, { "name": "colinmollenhour/cache-backend-file", @@ -87,7 +88,7 @@ ], "description": "The stock Zend_Cache_Backend_File backend has extremely poor performance for cleaning by tags making it become unusable as the number of cached items increases. This backend makes many changes resulting in a huge performance boost, especially for tag cleaning.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_File", - "time": "2016-05-02T16:24:47+00:00" + "time": "2016-05-02 16:24:47" }, { "name": "colinmollenhour/cache-backend-redis", @@ -123,7 +124,7 @@ ], "description": "Zend_Cache backend using Redis with full support for tags.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis", - "time": "2017-03-25T04:54:24+00:00" + "time": "2017-03-25 04:54:24" }, { "name": "colinmollenhour/credis", @@ -162,7 +163,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2015-11-28T01:20:04+00:00" + "time": "2015-11-28 01:20:04" }, { "name": "colinmollenhour/php-redis-session-abstract", @@ -199,7 +200,7 @@ ], "description": "A Redis-based session handler with optimistic locking", "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", - "time": "2017-04-19T14:21:43+00:00" + "time": "2017-04-19 14:21:43" }, { "name": "composer/ca-bundle", @@ -258,7 +259,7 @@ "ssl", "tls" ], - "time": "2017-09-11T07:24:36+00:00" + "time": "2017-09-11 07:24:36" }, { "name": "composer/composer", @@ -335,7 +336,7 @@ "dependency", "package" ], - "time": "2017-03-10T08:29:45+00:00" + "time": "2017-03-10 08:29:45" }, { "name": "composer/semver", @@ -397,7 +398,7 @@ "validation", "versioning" ], - "time": "2016-08-30T16:08:34+00:00" + "time": "2016-08-30 16:08:34" }, { "name": "composer/spdx-licenses", @@ -458,7 +459,7 @@ "spdx", "validator" ], - "time": "2017-04-03T19:08:52+00:00" + "time": "2017-04-03 19:08:52" }, { "name": "container-interop/container-interop", @@ -489,7 +490,7 @@ ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "homepage": "https://github.com/container-interop/container-interop", - "time": "2017-02-14T19:40:03+00:00" + "time": "2017-02-14 19:40:03" }, { "name": "justinrainbow/json-schema", @@ -556,7 +557,7 @@ "json", "schema" ], - "time": "2017-05-16T21:06:09+00:00" + "time": "2017-05-16 21:06:09" }, { "name": "league/climate", @@ -605,7 +606,7 @@ "php", "terminal" ], - "time": "2015-01-18T14:31:58+00:00" + "time": "2015-01-18 14:31:58" }, { "name": "magento/composer", @@ -641,7 +642,7 @@ "AFL-3.0" ], "description": "Magento composer library helps to instantiate Composer application and run composer commands.", - "time": "2017-04-24T09:57:02+00:00" + "time": "2017-04-24 09:57:02" }, { "name": "magento/magento-composer-installer", @@ -720,7 +721,7 @@ "composer-installer", "magento" ], - "time": "2016-10-06T16:05:07+00:00" + "time": "2016-10-06 16:05:07" }, { "name": "magento/zendframework1", @@ -767,7 +768,7 @@ "ZF1", "framework" ], - "time": "2017-06-21T14:56:23+00:00" + "time": "2017-06-21 14:56:23" }, { "name": "monolog/monolog", @@ -845,7 +846,7 @@ "logging", "psr-3" ], - "time": "2017-06-19T01:22:40+00:00" + "time": "2017-06-19 01:22:40" }, { "name": "oyejorge/less.php", @@ -907,7 +908,7 @@ "php", "stylesheet" ], - "time": "2017-03-28T22:19:25+00:00" + "time": "2017-03-28 22:19:25" }, { "name": "paragonie/random_compat", @@ -955,7 +956,7 @@ "pseudorandom", "random" ], - "time": "2017-03-13T16:27:32+00:00" + "time": "2017-03-13 16:27:32" }, { "name": "pelago/emogrifier", @@ -1011,7 +1012,7 @@ ], "description": "Converts CSS styles into inline style attributes in your HTML code", "homepage": "http://www.pelagodesign.com/sidecar/emogrifier/", - "time": "2015-05-15T11:37:51+00:00" + "time": "2015-05-15 11:37:51" }, { "name": "phpseclib/phpseclib", @@ -1103,7 +1104,7 @@ "x.509", "x509" ], - "time": "2017-06-05T06:31:10+00:00" + "time": "2017-06-05 06:31:10" }, { "name": "psr/container", @@ -1152,7 +1153,7 @@ "container-interop", "psr" ], - "time": "2017-02-14T16:28:37+00:00" + "time": "2017-02-14 16:28:37" }, { "name": "psr/log", @@ -1199,7 +1200,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2016-10-10 12:19:37" }, { "name": "ramsey/uuid", @@ -1281,7 +1282,7 @@ "identifier", "uuid" ], - "time": "2017-03-26T20:37:53+00:00" + "time": "2017-03-26 20:37:53" }, { "name": "seld/cli-prompt", @@ -1329,7 +1330,7 @@ "input", "prompt" ], - "time": "2017-03-18T11:32:45+00:00" + "time": "2017-03-18 11:32:45" }, { "name": "seld/jsonlint", @@ -1378,7 +1379,7 @@ "parser", "validator" ], - "time": "2017-06-18T15:11:04+00:00" + "time": "2017-06-18 15:11:04" }, { "name": "seld/phar-utils", @@ -1422,7 +1423,7 @@ "keywords": [ "phra" ], - "time": "2015-10-13T18:44:15+00:00" + "time": "2015-10-13 18:44:15" }, { "name": "sjparkinson/static-review", @@ -1475,7 +1476,7 @@ } ], "description": "An extendable framework for version control hooks.", - "time": "2014-09-22T08:40:36+00:00" + "time": "2014-09-22 08:40:36" }, { "name": "symfony/console", @@ -1536,7 +1537,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-08-27T14:29:03+00:00" + "time": "2017-08-27 14:29:03" }, { "name": "symfony/debug", @@ -1593,7 +1594,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-07-30T07:22:48+00:00" + "time": "2016-07-30 07:22:48" }, { "name": "symfony/event-dispatcher", @@ -1653,7 +1654,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-06-02T07:47:27+00:00" + "time": "2017-06-02 07:47:27" }, { "name": "symfony/filesystem", @@ -1702,7 +1703,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-07-29 21:54:42" }, { "name": "symfony/finder", @@ -1751,7 +1752,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-07-29 21:54:42" }, { "name": "symfony/polyfill-mbstring", @@ -1810,7 +1811,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/process", @@ -1859,7 +1860,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-07-03T08:04:30+00:00" + "time": "2017-07-03 08:04:30" }, { "name": "tedivm/jshrink", @@ -1905,7 +1906,7 @@ "javascript", "minifier" ], - "time": "2015-07-04T07:35:09+00:00" + "time": "2015-07-04 07:35:09" }, { "name": "tubalmartin/cssmin", @@ -1958,7 +1959,7 @@ "minify", "yui" ], - "time": "2017-05-16T13:45:26+00:00" + "time": "2017-05-16 13:45:26" }, { "name": "zendframework/zend-captcha", @@ -2015,7 +2016,7 @@ "captcha", "zf2" ], - "time": "2017-02-23T08:09:44+00:00" + "time": "2017-02-23 08:09:44" }, { "name": "zendframework/zend-code", @@ -2068,7 +2069,7 @@ "code", "zf2" ], - "time": "2016-10-24T13:23:32+00:00" + "time": "2016-10-24 13:23:32" }, { "name": "zendframework/zend-config", @@ -2124,7 +2125,7 @@ "config", "zf2" ], - "time": "2016-02-04T23:01:10+00:00" + "time": "2016-02-04 23:01:10" }, { "name": "zendframework/zend-console", @@ -2176,7 +2177,7 @@ "console", "zf2" ], - "time": "2016-02-09T17:15:12+00:00" + "time": "2016-02-09 17:15:12" }, { "name": "zendframework/zend-crypt", @@ -2226,7 +2227,7 @@ "crypt", "zf2" ], - "time": "2016-02-03T23:46:30+00:00" + "time": "2016-02-03 23:46:30" }, { "name": "zendframework/zend-db", @@ -2283,7 +2284,7 @@ "db", "zf2" ], - "time": "2016-08-09T19:28:55+00:00" + "time": "2016-08-09 19:28:55" }, { "name": "zendframework/zend-di", @@ -2330,7 +2331,7 @@ "di", "zf2" ], - "time": "2016-04-25T20:58:11+00:00" + "time": "2016-04-25 20:58:11" }, { "name": "zendframework/zend-escaper", @@ -2374,7 +2375,7 @@ "escaper", "zf2" ], - "time": "2016-06-30T19:48:38+00:00" + "time": "2016-06-30 19:48:38" }, { "name": "zendframework/zend-eventmanager", @@ -2421,7 +2422,7 @@ "eventmanager", "zf2" ], - "time": "2016-02-18T20:49:05+00:00" + "time": "2016-02-18 20:49:05" }, { "name": "zendframework/zend-filter", @@ -2481,7 +2482,7 @@ "filter", "zf2" ], - "time": "2017-05-17T20:56:17+00:00" + "time": "2017-05-17 20:56:17" }, { "name": "zendframework/zend-form", @@ -2558,7 +2559,7 @@ "form", "zf2" ], - "time": "2017-05-18T14:59:53+00:00" + "time": "2017-05-18 14:59:53" }, { "name": "zendframework/zend-http", @@ -2608,7 +2609,7 @@ "http", "zf2" ], - "time": "2017-01-31T14:41:02+00:00" + "time": "2017-01-31 14:41:02" }, { "name": "zendframework/zend-hydrator", @@ -2666,7 +2667,7 @@ "hydrator", "zf2" ], - "time": "2016-02-18T22:38:26+00:00" + "time": "2016-02-18 22:38:26" }, { "name": "zendframework/zend-i18n", @@ -2733,7 +2734,7 @@ "i18n", "zf2" ], - "time": "2017-05-17T17:00:12+00:00" + "time": "2017-05-17 17:00:12" }, { "name": "zendframework/zend-inputfilter", @@ -2788,7 +2789,7 @@ "inputfilter", "zf2" ], - "time": "2017-05-18T14:20:56+00:00" + "time": "2017-05-18 14:20:56" }, { "name": "zendframework/zend-json", @@ -2843,7 +2844,7 @@ "json", "zf2" ], - "time": "2016-02-04T21:20:26+00:00" + "time": "2016-02-04 21:20:26" }, { "name": "zendframework/zend-loader", @@ -2887,7 +2888,7 @@ "loader", "zf2" ], - "time": "2015-06-03T14:05:47+00:00" + "time": "2015-06-03 14:05:47" }, { "name": "zendframework/zend-log", @@ -2958,7 +2959,7 @@ "logging", "zf2" ], - "time": "2017-05-17T16:03:26+00:00" + "time": "2017-05-17 16:03:26" }, { "name": "zendframework/zend-math", @@ -3008,7 +3009,7 @@ "math", "zf2" ], - "time": "2016-04-07T16:29:53+00:00" + "time": "2016-04-07 16:29:53" }, { "name": "zendframework/zend-modulemanager", @@ -3066,7 +3067,7 @@ "modulemanager", "zf2" ], - "time": "2017-07-11T19:39:57+00:00" + "time": "2017-07-11 19:39:57" }, { "name": "zendframework/zend-mvc", @@ -3153,7 +3154,7 @@ "mvc", "zf2" ], - "time": "2016-02-23T15:24:59+00:00" + "time": "2016-02-23 15:24:59" }, { "name": "zendframework/zend-serializer", @@ -3210,7 +3211,7 @@ "serializer", "zf2" ], - "time": "2016-06-21T17:01:55+00:00" + "time": "2016-06-21 17:01:55" }, { "name": "zendframework/zend-server", @@ -3256,7 +3257,7 @@ "server", "zf2" ], - "time": "2016-06-20T22:27:55+00:00" + "time": "2016-06-20 22:27:55" }, { "name": "zendframework/zend-servicemanager", @@ -3308,7 +3309,7 @@ "servicemanager", "zf2" ], - "time": "2016-12-19T19:14:29+00:00" + "time": "2016-12-19 19:14:29" }, { "name": "zendframework/zend-session", @@ -3374,7 +3375,7 @@ "session", "zf2" ], - "time": "2017-06-19T21:31:39+00:00" + "time": "2017-06-19 21:31:39" }, { "name": "zendframework/zend-soap", @@ -3426,7 +3427,7 @@ "soap", "zf2" ], - "time": "2016-04-21T16:06:27+00:00" + "time": "2016-04-21 16:06:27" }, { "name": "zendframework/zend-stdlib", @@ -3485,7 +3486,7 @@ "stdlib", "zf2" ], - "time": "2016-04-12T21:17:31+00:00" + "time": "2016-04-12 21:17:31" }, { "name": "zendframework/zend-text", @@ -3532,7 +3533,7 @@ "text", "zf2" ], - "time": "2016-02-08T19:03:52+00:00" + "time": "2016-02-08 19:03:52" }, { "name": "zendframework/zend-uri", @@ -3579,7 +3580,7 @@ "uri", "zf2" ], - "time": "2016-02-17T22:38:51+00:00" + "time": "2016-02-17 22:38:51" }, { "name": "zendframework/zend-validator", @@ -3650,7 +3651,7 @@ "validator", "zf2" ], - "time": "2017-08-22T14:19:23+00:00" + "time": "2017-08-22 14:19:23" }, { "name": "zendframework/zend-view", @@ -3737,7 +3738,7 @@ "view", "zf2" ], - "time": "2017-03-21T15:05:56+00:00" + "time": "2017-03-21 15:05:56" } ], "packages-dev": [ @@ -3793,7 +3794,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2015-06-14 21:17:01" }, { "name": "friendsofphp/php-cs-fixer", @@ -3863,7 +3864,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2017-03-31T12:59:38+00:00" + "time": "2017-03-31 12:59:38" }, { "name": "ircmaxell/password-compat", @@ -3905,7 +3906,7 @@ "hashing", "password" ], - "time": "2014-11-20T16:49:30+00:00" + "time": "2014-11-20 16:49:30" }, { "name": "lusitanian/oauth", @@ -3972,7 +3973,7 @@ "oauth", "security" ], - "time": "2016-07-12T22:15:40+00:00" + "time": "2016-07-12 22:15:40" }, { "name": "myclabs/deep-copy", @@ -4014,7 +4015,7 @@ "object", "object graph" ], - "time": "2017-04-12T18:52:22+00:00" + "time": "2017-04-12 18:52:22" }, { "name": "pdepend/pdepend", @@ -4054,7 +4055,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2017-01-19T14:23:36+00:00" + "time": "2017-01-19 14:23:36" }, { "name": "phar-io/manifest", @@ -4109,7 +4110,7 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05T18:14:27+00:00" + "time": "2017-03-05 18:14:27" }, { "name": "phar-io/version", @@ -4156,7 +4157,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05T17:38:23+00:00" + "time": "2017-03-05 17:38:23" }, { "name": "phpdocumentor/reflection-common", @@ -4210,7 +4211,7 @@ "reflection", "static analysis" ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2017-09-11 18:02:19" }, { "name": "phpdocumentor/reflection-docblock", @@ -4255,7 +4256,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-08-30T18:51:59+00:00" + "time": "2017-08-30 18:51:59" }, { "name": "phpdocumentor/type-resolver", @@ -4302,7 +4303,7 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14T14:27:02+00:00" + "time": "2017-07-14 14:27:02" }, { "name": "phpmd/phpmd", @@ -4368,7 +4369,7 @@ "phpmd", "pmd" ], - "time": "2017-01-20T14:41:10+00:00" + "time": "2017-01-20 14:41:10" }, { "name": "phpspec/prophecy", @@ -4431,7 +4432,7 @@ "spy", "stub" ], - "time": "2017-09-04T11:05:03+00:00" + "time": "2017-09-04 11:05:03" }, { "name": "phpunit/php-code-coverage", @@ -4495,7 +4496,7 @@ "testing", "xunit" ], - "time": "2017-08-03T12:40:43+00:00" + "time": "2017-08-03 12:40:43" }, { "name": "phpunit/php-file-iterator", @@ -4542,7 +4543,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", @@ -4583,7 +4584,7 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "time": "2015-06-21 13:50:34" }, { "name": "phpunit/php-timer", @@ -4632,7 +4633,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26T11:10:40+00:00" + "time": "2017-02-26 11:10:40" }, { "name": "phpunit/php-token-stream", @@ -4681,7 +4682,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20T05:47:52+00:00" + "time": "2017-08-20 05:47:52" }, { "name": "phpunit/phpunit", @@ -4765,7 +4766,7 @@ "testing", "xunit" ], - "time": "2017-08-03T13:59:28+00:00" + "time": "2017-08-03 13:59:28" }, { "name": "phpunit/phpunit-mock-objects", @@ -4824,7 +4825,7 @@ "mock", "xunit" ], - "time": "2017-08-03T14:08:16+00:00" + "time": "2017-08-03 14:08:16" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -4869,7 +4870,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "time": "2017-03-04 06:30:41" }, { "name": "sebastian/comparator", @@ -4933,7 +4934,7 @@ "compare", "equality" ], - "time": "2017-03-03T06:26:08+00:00" + "time": "2017-03-03 06:26:08" }, { "name": "sebastian/diff", @@ -4985,7 +4986,7 @@ "keywords": [ "diff" ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2017-05-22 07:24:03" }, { "name": "sebastian/environment", @@ -5035,7 +5036,7 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2017-07-01 08:51:00" }, { "name": "sebastian/exporter", @@ -5102,7 +5103,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2017-04-03 13:19:02" }, { "name": "sebastian/finder-facade", @@ -5141,7 +5142,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2016-02-17T07:02:23+00:00" + "time": "2016-02-17 07:02:23" }, { "name": "sebastian/global-state", @@ -5192,7 +5193,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2017-04-27 15:39:26" }, { "name": "sebastian/object-enumerator", @@ -5239,7 +5240,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "time": "2017-08-03 12:35:26" }, { "name": "sebastian/object-reflector", @@ -5284,7 +5285,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" + "time": "2017-03-29 09:07:27" }, { "name": "sebastian/phpcpd", @@ -5335,7 +5336,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2016-04-17T19:32:49+00:00" + "time": "2016-04-17 19:32:49" }, { "name": "sebastian/recursion-context", @@ -5388,7 +5389,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" + "time": "2017-03-03 06:23:57" }, { "name": "sebastian/resource-operations", @@ -5430,7 +5431,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28T20:34:47+00:00" + "time": "2015-07-28 20:34:47" }, { "name": "sebastian/version", @@ -5473,7 +5474,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "time": "2016-10-03 07:35:21" }, { "name": "squizlabs/php_codesniffer", @@ -5524,7 +5525,7 @@ "phpcs", "standards" ], - "time": "2017-06-14T01:23:49+00:00" + "time": "2017-06-14 01:23:49" }, { "name": "symfony/config", @@ -5586,7 +5587,7 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-09-04T16:28:07+00:00" + "time": "2017-09-04 16:28:07" }, { "name": "symfony/dependency-injection", @@ -5656,7 +5657,7 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-09-05T20:39:38+00:00" + "time": "2017-09-05 20:39:38" }, { "name": "symfony/polyfill-php54", @@ -5714,7 +5715,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/polyfill-php55", @@ -5770,7 +5771,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/polyfill-php70", @@ -5829,7 +5830,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/polyfill-php72", @@ -5884,7 +5885,7 @@ "portable", "shim" ], - "time": "2017-07-11T13:25:55+00:00" + "time": "2017-07-11 13:25:55" }, { "name": "symfony/polyfill-xml", @@ -5932,7 +5933,7 @@ "portable", "shim" ], - "time": "2017-06-14T15:44:48+00:00" + "time": "2017-06-14 15:44:48" }, { "name": "symfony/stopwatch", @@ -5981,7 +5982,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-07-29 21:54:42" }, { "name": "theseer/fdomdocument", @@ -6021,7 +6022,7 @@ ], "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", "homepage": "https://github.com/theseer/fDOMDocument", - "time": "2017-06-30T11:53:12+00:00" + "time": "2017-06-30 11:53:12" }, { "name": "theseer/tokenizer", @@ -6061,7 +6062,7 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "time": "2017-04-07 12:08:54" }, { "name": "webmozart/assert", @@ -6111,7 +6112,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:58+00:00" + "time": "2016-11-23 20:04:58" } ], "aliases": [], From cbf7c18d2d6e6bcef06e272d8b942bb73582545e Mon Sep 17 00:00:00 2001 From: Carey Sizer Date: Wed, 16 Nov 2016 13:06:08 +1300 Subject: [PATCH 007/528] Fix Swagger-generated operation parameter names for "body" parameters These were previously all output as a string "$body". This improves Swagger-generated API clients and compatibility with swagger-codegen & janephp/openapi generator. This caused the following issues: - Variable variable output in janephp/openapi code generation - Incorrect code output (multiple models called "Body") in janephp/openapi - "Anonymous" class naming in swagger-codegen generated clients (approx 20 models called Body1, Body2, Body3 are output for a Magento Enterprise schema) The new format is: operationNamePostBody. Operation Id is guaranteed to be unique under the Open API specification. Changing the body parameter in the schema should also not affect clients conforming to the specification. --- .../Magento/Webapi/Model/Rest/Swagger/Generator.php | 11 ++++++----- .../Test/Unit/Model/Rest/Swagger/GeneratorTest.php | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php index ee7d65e484792..0805854c8f8de 100644 --- a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php +++ b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php @@ -204,14 +204,14 @@ protected function getGeneralInfo() protected function generatePathInfo($methodName, $httpMethodData, $tagName) { $methodData = $httpMethodData[Converter::KEY_METHOD]; + $operationId = $this->typeProcessor->getOperationName($tagName, $methodData[Converter::KEY_METHOD]) . ucfirst($methodName); $pathInfo = [ 'tags' => [$tagName], 'description' => $methodData['documentation'], - 'operationId' => $this->typeProcessor->getOperationName($tagName, $methodData[Converter::KEY_METHOD]) . - ucfirst($methodName) + 'operationId' => $operationId, ]; - $parameters = $this->generateMethodParameters($httpMethodData); + $parameters = $this->generateMethodParameters($httpMethodData, $operationId); if ($parameters) { $pathInfo['parameters'] = $parameters; } @@ -265,11 +265,12 @@ protected function generateMethodResponses($methodData) * Generate parameters based on method data * * @param array $httpMethodData + * @param string $operationId * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ - private function generateMethodParameters($httpMethodData) + private function generateMethodParameters($httpMethodData, $operationId) { $bodySchema = []; $parameters = []; @@ -335,7 +336,7 @@ private function generateMethodParameters($httpMethodData) if ($bodySchema) { $bodyParam = []; - $bodyParam['name'] = '$body'; + $bodyParam['name'] = $operationId . 'Body'; $bodyParam['in'] = 'body'; $bodyParam['schema'] = $bodySchema; $parameters[] = $bodyParam; diff --git a/app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php b/app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php index 9883c3a2766e9..611517df51657 100644 --- a/app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php +++ b/app/code/Magento/Webapi/Test/Unit/Model/Rest/Swagger/GeneratorTest.php @@ -223,7 +223,7 @@ public function generateDataProvider() ] ], // @codingStandardsIgnoreStart - '{"swagger":"2.0","info":{"version":"","title":""},"host":"magento.host","basePath":"/rest/default","schemes":["http://"],"tags":[{"name":"testModule5AllSoapAndRestV2","description":"AllSoapAndRestInterface"}],"paths":{"/V1/testModule5":{"post":{"tags":["testModule5AllSoapAndRestV2"],"description":"Add new item.","operationId":"' . self::OPERATION_NAME . 'Post","parameters":[{"name":"$body","in":"body","schema":{"required":["item"],"properties":{"item":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}}},"definitions":{"error-response":{"type":"object","properties":{"message":{"type":"string","description":"Error message"},"errors":{"$ref":"#/definitions/error-errors"},"code":{"type":"integer","description":"Error code"},"parameters":{"$ref":"#/definitions/error-parameters"},"trace":{"type":"string","description":"Stack trace"}},"required":["message"]},"error-errors":{"type":"array","description":"Errors list","items":{"$ref":"#/definitions/error-errors-item"}},"error-errors-item":{"type":"object","description":"Error details","properties":{"message":{"type":"string","description":"Error message"},"parameters":{"$ref":"#/definitions/error-parameters"}}},"error-parameters":{"type":"array","description":"Error parameters list","items":{"$ref":"#/definitions/error-parameters-item"}},"error-parameters-item":{"type":"object","description":"Error parameters item","properties":{"resources":{"type":"string","description":"ACL resource"},"fieldName":{"type":"string","description":"Missing or invalid field name"},"fieldValue":{"type":"string","description":"Incorrect field value"}}},"test-module5-v2-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object","properties":{"price":{"type":"integer"}},"required":["price"]}}}' + '{"swagger":"2.0","info":{"version":"","title":""},"host":"magento.host","basePath":"/rest/default","schemes":["http://"],"tags":[{"name":"testModule5AllSoapAndRestV2","description":"AllSoapAndRestInterface"}],"paths":{"/V1/testModule5":{"post":{"tags":["testModule5AllSoapAndRestV2"],"description":"Add new item.","operationId":"' . self::OPERATION_NAME . 'Post","parameters":[{"name":"operationNamePostBody","in":"body","schema":{"required":["item"],"properties":{"item":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"type":"object"}}],"responses":{"200":{"description":"200 Success.","schema":{"$ref":"#/definitions/test-module5-v2-entity-all-soap-and-rest"}},"401":{"description":"401 Unauthorized","schema":{"$ref":"#/definitions/error-response"}},"500":{"description":"Internal Server error","schema":{"$ref":"#/definitions/error-response"}},"default":{"description":"Unexpected error","schema":{"$ref":"#/definitions/error-response"}}}}}},"definitions":{"error-response":{"type":"object","properties":{"message":{"type":"string","description":"Error message"},"errors":{"$ref":"#/definitions/error-errors"},"code":{"type":"integer","description":"Error code"},"parameters":{"$ref":"#/definitions/error-parameters"},"trace":{"type":"string","description":"Stack trace"}},"required":["message"]},"error-errors":{"type":"array","description":"Errors list","items":{"$ref":"#/definitions/error-errors-item"}},"error-errors-item":{"type":"object","description":"Error details","properties":{"message":{"type":"string","description":"Error message"},"parameters":{"$ref":"#/definitions/error-parameters"}}},"error-parameters":{"type":"array","description":"Error parameters list","items":{"$ref":"#/definitions/error-parameters-item"}},"error-parameters-item":{"type":"object","description":"Error parameters item","properties":{"resources":{"type":"string","description":"ACL resource"},"fieldName":{"type":"string","description":"Missing or invalid field name"},"fieldValue":{"type":"string","description":"Incorrect field value"}}},"test-module5-v2-entity-all-soap-and-rest":{"type":"object","description":"Some Data Object","properties":{"price":{"type":"integer"}},"required":["price"]}}}' // @codingStandardsIgnoreEnd ], [ From 9c8addb72a04ef231a8b3eb5f5484e9c960f7ad9 Mon Sep 17 00:00:00 2001 From: Oleksii Korshenko Date: Tue, 11 Jul 2017 16:47:01 -0500 Subject: [PATCH 008/528] MAGETWO-70495: Fix Swagger-generated operation parameter names for "body" parameters #7446 - fixed REST tests --- app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php | 5 ++++- .../Magento/Webapi/JsonGenerationFromDataObjectTest.php | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php index 0805854c8f8de..3df6966fb01b3 100644 --- a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php +++ b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php @@ -204,7 +204,10 @@ protected function getGeneralInfo() protected function generatePathInfo($methodName, $httpMethodData, $tagName) { $methodData = $httpMethodData[Converter::KEY_METHOD]; - $operationId = $this->typeProcessor->getOperationName($tagName, $methodData[Converter::KEY_METHOD]) . ucfirst($methodName); + + $operationId = $this->typeProcessor->getOperationName($tagName, $methodData[Converter::KEY_METHOD]); + $operationId .= ucfirst($methodName); + $pathInfo = [ 'tags' => [$tagName], 'description' => $methodData['documentation'], diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php index 67068e3a11aa9..9a3fac9e8739f 100644 --- a/dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/JsonGenerationFromDataObjectTest.php @@ -10,6 +10,7 @@ use Magento\TestFramework\Helper\Bootstrap; use Magento\Framework\App\ProductMetadataInterface; +use Magento\Store\Model\StoreManagerInterface; /** * Test REST schema generation mechanisms. @@ -34,10 +35,10 @@ protected function setUp() { $this->_markTestAsRestOnly("JSON generation tests are intended to be executed for REST adapter only."); - $this->storeCode = Bootstrap::getObjectManager()->get(\Magento\Store\Model\StoreManagerInterface::class) + $this->storeCode = Bootstrap::getObjectManager()->get(StoreManagerInterface::class) ->getStore()->getCode(); - $this->productMetadata = Bootstrap::getObjectManager()->get(\Magento\Framework\App\ProductMetadataInterface::class); + $this->productMetadata = Bootstrap::getObjectManager()->get(ProductMetadataInterface::class); parent::setUp(); } @@ -197,7 +198,7 @@ public function getExpectedMultiServiceData() 'required' => true ], [ - 'name' => '$body', + 'name' => 'testModule5AllSoapAndRestV1NestedUpdatePutBody', 'in' => 'body', 'schema' => [ 'required' => [ From fb2ec44114e113d959d4b098cf7b2e1660e51cde Mon Sep 17 00:00:00 2001 From: larsroettig Date: Mon, 2 Oct 2017 20:38:41 +0200 Subject: [PATCH 009/528] FIX #11166: - Add Error Handling - Impelement Test Case --- app/code/Magento/Indexer/Model/Indexer.php | 5 ++ .../Indexer/Test/Unit/Model/IndexerTest.php | 50 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/app/code/Magento/Indexer/Model/Indexer.php b/app/code/Magento/Indexer/Model/Indexer.php index 412611d1dffd6..98355376ec848 100644 --- a/app/code/Magento/Indexer/Model/Indexer.php +++ b/app/code/Magento/Indexer/Model/Indexer.php @@ -418,6 +418,11 @@ public function reindexAll() $state->save(); $this->getView()->resume(); throw $exception; + }catch (\Error $error) { + $state->setStatus(StateInterface::STATUS_INVALID); + $state->save(); + $this->getView()->resume(); + throw $error; } } } diff --git a/app/code/Magento/Indexer/Test/Unit/Model/IndexerTest.php b/app/code/Magento/Indexer/Test/Unit/Model/IndexerTest.php index 2c25c698dd425..e9c82906121cc 100644 --- a/app/code/Magento/Indexer/Test/Unit/Model/IndexerTest.php +++ b/app/code/Magento/Indexer/Test/Unit/Model/IndexerTest.php @@ -273,6 +273,56 @@ function () { $this->model->reindexAll(); } + /** + * @expectedException \Error + * @expectedExceptionMessage Test Engine Error + */ + public function testReindexAllWithError() + { + + $indexId = 'indexer_internal_name'; + $this->loadIndexer($indexId); + + $stateMock = $this->createPartialMock( + \Magento\Indexer\Model\Indexer\State::class, + ['load', 'getId', 'setIndexerId', '__wakeup', 'getStatus', 'setStatus', 'save'] + ); + $stateMock->expects($this->once())->method('load')->with($indexId, 'indexer_id')->will($this->returnSelf()); + $stateMock->expects($this->never())->method('setIndexerId'); + $stateMock->expects($this->once())->method('getId')->will($this->returnValue(1)); + $stateMock->expects($this->exactly(2))->method('setStatus')->will($this->returnSelf()); + $stateMock->expects($this->once())->method('getStatus')->will($this->returnValue('idle')); + $stateMock->expects($this->exactly(2))->method('save')->will($this->returnSelf()); + $this->stateFactoryMock->expects($this->once())->method('create')->will($this->returnValue($stateMock)); + + $this->viewMock->expects($this->once())->method('isEnabled')->will($this->returnValue(false)); + $this->viewMock->expects($this->never())->method('suspend'); + $this->viewMock->expects($this->once())->method('resume'); + + $actionMock = $this->createPartialMock( + \Magento\Framework\Indexer\ActionInterface::class, + ['executeFull', 'executeList', 'executeRow'] + ); + $actionMock->expects($this->once())->method('executeFull')->will( + $this->returnCallback( + function () { + throw new \Error('Test Engine Error'); + } + ) + ); + $this->actionFactoryMock->expects( + $this->once() + )->method( + 'create' + )->with( + 'Some\Class\Name' + )->will( + $this->returnValue($actionMock) + ); + + $this->model->reindexAll(); + } + protected function getIndexerData() { return [ From 214fc33862252bbbfbe0da781b2f3383cb5eac87 Mon Sep 17 00:00:00 2001 From: larsroettig Date: Mon, 2 Oct 2017 20:57:39 +0200 Subject: [PATCH 010/528] Fix codesytle for my change in Magento\Indexer\Model\Indexer --- app/code/Magento/Indexer/Model/Indexer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Indexer/Model/Indexer.php b/app/code/Magento/Indexer/Model/Indexer.php index 98355376ec848..9faf5e7b728cd 100644 --- a/app/code/Magento/Indexer/Model/Indexer.php +++ b/app/code/Magento/Indexer/Model/Indexer.php @@ -418,7 +418,7 @@ public function reindexAll() $state->save(); $this->getView()->resume(); throw $exception; - }catch (\Error $error) { + } catch (\Error $error) { $state->setStatus(StateInterface::STATUS_INVALID); $state->save(); $this->getView()->resume(); From 2ab293917b54d4dd3ef11ead3701d5601f5a0451 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 2 Oct 2017 17:22:30 -0500 Subject: [PATCH 011/528] MAGETWO-80475: Start subscription after Magento installed/upgraded --- .../Backend/Enabled/SubscriptionHandler.php | 24 +++++----- .../Magento/Analytics/Setup/InstallData.php | 46 +++++++++++-------- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php index 95caceddebc88..03f3ddaeebbaa 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -28,6 +28,17 @@ class SubscriptionHandler */ const CRON_STRING_PATH = 'crontab/default/jobs/analytics_subscribe/schedule/cron_expr'; + /** + * Config value for schedule setting of subscription handler. + */ + const CRON_EXPR_ARRAY = [ + '0', # Minute + '*', # Hour + '*', # Day of the Month + '*', # Month of the Year + '*', # Day of the Week + ]; + /** * Max value for reserve counter of attempts to subscribe. * @@ -124,18 +135,7 @@ public function processEnabled() */ private function setCronSchedule() { - $cronExprArray = [ - '0', # Minute - '*', # Hour - '*', # Day of the Month - '*', # Month of the Year - '*', # Day of the Week - ]; - - $cronExprString = join(' ', $cronExprArray); - - $this->configWriter->save(self::CRON_STRING_PATH, $cronExprString); - + $this->configWriter->save(self::CRON_STRING_PATH, join(' ', self::CRON_EXPR_ARRAY)); return true; } diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php index 302cf00f9091f..5a67a6d5e6765 100644 --- a/app/code/Magento/Analytics/Setup/InstallData.php +++ b/app/code/Magento/Analytics/Setup/InstallData.php @@ -6,10 +6,10 @@ namespace Magento\Analytics\Setup; +use Magento\Analytics\Model\Config\Backend\Enabled\SubscriptionHandler; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; -use Magento\Analytics\Model\NotificationTime; /** * @codeCoverageIgnore @@ -17,23 +17,6 @@ */ class InstallData implements InstallDataInterface { - /** - * @var NotificationTime - * @since 2.2.0 - */ - private $notificationTime; - - /** - * InstallData constructor. - * - * @param NotificationTime $notificationTime - * @since 2.2.0 - */ - public function __construct( - NotificationTime $notificationTime - ) { - $this->notificationTime = $notificationTime; - } /** * {@inheritdoc} @@ -42,6 +25,31 @@ public function __construct( */ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { - $this->notificationTime->storeLastTimeNotification(1); + $setup->getConnection()->insertMultiple( + $setup->getTable('core_config_data'), + [ + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => 'analytics/subscription/enabled', + 'value' => 1 + ], + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => SubscriptionHandler::CRON_STRING_PATH, + 'value' => join(' ', SubscriptionHandler::CRON_EXPR_ARRAY) + ] + ] + ); + + $setup->getConnection()->insert( + $setup->getTable('flag'), + [ + 'flag_code' => SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, + 'state' => 0, + 'flag_data' => 24, + ] + ); } } From e6f9d804a236e1f4ad597fa93c069e4e31845098 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Tue, 3 Oct 2017 13:48:41 +0300 Subject: [PATCH 012/528] MAGETWO-71966: [2.2.x] Braintree online refund not working for two websites using individual Braintree accounts - Added store ID as additional parameter for configuration loading - Added request to retrieve correct Braintree token for new order in adminhtml area - Refactored Braintree adapter --- app/code/Magento/Braintree/Block/Form.php | 36 ++-- app/code/Magento/Braintree/Block/Payment.php | 4 + .../Adminhtml/Payment/GetClientToken.php | 73 ++++++++ .../Braintree/Controller/Payment/GetNonce.php | 5 +- .../Command/CaptureStrategyCommand.php | 49 ++--- .../Command/GetPaymentNonceCommand.php | 17 +- .../Braintree/Gateway/Config/Config.php | 121 ++++++++----- .../Gateway/Helper/SubjectReader.php | 14 +- .../Http/Client/AbstractTransaction.php | 12 +- .../Gateway/Http/Client/TransactionRefund.php | 10 +- .../Gateway/Http/Client/TransactionSale.php | 7 +- .../Client/TransactionSubmitForSettlement.php | 10 +- .../Gateway/Http/Client/TransactionVoid.php | 7 +- .../Gateway/Request/DescriptorDataBuilder.php | 17 +- .../Request/KountPaymentDataBuilder.php | 6 +- .../Gateway/Request/PaymentDataBuilder.php | 2 +- .../Gateway/Request/StoreConfigBuilder.php | 42 +++++ .../Request/ThreeDSecureDataBuilder.php | 7 +- .../Model/Adapter/BraintreeAdapter.php | 21 ++- .../Model/Adapter/BraintreeAdapterFactory.php | 56 ++++++ .../Model/Report/TransactionsCollection.php | 18 +- .../Braintree/Model/Ui/ConfigProvider.php | 52 +++--- .../Braintree/Test/Unit/Block/FormTest.php | 59 ++---- .../Unit/Controller/Payment/GetNonceTest.php | 75 ++++---- .../Command/CaptureStrategyCommandTest.php | 170 ++++++++---------- .../Command/GetPaymentNonceCommandTest.php | 117 +++++------- .../Http/Client/TransactionSaleTest.php | 56 +++--- .../TransactionSubmitForSettlementTest.php | 49 ++--- .../Request/AddressDataBuilderTest.php | 98 ++++------ .../Request/CaptureDataBuilderTest.php | 47 +---- .../Request/CustomerDataBuilderTest.php | 73 +++----- .../Request/DescriptorDataBuilderTest.php | 19 +- .../Request/KountPaymentDataBuilderTest.php | 55 +++--- .../Request/PayPal/DeviceDataBuilderTest.php | 32 +--- .../Request/PayPal/VaultDataBuilderTest.php | 31 +--- .../Request/PaymentDataBuilderTest.php | 78 +++----- .../Gateway/Request/RefundDataBuilderTest.php | 75 ++------ .../Request/SettlementDataBuilderTest.php | 2 +- .../Request/ThreeDSecureDataBuilderTest.php | 78 ++++---- .../Request/VaultCaptureDataBuilderTest.php | 39 +--- .../Gateway/Request/VaultDataBuilderTest.php | 2 +- .../Report/TransactionsCollectionTest.php | 124 ++++++------- .../Test/Unit/Model/Ui/ConfigProviderTest.php | 40 +++-- .../Magento/Braintree/etc/adminhtml/di.xml | 7 + app/code/Magento/Braintree/etc/di.xml | 30 +++- .../view/adminhtml/web/js/braintree.js | 75 +++++--- .../Adminhtml/Payment/GetClientTokenTest.php | 151 ++++++++++++++++ .../_files/payment_configuration.php | 58 ++++++ .../_files/payment_configuration_rollback.php | 42 +++++ 49 files changed, 1267 insertions(+), 1001 deletions(-) create mode 100644 app/code/Magento/Braintree/Controller/Adminhtml/Payment/GetClientToken.php create mode 100644 app/code/Magento/Braintree/Gateway/Request/StoreConfigBuilder.php create mode 100644 app/code/Magento/Braintree/Model/Adapter/BraintreeAdapterFactory.php create mode 100644 dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Payment/GetClientTokenTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration.php create mode 100644 dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration_rollback.php diff --git a/app/code/Magento/Braintree/Block/Form.php b/app/code/Magento/Braintree/Block/Form.php index f6cf62f5a2131..8a727ae87262f 100644 --- a/app/code/Magento/Braintree/Block/Form.php +++ b/app/code/Magento/Braintree/Block/Form.php @@ -9,7 +9,6 @@ use Magento\Braintree\Gateway\Config\Config as GatewayConfig; use Magento\Braintree\Model\Adminhtml\Source\CcType; use Magento\Braintree\Model\Ui\ConfigProvider; -use Magento\Framework\App\ObjectManager; use Magento\Framework\View\Element\Template\Context; use Magento\Payment\Block\Form\Cc; use Magento\Payment\Helper\Data; @@ -21,7 +20,6 @@ */ class Form extends Cc { - /** * @var Quote */ @@ -48,6 +46,7 @@ class Form extends Cc * @param Quote $sessionQuote * @param GatewayConfig $gatewayConfig * @param CcType $ccType + * @param Data $paymentDataHelper * @param array $data */ public function __construct( @@ -56,12 +55,14 @@ public function __construct( Quote $sessionQuote, GatewayConfig $gatewayConfig, CcType $ccType, + Data $paymentDataHelper, array $data = [] ) { parent::__construct($context, $paymentConfig, $data); $this->sessionQuote = $sessionQuote; $this->gatewayConfig = $gatewayConfig; $this->ccType = $ccType; + $this->paymentDataHelper = $paymentDataHelper; } /** @@ -81,7 +82,7 @@ public function getCcAvailableTypes() */ public function useCvv() { - return $this->gatewayConfig->isCvvEnabled(); + return $this->gatewayConfig->isCvvEnabled($this->sessionQuote->getStoreId()); } /** @@ -90,9 +91,8 @@ public function useCvv() */ public function isVaultEnabled() { - $storeId = $this->_storeManager->getStore()->getId(); $vaultPayment = $this->getVaultPayment(); - return $vaultPayment->isActive($storeId); + return $vaultPayment->isActive($this->sessionQuote->getStoreId()); } /** @@ -102,7 +102,10 @@ public function isVaultEnabled() private function getConfiguredCardTypes() { $types = $this->ccType->getCcTypeLabelMap(); - $configCardTypes = array_fill_keys($this->gatewayConfig->getAvailableCardTypes(), ''); + $configCardTypes = array_fill_keys( + $this->gatewayConfig->getAvailableCardTypes($this->sessionQuote->getStoreId()), + '' + ); return array_intersect_key($types, $configCardTypes); } @@ -116,7 +119,11 @@ private function getConfiguredCardTypes() private function filterCardTypesForCountry(array $configCardTypes, $countryId) { $filtered = $configCardTypes; - $countryCardTypes = $this->gatewayConfig->getCountryAvailableCardTypes($countryId); + $countryCardTypes = $this->gatewayConfig->getCountryAvailableCardTypes( + $countryId, + $this->sessionQuote->getStoreId() + ); + // filter card types only if specific card types are set for country if (!empty($countryCardTypes)) { $availableTypes = array_fill_keys($countryCardTypes, ''); @@ -131,19 +138,6 @@ private function filterCardTypesForCountry(array $configCardTypes, $countryId) */ private function getVaultPayment() { - return $this->getPaymentDataHelper()->getMethodInstance(ConfigProvider::CC_VAULT_CODE); - } - - /** - * Get payment data helper instance - * @return Data - * @deprecated 100.1.0 - */ - private function getPaymentDataHelper() - { - if ($this->paymentDataHelper === null) { - $this->paymentDataHelper = ObjectManager::getInstance()->get(Data::class); - } - return $this->paymentDataHelper; + return $this->paymentDataHelper->getMethodInstance(ConfigProvider::CC_VAULT_CODE); } } diff --git a/app/code/Magento/Braintree/Block/Payment.php b/app/code/Magento/Braintree/Block/Payment.php index 8e05856d9b57a..aa5b3b07fb23c 100644 --- a/app/code/Magento/Braintree/Block/Payment.php +++ b/app/code/Magento/Braintree/Block/Payment.php @@ -48,6 +48,10 @@ public function getPaymentConfig() $payment = $this->config->getConfig()['payment']; $config = $payment[$this->getCode()]; $config['code'] = $this->getCode(); + $config['clientTokenUrl'] = $this->_urlBuilder->getUrl( + ConfigProvider::CODE . '/payment/getClientToken', + ['_secure' => true] + ); return json_encode($config, JSON_UNESCAPED_SLASHES); } diff --git a/app/code/Magento/Braintree/Controller/Adminhtml/Payment/GetClientToken.php b/app/code/Magento/Braintree/Controller/Adminhtml/Payment/GetClientToken.php new file mode 100644 index 0000000000000..af0f1d75665d5 --- /dev/null +++ b/app/code/Magento/Braintree/Controller/Adminhtml/Payment/GetClientToken.php @@ -0,0 +1,73 @@ +config = $config; + $this->adapterFactory = $adapterFactory; + $this->quoteSession = $quoteSession; + } + + /** + * @inheritdoc + */ + public function execute() + { + $params = []; + $response = $this->resultFactory->create(ResultFactory::TYPE_JSON); + + $storeId = $this->quoteSession->getStoreId(); + $merchantAccountId = $this->config->getMerchantAccountId($storeId); + if (!empty($merchantAccountId)) { + $params[PaymentDataBuilder::MERCHANT_ACCOUNT_ID] = $merchantAccountId; + } + + $clientToken = $this->adapterFactory->create($storeId) + ->generate($params); + $response->setData(['clientToken' => $clientToken]); + + return $response; + } +} diff --git a/app/code/Magento/Braintree/Controller/Payment/GetNonce.php b/app/code/Magento/Braintree/Controller/Payment/GetNonce.php index aecde869ca196..f8b152ded1556 100644 --- a/app/code/Magento/Braintree/Controller/Payment/GetNonce.php +++ b/app/code/Magento/Braintree/Controller/Payment/GetNonce.php @@ -62,7 +62,10 @@ public function execute() try { $publicHash = $this->getRequest()->getParam('public_hash'); $customerId = $this->session->getCustomerId(); - $result = $this->command->execute(['public_hash' => $publicHash, 'customer_id' => $customerId])->get(); + $result = $this->command->execute( + ['public_hash' => $publicHash, 'customer_id' => $customerId, 'store_id' => $this->session->getStoreId()] + ) + ->get(); $response->setData(['paymentMethodNonce' => $result['paymentMethodNonce']]); } catch (\Exception $e) { $this->logger->critical($e); diff --git a/app/code/Magento/Braintree/Gateway/Command/CaptureStrategyCommand.php b/app/code/Magento/Braintree/Gateway/Command/CaptureStrategyCommand.php index f972eecf9f92d..53d113ff28dc6 100644 --- a/app/code/Magento/Braintree/Gateway/Command/CaptureStrategyCommand.php +++ b/app/code/Magento/Braintree/Gateway/Command/CaptureStrategyCommand.php @@ -6,18 +6,19 @@ namespace Magento\Braintree\Gateway\Command; use Braintree\Transaction; -use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Gateway\Helper\SubjectReader; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Braintree\Model\Adapter\BraintreeSearchAdapter; use Magento\Framework\Api\FilterBuilder; use Magento\Framework\Api\SearchCriteriaBuilder; -use Magento\Payment\Gateway\Command; use Magento\Payment\Gateway\Command\CommandPoolInterface; use Magento\Payment\Gateway\CommandInterface; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; use Magento\Payment\Gateway\Helper\ContextHelper; -use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Sales\Api\Data\OrderPaymentInterface; -use Magento\Sales\Api\TransactionRepositoryInterface; use Magento\Sales\Api\Data\TransactionInterface; +use Magento\Sales\Api\TransactionRepositoryInterface; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; /** * Class CaptureStrategyCommand @@ -66,9 +67,9 @@ class CaptureStrategyCommand implements CommandInterface private $subjectReader; /** - * @var BraintreeAdapter + * @var BraintreeAdapterFactory */ - private $braintreeAdapter; + private $braintreeAdapterFactory; /** * @var BraintreeSearchAdapter @@ -83,7 +84,7 @@ class CaptureStrategyCommand implements CommandInterface * @param FilterBuilder $filterBuilder * @param SearchCriteriaBuilder $searchCriteriaBuilder * @param SubjectReader $subjectReader - * @param BraintreeAdapter $braintreeAdapter + * @param BraintreeAdapterFactory $braintreeAdapterFactory, * @param BraintreeSearchAdapter $braintreeSearchAdapter */ public function __construct( @@ -92,7 +93,7 @@ public function __construct( FilterBuilder $filterBuilder, SearchCriteriaBuilder $searchCriteriaBuilder, SubjectReader $subjectReader, - BraintreeAdapter $braintreeAdapter, + BraintreeAdapterFactory $braintreeAdapterFactory, BraintreeSearchAdapter $braintreeSearchAdapter ) { $this->commandPool = $commandPool; @@ -100,7 +101,7 @@ public function __construct( $this->filterBuilder = $filterBuilder; $this->searchCriteriaBuilder = $searchCriteriaBuilder; $this->subjectReader = $subjectReader; - $this->braintreeAdapter = $braintreeAdapter; + $this->braintreeAdapterFactory = $braintreeAdapterFactory; $this->braintreeSearchAdapter = $braintreeSearchAdapter; } @@ -112,29 +113,29 @@ public function execute(array $commandSubject) /** @var \Magento\Payment\Gateway\Data\PaymentDataObjectInterface $paymentDO */ $paymentDO = $this->subjectReader->readPayment($commandSubject); - /** @var \Magento\Sales\Api\Data\OrderPaymentInterface $paymentInfo */ - $paymentInfo = $paymentDO->getPayment(); - ContextHelper::assertOrderPayment($paymentInfo); - - $command = $this->getCommand($paymentInfo); + $command = $this->getCommand($paymentDO); $this->commandPool->get($command)->execute($commandSubject); } /** - * Get execution command name - * @param OrderPaymentInterface $payment + * Gets command name. + * + * @param PaymentDataObjectInterface $paymentDO * @return string */ - private function getCommand(OrderPaymentInterface $payment) + private function getCommand(PaymentDataObjectInterface $paymentDO) { - // if auth transaction is not exists execute authorize&capture command + $payment = $paymentDO->getPayment(); + ContextHelper::assertOrderPayment($payment); + + // if auth transaction does not exist then execute authorize&capture command $existsCapture = $this->isExistsCaptureTransaction($payment); if (!$payment->getAuthorizationTransaction() && !$existsCapture) { return self::SALE; } // do capture for authorization transaction - if (!$existsCapture && !$this->isExpiredAuthorization($payment)) { + if (!$existsCapture && !$this->isExpiredAuthorization($payment, $paymentDO->getOrder())) { return self::CAPTURE; } @@ -143,12 +144,16 @@ private function getCommand(OrderPaymentInterface $payment) } /** + * Checks if authorization transaction does not expired yet. + * * @param OrderPaymentInterface $payment - * @return boolean + * @param OrderAdapterInterface $orderAdapter + * @return bool */ - private function isExpiredAuthorization(OrderPaymentInterface $payment) + private function isExpiredAuthorization(OrderPaymentInterface $payment, OrderAdapterInterface $orderAdapter) { - $collection = $this->braintreeAdapter->search( + $adapter = $this->braintreeAdapterFactory->create($orderAdapter->getStoreId()); + $collection = $adapter->search( [ $this->braintreeSearchAdapter->id()->is($payment->getLastTransId()), $this->braintreeSearchAdapter->status()->is(Transaction::AUTHORIZATION_EXPIRED) diff --git a/app/code/Magento/Braintree/Gateway/Command/GetPaymentNonceCommand.php b/app/code/Magento/Braintree/Gateway/Command/GetPaymentNonceCommand.php index 91c9f6c14bb5d..a40c4a1296a75 100644 --- a/app/code/Magento/Braintree/Gateway/Command/GetPaymentNonceCommand.php +++ b/app/code/Magento/Braintree/Gateway/Command/GetPaymentNonceCommand.php @@ -9,8 +9,7 @@ use Exception; use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Braintree\Gateway\Validator\PaymentNonceResponseValidator; -use Magento\Braintree\Model\Adapter\BraintreeAdapter; -use Magento\Payment\Gateway\Command; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Payment\Gateway\Command\Result\ArrayResultFactory; use Magento\Payment\Gateway\CommandInterface; use Magento\Vault\Api\PaymentTokenManagementInterface; @@ -27,9 +26,9 @@ class GetPaymentNonceCommand implements CommandInterface private $tokenManagement; /** - * @var BraintreeAdapter + * @var BraintreeAdapterFactory */ - private $adapter; + private $adapterFactory; /** * @var ArrayResultFactory @@ -48,20 +47,20 @@ class GetPaymentNonceCommand implements CommandInterface /** * @param PaymentTokenManagementInterface $tokenManagement - * @param BraintreeAdapter $adapter + * @param BraintreeAdapterFactory $adapterFactory * @param ArrayResultFactory $resultFactory * @param SubjectReader $subjectReader * @param PaymentNonceResponseValidator $responseValidator */ public function __construct( PaymentTokenManagementInterface $tokenManagement, - BraintreeAdapter $adapter, + BraintreeAdapterFactory $adapterFactory, ArrayResultFactory $resultFactory, SubjectReader $subjectReader, PaymentNonceResponseValidator $responseValidator ) { $this->tokenManagement = $tokenManagement; - $this->adapter = $adapter; + $this->adapterFactory = $adapterFactory; $this->resultFactory = $resultFactory; $this->subjectReader = $subjectReader; $this->responseValidator = $responseValidator; @@ -80,7 +79,9 @@ public function execute(array $commandSubject) throw new Exception('No available payment tokens'); } - $data = $this->adapter->createNonce($paymentToken->getGatewayToken()); + $storeId = $this->subjectReader->readStoreId($commandSubject); + $data = $this->adapterFactory->create($storeId) + ->createNonce($paymentToken->getGatewayToken()); $result = $this->responseValidator->validate(['response' => ['object' => $data]]); if (!$result->isValid()) { diff --git a/app/code/Magento/Braintree/Gateway/Config/Config.php b/app/code/Magento/Braintree/Gateway/Config/Config.php index 7badd2b87ac34..01bb32fbb1a7e 100644 --- a/app/code/Magento/Braintree/Gateway/Config/Config.php +++ b/app/code/Magento/Braintree/Gateway/Config/Config.php @@ -68,11 +68,12 @@ public function __construct( /** * Return the country specific card type config * + * @param int|null $storeId * @return array */ - public function getCountrySpecificCardTypeConfig() + public function getCountrySpecificCardTypeConfig($storeId = null) { - $countryCardTypes = $this->getValue(self::KEY_COUNTRY_CREDIT_CARD); + $countryCardTypes = $this->getValue(self::KEY_COUNTRY_CREDIT_CARD, $storeId); if (!$countryCardTypes) { return []; } @@ -83,11 +84,12 @@ public function getCountrySpecificCardTypeConfig() /** * Retrieve available credit card types * + * @param int|null $storeId * @return array */ - public function getAvailableCardTypes() + public function getAvailableCardTypes($storeId = null) { - $ccTypes = $this->getValue(self::KEY_CC_TYPES); + $ccTypes = $this->getValue(self::KEY_CC_TYPES, $storeId); return !empty($ccTypes) ? explode(',', $ccTypes) : []; } @@ -108,79 +110,111 @@ public function getCcTypesMapper() } /** - * Get list of card types available for country + * Gets list of card types available for country. + * * @param string $country + * @param int|null $storeId * @return array */ - public function getCountryAvailableCardTypes($country) + public function getCountryAvailableCardTypes($country, $storeId = null) { - $types = $this->getCountrySpecificCardTypeConfig(); + $types = $this->getCountrySpecificCardTypeConfig($storeId); return (!empty($types[$country])) ? $types[$country] : []; } /** - * Check if cvv field is enabled - * @return boolean + * Checks if cvv field is enabled. + * + * @param int|null $storeId + * @return bool */ - public function isCvvEnabled() + public function isCvvEnabled($storeId = null) { - return (bool) $this->getValue(self::KEY_USE_CVV); + return (bool) $this->getValue(self::KEY_USE_CVV, $storeId); } /** - * Check if 3d secure verification enabled + * Checks if 3d secure verification enabled. + * + * @param int|null $storeId * @return bool */ - public function isVerify3DSecure() + public function isVerify3DSecure($storeId = null) { - return (bool) $this->getValue(self::KEY_VERIFY_3DSECURE); + return (bool) $this->getValue(self::KEY_VERIFY_3DSECURE, $storeId); } /** - * Get threshold amount for 3d secure + * Gets threshold amount for 3d secure. + * + * @param int|null $storeId * @return float */ - public function getThresholdAmount() + public function getThresholdAmount($storeId = null) { - return (double) $this->getValue(self::KEY_THRESHOLD_AMOUNT); + return (double) $this->getValue(self::KEY_THRESHOLD_AMOUNT, $storeId); } /** - * Get list of specific countries for 3d secure + * Gets list of specific countries for 3d secure. + * + * @param int|null $storeId * @return array */ - public function get3DSecureSpecificCountries() + public function get3DSecureSpecificCountries($storeId = null) { - if ((int) $this->getValue(self::KEY_VERIFY_ALLOW_SPECIFIC) == self::VALUE_3DSECURE_ALL) { + if ((int) $this->getValue(self::KEY_VERIFY_ALLOW_SPECIFIC, $storeId) == self::VALUE_3DSECURE_ALL) { return []; } - return explode(',', $this->getValue(self::KEY_VERIFY_SPECIFIC)); + return explode(',', $this->getValue(self::KEY_VERIFY_SPECIFIC, $storeId)); + } + + /** + * Gets value of configured environment. + * Possible values: production or sandbox. + * + * @param int|null $storeId + * @return string + */ + public function getEnvironment($storeId = null) + { + return $this->getValue(Config::KEY_ENVIRONMENT, $storeId); } /** + * Gets Kount merchant ID. + * + * @param int|null $storeId * @return string + * @internal param null $storeId */ - public function getEnvironment() + public function getKountMerchantId($storeId = null) { - return $this->getValue(Config::KEY_ENVIRONMENT); + return $this->getValue(Config::KEY_KOUNT_MERCHANT_ID, $storeId); } /** + * Gets merchant ID. + * + * @param int|null $storeId * @return string */ - public function getKountMerchantId() + public function getMerchantId($storeId = null) { - return $this->getValue(Config::KEY_KOUNT_MERCHANT_ID); + return $this->getValue(Config::KEY_MERCHANT_ID, $storeId); } /** + * Gets Merchant account ID. + * + * @param int|null $storeId * @return string */ - public function getMerchantId() + public function getMerchantAccountId($storeId = null) { - return $this->getValue(Config::KEY_MERCHANT_ID); + return $this->getValue(self::KEY_MERCHANT_ACCOUNT_ID, $storeId); } /** @@ -192,45 +226,42 @@ public function getSdkUrl() } /** + * Checks if fraud protection is enabled. + * + * @param int|null $storeId * @return bool */ - public function hasFraudProtection() + public function hasFraudProtection($storeId = null) { - return (bool) $this->getValue(Config::FRAUD_PROTECTION); + return (bool) $this->getValue(Config::FRAUD_PROTECTION, $storeId); } /** - * Get Payment configuration status + * Gets Payment configuration status. + * + * @param int|null $storeId * @return bool */ - public function isActive() + public function isActive($storeId = null) { - return (bool) $this->getValue(self::KEY_ACTIVE); + return (bool) $this->getValue(self::KEY_ACTIVE, $storeId); } /** - * Get list of configured dynamic descriptors + * Gets list of configured dynamic descriptors. + * + * @param int|null $storeId * @return array */ - public function getDynamicDescriptors() + public function getDynamicDescriptors($storeId = null) { $values = []; foreach (self::$dynamicDescriptorKeys as $key) { - $value = $this->getValue('descriptor_' . $key); + $value = $this->getValue('descriptor_' . $key, $storeId); if (!empty($value)) { $values[$key] = $value; } } return $values; } - - /** - * Get Merchant account ID - * - * @return string - */ - public function getMerchantAccountId() - { - return $this->getValue(self::KEY_MERCHANT_ACCOUNT_ID); - } } diff --git a/app/code/Magento/Braintree/Gateway/Helper/SubjectReader.php b/app/code/Magento/Braintree/Gateway/Helper/SubjectReader.php index e98597655190f..6c3231978a54a 100644 --- a/app/code/Magento/Braintree/Gateway/Helper/SubjectReader.php +++ b/app/code/Magento/Braintree/Gateway/Helper/SubjectReader.php @@ -6,10 +6,9 @@ namespace Magento\Braintree\Gateway\Helper; use Braintree\Transaction; -use Magento\Quote\Model\Quote; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; use Magento\Payment\Gateway\Helper; use Magento\Vault\Api\Data\PaymentTokenInterface; -use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; /** * Class SubjectReader @@ -119,4 +118,15 @@ public function readPayPal(Transaction $transaction) return $transaction->paypal; } + + /** + * Reads store's ID, otherwise returns null. + * + * @param array $subject + * @return int|null + */ + public function readStoreId(array $subject) + { + return $subject['store_id'] ?? null; + } } diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/AbstractTransaction.php b/app/code/Magento/Braintree/Gateway/Http/Client/AbstractTransaction.php index caeaaa7fe45a2..ef35152bf7e95 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/AbstractTransaction.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/AbstractTransaction.php @@ -6,7 +6,7 @@ namespace Magento\Braintree\Gateway\Http\Client; -use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Payment\Gateway\Http\ClientException; use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\TransferInterface; @@ -29,22 +29,22 @@ abstract class AbstractTransaction implements ClientInterface protected $customLogger; /** - * @var BraintreeAdapter + * @var BraintreeAdapterFactory */ - protected $adapter; + protected $adapterFactory; /** * Constructor * * @param LoggerInterface $logger * @param Logger $customLogger - * @param BraintreeAdapter $transaction + * @param BraintreeAdapterFactory $adapterFactory */ - public function __construct(LoggerInterface $logger, Logger $customLogger, BraintreeAdapter $adapter) + public function __construct(LoggerInterface $logger, Logger $customLogger, BraintreeAdapterFactory $adapterFactory) { $this->logger = $logger; $this->customLogger = $customLogger; - $this->adapter = $adapter; + $this->adapterFactory = $adapterFactory; } /** diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php index 180344ab7263f..4c3f1e179d378 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionRefund.php @@ -16,9 +16,11 @@ class TransactionRefund extends AbstractTransaction */ protected function process(array $data) { - return $this->adapter->refund( - $data['transaction_id'], - $data[PaymentDataBuilder::AMOUNT] - ); + $storeId = $data['store_id'] ?? null; + // sending store id and other additional keys are restricted by Braintree API + unset($data['store_id']); + + return $this->adapterFactory->create($storeId) + ->refund($data['transaction_id'], $data[PaymentDataBuilder::AMOUNT]); } } diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSale.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSale.php index 81c79e522907d..529045b5b18f5 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSale.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSale.php @@ -15,6 +15,11 @@ class TransactionSale extends AbstractTransaction */ protected function process(array $data) { - return $this->adapter->sale($data); + $storeId = $data['store_id'] ?? null; + // sending store id and other additional keys are restricted by Braintree API + unset($data['store_id']); + + return $this->adapterFactory->create($storeId) + ->sale($data); } } diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php index 0df5799b54b83..16ebd7a7a00c5 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionSubmitForSettlement.php @@ -18,9 +18,11 @@ class TransactionSubmitForSettlement extends AbstractTransaction */ protected function process(array $data) { - return $this->adapter->submitForSettlement( - $data[CaptureDataBuilder::TRANSACTION_ID], - $data[PaymentDataBuilder::AMOUNT] - ); + $storeId = $data['store_id'] ?? null; + // sending store id and other additional keys are restricted by Braintree API + unset($data['store_id']); + + return $this->adapterFactory->create($storeId) + ->submitForSettlement($data[CaptureDataBuilder::TRANSACTION_ID], $data[PaymentDataBuilder::AMOUNT]); } } diff --git a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php index a774065365b47..133c7f0f4062e 100644 --- a/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php +++ b/app/code/Magento/Braintree/Gateway/Http/Client/TransactionVoid.php @@ -14,6 +14,11 @@ class TransactionVoid extends AbstractTransaction */ protected function process(array $data) { - return $this->adapter->void($data['transaction_id']); + $storeId = $data['store_id'] ?? null; + // sending store id and other additional keys are restricted by Braintree API + unset($data['store_id']); + + return $this->adapterFactory->create($storeId) + ->void($data['transaction_id']); } } diff --git a/app/code/Magento/Braintree/Gateway/Request/DescriptorDataBuilder.php b/app/code/Magento/Braintree/Gateway/Request/DescriptorDataBuilder.php index 3794058c2be8c..f70ff20206163 100644 --- a/app/code/Magento/Braintree/Gateway/Request/DescriptorDataBuilder.php +++ b/app/code/Magento/Braintree/Gateway/Request/DescriptorDataBuilder.php @@ -5,6 +5,7 @@ */ namespace Magento\Braintree\Gateway\Request; +use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Payment\Gateway\Request\BuilderInterface; use Magento\Braintree\Gateway\Config\Config; @@ -24,21 +25,29 @@ class DescriptorDataBuilder implements BuilderInterface private $config; /** - * DescriptorDataBuilder constructor. + * @var SubjectReader + */ + private $subjectReader; + + /** * @param Config $config + * @param SubjectReader $subjectReader */ - public function __construct(Config $config) + public function __construct(Config $config, SubjectReader $subjectReader) { $this->config = $config; + $this->subjectReader = $subjectReader; } /** * @inheritdoc - * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function build(array $buildSubject) { - $values = $this->config->getDynamicDescriptors(); + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $order = $paymentDO->getOrder(); + + $values = $this->config->getDynamicDescriptors($order->getStoreId()); return !empty($values) ? [self::$descriptorKey => $values] : []; } } diff --git a/app/code/Magento/Braintree/Gateway/Request/KountPaymentDataBuilder.php b/app/code/Magento/Braintree/Gateway/Request/KountPaymentDataBuilder.php index 7eebbca1d4290..29d6e5c958307 100644 --- a/app/code/Magento/Braintree/Gateway/Request/KountPaymentDataBuilder.php +++ b/app/code/Magento/Braintree/Gateway/Request/KountPaymentDataBuilder.php @@ -48,10 +48,12 @@ public function __construct(Config $config, SubjectReader $subjectReader) public function build(array $buildSubject) { $result = []; - if (!$this->config->hasFraudProtection()) { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $order = $paymentDO->getOrder(); + + if (!$this->config->hasFraudProtection($order->getStoreId())) { return $result; } - $paymentDO = $this->subjectReader->readPayment($buildSubject); $payment = $paymentDO->getPayment(); $data = $payment->getAdditionalInformation(); diff --git a/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php b/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php index a3341c3fc1873..51efea6e6ed29 100644 --- a/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php +++ b/app/code/Magento/Braintree/Gateway/Request/PaymentDataBuilder.php @@ -87,7 +87,7 @@ public function build(array $buildSubject) self::ORDER_ID => $order->getOrderIncrementId() ]; - $merchantAccountId = $this->config->getMerchantAccountId(); + $merchantAccountId = $this->config->getMerchantAccountId($order->getStoreId()); if (!empty($merchantAccountId)) { $result[self::MERCHANT_ACCOUNT_ID] = $merchantAccountId; } diff --git a/app/code/Magento/Braintree/Gateway/Request/StoreConfigBuilder.php b/app/code/Magento/Braintree/Gateway/Request/StoreConfigBuilder.php new file mode 100644 index 0000000000000..2f9243529bd15 --- /dev/null +++ b/app/code/Magento/Braintree/Gateway/Request/StoreConfigBuilder.php @@ -0,0 +1,42 @@ +subjectReader = $subjectReader; + } + + /** + * @inheritdoc + */ + public function build(array $buildSubject) + { + $paymentDO = $this->subjectReader->readPayment($buildSubject); + $order = $paymentDO->getOrder(); + + return [ + 'store_id' => $order->getStoreId() + ]; + } +} diff --git a/app/code/Magento/Braintree/Gateway/Request/ThreeDSecureDataBuilder.php b/app/code/Magento/Braintree/Gateway/Request/ThreeDSecureDataBuilder.php index c366a67701521..b28002a23486b 100644 --- a/app/code/Magento/Braintree/Gateway/Request/ThreeDSecureDataBuilder.php +++ b/app/code/Magento/Braintree/Gateway/Request/ThreeDSecureDataBuilder.php @@ -64,12 +64,15 @@ public function build(array $buildSubject) */ private function is3DSecureEnabled(OrderAdapterInterface $order, $amount) { - if (!$this->config->isVerify3DSecure() || $amount < $this->config->getThresholdAmount()) { + $storeId = $order->getStoreId(); + if (!$this->config->isVerify3DSecure($storeId) + || $amount < $this->config->getThresholdAmount($storeId) + ) { return false; } $billingAddress = $order->getBillingAddress(); - $specificCounties = $this->config->get3DSecureSpecificCountries(); + $specificCounties = $this->config->get3DSecureSpecificCountries($storeId); if (!empty($specificCounties) && !in_array($billingAddress->getCountryId(), $specificCounties)) { return false; } diff --git a/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php b/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php index 71f3828ebe9d4..d11be39a9bb49 100644 --- a/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php +++ b/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapter.php @@ -15,29 +15,40 @@ /** * Class BraintreeAdapter + * Use \Magento\Braintree\Model\Adapter\BraintreeAdapterFactory to create new instance of adapter. * @codeCoverageIgnore */ class BraintreeAdapter { - /** * @var Config */ private $config; /** - * @param Config $config + * @param string $merchantId + * @param string $publicKey + * @param string $privateKey + * @param string $environment */ - public function __construct(Config $config) + public function __construct($merchantId, $publicKey, $privateKey, $environment) { - $this->config = $config; - $this->initCredentials(); + $this->merchantId($merchantId); + $this->publicKey($publicKey); + $this->privateKey($privateKey); + + if ($environment == Environment::ENVIRONMENT_PRODUCTION) { + $this->environment(Environment::ENVIRONMENT_PRODUCTION); + } else { + $this->environment(Environment::ENVIRONMENT_SANDBOX); + } } /** * Initializes credentials. * * @return void + * @deprecated is not used anymore */ protected function initCredentials() { diff --git a/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapterFactory.php b/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapterFactory.php new file mode 100644 index 0000000000000..890f1a1021eda --- /dev/null +++ b/app/code/Magento/Braintree/Model/Adapter/BraintreeAdapterFactory.php @@ -0,0 +1,56 @@ +config = $config; + $this->objectManager = $objectManager; + } + + /** + * Creates instance of Braintree Adapter. + * + * @param int $storeId if null is provided as an argument, then current scope will be resolved + * by \Magento\Framework\App\Config\ScopeCodeResolver (useful for most cases) but for adminhtml area the store + * should be provided as the argument for correct config settings loading. + * @return BraintreeAdapter + */ + public function create($storeId = null) + { + return $this->objectManager->create( + BraintreeAdapter::class, + [ + 'merchantId' => $this->config->getMerchantId($storeId), + 'publicKey' => $this->config->getValue(Config::KEY_PUBLIC_KEY, $storeId), + 'privateKey' => $this->config->getValue(Config::KEY_PRIVATE_KEY, $storeId), + 'environment' => $this->config->getEnvironment($storeId) + ] + ); + } +} diff --git a/app/code/Magento/Braintree/Model/Report/TransactionsCollection.php b/app/code/Magento/Braintree/Model/Report/TransactionsCollection.php index edac6e3533849..a237b64bf58ee 100644 --- a/app/code/Magento/Braintree/Model/Report/TransactionsCollection.php +++ b/app/code/Magento/Braintree/Model/Report/TransactionsCollection.php @@ -5,7 +5,8 @@ */ namespace Magento\Braintree\Model\Report; -use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; +use Magento\Braintree\Model\Report\Row\TransactionMap; use Magento\Framework\Api\Search\SearchResultInterface; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Data\Collection; @@ -26,7 +27,7 @@ class TransactionsCollection extends Collection implements SearchResultInterface * * @var string */ - protected $_itemObjectClass = \Magento\Braintree\Model\Report\Row\TransactionMap::class; + protected $_itemObjectClass = TransactionMap::class; /** * @var array @@ -39,9 +40,9 @@ class TransactionsCollection extends Collection implements SearchResultInterface private $filterMapper; /** - * @var BraintreeAdapter + * @var BraintreeAdapterFactory */ - private $braintreeAdapter; + private $braintreeAdapterFactory; /** * @var \Braintree\ResourceCollection | null @@ -50,17 +51,17 @@ class TransactionsCollection extends Collection implements SearchResultInterface /** * @param EntityFactoryInterface $entityFactory - * @param BraintreeAdapter $braintreeAdapter + * @param BraintreeAdapterFactory $braintreeAdapterFactory * @param FilterMapper $filterMapper */ public function __construct( EntityFactoryInterface $entityFactory, - BraintreeAdapter $braintreeAdapter, + BraintreeAdapterFactory $braintreeAdapterFactory, FilterMapper $filterMapper ) { parent::__construct($entityFactory); $this->filterMapper = $filterMapper; - $this->braintreeAdapter = $braintreeAdapter; + $this->braintreeAdapterFactory = $braintreeAdapterFactory; } /** @@ -110,7 +111,8 @@ protected function fetchIdsCollection() // Fetch all transaction IDs in order to filter if (empty($this->collection)) { $filters = $this->getFilters(); - $this->collection = $this->braintreeAdapter->search($filters); + $this->collection = $this->braintreeAdapterFactory->create() + ->search($filters); } return $this->collection; diff --git a/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php b/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php index c420195446270..6ab69923760ce 100644 --- a/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php +++ b/app/code/Magento/Braintree/Model/Ui/ConfigProvider.php @@ -5,10 +5,11 @@ */ namespace Magento\Braintree\Model\Ui; +use Magento\Braintree\Gateway\Config\Config; use Magento\Braintree\Gateway\Request\PaymentDataBuilder; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Checkout\Model\ConfigProviderInterface; -use Magento\Braintree\Gateway\Config\Config; -use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Framework\Session\SessionManagerInterface; /** * Class ConfigProvider @@ -25,27 +26,35 @@ class ConfigProvider implements ConfigProviderInterface private $config; /** - * @var BraintreeAdapter + * @var BraintreeAdapterFactory */ - private $adapter; + private $adapterFactory; /** * @var string */ private $clientToken = ''; + /** + * @var SessionManagerInterface + */ + private $session; + /** * Constructor * * @param Config $config - * @param BraintreeAdapter $adapter + * @param BraintreeAdapterFactory $adapterFactory + * @param SessionManagerInterface $session */ public function __construct( Config $config, - BraintreeAdapter $adapter + BraintreeAdapterFactory $adapterFactory, + SessionManagerInterface $session ) { $this->config = $config; - $this->adapter = $adapter; + $this->adapterFactory = $adapterFactory; + $this->session = $session; } /** @@ -55,26 +64,27 @@ public function __construct( */ public function getConfig() { + $storeId = $this->session->getStoreId(); return [ 'payment' => [ self::CODE => [ - 'isActive' => $this->config->isActive(), + 'isActive' => $this->config->isActive($storeId), 'clientToken' => $this->getClientToken(), 'ccTypesMapper' => $this->config->getCctypesMapper(), 'sdkUrl' => $this->config->getSdkUrl(), - 'countrySpecificCardTypes' => $this->config->getCountrySpecificCardTypeConfig(), - 'availableCardTypes' => $this->config->getAvailableCardTypes(), - 'useCvv' => $this->config->isCvvEnabled(), - 'environment' => $this->config->getEnvironment(), - 'kountMerchantId' => $this->config->getKountMerchantId(), - 'hasFraudProtection' => $this->config->hasFraudProtection(), - 'merchantId' => $this->config->getMerchantId(), + 'countrySpecificCardTypes' => $this->config->getCountrySpecificCardTypeConfig($storeId), + 'availableCardTypes' => $this->config->getAvailableCardTypes($storeId), + 'useCvv' => $this->config->isCvvEnabled($storeId), + 'environment' => $this->config->getEnvironment($storeId), + 'kountMerchantId' => $this->config->getKountMerchantId($storeId), + 'hasFraudProtection' => $this->config->hasFraudProtection($storeId), + 'merchantId' => $this->config->getMerchantId($storeId), 'ccVaultCode' => self::CC_VAULT_CODE ], Config::CODE_3DSECURE => [ - 'enabled' => $this->config->isVerify3DSecure(), - 'thresholdAmount' => $this->config->getThresholdAmount(), - 'specificCountries' => $this->config->get3DSecureSpecificCountries() + 'enabled' => $this->config->isVerify3DSecure($storeId), + 'thresholdAmount' => $this->config->getThresholdAmount($storeId), + 'specificCountries' => $this->config->get3DSecureSpecificCountries($storeId) ], ] ]; @@ -89,12 +99,14 @@ public function getClientToken() if (empty($this->clientToken)) { $params = []; - $merchantAccountId = $this->config->getMerchantAccountId(); + $storeId = $this->session->getStoreId(); + $merchantAccountId = $this->config->getMerchantAccountId($storeId); if (!empty($merchantAccountId)) { $params[PaymentDataBuilder::MERCHANT_ACCOUNT_ID] = $merchantAccountId; } - $this->clientToken = $this->adapter->generate($params); + $this->clientToken = $this->adapterFactory->create($storeId) + ->generate($params); } return $this->clientToken; diff --git a/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php b/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php index 5b28e6d8aedcd..9d363c77f2b05 100644 --- a/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Block/FormTest.php @@ -13,8 +13,6 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Payment\Helper\Data; use Magento\Payment\Model\Config; -use Magento\Store\Api\Data\StoreInterface; -use Magento\Store\Model\StoreManagerInterface; use Magento\Vault\Model\VaultPaymentInterface; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -57,11 +55,6 @@ class FormTest extends \PHPUnit\Framework\TestCase */ private $ccType; - /** - * @var StoreManagerInterface|MockObject - */ - private $storeManager; - /** * @var Data|MockObject */ @@ -72,8 +65,7 @@ protected function setUp() $this->initCcTypeMock(); $this->initSessionQuoteMock(); $this->initGatewayConfigMock(); - - $this->storeManager = $this->getMockForAbstractClass(StoreManagerInterface::class); + $this->paymentDataHelper = $this->getMockBuilder(Data::class) ->disableOriginalConstructor() ->setMethods(['getMethodInstance']) @@ -84,15 +76,13 @@ protected function setUp() 'paymentConfig' => $managerHelper->getObject(Config::class), 'sessionQuote' => $this->sessionQuote, 'gatewayConfig' => $this->gatewayConfig, - 'ccType' => $this->ccType, - 'storeManager' => $this->storeManager + 'ccType' => $this->ccType ]); $managerHelper->setBackwardCompatibleProperty($this->block, 'paymentDataHelper', $this->paymentDataHelper); } /** - * @covers \Magento\Braintree\Block\Form::getCcAvailableTypes * @param string $countryId * @param array $availableTypes * @param array $expected @@ -100,21 +90,18 @@ protected function setUp() */ public function testGetCcAvailableTypes($countryId, array $availableTypes, array $expected) { - $this->sessionQuote->expects(static::once()) - ->method('getCountryId') + $this->sessionQuote->method('getCountryId') ->willReturn($countryId); - $this->gatewayConfig->expects(static::once()) - ->method('getAvailableCardTypes') + $this->gatewayConfig->method('getAvailableCardTypes') ->willReturn(self::$configCardTypes); - $this->gatewayConfig->expects(static::once()) - ->method('getCountryAvailableCardTypes') + $this->gatewayConfig->method('getCountryAvailableCardTypes') ->with($countryId) ->willReturn($availableTypes); $result = $this->block->getCcAvailableTypes(); - static::assertEquals($expected, array_values($result)); + self::assertEquals($expected, array_values($result)); } /** @@ -131,33 +118,20 @@ public function countryCardTypesDataProvider() ]; } - /** - * @covers \Magento\Braintree\Block\Form::isVaultEnabled - */ public function testIsVaultEnabled() { $storeId = 1; - $store = $this->getMockForAbstractClass(StoreInterface::class); - $this->storeManager->expects(static::once()) - ->method('getStore') - ->willReturn($store); - - $store->expects(static::once()) - ->method('getId') - ->willReturn($storeId); $vaultPayment = $this->getMockForAbstractClass(VaultPaymentInterface::class); - $this->paymentDataHelper->expects(static::once()) - ->method('getMethodInstance') + $this->paymentDataHelper->method('getMethodInstance') ->with(ConfigProvider::CC_VAULT_CODE) ->willReturn($vaultPayment); - $vaultPayment->expects(static::once()) - ->method('isActive') - ->with($storeId) + $vaultPayment->method('isActive') + ->with(self::equalTo($storeId)) ->willReturn(true); - static::assertTrue($this->block->isVaultEnabled()); + self::assertTrue($this->block->isVaultEnabled()); } /** @@ -170,8 +144,7 @@ private function initCcTypeMock() ->setMethods(['getCcTypeLabelMap']) ->getMock(); - $this->ccType->expects(static::any()) - ->method('getCcTypeLabelMap') + $this->ccType->method('getCcTypeLabelMap') ->willReturn(self::$baseCardTypes); } @@ -182,15 +155,15 @@ private function initSessionQuoteMock() { $this->sessionQuote = $this->getMockBuilder(Quote::class) ->disableOriginalConstructor() - ->setMethods(['getQuote', 'getBillingAddress', 'getCountryId', '__wakeup']) + ->setMethods(['getQuote', 'getBillingAddress', 'getCountryId', 'getStoreId']) ->getMock(); - $this->sessionQuote->expects(static::any()) - ->method('getQuote') + $this->sessionQuote->method('getQuote') ->willReturnSelf(); - $this->sessionQuote->expects(static::any()) - ->method('getBillingAddress') + $this->sessionQuote->method('getBillingAddress') ->willReturnSelf(); + $this->sessionQuote->method('getStoreId') + ->willReturn(1); } /** diff --git a/app/code/Magento/Braintree/Test/Unit/Controller/Payment/GetNonceTest.php b/app/code/Magento/Braintree/Test/Unit/Controller/Payment/GetNonceTest.php index e78e54f011d44..723897491da63 100644 --- a/app/code/Magento/Braintree/Test/Unit/Controller/Payment/GetNonceTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Controller/Payment/GetNonceTest.php @@ -16,6 +16,7 @@ use Magento\Framework\Webapi\Exception; use Magento\Payment\Gateway\Command\ResultInterface as CommandResultInterface; use Psr\Log\LoggerInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class GetNonceTest @@ -30,37 +31,37 @@ class GetNonceTest extends \PHPUnit\Framework\TestCase private $action; /** - * @var GetPaymentNonceCommand|\PHPUnit_Framework_MockObject_MockObject + * @var GetPaymentNonceCommand|MockObject */ private $command; /** - * @var Session|\PHPUnit_Framework_MockObject_MockObject + * @var Session|MockObject */ private $session; /** - * @var LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var LoggerInterface|MockObject */ private $logger; /** - * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject + * @var ResultFactory|MockObject */ private $resultFactory; /** - * @var ResultInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ResultInterface|MockObject */ private $result; /** - * @var Http|\PHPUnit_Framework_MockObject_MockObject + * @var Http|MockObject */ private $request; /** - * @var CommandResultInterface|\PHPUnit_Framework_MockObject_MockObject + * @var CommandResultInterface|MockObject */ private $commandResult; @@ -84,7 +85,7 @@ protected function setUp() $this->session = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() - ->setMethods(['getCustomerId']) + ->setMethods(['getCustomerId', 'getStoreId']) ->getMock(); $this->logger = $this->createMock(LoggerInterface::class); @@ -92,11 +93,9 @@ protected function setUp() $context = $this->getMockBuilder(Context::class) ->disableOriginalConstructor() ->getMock(); - $context->expects(static::any()) - ->method('getRequest') + $context->method('getRequest') ->willReturn($this->request); - $context->expects(static::any()) - ->method('getResultFactory') + $context->method('getResultFactory') ->willReturn($this->resultFactory); $managerHelper = new ObjectManager($this); @@ -108,81 +107,68 @@ protected function setUp() ]); } - /** - * @covers \Magento\Braintree\Controller\Payment\GetNonce::execute - */ public function testExecuteWithException() { - $this->request->expects(static::once()) - ->method('getParam') + $this->request->method('getParam') ->with('public_hash') ->willReturn(null); - $this->session->expects(static::once()) - ->method('getCustomerId') + $this->session->method('getCustomerId') + ->willReturn(null); + $this->session->method('getStoreId') ->willReturn(null); $exception = new \Exception('The "publicHash" field does not exists'); - $this->command->expects(static::once()) - ->method('execute') + $this->command->method('execute') ->willThrowException($exception); - $this->logger->expects(static::once()) - ->method('critical') + $this->logger->method('critical') ->with($exception); - $this->result->expects(static::once()) - ->method('setHttpResponseCode') + $this->result->method('setHttpResponseCode') ->with(Exception::HTTP_BAD_REQUEST); - $this->result->expects(static::once()) - ->method('setData') + $this->result->method('setData') ->with(['message' => 'Sorry, but something went wrong']); $this->action->execute(); } - /** - * @covers \Magento\Braintree\Controller\Payment\GetNonce::execute - */ public function testExecute() { $customerId = 1; $publicHash = '65b7bae0dcb690d93'; $nonce = 'f1hc45'; - $this->request->expects(static::once()) - ->method('getParam') + $this->request->method('getParam') ->with('public_hash') ->willReturn($publicHash); - $this->session->expects(static::once()) - ->method('getCustomerId') + $this->session->method('getCustomerId') ->willReturn($customerId); + $this->session->method('getStoreId') + ->willReturn(null); - $this->commandResult->expects(static::once()) - ->method('get') + $this->commandResult->method('get') ->willReturn([ 'paymentMethodNonce' => $nonce ]); - $this->command->expects(static::once()) - ->method('execute') + $this->command->method('execute') ->willReturn($this->commandResult); - $this->result->expects(static::once()) - ->method('setData') + $this->result->method('setData') ->with(['paymentMethodNonce' => $nonce]); - $this->logger->expects(static::never()) + $this->logger->expects(self::never()) ->method('critical'); - $this->result->expects(static::never()) + $this->result->expects(self::never()) ->method('setHttpResponseCode'); $this->action->execute(); } /** - * Create mock for result factory object + * Creates mock for result factory object */ private function initResultFactoryMock() { @@ -195,8 +181,7 @@ private function initResultFactoryMock() ->setMethods(['create']) ->getMock(); - $this->resultFactory->expects(static::once()) - ->method('create') + $this->resultFactory->method('create') ->willReturn($this->result); } } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php index 56ea1f97fa165..ede4bab8dfc56 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php @@ -6,23 +6,22 @@ namespace Magento\Braintree\Test\Unit\Gateway\Command; use Braintree\IsNode; -use Braintree\MultipleValueNode; -use Braintree\TextNode; use Magento\Braintree\Gateway\Command\CaptureStrategyCommand; use Magento\Braintree\Gateway\Helper\SubjectReader; +use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; +use Magento\Braintree\Model\Adapter\BraintreeSearchAdapter; use Magento\Framework\Api\FilterBuilder; use Magento\Framework\Api\Search\SearchCriteria; use Magento\Framework\Api\SearchCriteriaBuilder; -use Magento\Payment\Gateway\Command; use Magento\Payment\Gateway\Command\CommandPoolInterface; use Magento\Payment\Gateway\Command\GatewayCommand; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Sales\Api\TransactionRepositoryInterface; use Magento\Sales\Model\Order\Payment; -use Magento\Sales\Model\Order\Payment\Transaction; use Magento\Sales\Model\ResourceModel\Order\Payment\Transaction\CollectionFactory; -use Magento\Braintree\Model\Adapter\BraintreeAdapter; -use Magento\Braintree\Model\Adapter\BraintreeSearchAdapter; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class CaptureStrategyCommandTest @@ -37,42 +36,42 @@ class CaptureStrategyCommandTest extends \PHPUnit\Framework\TestCase private $strategyCommand; /** - * @var CommandPoolInterface|\PHPUnit_Framework_MockObject_MockObject + * @var CommandPoolInterface|MockObject */ private $commandPool; /** - * @var TransactionRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + * @var TransactionRepositoryInterface|MockObject */ private $transactionRepository; /** - * @var FilterBuilder|\PHPUnit_Framework_MockObject_MockObject + * @var FilterBuilder|MockObject */ private $filterBuilder; /** - * @var SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject + * @var SearchCriteriaBuilder|MockObject */ private $searchCriteriaBuilder; /** - * @var Payment|\PHPUnit_Framework_MockObject_MockObject + * @var Payment|MockObject */ private $payment; /** - * @var GatewayCommand|\PHPUnit_Framework_MockObject_MockObject + * @var GatewayCommand|MockObject */ private $command; /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject + * @var SubjectReader|MockObject */ - private $subjectReaderMock; + private $subjectReader; /** - * @var BraintreeAdapter|\PHPUnit_Framework_MockObject_MockObject + * @var BraintreeAdapter|MockObject */ private $braintreeAdapter; @@ -88,7 +87,7 @@ protected function setUp() ->setMethods(['get', '__wakeup']) ->getMock(); - $this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class) + $this->subjectReader = $this->getMockBuilder(SubjectReader::class) ->disableOriginalConstructor() ->getMock(); @@ -100,6 +99,13 @@ protected function setUp() $this->braintreeAdapter = $this->getMockBuilder(BraintreeAdapter::class) ->disableOriginalConstructor() ->getMock(); + /** @var BraintreeAdapterFactory|MockObject $adapterFactory */ + $adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $adapterFactory->method('create') + ->willReturn($this->braintreeAdapter); + $this->braintreeSearchAdapter = new BraintreeSearchAdapter(); $this->strategyCommand = new CaptureStrategyCommand( @@ -107,86 +113,68 @@ protected function setUp() $this->transactionRepository, $this->filterBuilder, $this->searchCriteriaBuilder, - $this->subjectReaderMock, - $this->braintreeAdapter, + $this->subjectReader, + $adapterFactory, $this->braintreeSearchAdapter ); } - /** - * @covers \Magento\Braintree\Gateway\Command\CaptureStrategyCommand::execute - */ public function testSaleExecute() { $paymentData = $this->getPaymentDataObjectMock(); $subject['payment'] = $paymentData; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') + $this->subjectReader->method('readPayment') ->with($subject) ->willReturn($paymentData); - $this->payment->expects(static::once()) - ->method('getAuthorizationTransaction') + $this->payment->method('getAuthorizationTransaction') ->willReturn(false); - $this->payment->expects(static::once()) - ->method('getId') + $this->payment->method('getId') ->willReturn(1); $this->buildSearchCriteria(); - $this->transactionRepository->expects(static::once()) - ->method('getTotalCount') + $this->transactionRepository->method('getTotalCount') ->willReturn(0); - $this->commandPool->expects(static::once()) - ->method('get') + $this->commandPool->method('get') ->with(CaptureStrategyCommand::SALE) ->willReturn($this->command); $this->strategyCommand->execute($subject); } - /** - * @covers \Magento\Braintree\Gateway\Command\CaptureStrategyCommand::execute - */ public function testCaptureExecute() { $paymentData = $this->getPaymentDataObjectMock(); $subject['payment'] = $paymentData; $lastTransId = 'txnds'; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') + $this->subjectReader->method('readPayment') ->with($subject) ->willReturn($paymentData); - $this->payment->expects(static::once()) - ->method('getAuthorizationTransaction') + $this->payment->method('getAuthorizationTransaction') ->willReturn(true); - $this->payment->expects(static::once()) - ->method('getLastTransId') + $this->payment->method('getLastTransId') ->willReturn($lastTransId); - $this->payment->expects(static::once()) - ->method('getId') + $this->payment->method('getId') ->willReturn(1); $this->buildSearchCriteria(); - $this->transactionRepository->expects(static::once()) - ->method('getTotalCount') + $this->transactionRepository->method('getTotalCount') ->willReturn(0); // authorization transaction was not expired $collection = $this->getNotExpiredExpectedCollection($lastTransId); - $collection->expects(static::once()) - ->method('maximumCount') + $collection->method('maximumCount') ->willReturn(0); - $this->commandPool->expects(static::once()) - ->method('get') + $this->commandPool->method('get') ->with(CaptureStrategyCommand::CAPTURE) ->willReturn($this->command); @@ -195,7 +183,7 @@ public function testCaptureExecute() /** * @param string $lastTransactionId - * @return \Braintree\ResourceCollection|\PHPUnit_Framework_MockObject_MockObject + * @return \Braintree\ResourceCollection|MockObject */ private function getNotExpiredExpectedCollection($lastTransactionId) { @@ -208,10 +196,9 @@ private function getNotExpiredExpectedCollection($lastTransactionId) ->disableOriginalConstructor() ->getMock(); - $this->braintreeAdapter->expects(static::once()) - ->method('search') + $this->braintreeAdapter->method('search') ->with( - static::callback( + self::callback( function (array $filters) use ($isExpectations) { foreach ($filters as $filter) { /** @var IsNode $filter */ @@ -233,80 +220,62 @@ function (array $filters) use ($isExpectations) { return $collection; } - /** - * @covers \Magento\Braintree\Gateway\Command\CaptureStrategyCommand::execute - */ public function testExpiredAuthorizationPerformVaultCaptureExecute() { $paymentData = $this->getPaymentDataObjectMock(); $subject['payment'] = $paymentData; $lastTransId = 'txnds'; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') + $this->subjectReader->method('readPayment') ->with($subject) ->willReturn($paymentData); - $this->payment->expects(static::once()) - ->method('getAuthorizationTransaction') + $this->payment->method('getAuthorizationTransaction') ->willReturn(true); - $this->payment->expects(static::once()) - ->method('getLastTransId') + $this->payment->method('getLastTransId') ->willReturn($lastTransId); - $this->payment->expects(static::once()) - ->method('getId') + $this->payment->method('getId') ->willReturn(1); $this->buildSearchCriteria(); - $this->transactionRepository->expects(static::once()) - ->method('getTotalCount') + $this->transactionRepository->method('getTotalCount') ->willReturn(0); // authorization transaction was expired $collection = $this->getNotExpiredExpectedCollection($lastTransId); - $collection->expects(static::once()) - ->method('maximumCount') + $collection->method('maximumCount') ->willReturn(1); - $this->commandPool->expects(static::once()) - ->method('get') + $this->commandPool->method('get') ->with(CaptureStrategyCommand::VAULT_CAPTURE) ->willReturn($this->command); $this->strategyCommand->execute($subject); } - /** - * @covers \Magento\Braintree\Gateway\Command\CaptureStrategyCommand::execute - */ public function testVaultCaptureExecute() { $paymentData = $this->getPaymentDataObjectMock(); $subject['payment'] = $paymentData; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') + $this->subjectReader->method('readPayment') ->with($subject) ->willReturn($paymentData); - $this->payment->expects(static::once()) - ->method('getAuthorizationTransaction') + $this->payment->method('getAuthorizationTransaction') ->willReturn(true); - $this->payment->expects(static::once()) - ->method('getId') + $this->payment->method('getId') ->willReturn(1); $this->buildSearchCriteria(); - $this->transactionRepository->expects(static::once()) - ->method('getTotalCount') + $this->transactionRepository->method('getTotalCount') ->willReturn(1); - $this->commandPool->expects(static::once()) - ->method('get') + $this->commandPool->method('get') ->with(CaptureStrategyCommand::VAULT_CAPTURE) ->willReturn($this->command); @@ -314,8 +283,8 @@ public function testVaultCaptureExecute() } /** - * Create mock for payment data object and order payment - * @return \PHPUnit_Framework_MockObject_MockObject + * Creates mock for payment data object and order payment + * @return MockObject */ private function getPaymentDataObjectMock() { @@ -324,19 +293,25 @@ private function getPaymentDataObjectMock() ->getMock(); $mock = $this->getMockBuilder(PaymentDataObject::class) - ->setMethods(['getPayment']) + ->setMethods(['getPayment', 'getOrder']) ->disableOriginalConstructor() ->getMock(); - $mock->expects(static::once()) - ->method('getPayment') + $mock->method('getPayment') ->willReturn($this->payment); + $order = $this->getMockBuilder(OrderAdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $mock->method('getOrder') + ->willReturn($order); + return $mock; } /** - * Create mock for gateway command object + * Creates mock for gateway command object */ private function initCommandMock() { @@ -345,13 +320,12 @@ private function initCommandMock() ->setMethods(['execute']) ->getMock(); - $this->command->expects(static::once()) - ->method('execute') + $this->command->method('execute') ->willReturn([]); } /** - * Create mock for filter object + * Creates mock for filter object */ private function initFilterBuilderMock() { @@ -362,27 +336,25 @@ private function initFilterBuilderMock() } /** - * Build search criteria + * Builds search criteria */ private function buildSearchCriteria() { - $this->filterBuilder->expects(static::exactly(2)) + $this->filterBuilder->expects(self::exactly(2)) ->method('setField') ->willReturnSelf(); - $this->filterBuilder->expects(static::exactly(2)) + $this->filterBuilder->expects(self::exactly(2)) ->method('setValue') ->willReturnSelf(); $searchCriteria = new SearchCriteria(); - $this->searchCriteriaBuilder->expects(static::exactly(2)) + $this->searchCriteriaBuilder->expects(self::exactly(2)) ->method('addFilters') ->willReturnSelf(); - $this->searchCriteriaBuilder->expects(static::once()) - ->method('create') + $this->searchCriteriaBuilder->method('create') ->willReturn($searchCriteria); - $this->transactionRepository->expects(static::once()) - ->method('getList') + $this->transactionRepository->method('getList') ->with($searchCriteria) ->willReturnSelf(); } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Command/GetPaymentNonceCommandTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Command/GetPaymentNonceCommandTest.php index 333f29eb29136..1eeb785c13aa7 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Command/GetPaymentNonceCommandTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Command/GetPaymentNonceCommandTest.php @@ -9,12 +9,13 @@ use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Braintree\Gateway\Validator\PaymentNonceResponseValidator; use Magento\Braintree\Model\Adapter\BraintreeAdapter; -use Magento\Payment\Gateway\Command; -use Magento\Payment\Gateway\Command\Result\ArrayResultFactory; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Payment\Gateway\Command\Result\ArrayResult; +use Magento\Payment\Gateway\Command\Result\ArrayResultFactory; use Magento\Payment\Gateway\Validator\ResultInterface; use Magento\Vault\Model\PaymentToken; use Magento\Vault\Model\PaymentTokenManagement; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class GetPaymentNonceCommandTest @@ -29,37 +30,37 @@ class GetPaymentNonceCommandTest extends \PHPUnit\Framework\TestCase private $command; /** - * @var BraintreeAdapter|\PHPUnit_Framework_MockObject_MockObject + * @var BraintreeAdapter|MockObject */ private $adapter; /** - * @var PaymentTokenManagement|\PHPUnit_Framework_MockObject_MockObject + * @var PaymentTokenManagement|MockObject */ private $tokenManagement; /** - * @var PaymentToken|\PHPUnit_Framework_MockObject_MockObject + * @var PaymentToken|MockObject */ private $paymentToken; /** - * @var ArrayResultFactory|\PHPUnit_Framework_MockObject_MockObject + * @var ArrayResultFactory|MockObject */ private $resultFactory; /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject + * @var SubjectReader|MockObject */ private $subjectReader; /** - * @var PaymentNonceResponseValidator|\PHPUnit_Framework_MockObject_MockObject + * @var PaymentNonceResponseValidator|MockObject */ private $responseValidator; /** - * @var ResultInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ResultInterface|MockObject */ private $validationResult; @@ -79,6 +80,12 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods(['createNonce']) ->getMock(); + /** @var BraintreeAdapterFactory|MockObject $adapterFactory */ + $adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $adapterFactory->method('create') + ->willReturn($this->adapter); $this->resultFactory = $this->getMockBuilder(ArrayResultFactory::class) ->disableOriginalConstructor() @@ -101,7 +108,7 @@ protected function setUp() $this->command = new GetPaymentNonceCommand( $this->tokenManagement, - $this->adapter, + $adapterFactory, $this->resultFactory, $this->subjectReader, $this->responseValidator @@ -109,7 +116,6 @@ protected function setUp() } /** - * @covers \Magento\Braintree\Gateway\Command\GetPaymentNonceCommand::execute * @expectedException \InvalidArgumentException * @expectedExceptionMessage The "publicHash" field does not exists */ @@ -117,18 +123,16 @@ public function testExecuteWithExceptionForPublicHash() { $exception = new \InvalidArgumentException('The "publicHash" field does not exists'); - $this->subjectReader->expects(static::once()) - ->method('readPublicHash') + $this->subjectReader->method('readPublicHash') ->willThrowException($exception); - $this->subjectReader->expects(static::never()) + $this->subjectReader->expects(self::never()) ->method('readCustomerId'); $this->command->execute([]); } /** - * @covers \Magento\Braintree\Gateway\Command\GetPaymentNonceCommand::execute * @expectedException \InvalidArgumentException * @expectedExceptionMessage The "customerId" field does not exists */ @@ -136,23 +140,20 @@ public function testExecuteWithExceptionForCustomerId() { $publicHash = '3wv2m24d2er3'; - $this->subjectReader->expects(static::once()) - ->method('readPublicHash') + $this->subjectReader->method('readPublicHash') ->willReturn($publicHash); $exception = new \InvalidArgumentException('The "customerId" field does not exists'); - $this->subjectReader->expects(static::once()) - ->method('readCustomerId') + $this->subjectReader->method('readCustomerId') ->willThrowException($exception); - $this->tokenManagement->expects(static::never()) + $this->tokenManagement->expects(self::never()) ->method('getByPublicHash'); $this->command->execute(['publicHash' => $publicHash]); } /** - * @covers \Magento\Braintree\Gateway\Command\GetPaymentNonceCommand::execute * @expectedException \Exception * @expectedExceptionMessage No available payment tokens */ @@ -161,27 +162,23 @@ public function testExecuteWithExceptionForTokenManagement() $publicHash = '3wv2m24d2er3'; $customerId = 1; - $this->subjectReader->expects(static::once()) - ->method('readPublicHash') + $this->subjectReader->method('readPublicHash') ->willReturn($publicHash); - $this->subjectReader->expects(static::once()) - ->method('readCustomerId') + $this->subjectReader->method('readCustomerId') ->willReturn($customerId); $exception = new \Exception('No available payment tokens'); - $this->tokenManagement->expects(static::once()) - ->method('getByPublicHash') + $this->tokenManagement->method('getByPublicHash') ->willThrowException($exception); - $this->paymentToken->expects(static::never()) + $this->paymentToken->expects(self::never()) ->method('getGatewayToken'); $this->command->execute(['publicHash' => $publicHash, 'customerId' => $customerId]); } /** - * @covers \Magento\Braintree\Gateway\Command\GetPaymentNonceCommand::execute * @expectedException \Exception * @expectedExceptionMessage Payment method nonce can't be retrieved. */ @@ -191,52 +188,41 @@ public function testExecuteWithFailedValidation() $customerId = 1; $token = 'jd2vnq'; - $this->subjectReader->expects(static::once()) - ->method('readPublicHash') + $this->subjectReader->method('readPublicHash') ->willReturn($publicHash); - $this->subjectReader->expects(static::once()) - ->method('readCustomerId') + $this->subjectReader->method('readCustomerId') ->willReturn($customerId); - $this->tokenManagement->expects(static::once()) - ->method('getByPublicHash') + $this->tokenManagement->method('getByPublicHash') ->with($publicHash, $customerId) ->willReturn($this->paymentToken); - $this->paymentToken->expects(static::once()) - ->method('getGatewayToken') + $this->paymentToken->method('getGatewayToken') ->willReturn($token); $obj = new \stdClass(); $obj->success = false; - $this->adapter->expects(static::once()) - ->method('createNonce') + $this->adapter->method('createNonce') ->with($token) ->willReturn($obj); - $this->responseValidator->expects(static::once()) - ->method('validate') + $this->responseValidator->method('validate') ->with(['response' => ['object' => $obj]]) ->willReturn($this->validationResult); - $this->validationResult->expects(static::once()) - ->method('isValid') + $this->validationResult->method('isValid') ->willReturn(false); - $this->validationResult->expects(static::once()) - ->method('getFailsDescription') + $this->validationResult->method('getFailsDescription') ->willReturn(['Payment method nonce can\'t be retrieved.']); - $this->resultFactory->expects(static::never()) + $this->resultFactory->expects(self::never()) ->method('create'); $this->command->execute(['publicHash' => $publicHash, 'customerId' => $customerId]); } - /** - * @covers \Magento\Braintree\Gateway\Command\GetPaymentNonceCommand::execute - */ public function testExecute() { $publicHash = '3wv2m24d2er3'; @@ -244,57 +230,48 @@ public function testExecute() $token = 'jd2vnq'; $nonce = 's1dj23'; - $this->subjectReader->expects(static::once()) - ->method('readPublicHash') + $this->subjectReader->method('readPublicHash') ->willReturn($publicHash); - $this->subjectReader->expects(static::once()) - ->method('readCustomerId') + $this->subjectReader->method('readCustomerId') ->willReturn($customerId); - $this->tokenManagement->expects(static::once()) - ->method('getByPublicHash') + $this->tokenManagement->method('getByPublicHash') ->with($publicHash, $customerId) ->willReturn($this->paymentToken); - $this->paymentToken->expects(static::once()) - ->method('getGatewayToken') + $this->paymentToken->method('getGatewayToken') ->willReturn($token); $obj = new \stdClass(); $obj->success = true; $obj->paymentMethodNonce = new \stdClass(); $obj->paymentMethodNonce->nonce = $nonce; - $this->adapter->expects(static::once()) - ->method('createNonce') + $this->adapter->method('createNonce') ->with($token) ->willReturn($obj); - $this->responseValidator->expects(static::once()) - ->method('validate') + $this->responseValidator->method('validate') ->with(['response' => ['object' => $obj]]) ->willReturn($this->validationResult); - $this->validationResult->expects(static::once()) - ->method('isValid') + $this->validationResult->method('isValid') ->willReturn(true); - $this->validationResult->expects(static::never()) + $this->validationResult->expects(self::never()) ->method('getFailsDescription'); $expected = $this->getMockBuilder(ArrayResult::class) ->disableOriginalConstructor() ->setMethods(['get']) ->getMock(); - $expected->expects(static::once()) - ->method('get') + $expected->method('get') ->willReturn(['paymentMethodNonce' => $nonce]); - $this->resultFactory->expects(static::once()) - ->method('create') + $this->resultFactory->method('create') ->willReturn($expected); $actual = $this->command->execute(['publicHash' => $publicHash, 'customerId' => $customerId]); - static::assertEquals($expected, $actual); - static::assertEquals($nonce, $actual->get()['paymentMethodNonce']); + self::assertEquals($expected, $actual); + self::assertEquals($nonce, $actual->get()['paymentMethodNonce']); } } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSaleTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSaleTest.php index 5cbcfef8b6b9e..48889f1efd2e5 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSaleTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSaleTest.php @@ -7,8 +7,10 @@ use Magento\Braintree\Gateway\Http\Client\TransactionSale; use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Payment\Gateway\Http\TransferInterface; use Magento\Payment\Model\Method\Logger; +use PHPUnit_Framework_MockObject_MockObject as MockObject; use Psr\Log\LoggerInterface; /** @@ -22,35 +24,41 @@ class TransactionSaleTest extends \PHPUnit\Framework\TestCase private $model; /** - * @var Logger|\PHPUnit_Framework_MockObject_MockObject + * @var Logger|MockObject */ - private $loggerMock; + private $logger; /** - * @var BraintreeAdapter|\PHPUnit_Framework_MockObject_MockObject + * @var BraintreeAdapter|MockObject */ private $adapter; /** - * Set up - * - * @return void + * @inheritdoc */ protected function setUp() { - $criticalLoggerMock = $this->getMockForAbstractClass(LoggerInterface::class); - $this->loggerMock = $this->getMockBuilder(Logger::class) + /** @var LoggerInterface|MockObject $criticalLogger */ + $criticalLogger = $this->getMockForAbstractClass(LoggerInterface::class); + $this->logger = $this->getMockBuilder(Logger::class) ->disableOriginalConstructor() ->getMock(); + $this->adapter = $this->getMockBuilder(BraintreeAdapter::class) ->disableOriginalConstructor() ->getMock(); + /** @var BraintreeAdapterFactory|MockObject $adapterFactory */ + $adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $adapterFactory->method('create') + ->willReturn($this->adapter); - $this->model = new TransactionSale($criticalLoggerMock, $this->loggerMock, $this->adapter); + $this->model = new TransactionSale($criticalLogger, $this->logger, $adapterFactory); } /** - * Run test placeRequest method (exception) + * Runs test placeRequest method (exception) * * @return void * @@ -59,8 +67,7 @@ protected function setUp() */ public function testPlaceRequestException() { - $this->loggerMock->expects($this->once()) - ->method('debug') + $this->logger->method('debug') ->with( [ 'request' => $this->getTransferData(), @@ -69,11 +76,10 @@ public function testPlaceRequestException() ] ); - $this->adapter->expects($this->once()) - ->method('sale') + $this->adapter->method('sale') ->willThrowException(new \Exception('Test messages')); - /** @var TransferInterface|\PHPUnit_Framework_MockObject_MockObject $transferObjectMock */ + /** @var TransferInterface|MockObject $transferObjectMock */ $transferObjectMock = $this->getTransferObjectMock(); $this->model->placeRequest($transferObjectMock); @@ -87,14 +93,11 @@ public function testPlaceRequestException() public function testPlaceRequestSuccess() { $response = $this->getResponseObject(); - $this->adapter->expects($this->once()) - ->method('sale') + $this->adapter->method('sale') ->with($this->getTransferData()) - ->willReturn($response) - ; + ->willReturn($response); - $this->loggerMock->expects($this->once()) - ->method('debug') + $this->logger->method('debug') ->with( [ 'request' => $this->getTransferData(), @@ -110,19 +113,22 @@ public function testPlaceRequestSuccess() } /** - * @return TransferInterface|\PHPUnit_Framework_MockObject_MockObject + * Creates mock object for TransferInterface. + * + * @return TransferInterface|MockObject */ private function getTransferObjectMock() { $transferObjectMock = $this->createMock(TransferInterface::class); - $transferObjectMock->expects($this->once()) - ->method('getBody') + $transferObjectMock->method('getBody') ->willReturn($this->getTransferData()); return $transferObjectMock; } /** + * Creates stub for a response. + * * @return \stdClass */ private function getResponseObject() @@ -134,6 +140,8 @@ private function getResponseObject() } /** + * Creates stub request data. + * * @return array */ private function getTransferData() diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSubmitForSettlementTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSubmitForSettlementTest.php index 86113c34ba218..09b0efc58f3fb 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSubmitForSettlementTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Http/Client/TransactionSubmitForSettlementTest.php @@ -8,8 +8,10 @@ use Braintree\Result\Successful; use Magento\Braintree\Gateway\Http\Client\TransactionSubmitForSettlement; use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Payment\Gateway\Http\TransferInterface; use Magento\Payment\Model\Method\Logger; +use PHPUnit_Framework_MockObject_MockObject as MockObject; use Psr\Log\LoggerInterface; /** @@ -23,76 +25,79 @@ class TransactionSubmitForSettlementTest extends \PHPUnit\Framework\TestCase private $client; /** - * @var Logger|\PHPUnit_Framework_MockObject_MockObject + * @var Logger|MockObject */ private $logger; /** - * @var BraintreeAdapter|\PHPUnit_Framework_MockObject_MockObject + * @var BraintreeAdapter|MockObject */ private $adapter; protected function setUp() { - $criticalLoggerMock = $this->getMockForAbstractClass(LoggerInterface::class); + /** @var LoggerInterface|MockObject $criticalLogger */ + $criticalLogger = $this->getMockForAbstractClass(LoggerInterface::class); $this->logger = $this->getMockBuilder(Logger::class) ->disableOriginalConstructor() ->setMethods(['debug']) ->getMock(); + $this->adapter = $this->getMockBuilder(BraintreeAdapter::class) ->disableOriginalConstructor() ->setMethods(['submitForSettlement']) ->getMock(); + /** @var BraintreeAdapterFactory|MockObject $adapterFactory */ + $adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $adapterFactory->method('create') + ->willReturn($this->adapter); $this->client = new TransactionSubmitForSettlement( - $criticalLoggerMock, + $criticalLogger, $this->logger, - $this->adapter + $adapterFactory ); } /** - * @covers \Magento\Braintree\Gateway\Http\Client\TransactionSubmitForSettlement::placeRequest * @expectedException \Magento\Payment\Gateway\Http\ClientException * @expectedExceptionMessage Transaction has been declined */ public function testPlaceRequestWithException() { $exception = new \Exception('Transaction has been declined'); - $this->adapter->expects(static::once()) - ->method('submitForSettlement') + $this->adapter->method('submitForSettlement') ->willThrowException($exception); - /** @var TransferInterface|\PHPUnit_Framework_MockObject_MockObject $transferObjectMock */ - $transferObjectMock = $this->getTransferObjectMock(); - $this->client->placeRequest($transferObjectMock); + /** @var TransferInterface|MockObject $transferObject */ + $transferObject = $this->getTransferObjectMock(); + $this->client->placeRequest($transferObject); } - /** - * @covers \Magento\Braintree\Gateway\Http\Client\TransactionSubmitForSettlement::process - */ public function testPlaceRequest() { $data = new Successful(['success'], [true]); - $this->adapter->expects(static::once()) - ->method('submitForSettlement') + $this->adapter->method('submitForSettlement') ->willReturn($data); - /** @var TransferInterface|\PHPUnit_Framework_MockObject_MockObject $transferObjectMock */ - $transferObjectMock = $this->getTransferObjectMock(); - $response = $this->client->placeRequest($transferObjectMock); + /** @var TransferInterface|MockObject $transferObject */ + $transferObject = $this->getTransferObjectMock(); + $response = $this->client->placeRequest($transferObject); static::assertTrue(is_object($response['object'])); static::assertEquals(['object' => $data], $response); } /** - * @return TransferInterface|\PHPUnit_Framework_MockObject_MockObject + * Creates mock for TransferInterface + * + * @return TransferInterface|MockObject */ private function getTransferObjectMock() { $mock = $this->createMock(TransferInterface::class); - $mock->expects($this->once()) - ->method('getBody') + $mock->method('getBody') ->willReturn([ 'transaction_id' => 'vb4c6b', 'amount' => 124.00 diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/AddressDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/AddressDataBuilderTest.php index 3f05aed45da60..95bb73d27f23f 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/AddressDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/AddressDataBuilderTest.php @@ -5,11 +5,12 @@ */ namespace Magento\Braintree\Test\Unit\Gateway\Request; +use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Braintree\Gateway\Request\AddressDataBuilder; -use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; -use Magento\Payment\Gateway\Data\OrderAdapterInterface; use Magento\Payment\Gateway\Data\AddressAdapterInterface; -use Magento\Braintree\Gateway\Helper\SubjectReader; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class AddressDataBuilderTest @@ -17,34 +18,26 @@ class AddressDataBuilderTest extends \PHPUnit\Framework\TestCase { /** - * @var PaymentDataObjectInterface|\PHPUnit_Framework_MockObject_MockObject + * @var PaymentDataObjectInterface|MockObject */ - private $paymentDOMock; + private $paymentDO; /** - * @var OrderAdapterInterface|\PHPUnit_Framework_MockObject_MockObject + * @var OrderAdapterInterface|MockObject */ - private $orderMock; + private $order; /** * @var AddressDataBuilder */ private $builder; - /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject - */ - private $subjectReaderMock; - protected function setUp() { - $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); - $this->orderMock = $this->createMock(OrderAdapterInterface::class); - $this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class) - ->disableOriginalConstructor() - ->getMock(); + $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); + $this->order = $this->createMock(OrderAdapterInterface::class); - $this->builder = new AddressDataBuilder($this->subjectReaderMock); + $this->builder = new AddressDataBuilder(new SubjectReader()); } /** @@ -56,37 +49,24 @@ public function testBuildReadPaymentException() 'payment' => null, ]; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willThrowException(new \InvalidArgumentException()); - $this->builder->build($buildSubject); } public function testBuildNoAddresses() { - $this->paymentDOMock->expects(static::once()) - ->method('getOrder') - ->willReturn($this->orderMock); + $this->paymentDO->method('getOrder') + ->willReturn($this->order); - $this->orderMock->expects(static::once()) - ->method('getShippingAddress') + $this->order->method('getShippingAddress') ->willReturn(null); - $this->orderMock->expects(static::once()) - ->method('getBillingAddress') + $this->order->method('getBillingAddress') ->willReturn(null); $buildSubject = [ - 'payment' => $this->paymentDOMock, + 'payment' => $this->paymentDO, ]; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDOMock); - - static::assertEquals([], $this->builder->build($buildSubject)); + self::assertEquals([], $this->builder->build($buildSubject)); } /** @@ -97,28 +77,20 @@ public function testBuildNoAddresses() */ public function testBuild($addressData, $expectedResult) { - $addressMock = $this->getAddressMock($addressData); + $address = $this->getAddressMock($addressData); - $this->paymentDOMock->expects(static::once()) - ->method('getOrder') - ->willReturn($this->orderMock); + $this->paymentDO->method('getOrder') + ->willReturn($this->order); - $this->orderMock->expects(static::once()) - ->method('getShippingAddress') - ->willReturn($addressMock); - $this->orderMock->expects(static::once()) - ->method('getBillingAddress') - ->willReturn($addressMock); + $this->order->method('getShippingAddress') + ->willReturn($address); + $this->order->method('getBillingAddress') + ->willReturn($address); $buildSubject = [ - 'payment' => $this->paymentDOMock, + 'payment' => $this->paymentDO, ]; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDOMock); - self::assertEquals($expectedResult, $this->builder->build($buildSubject)); } @@ -171,37 +143,37 @@ public function dataProviderBuild() /** * @param array $addressData - * @return AddressAdapterInterface|\PHPUnit_Framework_MockObject_MockObject + * @return AddressAdapterInterface|MockObject */ private function getAddressMock($addressData) { $addressMock = $this->createMock(AddressAdapterInterface::class); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getFirstname') ->willReturn($addressData['first_name']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getLastname') ->willReturn($addressData['last_name']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getCompany') ->willReturn($addressData['company']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getStreetLine1') ->willReturn($addressData['street_1']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getStreetLine2') ->willReturn($addressData['street_2']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getCity') ->willReturn($addressData['city']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getRegionCode') ->willReturn($addressData['region_code']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getPostcode') ->willReturn($addressData['post_code']); - $addressMock->expects(static::exactly(2)) + $addressMock->expects(self::exactly(2)) ->method('getCountryId') ->willReturn($addressData['country_id']); diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php index 9799b6f18c639..afe6588f01944 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php @@ -9,6 +9,7 @@ use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; use Magento\Sales\Model\Order\Payment; use Magento\Braintree\Gateway\Helper\SubjectReader; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class CaptureDataBuilderTest @@ -21,35 +22,26 @@ class CaptureDataBuilderTest extends \PHPUnit\Framework\TestCase private $builder; /** - * @var Payment|\PHPUnit_Framework_MockObject_MockObject + * @var Payment|MockObject */ private $payment; /** - * @var \Magento\Sales\Model\Order\Payment|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Sales\Model\Order\Payment|MockObject */ private $paymentDO; - /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject - */ - private $subjectReaderMock; - protected function setUp() { $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); $this->payment = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() ->getMock(); - $this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class) - ->disableOriginalConstructor() - ->getMock(); - $this->builder = new CaptureDataBuilder($this->subjectReaderMock); + $this->builder = new CaptureDataBuilder(new SubjectReader()); } /** - * @covers \Magento\Braintree\Gateway\Request\CaptureDataBuilder::build * @expectedException \Magento\Framework\Exception\LocalizedException * @expectedExceptionMessage No authorization transaction to proceed capture. */ @@ -61,25 +53,15 @@ public function testBuildWithException() 'amount' => $amount ]; - $this->payment->expects(static::once()) - ->method('getCcTransId') + $this->payment->method('getCcTransId') ->willReturn(''); - $this->paymentDO->expects(static::once()) - ->method('getPayment') + $this->paymentDO->method('getPayment') ->willReturn($this->payment); - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDO); - $this->builder->build($buildSubject); } - /** - * @covers \Magento\Braintree\Gateway\Request\CaptureDataBuilder::build - */ public function testBuild() { $transactionId = 'b3b99d'; @@ -95,23 +77,12 @@ public function testBuild() 'amount' => $amount ]; - $this->payment->expects(static::once()) - ->method('getCcTransId') + $this->payment->method('getCcTransId') ->willReturn($transactionId); - $this->paymentDO->expects(static::once()) - ->method('getPayment') + $this->paymentDO->method('getPayment') ->willReturn($this->payment); - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDO); - $this->subjectReaderMock->expects(self::once()) - ->method('readAmount') - ->with($buildSubject) - ->willReturn($amount); - - static::assertEquals($expected, $this->builder->build($buildSubject)); + self::assertEquals($expected, $this->builder->build($buildSubject)); } } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CustomerDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CustomerDataBuilderTest.php index 0f25b26fd2fa3..cac12f83051c1 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CustomerDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/CustomerDataBuilderTest.php @@ -5,46 +5,36 @@ */ namespace Magento\Braintree\Test\Unit\Gateway\Request; +use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Braintree\Gateway\Request\CustomerDataBuilder; -use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; -use Magento\Payment\Gateway\Data\OrderAdapterInterface; use Magento\Payment\Gateway\Data\AddressAdapterInterface; -use Magento\Braintree\Gateway\Helper\SubjectReader; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; -/** - * Class CustomerDataBuilderTest - */ class CustomerDataBuilderTest extends \PHPUnit\Framework\TestCase { /** - * @var PaymentDataObjectInterface|\PHPUnit_Framework_MockObject_MockObject + * @var PaymentDataObjectInterface|MockObject */ - private $paymentDOMock; + private $paymentDO; /** - * @var OrderAdapterInterface|\PHPUnit_Framework_MockObject_MockObject + * @var OrderAdapterInterface|MockObject */ - private $orderMock; + private $order; /** * @var CustomerDataBuilder */ private $builder; - /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject - */ - private $subjectReaderMock; - protected function setUp() { - $this->paymentDOMock = $this->createMock(PaymentDataObjectInterface::class); - $this->orderMock = $this->createMock(OrderAdapterInterface::class); - $this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class) - ->disableOriginalConstructor() - ->getMock(); + $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); + $this->order = $this->createMock(OrderAdapterInterface::class); - $this->builder = new CustomerDataBuilder($this->subjectReaderMock); + $this->builder = new CustomerDataBuilder(new SubjectReader()); } /** @@ -56,11 +46,6 @@ public function testBuildReadPaymentException() 'payment' => null, ]; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willThrowException(new \InvalidArgumentException()); - $this->builder->build($buildSubject); } @@ -74,22 +59,15 @@ public function testBuild($billingData, $expectedResult) { $billingMock = $this->getBillingMock($billingData); - $this->paymentDOMock->expects(static::once()) - ->method('getOrder') - ->willReturn($this->orderMock); - $this->orderMock->expects(static::once()) - ->method('getBillingAddress') + $this->paymentDO->method('getOrder') + ->willReturn($this->order); + $this->order->method('getBillingAddress') ->willReturn($billingMock); $buildSubject = [ - 'payment' => $this->paymentDOMock, + 'payment' => $this->paymentDO, ]; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDOMock); - self::assertEquals($expectedResult, $this->builder->build($buildSubject)); } @@ -122,28 +100,23 @@ public function dataProviderBuild() /** * @param array $billingData - * @return AddressAdapterInterface|\PHPUnit_Framework_MockObject_MockObject + * @return AddressAdapterInterface|MockObject */ private function getBillingMock($billingData) { - $addressMock = $this->createMock(AddressAdapterInterface::class); + $address = $this->createMock(AddressAdapterInterface::class); - $addressMock->expects(static::once()) - ->method('getFirstname') + $address->method('getFirstname') ->willReturn($billingData['first_name']); - $addressMock->expects(static::once()) - ->method('getLastname') + $address->method('getLastname') ->willReturn($billingData['last_name']); - $addressMock->expects(static::once()) - ->method('getCompany') + $address->method('getCompany') ->willReturn($billingData['company']); - $addressMock->expects(static::once()) - ->method('getTelephone') + $address->method('getTelephone') ->willReturn($billingData['phone']); - $addressMock->expects(static::once()) - ->method('getEmail') + $address->method('getEmail') ->willReturn($billingData['email']); - return $addressMock; + return $address; } } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/DescriptorDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/DescriptorDataBuilderTest.php index 761d88b636ed7..6b3b89832b250 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/DescriptorDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/DescriptorDataBuilderTest.php @@ -6,12 +6,12 @@ namespace Magento\Braintree\Test\Unit\Gateway\Request; use Magento\Braintree\Gateway\Config\Config; +use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Braintree\Gateway\Request\DescriptorDataBuilder; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; use PHPUnit_Framework_MockObject_MockObject as MockObject; -/** - * Class DescriptorDataBuilderTest - */ class DescriptorDataBuilderTest extends \PHPUnit\Framework\TestCase { /** @@ -31,22 +31,25 @@ protected function setUp() ->setMethods(['getDynamicDescriptors']) ->getMock(); - $this->builder = new DescriptorDataBuilder($this->config); + $this->builder = new DescriptorDataBuilder($this->config, new SubjectReader()); } /** - * @covers \Magento\Braintree\Gateway\Request\DescriptorDataBuilder::build * @param array $descriptors * @param array $expected * @dataProvider buildDataProvider */ public function testBuild(array $descriptors, array $expected) { - $this->config->expects(static::once()) - ->method('getDynamicDescriptors') + $paymentDO = $this->createMock(PaymentDataObjectInterface::class); + $order = $this->createMock(OrderAdapterInterface::class); + $paymentDO->method('getOrder') + ->willReturn($order); + + $this->config->method('getDynamicDescriptors') ->willReturn($descriptors); - $actual = $this->builder->build([]); + $actual = $this->builder->build(['payment' => $paymentDO]); static::assertEquals($expected, $actual); } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/KountPaymentDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/KountPaymentDataBuilderTest.php index ee0907a1ddbbb..a8db7f466131f 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/KountPaymentDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/KountPaymentDataBuilderTest.php @@ -5,12 +5,14 @@ */ namespace Magento\Braintree\Test\Unit\Gateway\Request; +use Magento\Payment\Gateway\Data\OrderAdapterInterface; use Magento\Sales\Model\Order\Payment; use Magento\Braintree\Gateway\Config\Config; use Magento\Braintree\Observer\DataAssignObserver; use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; use Magento\Braintree\Gateway\Request\KountPaymentDataBuilder; use Magento\Braintree\Gateway\Helper\SubjectReader; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class KountPaymentDataBuilderTest @@ -27,39 +29,31 @@ class KountPaymentDataBuilderTest extends \PHPUnit\Framework\TestCase private $builder; /** - * @var Config|\PHPUnit_Framework_MockObject_MockObject + * @var Config|MockObject */ - private $configMock; + private $config; /** - * @var Payment|\PHPUnit_Framework_MockObject_MockObject + * @var Payment|MockObject */ - private $paymentMock; + private $payment; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ private $paymentDO; - /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject - */ - private $subjectReaderMock; - protected function setUp() { $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); - $this->configMock = $this->getMockBuilder(Config::class) - ->disableOriginalConstructor() - ->getMock(); - $this->paymentMock = $this->getMockBuilder(Payment::class) + $this->config = $this->getMockBuilder(Config::class) ->disableOriginalConstructor() ->getMock(); - $this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class) + $this->payment = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() ->getMock(); - $this->builder = new KountPaymentDataBuilder($this->configMock, $this->subjectReaderMock); + $this->builder = new KountPaymentDataBuilder($this->config, new SubjectReader()); } /** @@ -69,15 +63,9 @@ public function testBuildReadPaymentException() { $buildSubject = []; - $this->configMock->expects(static::once()) - ->method('hasFraudProtection') + $this->config->method('hasFraudProtection') ->willReturn(true); - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willThrowException(new \InvalidArgumentException()); - $this->builder->build($buildSubject); } @@ -91,26 +79,23 @@ public function testBuild() KountPaymentDataBuilder::DEVICE_DATA => self::DEVICE_DATA, ]; + $order = $this->createMock(OrderAdapterInterface::class); + $this->paymentDO->method('getOrder') + ->willReturn($order); + $buildSubject = ['payment' => $this->paymentDO]; - $this->paymentMock->expects(static::exactly(count($additionalData))) + $this->payment->expects(self::exactly(count($additionalData))) ->method('getAdditionalInformation') ->willReturn($additionalData); - $this->configMock->expects(static::once()) - ->method('hasFraudProtection') + $this->config->method('hasFraudProtection') ->willReturn(true); - $this->paymentDO->expects(static::once()) - ->method('getPayment') - ->willReturn($this->paymentMock); - - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDO); + $this->paymentDO->method('getPayment') + ->willReturn($this->payment); - static::assertEquals( + self::assertEquals( $expectedResult, $this->builder->build($buildSubject) ); diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/DeviceDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/DeviceDataBuilderTest.php index fba65354d6095..c2e8d0f9335ce 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/DeviceDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/DeviceDataBuilderTest.php @@ -16,15 +16,10 @@ */ class DeviceDataBuilderTest extends \PHPUnit\Framework\TestCase { - /** - * @var SubjectReader|MockObject - */ - private $subjectReader; - /** * @var PaymentDataObjectInterface|MockObject */ - private $paymentDataObject; + private $paymentDO; /** * @var InfoInterface|MockObject @@ -38,16 +33,10 @@ class DeviceDataBuilderTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->subjectReader = $this->getMockBuilder(SubjectReader::class) - ->disableOriginalConstructor() - ->setMethods(['readPayment']) - ->getMock(); - - $this->paymentDataObject = $this->createMock(PaymentDataObjectInterface::class); - + $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); $this->paymentInfo = $this->createMock(InfoInterface::class); - $this->builder = new DeviceDataBuilder($this->subjectReader); + $this->builder = new DeviceDataBuilder(new SubjectReader()); } /** @@ -59,24 +48,17 @@ protected function setUp() public function testBuild(array $paymentData, array $expected) { $subject = [ - 'payment' => $this->paymentDataObject + 'payment' => $this->paymentDO ]; - $this->subjectReader->expects(static::once()) - ->method('readPayment') - ->with($subject) - ->willReturn($this->paymentDataObject); - - $this->paymentDataObject->expects(static::once()) - ->method('getPayment') + $this->paymentDO->method('getPayment') ->willReturn($this->paymentInfo); - $this->paymentInfo->expects(static::once()) - ->method('getAdditionalInformation') + $this->paymentInfo->method('getAdditionalInformation') ->willReturn($paymentData); $actual = $this->builder->build($subject); - static::assertEquals($expected, $actual); + self::assertEquals($expected, $actual); } /** diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/VaultDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/VaultDataBuilderTest.php index 8e83254727bf7..f7a2b721df165 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/VaultDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PayPal/VaultDataBuilderTest.php @@ -17,15 +17,10 @@ */ class VaultDataBuilderTest extends \PHPUnit\Framework\TestCase { - /** - * @var SubjectReader|MockObject - */ - private $subjectReader; - /** * @var PaymentDataObjectInterface|MockObject */ - private $paymentDataObject; + private $paymentDO; /** * @var InfoInterface|MockObject @@ -39,16 +34,11 @@ class VaultDataBuilderTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->paymentDataObject = $this->createMock(PaymentDataObjectInterface::class); + $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); $this->paymentInfo = $this->createMock(InfoInterface::class); - $this->subjectReader = $this->getMockBuilder(SubjectReader::class) - ->disableOriginalConstructor() - ->setMethods(['readPayment']) - ->getMock(); - - $this->builder = new VaultDataBuilder($this->subjectReader); + $this->builder = new VaultDataBuilder(new SubjectReader()); } /** @@ -60,24 +50,17 @@ protected function setUp() public function testBuild(array $additionalInfo, array $expected) { $subject = [ - 'payment' => $this->paymentDataObject + 'payment' => $this->paymentDO ]; - $this->subjectReader->expects(static::once()) - ->method('readPayment') - ->with($subject) - ->willReturn($this->paymentDataObject); - - $this->paymentDataObject->expects(static::once()) - ->method('getPayment') + $this->paymentDO->method('getPayment') ->willReturn($this->paymentInfo); - $this->paymentInfo->expects(static::once()) - ->method('getAdditionalInformation') + $this->paymentInfo->method('getAdditionalInformation') ->willReturn($additionalInfo); $actual = $this->builder->build($subject); - static::assertEquals($expected, $actual); + self::assertEquals($expected, $actual); } /** diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php index 12c613b8f216b..665232592889c 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/PaymentDataBuilderTest.php @@ -12,6 +12,7 @@ use Magento\Payment\Gateway\Data\OrderAdapterInterface; use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; use Magento\Sales\Model\Order\Payment; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class PaymentDataBuilderTest @@ -29,45 +30,37 @@ class PaymentDataBuilderTest extends \PHPUnit\Framework\TestCase private $builder; /** - * @var Config|\PHPUnit_Framework_MockObject_MockObject + * @var Config|MockObject */ - private $configMock; + private $config; /** - * @var Payment|\PHPUnit_Framework_MockObject_MockObject + * @var Payment|MockObject */ - private $paymentMock; + private $payment; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ private $paymentDO; /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject + * @var OrderAdapterInterface|MockObject */ - private $subjectReaderMock; - - /** - * @var OrderAdapterInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $orderMock; + private $order; protected function setUp() { $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); - $this->configMock = $this->getMockBuilder(Config::class) - ->disableOriginalConstructor() - ->getMock(); - $this->paymentMock = $this->getMockBuilder(Payment::class) + $this->config = $this->getMockBuilder(Config::class) ->disableOriginalConstructor() ->getMock(); - $this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class) + $this->payment = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() ->getMock(); - $this->orderMock = $this->createMock(OrderAdapterInterface::class); + $this->order = $this->createMock(OrderAdapterInterface::class); - $this->builder = new PaymentDataBuilder($this->configMock, $this->subjectReaderMock); + $this->builder = new PaymentDataBuilder($this->config, new SubjectReader()); } /** @@ -77,11 +70,6 @@ public function testBuildReadPaymentException() { $buildSubject = []; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willThrowException(new \InvalidArgumentException()); - $this->builder->build($buildSubject); } @@ -95,15 +83,6 @@ public function testBuildReadAmountException() 'amount' => null ]; - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDO); - $this->subjectReaderMock->expects(self::once()) - ->method('readAmount') - ->with($buildSubject) - ->willThrowException(new \InvalidArgumentException()); - $this->builder->build($buildSubject); } @@ -128,36 +107,23 @@ public function testBuild() 'amount' => 10.00 ]; - $this->paymentMock->expects(static::exactly(count($additionalData))) + $this->payment->expects(self::exactly(count($additionalData))) ->method('getAdditionalInformation') ->willReturnMap($additionalData); - $this->configMock->expects(static::once()) - ->method('getMerchantAccountId') + $this->config->method('getMerchantAccountId') ->willReturn(self::MERCHANT_ACCOUNT_ID); - $this->paymentDO->expects(static::once()) - ->method('getPayment') - ->willReturn($this->paymentMock); - - $this->paymentDO->expects(static::once()) - ->method('getOrder') - ->willReturn($this->orderMock); - - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDO); - $this->subjectReaderMock->expects(self::once()) - ->method('readAmount') - ->with($buildSubject) - ->willReturn(10.00); - - $this->orderMock->expects(static::once()) - ->method('getOrderIncrementId') + $this->paymentDO->method('getPayment') + ->willReturn($this->payment); + + $this->paymentDO->method('getOrder') + ->willReturn($this->order); + + $this->order->method('getOrderIncrementId') ->willReturn('000000101'); - static::assertEquals( + self::assertEquals( $expectedResult, $this->builder->build($buildSubject) ); diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/RefundDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/RefundDataBuilderTest.php index 5aa383d095a1e..ada4c881b3e74 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/RefundDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/RefundDataBuilderTest.php @@ -14,11 +14,6 @@ class RefundDataBuilderTest extends \PHPUnit\Framework\TestCase { - /** - * @var SubjectReader | \PHPUnit_Framework_MockObject_MockObject - */ - private $subjectReader; - /** * @var RefundDataBuilder */ @@ -26,41 +21,25 @@ class RefundDataBuilderTest extends \PHPUnit\Framework\TestCase public function setUp() { - $this->subjectReader = $this->getMockBuilder( - SubjectReader::class - )->disableOriginalConstructor() - ->getMock(); - - $this->dataBuilder = new RefundDataBuilder($this->subjectReader); + $this->dataBuilder = new RefundDataBuilder(new SubjectReader()); } public function testBuild() { $paymentDO = $this->createMock(PaymentDataObjectInterface::class); - $paymentModel = $this->getMockBuilder( - Payment::class - )->disableOriginalConstructor() + $paymentModel = $this->getMockBuilder(Payment::class) + ->disableOriginalConstructor() ->getMock(); $buildSubject = ['payment' => $paymentDO, 'amount' => 12.358]; $transactionId = 'xsd7n'; - $this->subjectReader->expects(static::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($paymentDO); - $paymentDO->expects(static::once()) - ->method('getPayment') + $paymentDO->method('getPayment') ->willReturn($paymentModel); - $paymentModel->expects(static::once()) - ->method('getParentTransactionId') + $paymentModel->method('getParentTransactionId') ->willReturn($transactionId); - $this->subjectReader->expects(static::once()) - ->method('readAmount') - ->with($buildSubject) - ->willReturn($buildSubject['amount']); - static::assertEquals( + self::assertEquals( [ 'transaction_id' => $transactionId, PaymentDataBuilder::AMOUNT => '12.36' @@ -72,30 +51,19 @@ public function testBuild() public function testBuildNullAmount() { $paymentDO = $this->createMock(PaymentDataObjectInterface::class); - $paymentModel = $this->getMockBuilder( - Payment::class - )->disableOriginalConstructor() + $paymentModel = $this->getMockBuilder(Payment::class) + ->disableOriginalConstructor() ->getMock(); $buildSubject = ['payment' => $paymentDO]; $transactionId = 'xsd7n'; - $this->subjectReader->expects(static::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($paymentDO); - $paymentDO->expects(static::once()) - ->method('getPayment') + $paymentDO->method('getPayment') ->willReturn($paymentModel); - $paymentModel->expects(static::once()) - ->method('getParentTransactionId') + $paymentModel->method('getParentTransactionId') ->willReturn($transactionId); - $this->subjectReader->expects(static::once()) - ->method('readAmount') - ->with($buildSubject) - ->willThrowException(new \InvalidArgumentException()); - static::assertEquals( + self::assertEquals( [ 'transaction_id' => $transactionId, PaymentDataBuilder::AMOUNT => null @@ -107,31 +75,20 @@ public function testBuildNullAmount() public function testBuildCutOffLegacyTransactionIdPostfix() { $paymentDO = $this->createMock(PaymentDataObjectInterface::class); - $paymentModel = $this->getMockBuilder( - Payment::class - )->disableOriginalConstructor() + $paymentModel = $this->getMockBuilder(Payment::class) + ->disableOriginalConstructor() ->getMock(); $buildSubject = ['payment' => $paymentDO]; $legacyTxnId = 'xsd7n-' . TransactionInterface::TYPE_CAPTURE; $transactionId = 'xsd7n'; - $this->subjectReader->expects(static::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($paymentDO); - $paymentDO->expects(static::once()) - ->method('getPayment') + $paymentDO->method('getPayment') ->willReturn($paymentModel); - $paymentModel->expects(static::once()) - ->method('getParentTransactionId') + $paymentModel->method('getParentTransactionId') ->willReturn($legacyTxnId); - $this->subjectReader->expects(static::once()) - ->method('readAmount') - ->with($buildSubject) - ->willThrowException(new \InvalidArgumentException()); - static::assertEquals( + self::assertEquals( [ 'transaction_id' => $transactionId, PaymentDataBuilder::AMOUNT => null diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/SettlementDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/SettlementDataBuilderTest.php index 2f8f954243749..beccad6e9a045 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/SettlementDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/SettlementDataBuilderTest.php @@ -11,7 +11,7 @@ class SettlementDataBuilderTest extends \PHPUnit\Framework\TestCase { public function testBuild() { - $this->assertEquals( + self::assertEquals( [ 'options' => [ SettlementDataBuilder::SUBMIT_FOR_SETTLEMENT => true diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/ThreeDSecureDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/ThreeDSecureDataBuilderTest.php index c28ac0c3ac372..0a2617f95eb66 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/ThreeDSecureDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/ThreeDSecureDataBuilderTest.php @@ -6,68 +6,63 @@ namespace Magento\Braintree\Test\Unit\Gateway\Request; use Magento\Braintree\Gateway\Config\Config; +use Magento\Braintree\Gateway\Helper\SubjectReader; use Magento\Braintree\Gateway\Request\ThreeDSecureDataBuilder; -use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; -use Magento\Payment\Gateway\Data\Order\OrderAdapter; use Magento\Payment\Gateway\Data\Order\AddressAdapter; -use Magento\Braintree\Gateway\Helper\SubjectReader; +use Magento\Payment\Gateway\Data\Order\OrderAdapter; +use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class ThreeDSecureDataBuilderTest */ class ThreeDSecureDataBuilderTest extends \PHPUnit\Framework\TestCase { + /** + * @var int + */ + private static $storeId = 1; + /** * @var ThreeDSecureDataBuilder */ private $builder; /** - * @var Config|\PHPUnit_Framework_MockObject_MockObject + * @var Config|MockObject */ - private $configMock; + private $config; /** - * @var PaymentDataObjectInterface|\PHPUnit_Framework_MockObject_MockObject + * @var PaymentDataObjectInterface|MockObject */ private $paymentDO; /** - * @var OrderAdapter|\PHPUnit_Framework_MockObject_MockObject + * @var OrderAdapter|MockObject */ private $order; /** - * @var \Magento\Payment\Gateway\Data\Order\AddressAdapter|\PHPUnit_Framework_MockObject_MockObject + * @var AddressAdapter|MockObject */ private $billingAddress; - /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject - */ - private $subjectReaderMock; - protected function setUp() { $this->initOrderMock(); $this->paymentDO = $this->getMockBuilder(PaymentDataObjectInterface::class) ->disableOriginalConstructor() - ->setMethods(['getOrder', 'getPayment']) ->getMock(); - $this->paymentDO->expects(static::once()) - ->method('getOrder') + $this->paymentDO->method('getOrder') ->willReturn($this->order); - $this->configMock = $this->getMockBuilder(Config::class) - ->setMethods(['isVerify3DSecure', 'getThresholdAmount', 'get3DSecureSpecificCountries']) - ->disableOriginalConstructor() - ->getMock(); - $this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class) + $this->config = $this->getMockBuilder(Config::class) ->disableOriginalConstructor() ->getMock(); - $this->builder = new ThreeDSecureDataBuilder($this->configMock, $this->subjectReaderMock); + $this->builder = new ThreeDSecureDataBuilder($this->config, new SubjectReader()); } /** @@ -76,7 +71,6 @@ protected function setUp() * @param string $countryId * @param array $countries * @param array $expected - * @covers \Magento\Braintree\Gateway\Request\ThreeDSecureDataBuilder::build * @dataProvider buildDataProvider */ public function testBuild($verify, $thresholdAmount, $countryId, array $countries, array $expected) @@ -86,37 +80,28 @@ public function testBuild($verify, $thresholdAmount, $countryId, array $countrie 'amount' => 25 ]; - $this->configMock->expects(static::once()) - ->method('isVerify3DSecure') + $this->config->method('isVerify3DSecure') + ->with(self::equalTo(self::$storeId)) ->willReturn($verify); - $this->configMock->expects(static::any()) - ->method('getThresholdAmount') + $this->config->method('getThresholdAmount') + ->with(self::equalTo(self::$storeId)) ->willReturn($thresholdAmount); - $this->configMock->expects(static::any()) - ->method('get3DSecureSpecificCountries') + $this->config->method('get3DSecureSpecificCountries') + ->with(self::equalTo(self::$storeId)) ->willReturn($countries); - $this->billingAddress->expects(static::any()) - ->method('getCountryId') + $this->billingAddress->method('getCountryId') ->willReturn($countryId); - $this->subjectReaderMock->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDO); - $this->subjectReaderMock->expects(self::once()) - ->method('readAmount') - ->with($buildSubject) - ->willReturn(25); - $result = $this->builder->build($buildSubject); - static::assertEquals($expected, $result); + self::assertEquals($expected, $result); } /** - * Get list of variations for build test + * Gets list of variations to build request data. + * * @return array */ public function buildDataProvider() @@ -144,22 +129,21 @@ public function buildDataProvider() } /** - * Create mock object for order adapter + * Creates mock object for order adapter. */ private function initOrderMock() { $this->billingAddress = $this->getMockBuilder(AddressAdapter::class) ->disableOriginalConstructor() - ->setMethods(['getCountryId']) ->getMock(); $this->order = $this->getMockBuilder(OrderAdapter::class) ->disableOriginalConstructor() - ->setMethods(['getBillingAddress']) ->getMock(); - $this->order->expects(static::any()) - ->method('getBillingAddress') + $this->order->method('getBillingAddress') ->willReturn($this->billingAddress); + $this->order->method('getStoreId') + ->willReturn(self::$storeId); } } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultCaptureDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultCaptureDataBuilderTest.php index df11938ddba70..94c889159b516 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultCaptureDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultCaptureDataBuilderTest.php @@ -11,6 +11,7 @@ use Magento\Sales\Api\Data\OrderPaymentExtension; use Magento\Sales\Model\Order\Payment; use Magento\Vault\Model\PaymentToken; +use PHPUnit_Framework_MockObject_MockObject as MockObject; class VaultCaptureDataBuilderTest extends \PHPUnit\Framework\TestCase { @@ -20,35 +21,25 @@ class VaultCaptureDataBuilderTest extends \PHPUnit\Framework\TestCase private $builder; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var PaymentDataObjectInterface|MockObject */ private $paymentDO; /** - * @var Payment|\PHPUnit_Framework_MockObject_MockObject + * @var Payment|MockObject */ private $payment; - /** - * @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject - */ - private $subjectReader; - public function setUp() { $this->paymentDO = $this->createMock(PaymentDataObjectInterface::class); $this->payment = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() ->getMock(); - $this->paymentDO->expects(static::once()) - ->method('getPayment') + $this->paymentDO->method('getPayment') ->willReturn($this->payment); - $this->subjectReader = $this->getMockBuilder(SubjectReader::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->builder = new VaultCaptureDataBuilder($this->subjectReader); + $this->builder = new VaultCaptureDataBuilder(new SubjectReader()); } /** @@ -68,15 +59,6 @@ public function testBuild() 'paymentMethodToken' => $token ]; - $this->subjectReader->expects(self::once()) - ->method('readPayment') - ->with($buildSubject) - ->willReturn($this->paymentDO); - $this->subjectReader->expects(self::once()) - ->method('readAmount') - ->with($buildSubject) - ->willReturn($amount); - $paymentExtension = $this->getMockBuilder(OrderPaymentExtension::class) ->setMethods(['getVaultPaymentToken']) ->disableOriginalConstructor() @@ -86,18 +68,15 @@ public function testBuild() ->disableOriginalConstructor() ->getMock(); - $paymentExtension->expects(static::once()) - ->method('getVaultPaymentToken') + $paymentExtension->method('getVaultPaymentToken') ->willReturn($paymentToken); - $this->payment->expects(static::once()) - ->method('getExtensionAttributes') + $this->payment->method('getExtensionAttributes') ->willReturn($paymentExtension); - $paymentToken->expects(static::once()) - ->method('getGatewayToken') + $paymentToken->method('getGatewayToken') ->willReturn($token); $result = $this->builder->build($buildSubject); - static::assertEquals($expected, $result); + self::assertEquals($expected, $result); } } diff --git a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultDataBuilderTest.php b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultDataBuilderTest.php index 08b5526daeb04..c4bd047a06bb8 100644 --- a/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultDataBuilderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Gateway/Request/VaultDataBuilderTest.php @@ -20,7 +20,7 @@ public function testBuild() $buildSubject = []; $builder = new VaultDataBuilder(); - static::assertEquals( + self::assertEquals( $expectedResult, $builder->build($buildSubject) ); diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php index e43e67c18744f..5fcb6a89244b5 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Report/TransactionsCollectionTest.php @@ -6,10 +6,12 @@ namespace Magento\Braintree\Test\Unit\Model\Report; use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Braintree\Model\Report\FilterMapper; use Magento\Braintree\Model\Report\TransactionsCollection; use Magento\Framework\Api\Search\DocumentInterface; use Magento\Framework\Data\Collection\EntityFactoryInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * Class TransactionsCollectionTest @@ -19,48 +21,58 @@ class TransactionsCollectionTest extends \PHPUnit\Framework\TestCase { /** - * @var BraintreeAdapter|\PHPUnit_Framework_MockObject_MockObject + * @var BraintreeAdapter|MockObject */ - private $braintreeAdapterMock; + private $braintreeAdapter; /** - * @var EntityFactoryInterface|\PHPUnit_Framework_MockObject_MockObject + * @var BraintreeAdapterFactory|MockObject */ - private $entityFactoryMock; + private $adapterFactory; /** - * @var FilterMapper|\PHPUnit_Framework_MockObject_MockObject + * @var EntityFactoryInterface|MockObject */ - private $filterMapperMock; + private $entityFactory; /** - * @var DocumentInterface|\PHPUnit_Framework_MockObject_MockObject + * @var FilterMapper|MockObject */ - private $transactionMapMock; + private $filterMapper; + + /** + * @var DocumentInterface|MockObject + */ + private $transactionMap; /** * Setup */ protected function setUp() { - $this->transactionMapMock = $this->getMockBuilder(DocumentInterface::class) + $this->transactionMap = $this->getMockBuilder(DocumentInterface::class) ->disableOriginalConstructor() ->getMock(); - $this->entityFactoryMock = $this->getMockBuilder(EntityFactoryInterface::class) + $this->entityFactory = $this->getMockBuilder(EntityFactoryInterface::class) ->setMethods(['create']) ->disableOriginalConstructor() ->getMock(); - $this->filterMapperMock = $this->getMockBuilder(FilterMapper::class) + $this->filterMapper = $this->getMockBuilder(FilterMapper::class) ->setMethods(['getFilter']) ->disableOriginalConstructor() ->getMock(); - $this->braintreeAdapterMock = $this->getMockBuilder(BraintreeAdapter::class) + $this->braintreeAdapter = $this->getMockBuilder(BraintreeAdapter::class) ->setMethods(['search']) ->disableOriginalConstructor() ->getMock(); + $this->adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->adapterFactory->method('create') + ->willReturn($this->braintreeAdapter); } /** @@ -68,28 +80,26 @@ protected function setUp() */ public function testGetItems() { - $this->filterMapperMock->expects($this->once()) - ->method('getFilter') + $this->filterMapper->method('getFilter') ->willReturn(new BraintreeSearchNodeStub()); - $this->braintreeAdapterMock->expects($this->once()) - ->method('search') + $this->braintreeAdapter->method('search') ->willReturn(['transaction1', 'transaction2']); - $this->entityFactoryMock->expects($this->exactly(2)) + $this->entityFactory->expects(self::exactly(2)) ->method('create') - ->willReturn($this->transactionMapMock); + ->willReturn($this->transactionMap); $collection = new TransactionsCollection( - $this->entityFactoryMock, - $this->braintreeAdapterMock, - $this->filterMapperMock + $this->entityFactory, + $this->adapterFactory, + $this->filterMapper ); $collection->addFieldToFilter('orderId', ['like' => '0']); $items = $collection->getItems(); - $this->assertEquals(2, count($items)); - $this->assertInstanceOf(DocumentInterface::class, $items[1]); + self::assertEquals(2, count($items)); + self::assertInstanceOf(DocumentInterface::class, $items[1]); } /** @@ -97,27 +107,25 @@ public function testGetItems() */ public function testGetItemsEmptyCollection() { - $this->filterMapperMock->expects($this->once()) - ->method('getFilter') + $this->filterMapper->method('getFilter') ->willReturn(new BraintreeSearchNodeStub()); - $this->braintreeAdapterMock->expects($this->once()) - ->method('search') + $this->braintreeAdapter->method('search') ->willReturn(null); - $this->entityFactoryMock->expects($this->never()) + $this->entityFactory->expects(self::never()) ->method('create') - ->willReturn($this->transactionMapMock); + ->willReturn($this->transactionMap); $collection = new TransactionsCollection( - $this->entityFactoryMock, - $this->braintreeAdapterMock, - $this->filterMapperMock + $this->entityFactory, + $this->adapterFactory, + $this->filterMapper ); $collection->addFieldToFilter('orderId', ['like' => '0']); $items = $collection->getItems(); - $this->assertEquals(0, count($items)); + self::assertEquals(0, count($items)); } /** @@ -127,29 +135,27 @@ public function testGetItemsWithLimit() { $transations = range(1, TransactionsCollection::TRANSACTION_MAXIMUM_COUNT + 10); - $this->filterMapperMock->expects($this->once()) - ->method('getFilter') + $this->filterMapper->method('getFilter') ->willReturn(new BraintreeSearchNodeStub()); - $this->braintreeAdapterMock->expects($this->once()) - ->method('search') + $this->braintreeAdapter->method('search') ->willReturn($transations); - $this->entityFactoryMock->expects($this->exactly(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT)) + $this->entityFactory->expects(self::exactly(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT)) ->method('create') - ->willReturn($this->transactionMapMock); + ->willReturn($this->transactionMap); $collection = new TransactionsCollection( - $this->entityFactoryMock, - $this->braintreeAdapterMock, - $this->filterMapperMock + $this->entityFactory, + $this->adapterFactory, + $this->filterMapper ); $collection->setPageSize(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT); $collection->addFieldToFilter('orderId', ['like' => '0']); $items = $collection->getItems(); - $this->assertEquals(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT, count($items)); - $this->assertInstanceOf(DocumentInterface::class, $items[1]); + self::assertEquals(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT, count($items)); + self::assertInstanceOf(DocumentInterface::class, $items[1]); } /** @@ -159,29 +165,27 @@ public function testGetItemsWithNullLimit() { $transations = range(1, TransactionsCollection::TRANSACTION_MAXIMUM_COUNT + 10); - $this->filterMapperMock->expects($this->once()) - ->method('getFilter') + $this->filterMapper->method('getFilter') ->willReturn(new BraintreeSearchNodeStub()); - $this->braintreeAdapterMock->expects($this->once()) - ->method('search') + $this->braintreeAdapter->method('search') ->willReturn($transations); - $this->entityFactoryMock->expects($this->exactly(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT)) + $this->entityFactory->expects(self::exactly(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT)) ->method('create') - ->willReturn($this->transactionMapMock); + ->willReturn($this->transactionMap); $collection = new TransactionsCollection( - $this->entityFactoryMock, - $this->braintreeAdapterMock, - $this->filterMapperMock + $this->entityFactory, + $this->adapterFactory, + $this->filterMapper ); $collection->setPageSize(null); $collection->addFieldToFilter('orderId', ['like' => '0']); $items = $collection->getItems(); - $this->assertEquals(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT, count($items)); - $this->assertInstanceOf(DocumentInterface::class, $items[1]); + self::assertEquals(TransactionsCollection::TRANSACTION_MAXIMUM_COUNT, count($items)); + self::assertInstanceOf(DocumentInterface::class, $items[1]); } /** @@ -191,18 +195,18 @@ public function testGetItemsWithNullLimit() */ public function testAddToFilter($field, $condition, $filterMapperCall, $expectedCondition) { - $this->filterMapperMock->expects(static::exactly($filterMapperCall)) + $this->filterMapper->expects(self::exactly($filterMapperCall)) ->method('getFilter') ->with($field, $expectedCondition) ->willReturn(new BraintreeSearchNodeStub()); $collection = new TransactionsCollection( - $this->entityFactoryMock, - $this->braintreeAdapterMock, - $this->filterMapperMock + $this->entityFactory, + $this->adapterFactory, + $this->filterMapper ); - static::assertInstanceOf( + self::assertInstanceOf( TransactionsCollection::class, $collection->addFieldToFilter($field, $condition) ); diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php index 6c85ae68eb7af..dca22c26c11da 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Ui/ConfigProviderTest.php @@ -7,7 +7,9 @@ use Magento\Braintree\Gateway\Config\Config; use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; use Magento\Braintree\Model\Ui\ConfigProvider; +use Magento\Customer\Model\Session; use PHPUnit_Framework_MockObject_MockObject as MockObject; /** @@ -31,6 +33,11 @@ class ConfigProviderTest extends \PHPUnit\Framework\TestCase */ private $braintreeAdapter; + /** + * @var Session|MockObject + */ + private $session; + /** * @var ConfigProvider */ @@ -45,10 +52,24 @@ protected function setUp() $this->braintreeAdapter = $this->getMockBuilder(BraintreeAdapter::class) ->disableOriginalConstructor() ->getMock(); + /** @var BraintreeAdapterFactory|MockObject $adapterFactory */ + $adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $adapterFactory->method('create') + ->willReturn($this->braintreeAdapter); + + $this->session = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods(['getStoreId']) + ->getMock(); + $this->session->method('getStoreId') + ->willReturn(null); $this->configProvider = new ConfigProvider( $this->config, - $this->braintreeAdapter + $adapterFactory, + $this->session ); } @@ -61,35 +82,30 @@ protected function setUp() */ public function testGetConfig($config, $expected) { - $this->braintreeAdapter->expects(static::once()) - ->method('generate') + $this->braintreeAdapter->method('generate') ->willReturn(self::CLIENT_TOKEN); foreach ($config as $method => $value) { - $this->config->expects(static::once()) - ->method($method) + $this->config->method($method) ->willReturn($value); } - static::assertEquals($expected, $this->configProvider->getConfig()); + self::assertEquals($expected, $this->configProvider->getConfig()); } /** - * @covers \Magento\Braintree\Model\Ui\ConfigProvider::getClientToken * @dataProvider getClientTokenDataProvider */ public function testGetClientToken($merchantAccountId, $params) { - $this->config->expects(static::once()) - ->method('getMerchantAccountId') + $this->config->method('getMerchantAccountId') ->willReturn($merchantAccountId); - $this->braintreeAdapter->expects(static::once()) - ->method('generate') + $this->braintreeAdapter->method('generate') ->with($params) ->willReturn(self::CLIENT_TOKEN); - static::assertEquals(self::CLIENT_TOKEN, $this->configProvider->getClientToken()); + self::assertEquals(self::CLIENT_TOKEN, $this->configProvider->getClientToken()); } /** diff --git a/app/code/Magento/Braintree/etc/adminhtml/di.xml b/app/code/Magento/Braintree/etc/adminhtml/di.xml index d0469ded83b67..90fc927ed4f80 100644 --- a/app/code/Magento/Braintree/etc/adminhtml/di.xml +++ b/app/code/Magento/Braintree/etc/adminhtml/di.xml @@ -28,6 +28,7 @@ Magento\Braintree\Gateway\Request\AddressDataBuilder Magento\Braintree\Gateway\Request\VaultDataBuilder Magento\Braintree\Gateway\Request\DescriptorDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -39,6 +40,7 @@ Magento\Braintree\Gateway\Request\ChannelDataBuilder Magento\Braintree\Gateway\Request\AddressDataBuilder Magento\Braintree\Gateway\Request\DescriptorDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -57,4 +59,9 @@ Magento\Backend\Model\Session\Quote + + + Magento\Backend\Model\Session\Quote + + diff --git a/app/code/Magento/Braintree/etc/di.xml b/app/code/Magento/Braintree/etc/di.xml index 2a451e132eab0..86c2911815754 100644 --- a/app/code/Magento/Braintree/etc/di.xml +++ b/app/code/Magento/Braintree/etc/di.xml @@ -214,6 +214,7 @@ Magento\Braintree\Gateway\Request\ThreeDSecureDataBuilder Magento\Braintree\Gateway\Request\KountPaymentDataBuilder Magento\Braintree\Gateway\Request\DescriptorDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -245,6 +246,7 @@ Magento\Braintree\Gateway\Request\CaptureDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -268,6 +270,7 @@ Magento\Braintree\Gateway\Request\ThreeDSecureDataBuilder Magento\Braintree\Gateway\Request\KountPaymentDataBuilder Magento\Braintree\Gateway\Request\DescriptorDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -300,6 +303,7 @@ Magento\Braintree\Gateway\Request\VaultCaptureDataBuilder Magento\Braintree\Gateway\Request\SettlementDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -321,6 +325,7 @@ Magento\Braintree\Gateway\Request\PayPal\VaultDataBuilder Magento\Braintree\Gateway\Request\PayPal\DeviceDataBuilder Magento\Braintree\Gateway\Request\DescriptorDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -353,6 +358,7 @@ Magento\Braintree\Gateway\Request\ChannelDataBuilder Magento\Braintree\Gateway\Request\AddressDataBuilder Magento\Braintree\Gateway\Request\DescriptorDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder @@ -463,23 +469,41 @@ Magento\Braintree\Gateway\Http\Client\TransactionVoid - Magento\Braintree\Gateway\Request\VoidDataBuilder + BraintreeVoidRequestBuilder Magento\Braintree\Gateway\Response\VoidHandler Magento\Braintree\Gateway\Validator\GeneralResponseValidator Magento\Braintree\Gateway\Http\TransferFactory + + + + Magento\Braintree\Gateway\Request\VoidDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder + + + + Magento\Braintree\Gateway\Http\Client\TransactionRefund - Magento\Braintree\Gateway\Request\RefundDataBuilder + BraintreeRefundBuilder Magento\Braintree\Gateway\Validator\GeneralResponseValidator Magento\Braintree\Gateway\Response\RefundHandler Magento\Braintree\Gateway\Http\TransferFactory + + + + Magento\Braintree\Gateway\Request\RefundDataBuilder + Magento\Braintree\Gateway\Request\StoreConfigBuilder + + + + @@ -494,7 +518,7 @@ - + diff --git a/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js b/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js index 8324cfe463bdb..5e1e85e6a3c48 100644 --- a/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js +++ b/app/code/Magento/Braintree/view/adminhtml/web/js/braintree.js @@ -116,7 +116,7 @@ define([ }, /** - * Setup Braintree SDK + * Retrieves client token and setup Braintree SDK */ initBraintree: function () { var self = this; @@ -124,35 +124,14 @@ define([ try { $('body').trigger('processStart'); - self.braintree.setup(self.clientToken, 'custom', { - id: self.selector, - hostedFields: self.getHostedFields(), - - /** - * Triggered when sdk was loaded - */ - onReady: function () { - $('body').trigger('processStop'); - }, + $.getJSON(self.clientTokenUrl).done(function (response) { + self.clientToken = response.clientToken; + self._initBraintree(); + }).fail(function (response) { + var failed = JSON.parse(response.responseText); - /** - * Callback for success response - * @param {Object} response - */ - onPaymentMethodReceived: function (response) { - if (self.validateCardType()) { - self.setPaymentDetails(response.nonce); - self.placeOrder(); - } - }, - - /** - * Error callback - * @param {Object} response - */ - onError: function (response) { - self.error(response.message); - } + $('body').trigger('processStop'); + self.error(failed.message); }); } catch (e) { $('body').trigger('processStop'); @@ -160,6 +139,44 @@ define([ } }, + /** + * Setup Braintree SDK + */ + _initBraintree: function () { + var self = this; + + self.braintree.setup(self.clientToken, 'custom', { + id: self.selector, + hostedFields: self.getHostedFields(), + + /** + * Triggered when sdk was loaded + */ + onReady: function () { + $('body').trigger('processStop'); + }, + + /** + * Callback for success response + * @param {Object} response + */ + onPaymentMethodReceived: function (response) { + if (self.validateCardType()) { + self.setPaymentDetails(response.nonce); + self.placeOrder(); + } + }, + + /** + * Error callback + * @param {Object} response + */ + onError: function (response) { + self.error(response.message); + } + }); + }, + /** * Get hosted fields configuration * @returns {Object} diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Payment/GetClientTokenTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Payment/GetClientTokenTest.php new file mode 100644 index 0000000000000..7546f20a42de9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Payment/GetClientTokenTest.php @@ -0,0 +1,151 @@ +quoteSession = $this->_objectManager->get(Quote::class); + + $this->stubObjectManager = $this->getMockBuilder(ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $adapterFactory = new BraintreeAdapterFactory( + $this->stubObjectManager, + $this->_objectManager->get(Config::class) + ); + + $this->_objectManager->addSharedInstance($adapterFactory, BraintreeAdapterFactory::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->_objectManager->removeSharedInstance(BraintreeAdapterFactory::class); + parent::tearDown(); + } + + /** + * Checks if client token will retrieved from Braintree initialized with default scope. + * + * @magentoDataFixture Magento/Braintree/_files/payment_configuration.php + * @magentoAppArea adminhtml + */ + public function testExecute() + { + $this->perform( + 'def_merchant_id', + 'def_public_key', + 'def_private_key' + ); + } + + /** + * Checks if client token will be retrieved from Braintree initialized per store. + * + * @magentoDataFixture Magento/Braintree/_files/payment_configuration.php + * @magentoAppArea adminhtml + */ + public function testExecuteWithStoreConfiguration() + { + /** @var StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->_objectManager->get(StoreRepositoryInterface::class); + $store = $storeRepository->get('test'); + $this->quoteSession->setStoreId($store->getId()); + + $this->perform( + 'store_merchant_id', + 'store_public_key', + 'def_private_key' // should be read from default scope + ); + } + + /** + * Checks if client token will be retrieved from Braintree initialized per website. + * + * @magentoDataFixture Magento/Braintree/_files/payment_configuration.php + * @magentoAppArea adminhtml + */ + public function testExecuteWithWebsiteConfiguration() + { + /** @var StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->_objectManager->get(StoreRepositoryInterface::class); + $store = $storeRepository->get('fixture_second_store'); + $this->quoteSession->setStoreId($store->getId()); + + $this->perform( + 'website_merchant_id', + 'def_public_key', // should be read from default scope + 'website_private_key' + ); + } + + private function perform($merchantId, $publicKey, $privateKey) + { + $args = [ + 'merchantId' => $merchantId, + 'publicKey' => $publicKey, + 'privateKey' => $privateKey, + 'environment' => 'sandbox' + ]; + + $adapter = $this->getMockBuilder(BraintreeAdapter::class) + ->setConstructorArgs($args) + ->setMethods(['generate']) + ->getMock(); + $adapter->method('generate') + ->willReturn('client_token'); + + $this->stubObjectManager->method('create') + ->with(BraintreeAdapter::class, $args) + ->willReturn($adapter); + + $this->dispatch('backend/braintree/payment/getClientToken'); + + /** @var SerializerInterface $serializer */ + $serializer = $this->_objectManager->get(SerializerInterface::class); + $decoded = $serializer->unserialize($this->getResponse()->getBody()); + $this->performAsserts($decoded['clientToken'], $merchantId, $publicKey, $privateKey); + } + + private function performAsserts($clientToken, $merchantId, $publicKey, $privateKey) + { + self::assertEquals('client_token', $clientToken); + self::assertEquals(Configuration::merchantId(), $merchantId); + self::assertEquals(Configuration::publicKey(), $publicKey); + self::assertEquals(Configuration::privateKey(), $privateKey); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration.php b/dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration.php new file mode 100644 index 0000000000000..da87ad5311d92 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration.php @@ -0,0 +1,58 @@ +get(EncryptorInterface::class); + +$processConfigData = function (Config $config, array $data) { + foreach ($data as $key => $value) { + $config->setDataByPath($key, $value); + $config->save(); + } +}; + +// save payment configuration for the default scope +$configData = [ + 'payment/braintree/merchant_id' => 'def_merchant_id', + 'payment/braintree/public_key' => $encryptor->encrypt('def_public_key'), + 'payment/braintree/private_key' => $encryptor->encrypt('def_private_key'), +]; +/** @var Config $defConfig */ +$defConfig = $objectManager->create(Config::class); +$defConfig->setScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT); +$processConfigData($defConfig, $configData); + +// save payment configuration per store +require __DIR__ . '/../../Store/_files/store.php'; +$storeConfigData = [ + 'payment/braintree/merchant_id' => 'store_merchant_id', + 'payment/braintree/public_key' => $encryptor->encrypt('store_public_key'), +]; +/** @var Config $storeConfig */ +$storeConfig = $objectManager->create(Config::class); +$storeConfig->setScope(ScopeInterface::SCOPE_STORES); +$storeConfig->setStore('test'); +$processConfigData($storeConfig, $storeConfigData); + +// save payment website config data +require __DIR__ . '/../../Store/_files/second_website_with_two_stores.php'; +$websiteConfigData = [ + 'payment/braintree/merchant_id' => 'website_merchant_id', + 'payment/braintree/private_key' => $encryptor->encrypt('website_private_key'), +]; +/** @var Config $websiteConfig */ +$websiteConfig = $objectManager->create(Config::class); +$websiteConfig->setScope(ScopeInterface::SCOPE_WEBSITES); +$websiteConfig->setWebsite($websiteId); +$processConfigData($websiteConfig, $websiteConfigData); diff --git a/dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration_rollback.php b/dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration_rollback.php new file mode 100644 index 0000000000000..0c0391769b093 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/_files/payment_configuration_rollback.php @@ -0,0 +1,42 @@ +delete($path, $scope, $scopeId); + } +}; + +/** @var WriterInterface $configWriter */ +$configWriter = $objectManager->get(WriterInterface::class); +$deleteConfigData($configWriter, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + +/** @var StoreRepositoryInterface $storeRepository */ +$storeRepository = $objectManager->get(StoreRepositoryInterface::class); +$store = $storeRepository->get('test'); +$deleteConfigData($configWriter, ScopeInterface::SCOPE_STORES, $store->getId()); + +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$website = $websiteRepository->get('test'); +$deleteConfigData($configWriter, ScopeInterface::SCOPE_WEBSITES, $website->getId()); + +require __DIR__ . '/../../Store/_files/second_website_with_two_stores_rollback.php'; +require __DIR__ . '/../../Store/_files/store_rollback.php'; From 124f3932b6cd7fd3a4b6cefd9c5876a541c8b6f5 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Tue, 3 Oct 2017 16:00:55 +0300 Subject: [PATCH 013/528] MAGETWO-80191: [2.2.x] - Fixes #10255: base_shipping_discount_tax_compensation_amnt was empty from order onwards #10435 --- app/code/Magento/Sales/etc/fieldset.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/etc/fieldset.xml b/app/code/Magento/Sales/etc/fieldset.xml index 3d29575063fef..2132e05dd8a9d 100644 --- a/app/code/Magento/Sales/etc/fieldset.xml +++ b/app/code/Magento/Sales/etc/fieldset.xml @@ -279,7 +279,7 @@ - + From 0e24d0bcfc86027dd6efce08b3792ea468e4f5f3 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Tue, 3 Oct 2017 16:53:19 +0300 Subject: [PATCH 014/528] MAGETWO-80191: [2.2.x] - Fixes #10255: base_shipping_discount_tax_compensation_amnt was empty from order onwards #10435 --- .../Model/Quote/Address/ConverterTest.php | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php new file mode 100644 index 0000000000000..cfb1967bf09d5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Address/ConverterTest.php @@ -0,0 +1,46 @@ +objectManager = Bootstrap::getObjectManager(); + $this->objectCopyService = $this->objectManager->create(\Magento\Framework\DataObject\Copy::class); + } + + public function testThatFieldBaseShippingDiscountTaxCompensationAmountPresentInOrderAddress() + { + $amountValue = 999.99; + /** @var \Magento\Quote\Model\Quote\Address $quoteAddress */ + $quoteAddress = $this->objectManager->create(\Magento\Quote\Model\Quote\Address::class); + $quoteAddress->setBaseShippingDiscountTaxCompensationAmount($amountValue); + + $orderAddressData = $this->objectCopyService->getDataFromFieldset( + 'sales_convert_quote_address', + 'to_order', + $quoteAddress + ); + + $this->assertArrayHasKey('base_shipping_discount_tax_compensation_amnt', $orderAddressData); + $this->assertEquals($amountValue, $orderAddressData['base_shipping_discount_tax_compensation_amnt']); + } +} From ae46c87691cc2a239378f452896fea582c96d701 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 3 Oct 2017 15:37:06 -0500 Subject: [PATCH 015/528] MAGETWO-80479: Update existing Advanced Reporting tests - Remove obsolete tests --- .../Analytics/Test/TestCase/InstallTest.xml | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml deleted file mode 100644 index 8e19e1116da19..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - severity:S1 - Apps and Games - - - - - - severity:S1 - - - - - severity:S1 - - - - - From 73cd1ea0824b39d381448b4d6ea9dfb7f81e58a0 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 3 Oct 2017 16:22:11 -0500 Subject: [PATCH 016/528] MAGETWO-80479: Update existing Advanced Reporting tests - Remove obsolete tests --- ...lyticsSubscriptionCheckPermissionsTest.php | 37 ------------------- ...lyticsSubscriptionCheckPermissionsTest.xml | 15 -------- 2 files changed, 52 deletions(-) delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php deleted file mode 100644 index 2fe656081d162..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.php +++ /dev/null @@ -1,37 +0,0 @@ -executeScenario(); - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml deleted file mode 100644 index f3ed3736e2ea2..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/AnalyticsSubscriptionCheckPermissionsTest.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - custom_admin_with_role_without_subscription_permissions - - - - From d98858e59b0fab496d7bc5b359f09f0792a4ade7 Mon Sep 17 00:00:00 2001 From: Tomasz Gregorczyk Date: Wed, 4 Oct 2017 01:16:29 +0200 Subject: [PATCH 017/528] Fixes #11163 missing data key code-entity in CMS page edit form --- .../view/adminhtml/ui_component/cms_page_form.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/GoogleOptimizer/view/adminhtml/ui_component/cms_page_form.xml b/app/code/Magento/GoogleOptimizer/view/adminhtml/ui_component/cms_page_form.xml index 735de2bd7b177..cc9249b2d3d38 100644 --- a/app/code/Magento/GoogleOptimizer/view/adminhtml/ui_component/cms_page_form.xml +++ b/app/code/Magento/GoogleOptimizer/view/adminhtml/ui_component/cms_page_form.xml @@ -13,7 +13,12 @@ - + + + Magento\GoogleOptimizer\Block\Adminhtml\Cms\Page\EntityCmsPage + cms_page_form + + From aa71aee076f9a8f9667703afa59f76d5f996a3a5 Mon Sep 17 00:00:00 2001 From: aakimov Date: Wed, 4 Oct 2017 14:23:59 +0300 Subject: [PATCH 018/528] MAGETWO-80205: [2.2.x] - Test cron expressions against localized time --- app/code/Magento/Cron/Model/Schedule.php | 15 ++++++++- .../Cron/Test/Unit/Model/ScheduleTest.php | 33 ++++++++++++++++++- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Cron/Model/Schedule.php b/app/code/Magento/Cron/Model/Schedule.php index 5670a6867e0fb..39a58ef360cb3 100644 --- a/app/code/Magento/Cron/Model/Schedule.php +++ b/app/code/Magento/Cron/Model/Schedule.php @@ -7,6 +7,8 @@ namespace Magento\Cron\Model; use Magento\Framework\Exception\CronException; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; /** * Crontab schedule model @@ -43,21 +45,29 @@ class Schedule extends \Magento\Framework\Model\AbstractModel const STATUS_ERROR = 'error'; + /** + * @var TimezoneInterface + */ + private $timezoneConverter; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data + * @param TimezoneInterface $timezoneConverter */ public function __construct( \Magento\Framework\Model\Context $context, \Magento\Framework\Registry $registry, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + TimezoneInterface $timezoneConverter = null ) { parent::__construct($context, $registry, $resource, $resourceCollection, $data); + $this->timezoneConverter = $timezoneConverter ?: ObjectManager::getInstance()->get(TimezoneInterface::class); } /** @@ -100,6 +110,9 @@ public function trySchedule() return false; } if (!is_numeric($time)) { + //convert time from UTC to admin store timezone + //we assume that all schedules in configuration (crontab.xml and DB tables) are in admin store timezone + $time = $this->timezoneConverter->date($time)->format('Y-m-d H:i'); $time = strtotime($time); } $match = $this->matchCronExpression($e[0], strftime('%M', $time)) diff --git a/app/code/Magento/Cron/Test/Unit/Model/ScheduleTest.php b/app/code/Magento/Cron/Test/Unit/Model/ScheduleTest.php index 04b47445cc7ba..e9f4c61c7f551 100644 --- a/app/code/Magento/Cron/Test/Unit/Model/ScheduleTest.php +++ b/app/code/Magento/Cron/Test/Unit/Model/ScheduleTest.php @@ -13,6 +13,9 @@ */ class ScheduleTest extends \PHPUnit\Framework\TestCase { + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ protected $helper; protected $resourceJobMock; @@ -174,6 +177,35 @@ public function testTrySchedule($scheduledAt, $cronExprArr, $expected) $this->assertEquals($expected, $result); } + public function testTryScheduleWithConversionToAdminStoreTime() + { + $scheduledAt = '2011-12-13 14:15:16'; + $cronExprArr = ['*', '*', '*', '*', '*']; + + // 1. Create mocks + $timezoneConverter = $this->createMock(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class); + $timezoneConverter->expects($this->once()) + ->method('date') + ->with($scheduledAt) + ->willReturn(new \DateTime($scheduledAt)); + + /** @var \Magento\Cron\Model\Schedule $model */ + $model = $this->helper->getObject( + \Magento\Cron\Model\Schedule::class, + ['timezoneConverter' => $timezoneConverter] + ); + + // 2. Set fixtures + $model->setScheduledAt($scheduledAt); + $model->setCronExprArr($cronExprArr); + + // 3. Run tested method + $result = $model->trySchedule(); + + // 4. Compare actual result with expected result + $this->assertTrue($result); + } + /** * @return array */ @@ -187,7 +219,6 @@ public function tryScheduleDataProvider() [$date, [], false], [$date, null, false], [$date, false, false], - [$date, ['*', '*', '*', '*', '*'], true], [strtotime($date), ['*', '*', '*', '*', '*'], true], [strtotime($date), ['15', '*', '*', '*', '*'], true], [strtotime($date), ['*', '14', '*', '*', '*'], true], From c1c5796bcf467584833ac49fc40f74187b89973b Mon Sep 17 00:00:00 2001 From: mszydlo Date: Wed, 4 Oct 2017 14:53:31 +0200 Subject: [PATCH 019/528] Fix typo in sessionStorage polyfill --- .../Magento/Theme/view/frontend/templates/js/polyfill.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml b/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml index 7e8854b914261..2b75bd2222e26 100644 --- a/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml @@ -126,7 +126,7 @@ }; window.localStorage.__proto__ = window.localStorage = new Storage('local'); - window.sessionStorage.__proto__ = window.sessionStorag = new Storage('session'); + window.sessionStorage.__proto__ = window.sessionStorage = new Storage('session'); })(); } From f103832dbdc3582f60725b3e7cbcc2e138d860dd Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Wed, 4 Oct 2017 16:14:40 +0300 Subject: [PATCH 020/528] MAGETWO-80207: [2.2.x] - Modified Bundle.js because of breaking Encoding in Production Mode. #10563 --- app/code/Magento/Deploy/Package/Bundle/RequireJs.php | 9 ++++++--- lib/internal/Magento/Framework/View/Asset/Bundle.php | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Deploy/Package/Bundle/RequireJs.php b/app/code/Magento/Deploy/Package/Bundle/RequireJs.php index 73a15554f8b78..c7c9e5315c7ab 100644 --- a/app/code/Magento/Deploy/Package/Bundle/RequireJs.php +++ b/app/code/Magento/Deploy/Package/Bundle/RequireJs.php @@ -240,9 +240,12 @@ private function endBundleFile(WriteInterface $bundleFile, array $contents) private function getFileContent($sourcePath) { if (!isset($this->fileContent[$sourcePath])) { - $this->fileContent[$sourcePath] = utf8_encode( - $this->staticDir->readFile($this->minification->addMinifiedSign($sourcePath)) - ); + $content = $this->staticDir->readFile($this->minification->addMinifiedSign($sourcePath)); + if (mb_detect_encoding($content) !== "UTF-8") { + $content = mb_convert_encoding($content, "UTF-8"); + } + + $this->fileContent[$sourcePath] = $content; } return $this->fileContent[$sourcePath]; } diff --git a/lib/internal/Magento/Framework/View/Asset/Bundle.php b/lib/internal/Magento/Framework/View/Asset/Bundle.php index bdaf13ddbbb27..80f35f9d57075 100644 --- a/lib/internal/Magento/Framework/View/Asset/Bundle.php +++ b/lib/internal/Magento/Framework/View/Asset/Bundle.php @@ -212,7 +212,11 @@ protected function getAssetContent(LocalInterface $asset) $assetContentType = $asset->getContentType(); $assetKey = $this->getAssetKey($asset); if (!isset($this->assetsContent[$assetContextCode][$assetContentType][$assetKey])) { - $this->assetsContent[$assetContextCode][$assetContentType][$assetKey] = utf8_encode($asset->getContent()); + $content = $asset->getContent(); + if (mb_detect_encoding($content) !== "UTF-8") { + $content = mb_convert_encoding($content, "UTF-8"); + } + $this->assetsContent[$assetContextCode][$assetContentType][$assetKey] = $content; } return $this->assetsContent[$assetContextCode][$assetContentType][$assetKey]; From 25202a0e504108397616405987daf473e7779eaf Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 13:38:02 -0500 Subject: [PATCH 021/528] MAGETWO-80474: Update Advanced Reporting Configuration Page --- .../Adminhtml/System/Config/Vertical.php | 43 +++++++++++ .../Adminhtml/System/Config/VerticalTest.php | 76 +++++++++++++++++++ .../Analytics/etc/adminhtml/system.xml | 24 +++--- .../web/css/source/_module.less | 24 ++++++ 4 files changed, 156 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php new file mode 100644 index 0000000000000..be3d8eabc899b --- /dev/null +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -0,0 +1,43 @@ +' . $element->getHint() . ''; + $html .= '
' . $element->getComment() . '
'; + return $this->decorateRowHtml($element, $html); + } + + /** + * @param \Magento\Framework\Data\Form\Element\AbstractElement $element + * @param string $html + * @return string + * @since 2.2.2 + */ + private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) + { + $rowHtml = sprintf('%s', $html); + $rowHtml .= sprintf( + '%s%s', + $element->getHtmlId(), + $element->getLabelHtml($element->getHtmlId(), "[WEBSITE]"), + $element->getElementHtml() + ); + return $rowHtml; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php new file mode 100644 index 0000000000000..331b487e5dd9d --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php @@ -0,0 +1,76 @@ +abstractElementMock = $this->getMockBuilder(AbstractElement::class) + ->setMethods(['getComment', 'getLabel', 'getHint']) + ->disableOriginalConstructor() + ->getMock(); + $this->contextMock = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->formMock = $this->getMockBuilder(Form::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->vertical = new Vertical($this->contextMock); + } + + /** + * @return void + */ + public function testRender() + { + $this->abstractElementMock->setForm($this->formMock); + $this->abstractElementMock->expects($this->any()) + ->method('getComment') + ->willReturn('New comment'); + $this->abstractElementMock->expects($this->any()) + ->method('getHint') + ->willReturn('New hint'); + $html = $this->vertical->render($this->abstractElementMock); + $this->assertRegexp( + "/New comment/", + $html + ); + $this->assertRegExp( + "/New hint/", + $html + ); + } +} diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml index 32d493451ca61..3d87c24176c81 100644 --- a/app/code/Magento/Analytics/etc/adminhtml/system.xml +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -13,10 +13,9 @@ Magento_Analytics::analytics_settings - For more information, view details or see our - terms and conditions.]]> + For more information, see our terms and conditions.]]> Magento\Config\Model\Config\Source\Enabledisable @@ -24,21 +23,24 @@ Magento\Analytics\Block\Adminhtml\System\Config\SubscriptionStatusLabel analytics/subscription/enabled - - - Magento\Analytics\Model\Config\Source\Vertical - Magento\Analytics\Model\Config\Backend\Vertical - - + Magento\Analytics\Block\Adminhtml\System\Config\CollectionTimeLabel Magento\Analytics\Model\Config\Backend\CollectionTime + + Industry Data + + In order to personalize your Advanced Reporting experience, please select your industry. + Magento\Analytics\Model\Config\Source\Vertical + Magento\Analytics\Model\Config\Backend\Vertical + Magento\Analytics\Block\Adminhtml\System\Config\Vertical + Learn more about BI Essentials tier.]]> + href="https://dashboard.rjmetrics.com/v2/magento/signup/">Magento BI Essentials and BI Pro tiers.]]> Magento\Analytics\Block\Adminhtml\System\Config\AdditionalComment diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less index db29bfcaf6355..85454effcbd67 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less @@ -190,3 +190,27 @@ .config-additional-comment-content { line-height: @line-height__l; } + +.config-vertical-title { + clear: both; + color: #303030; + font-size: 1.7rem; + font-weight: 600; + letter-spacing: .025em; + padding: 1.9rem 2.8rem 1.9rem 0; + position: relative; +} + +.config-vertical-comment { + line-height: 1.5; + margin-bottom: .5em; + margin-top: 1rem; +} + +#row_analytics_general_vertical { + >td.config-vertical-label { + >label.admin__field-label { + padding-right: 0; + } + } +} From 79bc973e7a82637aff1cd4a94c4504f9e391c86f Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 15:17:25 -0500 Subject: [PATCH 022/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Adminhtml/Subscription/Activate.php | 142 ---------- .../Adminhtml/Subscription/Postpone.php | 103 ------- .../Model/Condition/CanViewNotification.php | 47 +--- .../Backend/Enabled/SubscriptionHandler.php | 13 - .../Analytics/Model/NotificationTime.php | 51 ++-- .../Adminhtml/Subscription/ActivateTest.php | 252 ------------------ .../Adminhtml/Subscription/PostponeTest.php | 168 ------------ .../Condition/CanViewNotificationTest.php | 41 +-- .../Enabled/SubscriptionHandlerTest.php | 17 -- .../Test/Unit/Model/NotificationTimeTest.php | 76 +++++- .../layout/adminhtml_dashboard_index.xml | 2 +- .../analytics_subscription_form.xml | 247 ----------------- .../analytics_subscription_notification.xml | 98 +++++++ .../adminhtml/web/js/modal/modal-component.js | 66 ----- .../web/template/buttons-container.html | 13 - .../form/components/single/checkbox.html | 17 -- .../web/css/source/_module.less | 189 +++++-------- .../web/images/advanced-reporting-badge.svg | 7 + .../AdvancedReporting/SubscriptionBlock.php | 71 +---- 19 files changed, 302 insertions(+), 1318 deletions(-) delete mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php delete mode 100644 app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php delete mode 100644 app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_form.xml create mode 100644 app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml delete mode 100644 app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js delete mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html delete mode 100644 app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html create mode 100644 app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php deleted file mode 100644 index 59923e82ef46c..0000000000000 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Activate.php +++ /dev/null @@ -1,142 +0,0 @@ -logger = $logger; - $this->notificationTime = $notificationTime; - $this->configValueResource = $configValueResource; - $this->preparedValueFactory = $preparedValueFactory; - parent::__construct($context); - } - - /** - * Check admin permissions for this controller - * - * @return boolean - * @since 2.2.0 - */ - protected function _isAllowed() - { - return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); - } - - /** - * Activate subscription to Magento BI via AJAX. - * - * @return Json - * @since 2.2.0 - */ - public function execute() - { - try { - if ($this->getRequest()->getParam($this->subscriptionApprovedField)) { - $configValue = $this->preparedValueFactory->create( - Enabled::XML_ENABLED_CONFIG_STRUCTURE_PATH, - Enabledisable::ENABLE_VALUE, - ScopeConfigInterface::SCOPE_TYPE_DEFAULT - ); - - $this->configValueResource - ->save($configValue); - } else { - $this->notificationTime->unsetLastTimeNotificationValue(); - } - $responseContent = [ - 'success' => true, - 'error_message' => '', - ]; - } catch (LocalizedException $e) { - $responseContent = [ - 'success' => false, - 'error_message' => $e->getMessage(), - ]; - $this->logger->error($e->getMessage()); - } catch (\Exception $e) { - $responseContent = [ - 'success' => false, - 'error_message' => __( - 'Sorry, there was an error processing your registration request to Magento Analytics. ' - . 'Please try again later.' - ), - ]; - $this->logger->error($e->getMessage()); - } - /** @var Json $resultJson */ - $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); - return $resultJson->setData($responseContent); - } -} diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php deleted file mode 100644 index 068416157ae6a..0000000000000 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Postpone.php +++ /dev/null @@ -1,103 +0,0 @@ -dateTimeFactory = $dateTimeFactory; - $this->notificationTime = $notificationTime; - $this->logger = $logger; - parent::__construct($context); - } - - /** - * Check admin permissions for this controller - * - * @return boolean - * @since 2.2.0 - */ - protected function _isAllowed() - { - return $this->_authorization->isAllowed('Magento_Analytics::analytics_settings'); - } - - /** - * Postpones notification about subscription - * - * @return Json - * @since 2.2.0 - */ - public function execute() - { - try { - $dateTime = $this->dateTimeFactory->create(); - $responseContent = [ - 'success' => $this->notificationTime->storeLastTimeNotification($dateTime->getTimestamp()), - 'error_message' => '' - ]; - } catch (LocalizedException $e) { - $this->logger->error($e->getMessage()); - $responseContent = [ - 'success' => false, - 'error_message' => $e->getMessage() - ]; - } catch (\Exception $e) { - $this->logger->error($e->getMessage()); - $responseContent = [ - 'success' => false, - 'error_message' => __('Error occurred during postponement notification') - ]; - } - /** @var Json $resultJson */ - $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON); - return $resultJson->setData($responseContent); - } -} diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 9200361322dc2..157a033959c42 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -7,14 +7,13 @@ use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; use Magento\Analytics\Model\NotificationTime; -use Magento\Framework\Intl\DateTimeFactory; /** * Class CanViewNotification * - * Dynamic validator for UI signUp notification form, manage Ui component visibility. - * Return true if last notification was shipped seven days ago. - * @since 2.2.0 + * Dynamic validator for UI analytics notification, manage UI component visibility. + * Return true if the logged in user has not seen the notification. + * @since 2.2.2 */ class CanViewNotification implements VisibilityConditionInterface { @@ -23,62 +22,44 @@ class CanViewNotification implements VisibilityConditionInterface */ const NAME = 'can_view_notification'; - /** - * Time interval in seconds - * - * @var int - * @since 2.2.0 - */ - private $notificationInterval = 604800; - /** * @var NotificationTime - * @since 2.2.0 + * @since 2.2.2 */ private $notificationTime; - /** - * @var DateTimeFactory - * @since 2.2.0 - */ - private $dateTimeFactory; - /** * CanViewNotification constructor. * * @param NotificationTime $notificationTime - * @param DateTimeFactory $dateTimeFactory - * @since 2.2.0 + * @since 2.2.2 */ public function __construct( - NotificationTime $notificationTime, - DateTimeFactory $dateTimeFactory + NotificationTime $notificationTime ) { $this->notificationTime = $notificationTime; - $this->dateTimeFactory = $dateTimeFactory; } /** - * Validate is notification popup can be shown + * Validate if notification popup can be shown * * @inheritdoc - * @since 2.2.0 + * @since 2.2.2 */ public function isVisible(array $arguments) { - $lastNotificationTime = $this->notificationTime->getLastTimeNotification(); - if (!$lastNotificationTime) { + $lastNotificationTime = $this->notificationTime->getLastTimeNotificationForCurrentUser(); + + if ($lastNotificationTime) { return false; } - $datetime = $this->dateTimeFactory->create(); - return ( - $datetime->getTimestamp() >= $lastNotificationTime + $this->notificationInterval - ); + + return $this->notificationTime->storeLastTimeNotificationForCurrentUser(); } /** * @return string - * @since 2.2.0 + * @since 2.2.2 */ public function getName() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php index 03f3ddaeebbaa..04202cdcda11c 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -7,7 +7,6 @@ use Magento\Analytics\Model\AnalyticsToken; use Magento\Analytics\Model\Config\Backend\CollectionTime; -use Magento\Analytics\Model\NotificationTime; use Magento\Framework\App\Config\ReinitableConfigInterface; use Magento\Framework\App\Config\Storage\WriterInterface; use Magento\Framework\FlagManager; @@ -71,14 +70,6 @@ class SubscriptionHandler */ private $analyticsToken; - /** - * Resource for managing last notification time about subscription to Magento Analytics. - * - * @var NotificationTime - * @since 2.2.0 - */ - private $notificationTime; - /** * @var ReinitableConfigInterface * @since 2.2.0 @@ -89,7 +80,6 @@ class SubscriptionHandler * @param WriterInterface $configWriter * @param FlagManager $flagManager * @param AnalyticsToken $analyticsToken - * @param NotificationTime $notificationTime * @param ReinitableConfigInterface $reinitableConfig * @since 2.2.0 */ @@ -97,13 +87,11 @@ public function __construct( WriterInterface $configWriter, FlagManager $flagManager, AnalyticsToken $analyticsToken, - NotificationTime $notificationTime, ReinitableConfigInterface $reinitableConfig ) { $this->configWriter = $configWriter; $this->flagManager = $flagManager; $this->analyticsToken = $analyticsToken; - $this->notificationTime = $notificationTime; $this->reinitableConfig = $reinitableConfig; } @@ -120,7 +108,6 @@ public function processEnabled() if (!$this->analyticsToken->isTokenExist()) { $this->setCronSchedule(); $this->setAttemptsFlag(); - $this->notificationTime->unsetLastTimeNotificationValue(); $this->reinitableConfig->reinit(); } diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php index c36f830a70762..b831c4e20dc5f 100644 --- a/app/code/Magento/Analytics/Model/NotificationTime.php +++ b/app/code/Magento/Analytics/Model/NotificationTime.php @@ -6,67 +6,88 @@ namespace Magento\Analytics\Model; use Magento\Framework\FlagManager; +use Magento\Authorization\Model\UserContextInterface; +use Magento\Framework\Intl\DateTimeFactory; /** * Class NotificationTime * * Manage access to notification time flag * - * @since 2.2.0 + * @since 2.2.2 */ class NotificationTime { - const NOTIFICATION_TIME = 'notification_time'; + const NOTIFICATION_TIME = 'analytics_notification_time_admin_'; /** * @var FlagManager - * @since 2.2.0 + * @since 2.2.2 */ private $flagManager; + /** + * @var UserContextInterface + * @since 2.2.2 + */ + private $userContext; + + /** + * @var DateTimeFactory + * @since 2.2.2 + */ + private $dateTimeFactory; + /** * NotificationTime constructor. * * @param FlagManager $flagManager - * @since 2.2.0 + * @param UserContextInterface $userContext + * @param DateTimeFactory $dateTimeFactory + * @since 2.2.2 */ public function __construct( - FlagManager $flagManager + FlagManager $flagManager, + UserContextInterface $userContext, + DateTimeFactory $dateTimeFactory ) { $this->flagManager = $flagManager; + $this->userContext = $userContext; + $this->dateTimeFactory = $dateTimeFactory; } /** * Stores last notification time * - * @param string $value * @return bool - * @since 2.2.0 + * @since 2.2.2 */ - public function storeLastTimeNotification($value) + public function storeLastTimeNotificationForCurrentUser() { - return $this->flagManager->saveFlag(self::NOTIFICATION_TIME, $value); + $flagCode = self::NOTIFICATION_TIME . $this->userContext->getUserId(); + $dateTime = $this->dateTimeFactory->create(); + return $this->flagManager->saveFlag($flagCode, $dateTime->getTimestamp()); } /** * Returns last time when merchant was notified about Analytic services * * @return int - * @since 2.2.0 + * @since 2.2.2 */ - public function getLastTimeNotification() + public function getLastTimeNotificationForCurrentUser() { - return $this->flagManager->getFlagData(self::NOTIFICATION_TIME); + return $this->flagManager->getFlagData(self::NOTIFICATION_TIME . $this->userContext->getUserId()); } /** * Remove last notification time flag. * * @return bool - * @since 2.2.0 + * @since 2.2.2 */ - public function unsetLastTimeNotificationValue() + public function unsetLastTimeNotificationValueForCurrentUser() { - return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME); + return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME . $this->userContext->getUserId()); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php deleted file mode 100644 index 66c7ae4fac448..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/ActivateTest.php +++ /dev/null @@ -1,252 +0,0 @@ -resultFactoryMock = $this->getMockBuilder(ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->resultJsonMock = $this->getMockBuilder(Json::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->preparedValueFactoryMock = $this->getMockBuilder(PreparedValueFactory::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->configValueResourceMock = $this->getMockBuilder(AbstractDb::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->requestMock = $this->getMockBuilder(RequestInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - - $this->activateController = $this->objectManagerHelper->getObject( - Activate::class, - [ - 'resultFactory' => $this->resultFactoryMock, - 'preparedValueFactory' => $this->preparedValueFactoryMock, - 'configValueResource' => $this->configValueResourceMock, - 'logger' => $this->loggerMock, - 'notificationTime' => $this->notificationTimeMock, - '_request' => $this->requestMock, - 'subscriptionApprovedFiled' => $this->subscriptionApprovedField, - ] - ); - } - - /** - * @dataProvider executeDataProvider - * - * @param bool $isSubscriptionEnabled - * @return void - */ - public function testExecute($isSubscriptionEnabled) - { - $successResult = [ - 'success' => true, - 'error_message' => '', - ]; - - $this->requestMock - ->expects($this->once()) - ->method('getParam') - ->with($this->subscriptionApprovedField) - ->willReturn($isSubscriptionEnabled); - - if ($isSubscriptionEnabled) { - $configValue = $this->createConfigValueMock(); - $this->preparedValueFactoryMock - ->expects($this->once()) - ->method('create') - ->willReturn($configValue); - $this->configValueResourceMock->expects($this->once())->method('save')->with($configValue); - } else { - $this->notificationTimeMock - ->expects($this->once()) - ->method('unsetLastTimeNotificationValue') - ->willReturn(true); - } - - $this->resultFactoryMock->expects($this->once()) - ->method('create') - ->with(ResultFactory::TYPE_JSON) - ->willReturn($this->resultJsonMock); - $this->resultJsonMock->expects($this->once()) - ->method('setData') - ->with($successResult) - ->willReturnSelf(); - $this->assertSame( - $this->resultJsonMock, - $this->activateController->execute() - ); - } - - /** - * @dataProvider executeExceptionsDataProvider - * - * @param \Exception $exception - */ - public function testExecuteWithException(\Exception $exception) - { - $this->requestMock - ->expects($this->once()) - ->method('getParam') - ->with($this->subscriptionApprovedField) - ->willReturn(true); - - $this->preparedValueFactoryMock - ->expects($this->once()) - ->method('create') - ->willThrowException($exception); - $this->loggerMock - ->expects($this->once()) - ->method('error') - ->with($exception->getMessage()); - $this->resultFactoryMock - ->expects($this->once()) - ->method('create') - ->with(ResultFactory::TYPE_JSON) - ->willReturn($this->resultJsonMock); - - if ($exception instanceof LocalizedException) { - $this->resultJsonMock - ->expects($this->once()) - ->method('setData') - ->with([ - 'success' => false, - 'error_message' => $exception->getMessage(), - ]) - ->willReturnSelf(); - } else { - $this->resultJsonMock - ->expects($this->once()) - ->method('setData') - ->withAnyParameters() - ->willReturnSelf(); - } - - $this->assertSame( - $this->resultJsonMock, - $this->activateController->execute() - ); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function createConfigValueMock() - { - return $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) - ->disableOriginalConstructor() - ->getMock(); - } - - /** - * @return array - */ - public function executeExceptionsDataProvider() - { - return [ - [new LocalizedException(__('TestMessage'))], - [new \Exception('TestMessage')], - ]; - } - - /** - * @return array - */ - public function executeDataProvider() - { - return [ - [true], - [false], - ]; - } -} diff --git a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php b/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php deleted file mode 100644 index 1fb7126146767..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Controller/Adminhtml/Subscription/PostponeTest.php +++ /dev/null @@ -1,168 +0,0 @@ -dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) - ->disableOriginalConstructor() - ->getMock(); - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) - ->disableOriginalConstructor() - ->getMock(); - $this->loggerMock = $this->getMockBuilder(LoggerInterface::class) - ->getMock(); - $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultMock = $this->getMockBuilder(Json::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resultFactoryMock->expects($this->once()) - ->method('create') - ->with(ResultFactory::TYPE_JSON) - ->willReturn($this->resultMock); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->action = $objectManagerHelper->getObject( - Postpone::class, - [ - 'resultFactory' => $this->resultFactoryMock, - 'dateTimeFactory' => $this->dateTimeFactoryMock, - 'notificationTime' => $this->notificationTimeMock, - 'logger' => $this->loggerMock - ] - ); - } - - public function testExecuteSuccess() - { - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(100500); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotification') - ->with(100500) - ->willReturn(true); - $this->resultMock->expects($this->once()) - ->method('setData') - ->with( - [ - 'success' => true, - 'error_message' => '' - ], - false, - [] - )->willReturnSelf(); - $this->assertEquals($this->resultMock, $this->action->execute()); - } - - public function testExecuteFailedWithLocalizedException() - { - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(100500); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotification') - ->with(100500) - ->willThrowException(new LocalizedException(__('Error message'))); - $this->resultMock->expects($this->once()) - ->method('setData') - ->with( - [ - 'success' => false, - 'error_message' => 'Error message' - ], - false, - [] - )->willReturnSelf(); - $this->assertEquals($this->resultMock, $this->action->execute()); - } - - public function testExecuteFailedWithException() - { - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(100500); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotification') - ->with(100500) - ->willThrowException(new \Exception('Any message')); - $this->resultMock->expects($this->once()) - ->method('setData') - ->with( - [ - 'success' => false, - 'error_message' => __('Error occurred during postponement notification') - ], - false, - [] - )->willReturnSelf(); - $this->assertEquals($this->resultMock, $this->action->execute()); - } -} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 755db7e0b3ab1..b12325a0ee511 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -9,7 +9,6 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Analytics\Model\NotificationTime; -use Magento\Framework\Intl\DateTimeFactory; /** * Class CanViewNotificationTest @@ -21,16 +20,6 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase */ private $notificationTimeMock; - /** - * @var DateTimeFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $dateTimeFactoryMock; - - /** - * @var \DateTime|\PHPUnit_Framework_MockObject_MockObject - */ - private $dateTimeMock; - /** * @var CanViewNotification */ @@ -38,10 +27,6 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase public function setUp() { - $this->dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) - ->getMock(); - $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) - ->getMock(); $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) ->disableOriginalConstructor() ->getMock(); @@ -49,33 +34,27 @@ public function setUp() $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'notificationTime' => $this->notificationTimeMock, - 'dateTimeFactory' => $this->dateTimeFactoryMock + 'notificationTime' => $this->notificationTimeMock ] ); } - public function testValidate() + public function testUserShouldSeeNotification() { $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotification') - ->willReturn(1); - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(10005000); + ->method('getLastTimeNotificationForCurrentUser') + ->willReturn(false); + $this->notificationTimeMock->expects($this->once()) + ->method('storeLastTimeNotificationForCurrentUser') + ->willReturn(true); $this->assertTrue($this->canViewNotification->isVisible([])); } - public function testValidateFlagRemoved() + public function testUserShouldNotSeeNotification() { $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotification') - ->willReturn(null); - $this->dateTimeFactoryMock->expects($this->never()) - ->method('create'); + ->method('getLastTimeNotificationForCurrentUser') + ->willReturn(true); $this->assertFalse($this->canViewNotification->isVisible([])); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php index e5ec3f80322a9..ff3b807e5d8c5 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -34,11 +34,6 @@ class SubscriptionHandlerTest extends \PHPUnit\Framework\TestCase */ private $tokenMock; - /** - * @var NotificationTime|\PHPUnit_Framework_MockObject_MockObject - */ - private $notificationTimeMock; - /** * @var ObjectManagerHelper */ @@ -71,10 +66,6 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) - ->disableOriginalConstructor() - ->getMock(); - $this->objectManagerHelper = new ObjectManagerHelper($this); $this->subscriptionHandler = $this->objectManagerHelper->getObject( @@ -84,7 +75,6 @@ protected function setUp() 'configWriter' => $this->configWriterMock, 'attemptsInitValue' => $this->attemptsInitValue, 'analyticsToken' => $this->tokenMock, - 'notificationTime' => $this->notificationTimeMock, ] ); } @@ -104,9 +94,6 @@ public function testProcessEnabledTokenExist() $this->flagManagerMock ->expects($this->never()) ->method('saveFlag'); - $this->notificationTimeMock - ->expects($this->never()) - ->method('unsetLastTimeNotificationValue'); $this->assertTrue( $this->subscriptionHandler->processEnabled() ); @@ -130,10 +117,6 @@ public function testProcessEnabledTokenDoesNotExist() ->method('saveFlag') ->with(SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, $this->attemptsInitValue) ->willReturn(true); - $this->notificationTimeMock - ->expects($this->once()) - ->method('unsetLastTimeNotificationValue') - ->willReturn(true); $this->assertTrue( $this->subscriptionHandler->processEnabled() ); diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php index 581cb1171d318..e60407f9bf8dd 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php @@ -7,6 +7,8 @@ namespace Magento\Analytics\Test\Unit\Model; use Magento\Analytics\Model\NotificationTime; +use Magento\Authorization\Model\UserContextInterface; +use Magento\Framework\Intl\DateTimeFactory; use Magento\Framework\FlagManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; @@ -20,57 +22,105 @@ class NotificationTimeTest extends \PHPUnit\Framework\TestCase */ private $flagManagerMock; + /** + * @var UserContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $userContextInterfaceMock; + + /** + * @var DateTimeFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $dateTimeFactoryMock; + + /** + * @var \DateTime|\PHPUnit_Framework_MockObject_MockObject + */ + private $dateTimeMock; + /** * @var NotificationTime */ private $notificationTime; + /** + * @var int + */ + private $value; + + /** + * @var int + */ + private $userId; + public function setUp() { + $this->value = 10005000; + $this->userId = 1; + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) ->disableOriginalConstructor() ->getMock(); - + $this->userContextInterfaceMock = $this->getMockBuilder(UserContextInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) + ->getMock(); + $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->getMock(); $objectManagerHelper = new ObjectManagerHelper($this); $this->notificationTime = $objectManagerHelper->getObject( NotificationTime::class, [ 'flagManager' => $this->flagManagerMock, + 'userContext' => $this->userContextInterfaceMock, + 'dateTimeFactory' => $this->dateTimeFactoryMock ] ); } - public function testStoreLastTimeNotification() + public function testStoreLastTimeNotificationForCurrentUser() { - $value = 100500; + $this->userContextInterfaceMock->expects($this->once()) + ->method("getUserId") + ->willReturn(1); + $this->dateTimeFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->dateTimeMock); + $this->dateTimeMock->expects($this->once()) + ->method('getTimestamp') + ->willReturn(10005000); $this->flagManagerMock ->expects($this->once()) ->method('saveFlag') - ->with(NotificationTime::NOTIFICATION_TIME, $value) + ->with(NotificationTime::NOTIFICATION_TIME . $this->userId, $this->value) ->willReturn(true); - $this->assertTrue($this->notificationTime->storeLastTimeNotification($value)); + $this->assertTrue($this->notificationTime->storeLastTimeNotificationForCurrentUser()); } - public function testGetLastTimeNotification() + public function testGetLastTimeNotificationForCurrentUser() { - $value = 100500; - + $this->userContextInterfaceMock->expects($this->once()) + ->method("getUserId") + ->willReturn(1); $this->flagManagerMock ->expects($this->once()) ->method('getFlagData') - ->with(NotificationTime::NOTIFICATION_TIME) + ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) ->willReturn(true); - $this->assertEquals($value, $this->notificationTime->getLastTimeNotification()); + $this->assertEquals($this->value, $this->notificationTime->getLastTimeNotificationForCurrentUser()); } - public function testUnsetLastTimeNotificationValue() + public function testUnsetLastTimeNotificationValueForCurrentUser() { + $this->userContextInterfaceMock->expects($this->once()) + ->method("getUserId") + ->willReturn(1); $this->flagManagerMock ->expects($this->once()) ->method('deleteFlag') - ->with(NotificationTime::NOTIFICATION_TIME) + ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) ->willReturn(true); - $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValue()); + $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValueForCurrentUser()); } } diff --git a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml index 42cf4f937958b..3bfb5ca595790 100644 --- a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> - + - -
- - - analytics_subscription_form.analytics_subscription_form_data_source - - Analytics Subscription - templates/form/collapsible - - - analytics_subscription_form - true - simple - data - - analytics_subscription_form.analytics_subscription_form_data_source - - - - - - - - - - - - - Magento_Ui/js/form/provider - - - - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - - -
- - - - - - - advanced-reports-subscription-text - When you turn on Advanced - Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example - of the new data and trend reports, listed by category, include:

    -
  • Order: Number of orders, total revenue, and AOV
  • Customer: - New registered accounts, unique customers, number of orders, AOV, revenue by email -
  • Product: Quantity sold, bestsellers by volume/revenue

A - personalized dashboard includes all reports - separate from your Admin Panel, yet still at your - fingertips.

We're excited to offer these valuable tools that can help your business become - more data-driven. For more information, view details or see our - terms and conditions.

]]> -
-
-
-
- - - - - - - - - - - - - 1 - - - - - true - - analytics_subscription_checkbox - - - - - - Learn more.]]> - - 1 - 0 - - - - - - -
-
- - - actionCancel - - - - - - - - - - - - - - - advanced-reports-subscription-text - Advanced Reporting in included, - free of charge, in your Magento software. When you opt out, we collect no product, order, and - customer data to generate our dynamic reports.

To opt in later: You can always turn on Advanced - Reporting in you Admin Panel.

]]>
-
-
-
-
-
diff --git a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml new file mode 100644 index 0000000000000..c26b4e15dfe17 --- /dev/null +++ b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml @@ -0,0 +1,98 @@ + + +
+ + + analytics_subscription_notification.analytics_subscription_notification_data_source + + Analytics Subscription + templates/form/collapsible + + + analytics_subscription_notification + true + simple + data + + analytics_subscription_notification.analytics_subscription_notification_data_source + + + + + + Magento_Ui/js/form/provider + + + + + + false + + + + + + + actionCancel + true + + + + + + + + + +
+ + + + + + + advanced-reports-subscription-text + Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy and Terms + of Service. You may opt out at any time from the Stores Configuration page.

]]> +
+
+
+
+ + + + + + + + +
+
+
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js b/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js deleted file mode 100644 index 9dee8d0c8e9ce..0000000000000 --- a/app/code/Magento/Analytics/view/adminhtml/web/js/modal/modal-component.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -define([ - 'jquery', - 'Magento_Ui/js/modal/modal-component', - 'Magento_Ui/js/modal/alert', - 'mage/translate' -], function ($, Modal, alert, $t) { - 'use strict'; - - return Modal.extend({ - defaults: { - postponeOptions: {}, - imports: { - postponeUrl: '${ $.provider }:postpone_url' - }, - modules: { - form: '${ $.parentName }' - } - }, - - /** - * Send request to postpone modal appearance for a certain time. - * - * @param {Object} options - additional request options. - */ - sendPostponeRequest: function (options) { - var self = this, - data = $.extend(this.form().source.data, options); - - $.ajax({ - type: 'POST', - url: this.postponeUrl, - data: data, - showLoader: true - }).done(function (xhr) { - if (xhr.error) { - self.onError(xhr); - } - }).fail(this.onError); - }, - - /** - * Error handler. - * - * @param {Object} xhr - request result. - */ - onError: function (xhr) { - if (xhr.statusText === 'abort') { - return; - } - - alert({ - content: xhr.message || $t('An error occurred while subscription process.') - }); - }, - - /** @inheritdoc */ - actionCancel: function () { - this.sendPostponeRequest(this.postponeOptions); - this.closeModal(); - } - }); -}); diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html b/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html deleted file mode 100644 index 784e16d72c3f5..0000000000000 --- a/app/code/Magento/Analytics/view/adminhtml/web/template/buttons-container.html +++ /dev/null @@ -1,13 +0,0 @@ - -
- - -
- -
-
diff --git a/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html b/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html deleted file mode 100644 index 297867c60c1e4..0000000000000 --- a/app/code/Magento/Analytics/view/adminhtml/web/template/form/components/single/checkbox.html +++ /dev/null @@ -1,17 +0,0 @@ - -
- - -
diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less index 85454effcbd67..cb01cb5fbcda9 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/css/source/_module.less @@ -18,157 +18,108 @@ // _____________________________________________ .dashboard-advanced-reports { - .lib-vendor-prefix-display(flex); - border-color: @color-gray89; - border-style: solid; - border-width: 1px 0; - margin-bottom: @indent__l; - padding: @indent__m 0; + .lib-vendor-prefix-display(flex); + border-color: @color-gray89; + border-style: solid; + border-width: 1px 0; + margin-bottom: @indent__l; + padding: @indent__m 0; } .dashboard-advanced-reports-title { - &:extend(.dashboard-item-title all); - margin-bottom: @indent__s; + &:extend(.dashboard-item-title all); + margin-bottom: @indent__s; } .dashboard-advanced-reports-content { - line-height: @line-height__xl; + line-height: @line-height__xl; } .dashboard-advanced-reports-actions { - .lib-vendor-prefix-flex-basis(auto); - .lib-vendor-prefix-flex-grow(1); - .lib-vendor-prefix-flex-shrink(1); - align-self: center; - margin-left: @indent__m; - margin-right: @page-main-actions__padding; - text-align: right; + .lib-vendor-prefix-flex-basis(auto); + .lib-vendor-prefix-flex-grow(1); + .lib-vendor-prefix-flex-shrink(1); + align-self: center; + margin-left: @indent__m; + margin-right: @page-main-actions__padding; + text-align: right; } .action-advanced-reports { - &:extend(.abs-action-l all); - &:extend(.abs-action-pattern all); - background-color: @button-advanced-reports__background-color; - border-color: @button-advanced-reports__background-color; - color: @button-advanced-reports__color; - text-shadow: 1px 1px 0 rgba(0, 0, 0, .25); - white-space: nowrap; - - &:after { - &:extend(.abs-icon all); - content: @icon-external-link__content; - font-size: @font-size__xs; - vertical-align: super; - } + &:extend(.abs-action-l all); + &:extend(.abs-action-pattern all); + background-color: @button-advanced-reports__background-color; + border-color: @button-advanced-reports__background-color; + color: @button-advanced-reports__color; + text-shadow: 1px 1px 0 rgba(0, 0, 0, .25); + white-space: nowrap; + + &:after { + &:extend(.abs-icon all); + content: @icon-external-link__content; + font-size: @font-size__xs; + vertical-align: super; + } - &:hover, - &:active, - &:focus { - background-color: @button-advanced-reports__hover__background-color; - border-color: @button-advanced-reports__hover__border-color; - box-shadow: @button__hover__box-shadow; - color: @button-advanced-reports__color; - text-decoration: none; - } + &:hover, + &:active, + &:focus { + background-color: @button-advanced-reports__hover__background-color; + border-color: @button-advanced-reports__hover__border-color; + box-shadow: @button__hover__box-shadow; + color: @button-advanced-reports__color; + text-decoration: none; + } - &.disabled, - &[disabled] { - cursor: default; - opacity: @disabled__opacity; - pointer-events: none; - } + &.disabled, + &[disabled] { + cursor: default; + opacity: @disabled__opacity; + pointer-events: none; + } } // // Modal on dashboard // --------------------------------------------- -.advanced-reports-decline-subscription-modal, .advanced-reports-subscription-modal { - .modal-inner-wrap { - max-width: 80rem; - } -} + .modal-inner-wrap { + max-width: 75rem; + margin-top: 13rem; -.advanced-reports-subscription-modal { - .admin__fieldset { - padding: 0; - } -} + .modal-content, .modal-header { + padding-left: 4rem; + padding-right: 4rem; -.advanced-reports-decline-subscription-modal { - .advanced-reports-subscription-text { - margin-bottom: 0; + .action-close { + display: none; + } } + } - .modal-content { - padding-bottom: 0; - } + .admin__fieldset { + padding: 0; + } } .advanced-reports-subscription-text { - line-height: @line-height__xl; - - .list { - .lib-list-reset-styles(@_margin: @indent__m 0, @_padding: 0); - - li { - padding-left: @indent__l; - position: relative; - - &:before { - content: '\2022'; - left: 1rem; - position: absolute; - } - - + li { - margin-top: @indent__m; - } - } - } + line-height: @line-height__xl; + padding-bottom: 8rem; } -.advanced-reports-subscription-actions { - font-size: 0; - text-align: justify; - - &:after { - content: ''; - display: inline-block; - height: 0; - overflow: hidden; - visibility: hidden; - width: 100%; - } - - .action-basic, - .action-additional { - &:extend(.abs-action-l all); - } - - .advanced-reports-subscription-postpone, - .advanced-reports-subscription-disable, - .advanced-reports-subscription-enable { - display: inline-block; - vertical-align: top; - } +.advanced-reports-subscription-close { + display: inline-block; + vertical-align: top; + float: right; } -.advanced-reports-subscription-enable { - .admin__field { - max-width: 22rem; - } - - .admin__field-label { - font-size: @font-size__s; - line-height: @line-height__l; - } - - .action-basic { - &:extend(.abs-action-primary all); - margin-bottom: @indent__s; - } +.advanced-reports-subscription-modal { + h1:first-of-type { + background: url("Magento_Analytics::images/advanced-reporting-badge.svg") no-repeat; + background-size: 44px 50px; + padding: 1.3rem 0 2rem 6rem; + } } // diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg new file mode 100644 index 0000000000000..5abae13c5fa99 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg @@ -0,0 +1,7 @@ + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php index 0cbb853167f30..e362d51790a76 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php @@ -14,76 +14,11 @@ class SubscriptionBlock extends Modal { /** - * Modal checkbox + * Close subscription pop-up button * * @var string */ - private $checkbox = '[name="analytics_subscription_checkbox"]'; - - /** - * Enable Advanced Reporting button - * - * @var string - */ - private $acceptReportingButton = '[data-index="analytics_subscription_button_accept"]'; - - /** - * Disable Advanced Reporting button - * - * @var string - */ - private $declineReportingButton = '[data-index="analytics_subscription_button_decline"]'; - - /** - * Skip subscription pop-up button - * - * @var string - */ - private $skipReportingButton = '[data-index="analytics_subscription_button_postpone"]'; - - /** - * Enable checkbox in modal window. - * - * @return void - */ - public function enableCheckbox() - { - $this->_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('Yes'); - } - - /** - * Disable checkbox in modal window. - * - * @return void - */ - public function disableCheckbox() - { - $this->_rootElement->find($this->checkbox, Locator::SELECTOR_CSS, 'checkbox')->setValue('No'); - } - - /** - * Enable Advanced Reporting on a subscription popup. - * - * @return void - */ - public function acceptAdvancedReporting() - { - $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->acceptReportingButton)->click(); - $this->waitForElementNotVisible($this->loadingMask); - } - - /** - * Disable Advanced Reporting on a subscription popup. - * - * @return void - */ - public function declineAdvancedReporting() - { - $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->declineReportingButton)->click(); - $this->waitForElementNotVisible($this->loadingMask); - } + private $closeReportingButton = '[data-index="analytics_subscription_button_close"]'; /** * Skip subscription popup. @@ -93,7 +28,7 @@ public function declineAdvancedReporting() public function skipAdvancedReporting() { $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->skipReportingButton)->click(); + $this->_rootElement->find($this->closeReportingButton)->click(); $this->waitForElementNotVisible($this->loadingMask); } } From 8598aa6fef44d52805428402282f78f122a0ab86 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 16:02:48 -0500 Subject: [PATCH 023/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- app/code/Magento/Analytics/etc/di.xml | 5 ----- app/code/Magento/Analytics/etc/module.xml | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/code/Magento/Analytics/etc/di.xml b/app/code/Magento/Analytics/etc/di.xml index 09efd7c36ad83..56657b58475d3 100644 --- a/app/code/Magento/Analytics/etc/di.xml +++ b/app/code/Magento/Analytics/etc/di.xml @@ -23,11 +23,6 @@ - - - Magento\Config\Model\ResourceModel\Config\Data - - diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml index 32ee5d23a4d86..b78ecc9256ffb 100644 --- a/app/code/Magento/Analytics/etc/module.xml +++ b/app/code/Magento/Analytics/etc/module.xml @@ -12,6 +12,7 @@ + From 54c029c455319d2fc2f454f19c7fab798a010d9e Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 4 Oct 2017 16:04:45 -0500 Subject: [PATCH 024/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- app/code/Magento/Analytics/etc/module.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml index b78ecc9256ffb..37d1a9e79ad70 100644 --- a/app/code/Magento/Analytics/etc/module.xml +++ b/app/code/Magento/Analytics/etc/module.xml @@ -12,7 +12,7 @@ - + From f5db6a86dd63a0ca400f080a4dca503d1b5f935c Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Thu, 5 Oct 2017 09:34:18 +0300 Subject: [PATCH 025/528] MAGETWO-71966: [2.2.x] Braintree online refund not working for two websites using individual Braintree accounts - Updated controller URL --- app/code/Magento/Braintree/Block/Payment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Braintree/Block/Payment.php b/app/code/Magento/Braintree/Block/Payment.php index aa5b3b07fb23c..1ba2f862e2fe5 100644 --- a/app/code/Magento/Braintree/Block/Payment.php +++ b/app/code/Magento/Braintree/Block/Payment.php @@ -49,7 +49,7 @@ public function getPaymentConfig() $config = $payment[$this->getCode()]; $config['code'] = $this->getCode(); $config['clientTokenUrl'] = $this->_urlBuilder->getUrl( - ConfigProvider::CODE . '/payment/getClientToken', + 'braintree/payment/getClientToken', ['_secure' => true] ); return json_encode($config, JSON_UNESCAPED_SLASHES); From 438dc1309296f44ee4715098397b7615356ef1bd Mon Sep 17 00:00:00 2001 From: Ihor Sviziev Date: Mon, 2 Oct 2017 08:26:27 +0300 Subject: [PATCH 026/528] Add static test to detect blocks without name attribute Run all static tests on Travis (cherry picked from commit 117287f) --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 42c2bcab0c901..28515b5f72ed6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,7 +55,6 @@ install: composer install --no-interaction --prefer-dist before_script: ./dev/travis/before_script.sh script: # Set arguments for variants of phpunit based tests; '|| true' prevents failing script when leading test fails - - test $TEST_SUITE = "static" && TEST_FILTER='--filter "Magento\\Test\\Php\\LiveCodeTest"' || true - test $TEST_SUITE = "functional" && TEST_FILTER='dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests.php' || true # The scripts for grunt/phpunit type tests From ff2c4ba2b2e5c28e786ddffbc736b58fce3dce99 Mon Sep 17 00:00:00 2001 From: Ihor Sviziev Date: Mon, 2 Oct 2017 08:26:35 +0300 Subject: [PATCH 027/528] Add static test to detect blocks without name attribute (cherry picked from commit b0f5a66) --- .../Test/Integrity/Layout/BlockNamesTest.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 dev/tests/static/testsuite/Magento/Test/Integrity/Layout/BlockNamesTest.php diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Layout/BlockNamesTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Layout/BlockNamesTest.php new file mode 100644 index 0000000000000..ec1d719df2e5e --- /dev/null +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Layout/BlockNamesTest.php @@ -0,0 +1,36 @@ +load($layoutFile); + $xpath = new \DOMXpath($dom); + $count = $xpath->query('//block[not(@name)]')->length; + + if ($count) { + $this->fail('Following file contains ' . $count . ' blocks without name. ' . + 'File Path:' . "\n" . $layoutFile); + } + }, + \Magento\Framework\App\Utility\Files::init()->getLayoutFiles() + ); + } +} From 34ba6ca14993b93c84bf37189907ef29c86a6765 Mon Sep 17 00:00:00 2001 From: Ihor Sviziev Date: Mon, 2 Oct 2017 08:26:55 +0300 Subject: [PATCH 028/528] Add static test to detect blocks without name attribute Fix static test failures (cherry picked from commit e57ef72) --- .../layout/adminhtml_notification_block.xml | 8 ++++---- .../layout/adminhtml_cache_block.xml | 8 ++++---- .../adminhtml_system_design_grid_block.xml | 8 ++++---- .../adminhtml_system_store_grid_block.xml | 6 +++--- .../adminhtml/layout/backup_index_block.xml | 12 +++++------ .../layout/adminhtml_order_shipment_new.xml | 2 +- .../adminhtml/layout/catalog_product_new.xml | 2 +- .../layout/sales_order_creditmemo_new.xml | 2 +- .../sales_order_creditmemo_updateqty.xml | 2 +- .../layout/sales_order_creditmemo_view.xml | 2 +- .../layout/sales_order_invoice_new.xml | 2 +- .../layout/sales_order_invoice_updateqty.xml | 2 +- .../layout/sales_order_invoice_view.xml | 2 +- .../adminhtml/layout/sales_order_view.xml | 2 +- .../layout/checkout_cart_item_renderers.xml | 2 +- .../CATALOG_PRODUCT_COMPOSITE_CONFIGURE.xml | 10 +++++----- .../layout/catalog_product_attribute_edit.xml | 10 +++++----- .../catalog_product_attribute_edit_popup.xml | 10 +++++----- .../layout/catalog_product_set_block.xml | 2 +- .../frontend/layout/catalog_category_view.xml | 2 +- .../layout/checkout_cart_item_renderers.xml | 2 +- .../catalog_product_view_type_simple.xml | 2 +- .../catalog_product_view_type_virtual.xml | 2 +- .../catalog_rule_promo_catalog_block.xml | 12 +++++------ .../layout/catalogsearch_advanced_result.xml | 2 +- .../layout/catalogsearch_result_index.xml | 2 +- ...checkout_onepage_review_item_renderers.xml | 2 +- .../layout/adminhtml_system_config_edit.xml | 4 ++-- .../layout/catalog_product_addattribute.xml | 2 +- .../adminhtml/layout/catalog_product_new.xml | 4 ++-- .../layout/catalog_product_wizard.xml | 2 +- ...catalog_product_view_type_configurable.xml | 2 +- .../layout/checkout_cart_item_renderers.xml | 2 +- ...checkout_onepage_review_item_renderers.xml | 2 +- .../adminhtml/layout/customer_group_index.xml | 6 +++--- .../view/frontend/layout/customer_account.xml | 2 +- .../layout/checkout_cart_item_renderers.xml | 2 +- .../adminhtml_email_template_grid_block.xml | 14 ++++++------- .../adminhtml/layout/catalog_product_new.xml | 2 +- .../layout/groupedproduct_popup_grid.xml | 10 +++++----- .../frontend/layout/sales_guest_invoice.xml | 2 +- .../layout/adminhtml_history_grid_block.xml | 14 ++++++------- .../layout/indexer_indexer_list_grid.xml | 10 +++++----- .../adminhtml_integration_grid_block.xml | 10 +++++----- .../layout/newsletter_problem_block.xml | 14 ++++++------- .../layout/newsletter_queue_grid_block.xml | 16 +++++++-------- .../layout/newsletter_subscriber_block.xml | 18 ++++++++--------- .../layout/adminhtml_system_config_edit.xml | 2 +- .../layout/adminhtml_paypal_reports_block.xml | 20 +++++++++---------- .../layout/adminhtml_system_config_edit.xml | 2 +- .../reports_report_customer_accounts_grid.xml | 2 +- .../reports_report_customer_orders_grid.xml | 8 ++++---- .../adminhtml/layout/reports_report_grid.xml | 2 +- .../reports_report_product_lowstock_grid.xml | 6 +++--- .../reports_report_product_sold_grid.xml | 6 +++--- .../reports_report_review_customer_grid.xml | 6 +++--- .../reports_report_review_product_grid.xml | 14 ++++++------- .../reports_report_statistics_index.xml | 6 +++--- .../view/adminhtml/layout/rating_block.xml | 8 ++++---- .../sales_order_create_customer_block.xml | 18 ++++++++--------- .../layout/sales_order_create_index.xml | 2 +- .../sales_order_creditmemo_grid_block.xml | 10 +++++----- .../layout/sales_order_creditmemo_new.xml | 2 +- .../sales_order_creditmemo_updateqty.xml | 2 +- .../layout/sales_order_creditmemo_view.xml | 2 +- .../layout/sales_order_invoice_grid_block.xml | 10 +++++----- .../layout/sales_order_invoice_new.xml | 2 +- .../layout/sales_order_invoice_updateqty.xml | 2 +- .../layout/sales_order_invoice_view.xml | 2 +- .../sales_order_shipment_grid_block.xml | 8 ++++---- .../layout/sales_order_status_index.xml | 12 +++++------ .../layout/sales_rule_promo_quote_index.xml | 16 +++++++-------- .../layout/adminhtml_dashboard_index.xml | 4 ++-- .../adminhtml/layout/search_term_block.xml | 10 +++++----- .../layout/search_term_grid_block.xml | 14 ++++++------- .../layout/search_term_report_block.xml | 10 +++++----- .../adminhtml_sitemap_index_grid_block.xml | 14 ++++++------- .../layout/catalog_product_attribute_edit.xml | 4 ++-- .../catalog_product_attribute_edit_popup.xml | 4 ++-- .../frontend/layout/catalog_category_view.xml | 2 +- .../layout/catalogsearch_advanced_result.xml | 2 +- .../layout/catalogsearch_result_index.xml | 2 +- .../view/adminhtml/layout/tax_rule_block.xml | 14 ++++++------- .../view/adminhtml/layout/tax_rule_edit.xml | 2 +- .../adminhtml_system_design_theme_block.xml | 6 +++--- .../layout/adminhtml_system_config_edit.xml | 2 +- .../layout/adminhtml_url_rewrite_index.xml | 12 +++++------ .../layout/adminhtml_locks_block.xml | 12 +++++------ .../layout/adminhtml_user_grid_block.xml | 12 +++++------ .../layout/adminhtml_user_role_grid_block.xml | 4 ++-- .../adminhtml_system_variable_grid_block.xml | 6 +++--- .../adminhtml_widget_instance_block.xml | 10 +++++----- .../layout/customer_index_wishlist.xml | 16 +++++++-------- .../frontend/layout/catalog_category_view.xml | 2 +- 94 files changed, 296 insertions(+), 296 deletions(-) diff --git a/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_block.xml b/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_block.xml index 7778c1dd5ca98..c68313211c2e6 100644 --- a/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_block.xml +++ b/app/code/Magento/AdminNotification/view/adminhtml/layout/adminhtml_notification_block.xml @@ -20,14 +20,14 @@ 0 - + Severity severity Magento\AdminNotification\Block\Grid\Renderer\Severity - + Date Added date_added @@ -37,14 +37,14 @@ col-date - + Message title Magento\AdminNotification\Block\Grid\Renderer\Notice - + Actions 0 diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml index f6a93fbd84099..50d210f71025b 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_cache_block.xml @@ -42,7 +42,7 @@ 0 - + Cache Type cache_type @@ -53,7 +53,7 @@ true - + Description description @@ -63,7 +63,7 @@ true - + Tags tags @@ -73,7 +73,7 @@ 0 - + Status status diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml index 52d88ce717043..b96614f4bd8db 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_design_grid_block.xml @@ -28,7 +28,7 @@ - + Store 100px @@ -38,7 +38,7 @@ store_id - + Design options @@ -47,7 +47,7 @@ design - + Date From left @@ -57,7 +57,7 @@ date_from - + Date To left diff --git a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml index 8dcb6e07b3c4e..126de5eb4084f 100644 --- a/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml +++ b/app/code/Magento/Backend/view/adminhtml/layout/adminhtml_system_store_grid_block.xml @@ -18,7 +18,7 @@ storeGrid - + Web Site left @@ -27,7 +27,7 @@ Magento\Backend\Block\System\Store\Grid\Render\Website - + Store left @@ -36,7 +36,7 @@ Magento\Backend\Block\System\Store\Grid\Render\Group - + Store View left diff --git a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml index df6f6ad785553..e17618b97e21f 100644 --- a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml +++ b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml @@ -33,7 +33,7 @@ backupsGrid - + Time date_object @@ -42,7 +42,7 @@ col-date - + Name display_name @@ -51,7 +51,7 @@ col-name - + Size(bytes) size @@ -60,7 +60,7 @@ 1 - + Type type @@ -68,7 +68,7 @@ - + Download type @@ -78,7 +78,7 @@ Magento\Backup\Block\Adminhtml\Grid\Column\Renderer\Download - + Action type diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_new.xml b/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_new.xml index e1c4a0a0b308f..ce30a509bf03c 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_new.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/adminhtml_order_shipment_new.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml index 34f47b745b8e9..8fcf88037a8fd 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/catalog_product_new.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml index cacf7dd0c47de..95ae3bf4709b7 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_new.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml index cacf7dd0c47de..95ae3bf4709b7 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml index 8fc9eed8656a8..f9951c66abd53 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_creditmemo_view.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml index fcde059ba0972..a64f46bb72ed1 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_new.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml index fcde059ba0972..a64f46bb72ed1 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_updateqty.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml index 4d649c1b3c38c..0eaa57ab47952 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_invoice_view.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml index e212c08215d41..1b1419870b98d 100644 --- a/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml +++ b/app/code/Magento/Bundle/view/adminhtml/layout/sales_order_view.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml index 5137782656269..aa74a80e64750 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/checkout_cart_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE.xml b/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE.xml index 92663f0ce5c44..f4a5bbba8f571 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/CATALOG_PRODUCT_COMPOSITE_CONFIGURE.xml @@ -9,11 +9,11 @@ - - - - - + + + + + diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml index c3328455be8ab..94e9425593404 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit.xml @@ -10,12 +10,12 @@ - - - + + + - - + + diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml index a46f6e5b0e8b4..ff241dca1dfe6 100755 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml @@ -13,11 +13,11 @@ - - - - - + + + + + diff --git a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml index 22e16cac8cef2..44884897461a8 100644 --- a/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml +++ b/app/code/Magento/Catalog/view/adminhtml/layout/catalog_product_set_block.xml @@ -26,7 +26,7 @@ - + Set left diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml index 00c71d6163153..5fee1d8447e5a 100644 --- a/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml +++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_category_view.xml @@ -19,7 +19,7 @@ - + - + diff --git a/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_simple.xml b/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_simple.xml index 7b595e9822ff0..4cdde39061945 100644 --- a/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_simple.xml +++ b/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_simple.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_virtual.xml b/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_virtual.xml index 5bc03f9c1c45a..b393f88c7746a 100644 --- a/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_virtual.xml +++ b/app/code/Magento/CatalogInventory/view/frontend/layout/catalog_product_view_type_virtual.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml index a70b9968529b1..99d64ed7a635f 100644 --- a/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml +++ b/app/code/Magento/CatalogRule/view/adminhtml/layout/catalog_rule_promo_catalog_block.xml @@ -25,7 +25,7 @@ - + ID rule_id @@ -34,14 +34,14 @@ col-id - + Rule name text - + Start date @@ -51,7 +51,7 @@ col-date - + End date @@ -62,7 +62,7 @@ col-date - + Status is_active @@ -79,7 +79,7 @@ - + Web Site website_ids diff --git a/app/code/Magento/CatalogSearch/view/frontend/layout/catalogsearch_advanced_result.xml b/app/code/Magento/CatalogSearch/view/frontend/layout/catalogsearch_advanced_result.xml index 4a66ef5a7f20c..9c20f614076b3 100644 --- a/app/code/Magento/CatalogSearch/view/frontend/layout/catalogsearch_advanced_result.xml +++ b/app/code/Magento/CatalogSearch/view/frontend/layout/catalogsearch_advanced_result.xml @@ -23,7 +23,7 @@ product_list_toolbar - + product_list_toolbar - + - + diff --git a/app/code/Magento/Config/view/adminhtml/layout/adminhtml_system_config_edit.xml b/app/code/Magento/Config/view/adminhtml/layout/adminhtml_system_config_edit.xml index 4d114d237b91b..1a58798c386c0 100644 --- a/app/code/Magento/Config/view/adminhtml/layout/adminhtml_system_config_edit.xml +++ b/app/code/Magento/Config/view/adminhtml/layout/adminhtml_system_config_edit.xml @@ -8,8 +8,8 @@ - - + + diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_addattribute.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_addattribute.xml index 256092072c31b..3fc6855066c1b 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_addattribute.xml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_addattribute.xml @@ -7,6 +7,6 @@ --> - + diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_new.xml index c2153017708df..9ff4730d94bda 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_new.xml @@ -11,8 +11,8 @@ - - + + diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_wizard.xml b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_wizard.xml index f6c472b209b6c..a084abfc31eaa 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_wizard.xml +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_wizard.xml @@ -7,7 +7,7 @@ --> - + false diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml index 9ca21540ecff2..d9fec680a3aeb 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/catalog_product_view_type_configurable.xml @@ -14,7 +14,7 @@ - + diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml index d3e1d7d89c957..4511d58b6fc26 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_cart_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml index 57cc1055db25f..7de2a5e958134 100644 --- a/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml +++ b/app/code/Magento/ConfigurableProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_group_index.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_group_index.xml index c33f35b3b4dda..ecb64711bdb94 100644 --- a/app/code/Magento/Customer/view/adminhtml/layout/customer_group_index.xml +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_group_index.xml @@ -26,7 +26,7 @@ - + ID id @@ -35,13 +35,13 @@ col-id - + Group code - + Tax Class tax_class_name diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml index 87f105005ea54..ac03fa7d293a4 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account.xml @@ -9,7 +9,7 @@ - + account-nav diff --git a/app/code/Magento/Downloadable/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/checkout_cart_item_renderers.xml index 7aeab211add94..23bc140904fab 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/checkout_cart_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Email/view/adminhtml/layout/adminhtml_email_template_grid_block.xml b/app/code/Magento/Email/view/adminhtml/layout/adminhtml_email_template_grid_block.xml index edb49e8633df4..fa15560817dd9 100644 --- a/app/code/Magento/Email/view/adminhtml/layout/adminhtml_email_template_grid_block.xml +++ b/app/code/Magento/Email/view/adminhtml/layout/adminhtml_email_template_grid_block.xml @@ -28,7 +28,7 @@ No Templates Found - + ID template_id @@ -36,13 +36,13 @@ col-id - + Template template_code - + Added added_at @@ -52,7 +52,7 @@ col-date - + Updated modified_at @@ -62,13 +62,13 @@ col-date - + Subject template_subject - + Template Type template_type @@ -76,7 +76,7 @@ Magento\Email\Block\Adminhtml\Template\Grid\Renderer\Type - + Action template_id diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_new.xml index b264471d278be..466d9014a9745 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/GroupedProduct/view/adminhtml/layout/catalog_product_new.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/layout/groupedproduct_popup_grid.xml b/app/code/Magento/GroupedProduct/view/adminhtml/layout/groupedproduct_popup_grid.xml index d8e344771860c..503404c6cb3cf 100644 --- a/app/code/Magento/GroupedProduct/view/adminhtml/layout/groupedproduct_popup_grid.xml +++ b/app/code/Magento/GroupedProduct/view/adminhtml/layout/groupedproduct_popup_grid.xml @@ -24,7 +24,7 @@ grouped_grid_popup - + skip-list Magento\Backend\Block\Widget\Grid\Column\Renderer\Checkbox @@ -32,13 +32,13 @@ entity_id - + ID entity_id - + Name text @@ -47,7 +47,7 @@ 1 - + SKU text @@ -55,7 +55,7 @@ 1 - + Price currency diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_guest_invoice.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_guest_invoice.xml index c451fe6baca30..57eeb4c360666 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_guest_invoice.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_guest_invoice.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml b/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml index 7af022b8f2e53..02fc198cb0ada 100644 --- a/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml +++ b/app/code/Magento/ImportExport/view/adminhtml/layout/adminhtml_history_grid_block.xml @@ -16,7 +16,7 @@ desc - + ID true @@ -25,7 +25,7 @@ col-id - + Start Date&Time datetime @@ -33,7 +33,7 @@ true - + User text @@ -43,7 +43,7 @@ col-name - + Imported File type @@ -54,7 +54,7 @@ Magento\ImportExport\Block\Adminhtml\Grid\Column\Renderer\Download - + Error File type @@ -66,7 +66,7 @@ - + Execution Time text @@ -74,7 +74,7 @@ 0 - + Summary text diff --git a/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml b/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml index 54888f94d9ae9..bf6b2351f75f1 100644 --- a/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml +++ b/app/code/Magento/Indexer/view/adminhtml/layout/indexer_indexer_list_grid.xml @@ -38,7 +38,7 @@ indexer_grid 0 - + Indexer 180 @@ -49,7 +49,7 @@ true - + Description description @@ -58,7 +58,7 @@ true - + Mode is_scheduled @@ -67,7 +67,7 @@ indexer-mode - + Status status @@ -76,7 +76,7 @@ indexer-status - + Updated updated diff --git a/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_grid_block.xml b/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_grid_block.xml index 8d9e60a872cec..506f836f99514 100644 --- a/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_grid_block.xml +++ b/app/code/Magento/Integration/view/adminhtml/layout/adminhtml_integration_grid_block.xml @@ -28,7 +28,7 @@ We couldn't find any records. - + Name text @@ -38,7 +38,7 @@ 1 - + Status options @@ -47,7 +47,7 @@ status - + Magento\Integration\Block\Adminhtml\Widget\Grid\Column\Renderer\Link\Activate activate @@ -56,7 +56,7 @@ 0 - + Magento\Integration\Block\Adminhtml\Widget\Grid\Column\Renderer\Button\Edit edit @@ -65,7 +65,7 @@ 0 - + Magento\Integration\Block\Adminhtml\Widget\Grid\Column\Renderer\Button\Delete action delete diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_problem_block.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_problem_block.xml index 2e2effa496b2f..3eb7de194d242 100644 --- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_problem_block.xml +++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_problem_block.xml @@ -21,7 +21,7 @@ problemGrid We found no problems. - + 0 Magento\Newsletter\Block\Adminhtml\Problem\Grid\Filter\Checkbox @@ -30,7 +30,7 @@ col-select - + ID problem_id @@ -38,7 +38,7 @@ col-id - + Subscriber #$subscriber_id $customer_name ($subscriber_email) @@ -47,7 +47,7 @@ col-subscriber col-name - + Queue Start Date queue_start_at @@ -57,7 +57,7 @@ col-start col-date - + Queue Subject template_subject @@ -65,7 +65,7 @@ col-subject - + Error Code problem_error_code @@ -74,7 +74,7 @@ col-error-code - + Error Text problem_error_text diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_grid_block.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_grid_block.xml index 2c2ac7d32d71c..3bfb52157bb99 100644 --- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_grid_block.xml +++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_queue_grid_block.xml @@ -26,7 +26,7 @@ - + ID queue_id @@ -34,7 +34,7 @@ col-id - + Queue Start datetime @@ -45,7 +45,7 @@ col-start - + Queue End datetime @@ -56,7 +56,7 @@ col-finish - + Subject newsletter_subject @@ -64,7 +64,7 @@ col-subject - + Status queue_status @@ -74,7 +74,7 @@ col-status - + Processed number @@ -83,7 +83,7 @@ col-processed - + Recipients number @@ -92,7 +92,7 @@ col-recipients - + Action 0 diff --git a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_subscriber_block.xml b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_subscriber_block.xml index 0dd1c6d744a8f..9de1807af18ec 100644 --- a/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_subscriber_block.xml +++ b/app/code/Magento/Newsletter/view/adminhtml/layout/newsletter_subscriber_block.xml @@ -51,7 +51,7 @@ problemGrid - + ID subscriber_id @@ -59,7 +59,7 @@ col-id - + Email subscriber_email @@ -67,7 +67,7 @@ ccol-email - + Type type @@ -86,7 +86,7 @@ col-type - + Customer First Name firstname @@ -95,7 +95,7 @@ col-first-name - + Customer Last Name lastname @@ -104,7 +104,7 @@ col-last-name - + Status subscriber_status @@ -131,7 +131,7 @@ col-status - + Web Site website_id @@ -141,7 +141,7 @@ col-website - + Store group_id @@ -151,7 +151,7 @@ col-store - + Store View store_id diff --git a/app/code/Magento/PageCache/view/adminhtml/layout/adminhtml_system_config_edit.xml b/app/code/Magento/PageCache/view/adminhtml/layout/adminhtml_system_config_edit.xml index ac0271434bc62..2938e1bc961d7 100644 --- a/app/code/Magento/PageCache/view/adminhtml/layout/adminhtml_system_config_edit.xml +++ b/app/code/Magento/PageCache/view/adminhtml/layout/adminhtml_system_config_edit.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_paypal_reports_block.xml b/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_paypal_reports_block.xml index 49bc4c48ed416..12dcc46e3ecee 100644 --- a/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_paypal_reports_block.xml +++ b/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_paypal_reports_block.xml @@ -27,7 +27,7 @@ - + Report Date report_date @@ -36,7 +36,7 @@ col-date - + Merchant Account account_id @@ -44,7 +44,7 @@ col-merchant - + Transaction ID transaction_id @@ -52,7 +52,7 @@ col-transaction - + Invoice ID invoice_id @@ -60,7 +60,7 @@ col-invoice - + PayPal Reference ID paypal_reference_id @@ -68,7 +68,7 @@ col-reference - + Event transaction_event_code @@ -78,7 +78,7 @@ ol-event - + Start Date transaction_initiation_date @@ -87,7 +87,7 @@ col-initiation - + Finish Date transaction_completion_date @@ -96,7 +96,7 @@ col-completion - + Gross Amount gross_transaction_amount @@ -106,7 +106,7 @@ col-amount - + Fee Amount fee_amount diff --git a/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_system_config_edit.xml b/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_system_config_edit.xml index c84c9290dd1d5..3f1abb95b8fa7 100644 --- a/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_system_config_edit.xml +++ b/app/code/Magento/Paypal/view/adminhtml/layout/adminhtml_system_config_edit.xml @@ -11,7 +11,7 @@ - + diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_accounts_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_accounts_grid.xml index fa2e8b3d0a986..900dc08d571da 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_accounts_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_accounts_grid.xml @@ -31,7 +31,7 @@ gridAccounts 1 - + New Accounts accounts diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_orders_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_orders_grid.xml index 47af0edcf2c50..d886e5724cb0b 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_orders_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_customer_orders_grid.xml @@ -30,7 +30,7 @@ 1 - + Customer 0 @@ -41,7 +41,7 @@ col-name - + Orders 0 @@ -53,7 +53,7 @@ col-qty - + Average 0 @@ -65,7 +65,7 @@ col-average - + Total 0 diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_grid.xml index aa8dbf74085e7..82aa475807a25 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_grid.xml @@ -46,7 +46,7 @@ We can't find records for this period. We can't find records for this period. - + Interval 0 diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_lowstock_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_lowstock_grid.xml index c0826bd6716c7..070c39259aabd 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_lowstock_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_lowstock_grid.xml @@ -29,7 +29,7 @@ - + Product 0 @@ -38,7 +38,7 @@ col-product - + SKU 0 @@ -47,7 +47,7 @@ col-sku - + Stock Quantity Magento\Backend\Block\Widget\Grid\Column\Filter\Range diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_sold_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_sold_grid.xml index de82b724e8cf0..a1b01aeeb526f 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_sold_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_product_sold_grid.xml @@ -31,7 +31,7 @@ report_product_sold 1 - + Product text @@ -41,7 +41,7 @@ col-product - + SKU text @@ -51,7 +51,7 @@ col-sku - + Ordered Quantity sum diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_customer_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_customer_grid.xml index c3f1c0f242b7b..f941ca52eef59 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_customer_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_customer_grid.xml @@ -40,7 +40,7 @@ - + Customer customer_name @@ -51,7 +51,7 @@ col-name - + Reviews text @@ -60,7 +60,7 @@ col-qty - + Action 0 diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml index f4d2deac0a3da..1275e761ade3c 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml @@ -40,7 +40,7 @@ - + ID entity_id @@ -50,7 +50,7 @@ col-id - + Product text @@ -59,7 +59,7 @@ col-product - + Reviews review_cnt @@ -68,7 +68,7 @@ col-qty - + Average avg_rating @@ -77,7 +77,7 @@ col-rating - + Average (Approved) avg_rating_approved @@ -86,7 +86,7 @@ col-avg-rating - + Last Review datetime @@ -96,7 +96,7 @@ col-date - + Action center diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_statistics_index.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_statistics_index.xml index e02c3c2bea744..4ec984ef9fc11 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_statistics_index.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_statistics_index.xml @@ -42,7 +42,7 @@ 0 gridRefreshStatistics - + Report string @@ -53,7 +53,7 @@ col-report - + Description string @@ -64,7 +64,7 @@ col-description - + Updated datetime diff --git a/app/code/Magento/Review/view/adminhtml/layout/rating_block.xml b/app/code/Magento/Review/view/adminhtml/layout/rating_block.xml index 0b78bb34b31d3..b439bcb1c2710 100644 --- a/app/code/Magento/Review/view/adminhtml/layout/rating_block.xml +++ b/app/code/Magento/Review/view/adminhtml/layout/rating_block.xml @@ -25,7 +25,7 @@ - + ID rating_id @@ -33,19 +33,19 @@ col-id - + Rating rating_code - + Sort Order position - + Is Active is_active diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml index 5cd530defd493..c321bee460e46 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_customer_block.xml @@ -27,26 +27,26 @@ Magento\Backend\Model\Widget\Grid\Row\UrlGeneratorId - + ID entity_id right - + Name name - + Email email - + Phone billing_telephone @@ -54,26 +54,26 @@ col-phone - + ZIP/Post Code billing_postcode - + Country billing_country_id country - + State/Province billing_regione - + Signed-up Point store_name @@ -81,7 +81,7 @@ - + Website website_name diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml index 79b686f7d0a0c..eb0a7685e5e22 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_create_index.xml @@ -21,7 +21,7 @@ - + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml index 3ee6753d743d2..7f14ff3728a47 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_grid_block.xml @@ -30,7 +30,7 @@ - + Credit Memo text @@ -40,7 +40,7 @@ col-memo - + billing_name Bill-to Name @@ -49,7 +49,7 @@ col-name - + Created datetime @@ -59,7 +59,7 @@ col-period - + state Status @@ -70,7 +70,7 @@ col-status - + base_grand_total Refunded diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml index e1db288398c7b..0c1b395b5116d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_new.xml @@ -18,7 +18,7 @@ - + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml index e373eb0461dc5..29a61308391c6 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_updateqty.xml @@ -9,7 +9,7 @@ - + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml index ffae243c3e5bc..61dda8e23301d 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_creditmemo_view.xml @@ -17,7 +17,7 @@ - + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml index 52492c0f250e3..941696f0ce898 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_grid_block.xml @@ -30,7 +30,7 @@ - + Invoice text @@ -40,7 +40,7 @@ col-invoice-number - + billing_name Bill-to Name @@ -49,7 +49,7 @@ col-name - + Invoice Date datetime @@ -59,7 +59,7 @@ col-period - + state Status @@ -70,7 +70,7 @@ col-status - + grand_total Amount diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml index 9f443425e1ac3..def5ebaf546cd 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_new.xml @@ -21,7 +21,7 @@ - + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml index 2e972172fd10a..4df3f057f6a58 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_updateqty.xml @@ -9,7 +9,7 @@ - + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml index 2a6598d69462e..6227412852c84 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_invoice_view.xml @@ -18,7 +18,7 @@ - + diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml index 8d783975a404f..0180efd29d2fc 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_shipment_grid_block.xml @@ -30,7 +30,7 @@ - + Shipment text @@ -40,7 +40,7 @@ col-memo - + shipping_name Ship-to Name @@ -49,7 +49,7 @@ col-name - + Ship Date datetime @@ -59,7 +59,7 @@ col-period - + total_qty Total Quantity diff --git a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml index e96932789e70e..87d7644a4b00f 100644 --- a/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml +++ b/app/code/Magento/Sales/view/adminhtml/layout/sales_order_status_index.xml @@ -27,13 +27,13 @@ 1 - + Status label - + Status Code status @@ -42,7 +42,7 @@ 200 - + Default Status is_default @@ -62,7 +62,7 @@ - + Visible On Storefront visible_on_front @@ -82,14 +82,14 @@ - + State Code and Title state text - + Action unassign diff --git a/app/code/Magento/SalesRule/view/adminhtml/layout/sales_rule_promo_quote_index.xml b/app/code/Magento/SalesRule/view/adminhtml/layout/sales_rule_promo_quote_index.xml index 4b670d5815554..21ce8bfc3eaac 100644 --- a/app/code/Magento/SalesRule/view/adminhtml/layout/sales_rule_promo_quote_index.xml +++ b/app/code/Magento/SalesRule/view/adminhtml/layout/sales_rule_promo_quote_index.xml @@ -26,7 +26,7 @@ - + ID rule_id @@ -34,19 +34,19 @@ col-id - + Rule name - + Coupon Code code - + Start date @@ -56,7 +56,7 @@ col-date - + End date @@ -67,7 +67,7 @@ col-date - + Status is_active @@ -84,7 +84,7 @@ - + Web Site website_ids @@ -93,7 +93,7 @@ - + Priority sort_order diff --git a/app/code/Magento/Search/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/Search/view/adminhtml/layout/adminhtml_dashboard_index.xml index f5ec48c2d5c58..2efe8cb8f0104 100644 --- a/app/code/Magento/Search/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/Search/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -8,8 +8,8 @@ - - + + diff --git a/app/code/Magento/Search/view/adminhtml/layout/search_term_block.xml b/app/code/Magento/Search/view/adminhtml/layout/search_term_block.xml index 594a3993d3adb..cc2e1509e4412 100644 --- a/app/code/Magento/Search/view/adminhtml/layout/search_term_block.xml +++ b/app/code/Magento/Search/view/adminhtml/layout/search_term_block.xml @@ -38,7 +38,7 @@ - + ID 0 @@ -48,7 +48,7 @@ col-id - + Search Query query_text @@ -56,7 +56,7 @@ col-query - + Store store_id @@ -68,7 +68,7 @@ col-store - + Results number @@ -77,7 +77,7 @@ col-results - + Hits number diff --git a/app/code/Magento/Search/view/adminhtml/layout/search_term_grid_block.xml b/app/code/Magento/Search/view/adminhtml/layout/search_term_grid_block.xml index 6bc9680aa3ba6..7330ac1f92712 100644 --- a/app/code/Magento/Search/view/adminhtml/layout/search_term_grid_block.xml +++ b/app/code/Magento/Search/view/adminhtml/layout/search_term_grid_block.xml @@ -39,13 +39,13 @@ - + Search Query query_text - + Store store @@ -55,27 +55,27 @@ 0 - + Results num_results number - + Uses popularity number - + Redirect URL redirect - + Suggested Terms 1 @@ -93,7 +93,7 @@ - + action Action diff --git a/app/code/Magento/Search/view/adminhtml/layout/search_term_report_block.xml b/app/code/Magento/Search/view/adminhtml/layout/search_term_report_block.xml index 83f8d94897b67..b6b1455cf27ca 100644 --- a/app/code/Magento/Search/view/adminhtml/layout/search_term_report_block.xml +++ b/app/code/Magento/Search/view/adminhtml/layout/search_term_report_block.xml @@ -41,7 +41,7 @@ - + ID 0 @@ -51,7 +51,7 @@ col-id - + Search Query query_text @@ -59,7 +59,7 @@ col-query - + Store store_id @@ -71,7 +71,7 @@ col-store - + Results number @@ -80,7 +80,7 @@ col-results - + Hits number diff --git a/app/code/Magento/Sitemap/view/adminhtml/layout/adminhtml_sitemap_index_grid_block.xml b/app/code/Magento/Sitemap/view/adminhtml/layout/adminhtml_sitemap_index_grid_block.xml index 23c96db891a15..cdaa6575d559c 100644 --- a/app/code/Magento/Sitemap/view/adminhtml/layout/adminhtml_sitemap_index_grid_block.xml +++ b/app/code/Magento/Sitemap/view/adminhtml/layout/adminhtml_sitemap_index_grid_block.xml @@ -24,7 +24,7 @@ - + ID sitemap_id @@ -32,25 +32,25 @@ col-id - + Filename sitemap_filename - + Path sitemap_path - + Link for Google Magento\Sitemap\Block\Adminhtml\Grid\Renderer\Link - + Last Generated sitemap_time @@ -59,7 +59,7 @@ col-date - + Store View store @@ -68,7 +68,7 @@ true - + Action 0 diff --git a/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit.xml b/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit.xml index 481c0b2293d0c..018db9cbfe7b1 100644 --- a/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit.xml +++ b/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit.xml @@ -12,8 +12,8 @@ - - + + diff --git a/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml b/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml index 03a724c3c62e3..7d6872139ba0f 100755 --- a/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml +++ b/app/code/Magento/Swatches/view/adminhtml/layout/catalog_product_attribute_edit_popup.xml @@ -12,8 +12,8 @@ - - + + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml b/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml index edbdec6f48115..69a4c3f944daa 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalog_category_view.xml @@ -11,7 +11,7 @@ - + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml index edbdec6f48115..69a4c3f944daa 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_advanced_result.xml @@ -11,7 +11,7 @@ - + diff --git a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml index 04972bac26d78..3d8c8dd020421 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/catalogsearch_result_index.xml @@ -11,7 +11,7 @@ - + diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml index ecc8092a565d0..5e42b835c035d 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml @@ -25,7 +25,7 @@ - + Name code @@ -35,7 +35,7 @@ col-name - + Customer Tax Class 0 @@ -46,7 +46,7 @@ - + Product Tax Class 0 @@ -57,7 +57,7 @@ - + Tax Rate 0 @@ -69,21 +69,21 @@ Magento\Tax\Block\Grid\Renderer\Codes - + Priority priority text - + Subtotal Only calculate_subtotal text - + Sort Order position diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml index bb050eead617f..fb19104a8c009 100644 --- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml +++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_edit.xml @@ -12,7 +12,7 @@ - + diff --git a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_block.xml b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_block.xml index 94a1d4f1f75ae..bb8fbd44629cf 100644 --- a/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_block.xml +++ b/app/code/Magento/Theme/view/adminhtml/layout/adminhtml_system_design_theme_block.xml @@ -28,7 +28,7 @@ - + Theme Title theme_title @@ -36,7 +36,7 @@ theme-title - + Parent Theme parent_theme_title @@ -44,7 +44,7 @@ parent-theme-title - + Theme Path theme_path diff --git a/app/code/Magento/Ups/view/adminhtml/layout/adminhtml_system_config_edit.xml b/app/code/Magento/Ups/view/adminhtml/layout/adminhtml_system_config_edit.xml index 4b056d852a1a9..ba79f98fde700 100644 --- a/app/code/Magento/Ups/view/adminhtml/layout/adminhtml_system_config_edit.xml +++ b/app/code/Magento/Ups/view/adminhtml/layout/adminhtml_system_config_edit.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/UrlRewrite/view/adminhtml/layout/adminhtml_url_rewrite_index.xml b/app/code/Magento/UrlRewrite/view/adminhtml/layout/adminhtml_url_rewrite_index.xml index a1cd1b2966db7..7d8151d270308 100644 --- a/app/code/Magento/UrlRewrite/view/adminhtml/layout/adminhtml_url_rewrite_index.xml +++ b/app/code/Magento/UrlRewrite/view/adminhtml/layout/adminhtml_url_rewrite_index.xml @@ -24,7 +24,7 @@ - + ID text @@ -34,7 +34,7 @@ col-id - + Store View store @@ -43,7 +43,7 @@ true - + Request Path text @@ -51,7 +51,7 @@ request_path - + Target Path text @@ -59,7 +59,7 @@ target_path - + Redirect Type options @@ -68,7 +68,7 @@ - + Action 0 diff --git a/app/code/Magento/User/view/adminhtml/layout/adminhtml_locks_block.xml b/app/code/Magento/User/view/adminhtml/layout/adminhtml_locks_block.xml index 326e7d3734916..13cfbfe859333 100644 --- a/app/code/Magento/User/view/adminhtml/layout/adminhtml_locks_block.xml +++ b/app/code/Magento/User/view/adminhtml/layout/adminhtml_locks_block.xml @@ -33,11 +33,11 @@ - + lockedAdminsGrid - + ID number @@ -48,7 +48,7 @@ col-id - + Username text @@ -58,7 +58,7 @@ col-name - + Last login datetime @@ -69,7 +69,7 @@ col-date - + Failures 0 @@ -77,7 +77,7 @@ failures_num - + Unlocked datetime diff --git a/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_grid_block.xml b/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_grid_block.xml index b182dc7a4afbf..7ce62918a8a6f 100644 --- a/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_grid_block.xml +++ b/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_grid_block.xml @@ -28,7 +28,7 @@ - + ID true @@ -37,7 +37,7 @@ col-id - + User Name text @@ -47,7 +47,7 @@ col-name - + First Name text @@ -57,7 +57,7 @@ col-name - + Last Name text @@ -67,14 +67,14 @@ col-name - + Email text email - + Status options diff --git a/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_role_grid_block.xml b/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_role_grid_block.xml index a33d96868026a..6d7ce67e2352b 100644 --- a/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_role_grid_block.xml +++ b/app/code/Magento/User/view/adminhtml/layout/adminhtml_user_role_grid_block.xml @@ -30,7 +30,7 @@ - + ID role_id @@ -38,7 +38,7 @@ col-id - + Role text diff --git a/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml b/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml index a66871163b262..d934e46117fb1 100644 --- a/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml +++ b/app/code/Magento/Variable/view/adminhtml/layout/adminhtml_system_variable_grid_block.xml @@ -24,7 +24,7 @@ - + Variable ID variable_id @@ -32,13 +32,13 @@ col-id - + Variable Code code - + Name name diff --git a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml index fc981e8a5fe76..934b0ca1a85b2 100644 --- a/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml +++ b/app/code/Magento/Widget/view/adminhtml/layout/adminhtml_widget_instance_block.xml @@ -25,7 +25,7 @@ - + Widget ID instance_id @@ -33,13 +33,13 @@ col-id - + Widget title - + Type instance_type @@ -47,7 +47,7 @@ - + Design Theme theme_id @@ -56,7 +56,7 @@ 1 - + Sort Order sort_order diff --git a/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml b/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml index 3517169f587c5..95b786603390c 100644 --- a/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml +++ b/app/code/Magento/Wishlist/view/adminhtml/layout/customer_index_wishlist.xml @@ -30,7 +30,7 @@ No Items Found - + Product Name product_name @@ -41,7 +41,7 @@ col-name - + User Description description @@ -49,7 +49,7 @@ Magento\Customer\Block\Adminhtml\Edit\Tab\Wishlist\Grid\Renderer\Description - + Quantity qty @@ -57,14 +57,14 @@ qty - + Add Locale store_id store - + Add Date added_at @@ -73,7 +73,7 @@ added_at - + Days in Wish List days_in_wishlist @@ -81,7 +81,7 @@ days - + Action wishlist_item_id @@ -104,7 +104,7 @@ - + wishlistGridJsObject Magento_Wishlist::customer/edit/tab/wishlist.phtml diff --git a/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml b/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml index b00266f365cba..a4860ace166d8 100644 --- a/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml +++ b/app/code/Magento/Wishlist/view/frontend/layout/catalog_category_view.xml @@ -21,7 +21,7 @@ template="Magento_Wishlist::catalog/product/list/addto/wishlist.phtml"/> - +
From 118c86ca575088e50fa4fd53aed83f15a0661135 Mon Sep 17 00:00:00 2001 From: Ihor Sviziev Date: Thu, 27 Jul 2017 18:07:06 +0300 Subject: [PATCH 029/528] Add missing block name to allow block customisation (cherry picked from commit 2e70f00) --- .../frontend/layout/checkout_onepage_review_item_renderers.xml | 2 +- .../frontend/layout/sales_email_order_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_email_order_invoice_renderers.xml | 2 +- .../Bundle/view/frontend/layout/sales_email_order_renderers.xml | 2 +- .../frontend/layout/sales_email_order_shipment_renderers.xml | 2 +- .../view/frontend/layout/sales_order_creditmemo_renderers.xml | 2 +- .../view/frontend/layout/sales_order_invoice_renderers.xml | 2 +- .../Bundle/view/frontend/layout/sales_order_item_renderers.xml | 2 +- .../frontend/layout/sales_order_print_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_order_print_invoice_renderers.xml | 2 +- .../Bundle/view/frontend/layout/sales_order_print_renderers.xml | 2 +- .../frontend/layout/sales_order_print_shipment_renderers.xml | 2 +- .../view/frontend/layout/sales_order_shipment_renderers.xml | 2 +- .../frontend/layout/checkout_onepage_review_item_renderers.xml | 2 +- .../frontend/layout/sales_email_order_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_email_order_invoice_renderers.xml | 2 +- .../view/frontend/layout/sales_email_order_renderers.xml | 2 +- .../view/frontend/layout/sales_order_creditmemo_renderers.xml | 2 +- .../view/frontend/layout/sales_order_invoice_renderers.xml | 2 +- .../view/frontend/layout/sales_order_item_renderers.xml | 2 +- .../frontend/layout/sales_order_print_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_order_print_invoice_renderers.xml | 2 +- .../view/frontend/layout/sales_order_print_renderers.xml | 2 +- .../view/frontend/layout/checkout_cart_item_renderers.xml | 2 +- .../frontend/layout/checkout_onepage_review_item_renderers.xml | 2 +- .../frontend/layout/sales_email_order_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_email_order_invoice_renderers.xml | 2 +- .../view/frontend/layout/sales_email_order_renderers.xml | 2 +- .../view/frontend/layout/sales_order_creditmemo_renderers.xml | 2 +- .../view/frontend/layout/sales_order_invoice_renderers.xml | 2 +- .../view/frontend/layout/sales_order_item_renderers.xml | 2 +- .../frontend/layout/sales_order_print_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_order_print_invoice_renderers.xml | 2 +- .../view/frontend/layout/sales_order_print_renderers.xml | 2 +- .../frontend/layout/sales_email_order_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_email_order_invoice_renderers.xml | 2 +- .../frontend/layout/sales_email_order_shipment_renderers.xml | 2 +- .../view/frontend/layout/sales_order_creditmemo_renderers.xml | 2 +- .../view/frontend/layout/sales_order_invoice_renderers.xml | 2 +- .../Sales/view/frontend/layout/sales_order_item_renderers.xml | 2 +- .../frontend/layout/sales_order_print_creditmemo_renderers.xml | 2 +- .../frontend/layout/sales_order_print_invoice_renderers.xml | 2 +- .../Sales/view/frontend/layout/sales_order_print_renderers.xml | 2 +- .../frontend/layout/sales_order_print_shipment_renderers.xml | 2 +- .../view/frontend/layout/sales_order_shipment_renderers.xml | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) diff --git a/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml index dce5945e3221d..686e12da7de21 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/checkout_onepage_review_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml index 97f07511d2fda..f92a04de2b57c 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml index 1041965f2c77b..051365f99021f 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml index f46300afd518c..b48e196c52866 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml index d6e8812b02165..c2c80e0ba6763 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_email_order_shipment_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml index da9b7fa494ed4..deb7334b726b3 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml index a1c1d23ad4788..c4865e22ad9be 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml index c02075bee5e59..86cfb1c0f7ade 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml index 2f16633a2bcca..bd1310acbcdee 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml index f143da9b57dfe..5bea1dd1c672e 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml index 384a0665a80f7..27c7aabfeb195 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml index bfa85a0a9c9d8..481d72ae10bdb 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_print_shipment_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml b/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml index e1b6ba0e86130..99124dfeeef93 100644 --- a/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml +++ b/app/code/Magento/Bundle/view/frontend/layout/sales_order_shipment_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/checkout_onepage_review_item_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/checkout_onepage_review_item_renderers.xml index a067c9b77d1e8..9929efe85c924 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/checkout_onepage_review_item_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/checkout_onepage_review_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_creditmemo_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_creditmemo_renderers.xml index 5772a322c1c80..34e61b3c59ae4 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_creditmemo_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_invoice_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_invoice_renderers.xml index 8d6e3b364c55a..ab9adf10cc59c 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_invoice_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_renderers.xml index 3aeec25a27a66..8e1866c5028a1 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_email_order_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_creditmemo_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_creditmemo_renderers.xml index e52604bae38bd..fd9acd0268cf6 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_creditmemo_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_invoice_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_invoice_renderers.xml index 6d233cb56be47..75aa46b38c419 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_invoice_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_item_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_item_renderers.xml index 53d2e6c2875bb..89274506eadee 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_item_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_creditmemo_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_creditmemo_renderers.xml index 8720ebe1ce6a4..9bb75ff838549 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_creditmemo_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_invoice_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_invoice_renderers.xml index 2b37982706919..4a3ebd34d5be1 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_invoice_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_renderers.xml b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_renderers.xml index 1077e7db05fb6..1efd0adfc28d6 100644 --- a/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_renderers.xml +++ b/app/code/Magento/Downloadable/view/frontend/layout/sales_order_print_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_cart_item_renderers.xml index 958f73c6c1576..03a1d3745220d 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_cart_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml index dabddb4f4d851..f3bf47e5b17af 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/checkout_onepage_review_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_creditmemo_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_creditmemo_renderers.xml index 1cd91018be9e7..77875ac70427c 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_creditmemo_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_invoice_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_invoice_renderers.xml index 21cd7dd0173a1..06afa045f574b 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_invoice_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_renderers.xml index e8f56212470a0..afcd902420d15 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_email_order_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_creditmemo_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_creditmemo_renderers.xml index 72da33456f1ec..379f8faafa942 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_creditmemo_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_invoice_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_invoice_renderers.xml index c451fe6baca30..57eeb4c360666 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_invoice_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_item_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_item_renderers.xml index 339ba3629b955..fee947e013c4a 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_item_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_creditmemo_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_creditmemo_renderers.xml index 2d0a482c02d10..5f8ed4a319492 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_creditmemo_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_invoice_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_invoice_renderers.xml index ffa26e8d1ecca..bac5c6a6fef3a 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_invoice_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_renderers.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_renderers.xml index 0d48958e4784c..d20043ee5c9f4 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_renderers.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/sales_order_print_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_creditmemo_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_creditmemo_renderers.xml index bbbc606a58cd5..e2d859cb66f63 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_creditmemo_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_invoice_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_invoice_renderers.xml index 37d3e468329d7..06520d80e27a3 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_invoice_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_renderers.xml index 6e1eb26986cc7..48a7c68b538b5 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_creditmemo_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_creditmemo_renderers.xml index ff82bcdff2111..1e6b510c8f822 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_creditmemo_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_invoice_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_invoice_renderers.xml index d1c9d765b5101..4cdff0e304f70 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_invoice_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_item_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_item_renderers.xml index c8c94cef5bc4c..d10f957151a12 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_item_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_item_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_creditmemo_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_creditmemo_renderers.xml index a010534052bf5..87a826fbfa448 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_creditmemo_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_creditmemo_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_invoice_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_invoice_renderers.xml index 3ed5b275666d5..34593a20f1188 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_invoice_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_invoice_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_renderers.xml index 1c1d3bf1504ba..095283c89c2ee 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_shipment_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_shipment_renderers.xml index 231b283a12643..57f812e180aa1 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_print_shipment_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_print_shipment_renderers.xml @@ -8,7 +8,7 @@ - + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_shipment_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_shipment_renderers.xml index a666ef5d6c5bd..61870813b8659 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_shipment_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_shipment_renderers.xml @@ -8,7 +8,7 @@ - + From 7f30f6cba92d3c2b41fd4aeec6ca3773392a7d46 Mon Sep 17 00:00:00 2001 From: kweij Date: Thu, 24 Aug 2017 16:39:51 +0300 Subject: [PATCH 030/528] Add names to existing block Add names to blocks in layout XML `catalog_product_view_type_grouped.xml` to make them accessible (cherry picked from commit a4edec7) --- .../frontend/layout/catalog_product_view_type_grouped.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/GroupedProduct/view/frontend/layout/catalog_product_view_type_grouped.xml b/app/code/Magento/GroupedProduct/view/frontend/layout/catalog_product_view_type_grouped.xml index a9ba334e53c28..a774f384d947a 100644 --- a/app/code/Magento/GroupedProduct/view/frontend/layout/catalog_product_view_type_grouped.xml +++ b/app/code/Magento/GroupedProduct/view/frontend/layout/catalog_product_view_type_grouped.xml @@ -13,10 +13,10 @@ - + - + From 4a038feacccfabc322b021db360c6667e5a76031 Mon Sep 17 00:00:00 2001 From: alojua Date: Thu, 27 Jul 2017 15:32:32 +0300 Subject: [PATCH 031/528] Add missing block name to allow block customisation (cherry picked from commit 50105b4) --- .../Sales/view/frontend/layout/sales_email_order_renderers.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_renderers.xml b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_renderers.xml index 9eaf7370eaa8b..845d03e119280 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_renderers.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_renderers.xml @@ -8,7 +8,7 @@ - + From a248de519ff82c8ba6efe517e2e5132317d298c9 Mon Sep 17 00:00:00 2001 From: alojua Date: Tue, 25 Jul 2017 15:42:39 +0300 Subject: [PATCH 032/528] Adding missing block names in checkout_cart_item_renderers.xml layout to be able to extend them using referenceBlock functionality (cherry picked from commit d2a37e4) --- .../view/frontend/layout/checkout_cart_item_renderers.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_item_renderers.xml b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_item_renderers.xml index 3e931611b9189..692089333715a 100644 --- a/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_item_renderers.xml +++ b/app/code/Magento/Checkout/view/frontend/layout/checkout_cart_item_renderers.xml @@ -9,13 +9,13 @@ - + - + From e1d437a70f0429a8c24711f48d3eeb29b786a47b Mon Sep 17 00:00:00 2001 From: aakimov Date: Thu, 5 Oct 2017 12:11:07 +0300 Subject: [PATCH 033/528] MAGETWO-80203: [2.2.x] Asymmetric Transaction Error with ElasticSearch --- app/code/Magento/Catalog/Model/Product/Gallery/Processor.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php index 977d93f350145..31e322f4e38f2 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/Processor.php @@ -192,6 +192,7 @@ public function addImage( $mediaGalleryData['images'][] = [ 'file' => $fileName, 'position' => $position, + 'media_type' => 'image', 'label' => '', 'disabled' => (int)$exclude, ]; From 16a8050e1252a943a80cf111b8392102135df617 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 5 Oct 2017 12:25:47 +0200 Subject: [PATCH 034/528] check for null to actually reach the code that handles this case to throw the appropriate exception --- lib/internal/Magento/Framework/View/Model/Layout/Merge.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/View/Model/Layout/Merge.php b/lib/internal/Magento/Framework/View/Model/Layout/Merge.php index 97cbeb83a7a86..1bae54e8728d9 100644 --- a/lib/internal/Magento/Framework/View/Model/Layout/Merge.php +++ b/lib/internal/Magento/Framework/View/Model/Layout/Merge.php @@ -799,7 +799,7 @@ private function getXmlErrors($libXmlErrors) protected function _getPhysicalTheme(\Magento\Framework\View\Design\ThemeInterface $theme) { $result = $theme; - while ($result->getId() && !$result->isPhysical()) { + while (!is_null($result) && $result->getId() && !$result->isPhysical()) { $result = $result->getParentTheme(); } if (!$result) { From 0da089d0a662d3da69200ec84e108c09a85339c2 Mon Sep 17 00:00:00 2001 From: Navarr Barnier Date: Thu, 5 Oct 2017 10:07:05 -0400 Subject: [PATCH 035/528] Add a payload extender to the default shipping-save-processor This will allow third party extensions to modify the payload for the shipping address selection process, with the goal being the easy addition of extension_attributes with as few extension conflicts as possible. By separating this out into it's own model (as opposed to including it in the result of the processor return), non-default processors will also be able to utilize it. Backports #10991 to 2.2 --- .../web/js/model/shipping-save-processor/default.js | 8 ++++++-- .../shipping-save-processor/payload-extender.js | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/payload-extender.js diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js index b2a273513181d..3a6574bff8948 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/default.js @@ -12,7 +12,8 @@ define([ 'Magento_Checkout/js/model/payment/method-converter', 'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/full-screen-loader', - 'Magento_Checkout/js/action/select-billing-address' + 'Magento_Checkout/js/action/select-billing-address', + 'Magento_Checkout/js/model/shipping-save-processor/payload-extender' ], function ( ko, quote, @@ -22,7 +23,8 @@ define([ methodConverter, errorProcessor, fullScreenLoader, - selectBillingAddressAction + selectBillingAddressAction, + payloadExtender ) { 'use strict'; @@ -46,6 +48,8 @@ define([ } }; + payloadExtender(payload); + fullScreenLoader.startLoader(); return storage.post( diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/payload-extender.js b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/payload-extender.js new file mode 100644 index 0000000000000..9a082a056a382 --- /dev/null +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/shipping-save-processor/payload-extender.js @@ -0,0 +1,13 @@ +/** + * Copyright © 2013-2017 Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define(function () { + 'use strict'; + + return function (payload) { + payload.addressInformation['extension_attributes'] = {}; + + return payload; + }; +}); From c2b7513c03ca0dee00e5e924d5542042536d7db7 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi Date: Thu, 5 Oct 2017 18:02:24 +0300 Subject: [PATCH 036/528] MAGETWO-80188: [2.2.x] - Prevent change log entry when nothing has changed #4893 --- app/etc/di.xml | 7 +++ .../Framework/Mview/View/Subscription.php | 62 ++++++++++++++----- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/app/etc/di.xml b/app/etc/di.xml index 71168ab5220f7..e17505e78da31 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -1337,4 +1337,11 @@ Magento\Framework\Message\ExceptionMessageFactory + + + + updated_at + + + diff --git a/lib/internal/Magento/Framework/Mview/View/Subscription.php b/lib/internal/Magento/Framework/Mview/View/Subscription.php index e621909ec99b6..f2019d6f8c3df 100644 --- a/lib/internal/Magento/Framework/Mview/View/Subscription.php +++ b/lib/internal/Magento/Framework/Mview/View/Subscription.php @@ -57,6 +57,14 @@ class Subscription implements SubscriptionInterface */ protected $resource; + /** + * List of columns that can be updated in a subscribed table + * without creating a new change log entry + * + * @var array + */ + private $ignoredUpdateColumns = []; + /** * @param ResourceConnection $resource * @param \Magento\Framework\DB\Ddl\TriggerFactory $triggerFactory @@ -64,6 +72,7 @@ class Subscription implements SubscriptionInterface * @param \Magento\Framework\Mview\ViewInterface $view * @param string $tableName * @param string $columnName + * @param array $ignoredUpdateColumns */ public function __construct( ResourceConnection $resource, @@ -71,7 +80,8 @@ public function __construct( \Magento\Framework\Mview\View\CollectionInterface $viewCollection, \Magento\Framework\Mview\ViewInterface $view, $tableName, - $columnName + $columnName, + $ignoredUpdateColumns = [] ) { $this->connection = $resource->getConnection(); $this->triggerFactory = $triggerFactory; @@ -80,6 +90,7 @@ public function __construct( $this->tableName = $tableName; $this->columnName = $columnName; $this->resource = $resource; + $this->ignoredUpdateColumns = $ignoredUpdateColumns; } /** @@ -175,7 +186,7 @@ protected function getLinkedViews() } /** - * Build trigger statement for INSER, UPDATE, DELETE events + * Build trigger statement for INSERT, UPDATE, DELETE events * * @param string $event * @param \Magento\Framework\Mview\View\ChangelogInterface $changelog @@ -185,25 +196,48 @@ protected function buildStatement($event, $changelog) { switch ($event) { case Trigger::EVENT_INSERT: + $trigger = "INSERT IGNORE INTO %s (%s) VALUES (NEW.%s);"; + break; + case Trigger::EVENT_UPDATE: - return sprintf( - "INSERT IGNORE INTO %s (%s) VALUES (NEW.%s);", - $this->connection->quoteIdentifier($this->resource->getTableName($changelog->getName())), - $this->connection->quoteIdentifier($changelog->getColumnName()), - $this->connection->quoteIdentifier($this->getColumnName()) - ); + $trigger = "INSERT IGNORE INTO %s (%s) VALUES (NEW.%s);"; + + if ($this->connection->isTableExists($this->getTableName()) + && $describe = $this->connection->describeTable($this->getTableName()) + ) { + $columnNames = array_column($describe, 'COLUMN_NAME'); + $columnNames = array_diff($columnNames, $this->ignoredUpdateColumns); + if ($columnNames) { + $columns = []; + foreach ($columnNames as $columnName) { + $columns[] = sprintf( + 'NEW.%1$s != OLD.%1$s', + $this->connection->quoteIdentifier($columnName) + ); + } + $trigger = sprintf( + "IF (%s) THEN %s END IF;", + implode(' OR ', $columns), + $trigger + ); + } + } + break; case Trigger::EVENT_DELETE: - return sprintf( - "INSERT IGNORE INTO %s (%s) VALUES (OLD.%s);", - $this->connection->quoteIdentifier($this->resource->getTableName($changelog->getName())), - $this->connection->quoteIdentifier($changelog->getColumnName()), - $this->connection->quoteIdentifier($this->getColumnName()) - ); + $trigger = "INSERT IGNORE INTO %s (%s) VALUES (OLD.%s);"; + break; default: return ''; } + + return sprintf( + $trigger, + $this->connection->quoteIdentifier($this->resource->getTableName($changelog->getName())), + $this->connection->quoteIdentifier($changelog->getColumnName()), + $this->connection->quoteIdentifier($this->getColumnName()) + ); } /** From 378ea5073184b233153c14ed4ec3ba4b964245d7 Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 5 Oct 2017 10:49:20 -0500 Subject: [PATCH 037/528] MAGETWO-80488: Apply AR code from previous development - remove @since annotation in Analytics module --- .../Analytics/Api/Data/LinkInterface.php | 3 -- .../Analytics/Api/LinkProviderInterface.php | 2 -- .../System/Config/AdditionalComment.php | 3 -- .../System/Config/CollectionTimeLabel.php | 2 -- .../System/Config/SubscriptionStatusLabel.php | 5 ---- .../Adminhtml/System/Config/Vertical.php | 3 -- .../Adminhtml/BIEssentials/SignUp.php | 6 ---- .../Controller/Adminhtml/Reports/Show.php | 5 ---- .../Adminhtml/Subscription/Retry.php | 5 ---- .../Magento/Analytics/Cron/CollectData.php | 5 ---- app/code/Magento/Analytics/Cron/SignUp.php | 8 ----- app/code/Magento/Analytics/Cron/Update.php | 8 ----- .../Analytics/Model/AnalyticsToken.php | 9 ------ .../Model/Condition/CanViewNotification.php | 5 ---- app/code/Magento/Analytics/Model/Config.php | 4 --- .../Baseurl/SubscriptionUpdateHandler.php | 9 ------ .../Model/Config/Backend/CollectionTime.php | 4 --- .../Model/Config/Backend/Enabled.php | 4 --- .../Backend/Enabled/SubscriptionHandler.php | 13 --------- .../Model/Config/Backend/Vertical.php | 2 -- .../Magento/Analytics/Model/Config/Mapper.php | 2 -- .../Magento/Analytics/Model/Config/Reader.php | 5 ---- .../Model/Config/Source/Vertical.php | 4 --- .../Analytics/Model/ConfigInterface.php | 2 -- .../Magento/Analytics/Model/Connector.php | 5 ---- .../Model/Connector/CommandInterface.php | 2 -- .../Model/Connector/Http/Client/Curl.php | 8 ----- .../Model/Connector/Http/ClientInterface.php | 2 -- .../Connector/Http/ConverterInterface.php | 4 --- .../Model/Connector/Http/JsonConverter.php | 4 --- .../Model/Connector/Http/ResponseFactory.php | 2 -- .../Http/ResponseHandlerInterface.php | 2 -- .../Model/Connector/Http/ResponseResolver.php | 5 ---- .../Connector/NotifyDataChangedCommand.php | 9 ------ .../Analytics/Model/Connector/OTPRequest.php | 9 ------ .../Model/Connector/ResponseHandler/OTP.php | 2 -- .../Connector/ResponseHandler/ReSignUp.php | 6 ---- .../Connector/ResponseHandler/SignUp.php | 5 ---- .../Connector/ResponseHandler/Update.php | 2 -- .../Model/Connector/SignUpCommand.php | 10 ------- .../Model/Connector/UpdateCommand.php | 10 ------- .../Magento/Analytics/Model/Cryptographer.php | 10 ------- .../Analytics/Model/EncodedContext.php | 6 ---- .../State/SubscriptionUpdateException.php | 1 - .../Analytics/Model/ExportDataHandler.php | 16 ---------- .../Model/ExportDataHandlerInterface.php | 2 -- .../Model/ExportDataHandlerNotification.php | 5 ---- app/code/Magento/Analytics/Model/FileInfo.php | 6 ---- .../Analytics/Model/FileInfoManager.php | 10 ------- .../Magento/Analytics/Model/FileRecorder.php | 11 ------- .../Analytics/Model/IntegrationManager.php | 9 ------ app/code/Magento/Analytics/Model/Link.php | 6 ---- .../Magento/Analytics/Model/LinkProvider.php | 8 ----- .../Analytics/Model/NotificationTime.php | 8 ----- .../Model/Plugin/BaseUrlConfigPlugin.php | 5 ---- .../Analytics/Model/ProviderFactory.php | 4 --- .../Analytics/Model/ReportUrlProvider.php | 8 ----- .../Magento/Analytics/Model/ReportWriter.php | 7 ----- .../Analytics/Model/ReportWriterInterface.php | 2 -- .../Model/ReportXml/ModuleIterator.php | 4 --- .../Model/StoreConfigurationProvider.php | 7 ----- .../Model/SubscriptionStatusProvider.php | 8 ----- .../NotificationAboutFailedSubscription.php | 8 ----- .../Magento/Analytics/ReportXml/Config.php | 4 --- .../ReportXml/Config/Converter/Xml.php | 3 -- .../Analytics/ReportXml/Config/Mapper.php | 2 -- .../Analytics/ReportXml/Config/Reader.php | 5 ---- .../Analytics/ReportXml/ConfigInterface.php | 2 -- .../Analytics/ReportXml/ConnectionFactory.php | 5 ---- .../DB/Assembler/AssemblerInterface.php | 2 -- .../DB/Assembler/FilterAssembler.php | 5 ---- .../ReportXml/DB/Assembler/FromAssembler.php | 6 ---- .../ReportXml/DB/Assembler/JoinAssembler.php | 7 ----- .../ReportXml/DB/ColumnsResolver.php | 7 ----- .../ReportXml/DB/ConditionResolver.php | 9 ------ .../Analytics/ReportXml/DB/NameResolver.php | 3 -- .../ReportXml/DB/ReportValidator.php | 5 ---- .../Analytics/ReportXml/DB/SelectBuilder.php | 29 ------------------- .../ReportXml/DB/SelectBuilderFactory.php | 4 --- .../Analytics/ReportXml/IteratorFactory.php | 5 ---- .../Magento/Analytics/ReportXml/Query.php | 9 ------ .../Analytics/ReportXml/QueryFactory.php | 11 ------- .../Analytics/ReportXml/ReportProvider.php | 7 ----- .../Analytics/ReportXml/SelectHydrator.php | 10 ------- .../Magento/Analytics/Setup/InstallData.php | 2 -- .../Ui/DataProvider/DummyDataProvider.php | 22 -------------- 86 files changed, 520 deletions(-) diff --git a/app/code/Magento/Analytics/Api/Data/LinkInterface.php b/app/code/Magento/Analytics/Api/Data/LinkInterface.php index f2b1ec579c4ab..6597dff868b9f 100644 --- a/app/code/Magento/Analytics/Api/Data/LinkInterface.php +++ b/app/code/Magento/Analytics/Api/Data/LinkInterface.php @@ -9,19 +9,16 @@ * Interface LinkInterface * * Represents link with collected data and initialized vector for decryption. - * @since 2.2.0 */ interface LinkInterface { /** * @return string - * @since 2.2.0 */ public function getUrl(); /** * @return string - * @since 2.2.0 */ public function getInitializationVector(); } diff --git a/app/code/Magento/Analytics/Api/LinkProviderInterface.php b/app/code/Magento/Analytics/Api/LinkProviderInterface.php index 54b21ed731e3d..6ee43a423337e 100644 --- a/app/code/Magento/Analytics/Api/LinkProviderInterface.php +++ b/app/code/Magento/Analytics/Api/LinkProviderInterface.php @@ -7,13 +7,11 @@ /** * Provides link to file with collected report data. - * @since 2.2.0 */ interface LinkProviderInterface { /** * @return \Magento\Analytics\Api\Data\LinkInterface - * @since 2.2.0 */ public function get(); } diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php index 9f450b9b6936d..c66996d839c09 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/AdditionalComment.php @@ -7,14 +7,12 @@ /** * Provides field with additional information - * @since 2.2.0 */ class AdditionalComment extends \Magento\Config\Block\System\Config\Form\Field { /** * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.0 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { @@ -27,7 +25,6 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @param string $html * @return string - * @since 2.2.0 */ private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) { diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php index 9e19a9e6c2388..c4118792255cd 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabel.php @@ -7,7 +7,6 @@ /** * Provides label with default Time Zone - * @since 2.2.0 */ class CollectionTimeLabel extends \Magento\Config\Block\System\Config\Form\Field { @@ -16,7 +15,6 @@ class CollectionTimeLabel extends \Magento\Config\Block\System\Config\Form\Field * * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.0 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php index bfdee16707618..c09213c7f009d 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/SubscriptionStatusLabel.php @@ -13,13 +13,11 @@ * * Provides labels for subscription status * Status can be reviewed in System Configuration - * @since 2.2.0 */ class SubscriptionStatusLabel extends \Magento\Config\Block\System\Config\Form\Field { /** * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatusProvider; @@ -29,7 +27,6 @@ class SubscriptionStatusLabel extends \Magento\Config\Block\System\Config\Form\F * @param Context $context * @param SubscriptionStatusProvider $labelStatusProvider * @param array $data - * @since 2.2.0 */ public function __construct( Context $context, @@ -45,7 +42,6 @@ public function __construct( * * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.0 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { @@ -60,7 +56,6 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele * Prepare label for subscription status * * @return string - * @since 2.2.0 */ private function prepareLabelValue() { diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php index be3d8eabc899b..b7ec114e69563 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -7,14 +7,12 @@ /** * Provides select with industry information - * @since 2.2.2 */ class Vertical extends \Magento\Config\Block\System\Config\Form\Field { /** * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string - * @since 2.2.2 */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { @@ -27,7 +25,6 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @param string $html * @return string - * @since 2.2.2 */ private function decorateRowHtml(\Magento\Framework\Data\Form\Element\AbstractElement $element, $html) { diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php index 4cbfa639d23b4..a90a971cf41b4 100644 --- a/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php +++ b/app/code/Magento/Analytics/Controller/Adminhtml/BIEssentials/SignUp.php @@ -13,7 +13,6 @@ * Class SignUp * * Provides link to BI Essentials signup - * @since 2.2.0 */ class SignUp extends Action { @@ -21,20 +20,17 @@ class SignUp extends Action * Path to config value with URL to BI Essentials sign-up page. * * @var string - * @since 2.2.0 */ private $urlBIEssentialsConfigPath = 'analytics/url/bi_essentials'; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @param Context $context * @param ScopeConfigInterface $config - * @since 2.2.0 */ public function __construct( Context $context, @@ -48,7 +44,6 @@ public function __construct( * Check admin permissions for this controller * * @return boolean - * @since 2.2.0 */ protected function _isAllowed() { @@ -59,7 +54,6 @@ protected function _isAllowed() * Provides link to BI Essentials signup * * @return \Magento\Framework\Controller\AbstractResult - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php index 5fb0085fee43d..1b0e5c92420de 100644 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Reports/Show.php @@ -15,20 +15,17 @@ /** * Provide redirect to resource with reports. - * @since 2.2.0 */ class Show extends Action { /** * @var ReportUrlProvider - * @since 2.2.0 */ private $reportUrlProvider; /** * @param Context $context * @param ReportUrlProvider $reportUrlProvider - * @since 2.2.0 */ public function __construct( Context $context, @@ -42,7 +39,6 @@ public function __construct( * Check admin permissions for this controller. * * @return boolean - * @since 2.2.0 */ protected function _isAllowed() { @@ -53,7 +49,6 @@ protected function _isAllowed() * Redirect to resource with reports. * * @return Redirect $resultRedirect - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php index 85d34e83f0c9f..122cf74123cc9 100644 --- a/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php +++ b/app/code/Magento/Analytics/Controller/Adminhtml/Subscription/Retry.php @@ -15,7 +15,6 @@ /** * Retry subscription to Magento BI Advanced Reporting. - * @since 2.2.0 */ class Retry extends Action { @@ -23,14 +22,12 @@ class Retry extends Action * Resource for managing subscription to Magento Analytics. * * @var SubscriptionHandler - * @since 2.2.0 */ private $subscriptionHandler; /** * @param Context $context * @param SubscriptionHandler $subscriptionHandler - * @since 2.2.0 */ public function __construct( Context $context, @@ -44,7 +41,6 @@ public function __construct( * Check admin permissions for this controller * * @return boolean - * @since 2.2.0 */ protected function _isAllowed() { @@ -55,7 +51,6 @@ protected function _isAllowed() * Retry process of subscription. * * @return Redirect - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Cron/CollectData.php b/app/code/Magento/Analytics/Cron/CollectData.php index d11ade9a812ff..ff0b3e4f67638 100644 --- a/app/code/Magento/Analytics/Cron/CollectData.php +++ b/app/code/Magento/Analytics/Cron/CollectData.php @@ -10,7 +10,6 @@ /** * Cron for data collection by a schedule for MBI. - * @since 2.2.0 */ class CollectData { @@ -18,7 +17,6 @@ class CollectData * Resource for the handling of a new data collection. * * @var ExportDataHandlerInterface - * @since 2.2.0 */ private $exportDataHandler; @@ -26,14 +24,12 @@ class CollectData * Resource which provides a status of subscription. * * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatus; /** * @param ExportDataHandlerInterface $exportDataHandler * @param SubscriptionStatusProvider $subscriptionStatus - * @since 2.2.0 */ public function __construct( ExportDataHandlerInterface $exportDataHandler, @@ -45,7 +41,6 @@ public function __construct( /** * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Cron/SignUp.php b/app/code/Magento/Analytics/Cron/SignUp.php index cc5c84e93a6d9..c17b9b8c381c3 100644 --- a/app/code/Magento/Analytics/Cron/SignUp.php +++ b/app/code/Magento/Analytics/Cron/SignUp.php @@ -13,25 +13,21 @@ /** * Class SignUp - * @since 2.2.0 */ class SignUp { /** * @var Connector - * @since 2.2.0 */ private $connector; /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -39,7 +35,6 @@ class SignUp * Reinitable Config Model. * * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; @@ -48,7 +43,6 @@ class SignUp * @param WriterInterface $configWriter * @param FlagManager $flagManager * @param ReinitableConfigInterface $reinitableConfig - * @since 2.2.0 */ public function __construct( Connector $connector, @@ -67,7 +61,6 @@ public function __construct( * In case of failure writes message to notifications inbox * * @return bool - * @since 2.2.0 */ public function execute() { @@ -98,7 +91,6 @@ public function execute() * re-initialize config cache to avoid auto-generate new schedule items. * * @return bool - * @since 2.2.0 */ private function deleteAnalyticsCronExpr() { diff --git a/app/code/Magento/Analytics/Cron/Update.php b/app/code/Magento/Analytics/Cron/Update.php index 89a2496e088c1..9062a7bac7551 100644 --- a/app/code/Magento/Analytics/Cron/Update.php +++ b/app/code/Magento/Analytics/Cron/Update.php @@ -14,37 +14,31 @@ /** * Executes by cron schedule in case base url was changed - * @since 2.2.0 */ class Update { /** * @var Connector - * @since 2.2.0 */ private $connector; /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; /** * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -54,7 +48,6 @@ class Update * @param ReinitableConfigInterface $reinitableConfig * @param FlagManager $flagManager * @param AnalyticsToken $analyticsToken - * @since 2.2.0 */ public function __construct( Connector $connector, @@ -74,7 +67,6 @@ public function __construct( * Execute scheduled update operation * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/AnalyticsToken.php b/app/code/Magento/Analytics/Model/AnalyticsToken.php index 58ef45b4f4279..ccec4d1bbe958 100644 --- a/app/code/Magento/Analytics/Model/AnalyticsToken.php +++ b/app/code/Magento/Analytics/Model/AnalyticsToken.php @@ -11,13 +11,11 @@ /** * Model for handling Magento BI token value into config. - * @since 2.2.0 */ class AnalyticsToken { /** * Path to value of Magento BI token into config. - * @since 2.2.0 */ private $tokenPath = 'analytics/general/token'; @@ -25,7 +23,6 @@ class AnalyticsToken * Reinitable Config Model. * * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; @@ -33,7 +30,6 @@ class AnalyticsToken * Scope config model. * * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; @@ -41,7 +37,6 @@ class AnalyticsToken * Service which allows to write values into config. * * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -49,7 +44,6 @@ class AnalyticsToken * @param ReinitableConfigInterface $reinitableConfig * @param ScopeConfigInterface $config * @param WriterInterface $configWriter - * @since 2.2.0 */ public function __construct( ReinitableConfigInterface $reinitableConfig, @@ -65,7 +59,6 @@ public function __construct( * Get Magento BI token value. * * @return string|null - * @since 2.2.0 */ public function getToken() { @@ -78,7 +71,6 @@ public function getToken() * @param string $value * * @return bool - * @since 2.2.0 */ public function storeToken($value) { @@ -92,7 +84,6 @@ public function storeToken($value) * Check Magento BI token value exist. * * @return bool - * @since 2.2.0 */ public function isTokenExist() { diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 157a033959c42..88bc50e622f01 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -13,7 +13,6 @@ * * Dynamic validator for UI analytics notification, manage UI component visibility. * Return true if the logged in user has not seen the notification. - * @since 2.2.2 */ class CanViewNotification implements VisibilityConditionInterface { @@ -24,7 +23,6 @@ class CanViewNotification implements VisibilityConditionInterface /** * @var NotificationTime - * @since 2.2.2 */ private $notificationTime; @@ -32,7 +30,6 @@ class CanViewNotification implements VisibilityConditionInterface * CanViewNotification constructor. * * @param NotificationTime $notificationTime - * @since 2.2.2 */ public function __construct( NotificationTime $notificationTime @@ -44,7 +41,6 @@ public function __construct( * Validate if notification popup can be shown * * @inheritdoc - * @since 2.2.2 */ public function isVisible(array $arguments) { @@ -59,7 +55,6 @@ public function isVisible(array $arguments) /** * @return string - * @since 2.2.2 */ public function getName() { diff --git a/app/code/Magento/Analytics/Model/Config.php b/app/code/Magento/Analytics/Model/Config.php index 140d7130260a2..ba508187b4b9f 100644 --- a/app/code/Magento/Analytics/Model/Config.php +++ b/app/code/Magento/Analytics/Model/Config.php @@ -10,19 +10,16 @@ /** * Config of Analytics. - * @since 2.2.0 */ class Config implements ConfigInterface { /** * @var DataInterface - * @since 2.2.0 */ private $data; /** * @param DataInterface $data - * @since 2.2.0 */ public function __construct(DataInterface $data) { @@ -35,7 +32,6 @@ public function __construct(DataInterface $data) * @param string|null $key * @param string|null $default * @return array - * @since 2.2.0 */ public function get($key = null, $default = null) { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php index f9fa38fe7f5fb..6e6f008d49f7e 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Baseurl/SubscriptionUpdateHandler.php @@ -13,7 +13,6 @@ /** * Class for processing of change of Base URL. - * @since 2.2.0 */ class SubscriptionUpdateHandler { @@ -36,13 +35,11 @@ class SubscriptionUpdateHandler * Max value for a reserve counter to update subscription. * * @var int - * @since 2.2.0 */ private $attemptsInitValue = 48; /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -50,25 +47,21 @@ class SubscriptionUpdateHandler * Cron expression for a update handler. * * @var string - * @since 2.2.0 */ private $cronExpression = '0 * * * *'; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -77,7 +70,6 @@ class SubscriptionUpdateHandler * @param FlagManager $flagManager * @param ReinitableConfigInterface $reinitableConfig * @param WriterInterface $configWriter - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -96,7 +88,6 @@ public function __construct( * * @param string $url * @return bool - * @since 2.2.0 */ public function processUrlUpdate(string $url) { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php index beb6f9d79f7ab..e26ad01fc74bf 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/CollectionTime.php @@ -17,7 +17,6 @@ /** * Config value backend model. - * @since 2.2.0 */ class CollectionTime extends Value { @@ -28,7 +27,6 @@ class CollectionTime extends Value /** * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -41,7 +39,6 @@ class CollectionTime extends Value * @param AbstractResource|null $resource * @param AbstractDb|null $resourceCollection * @param array $data - * @since 2.2.0 */ public function __construct( Context $context, @@ -63,7 +60,6 @@ public function __construct( * {@inheritdoc}. Set schedule setting for cron. * * @return Value - * @since 2.2.0 */ public function afterSave() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php index 5544cd0df9454..ac97f2a843e61 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled.php @@ -17,7 +17,6 @@ /** * Config value backend model. - * @since 2.2.0 */ class Enabled extends Value { @@ -30,7 +29,6 @@ class Enabled extends Value * Service for processing of activation/deactivation MBI subscription. * * @var SubscriptionHandler - * @since 2.2.0 */ private $subscriptionHandler; @@ -43,7 +41,6 @@ class Enabled extends Value * @param AbstractResource|null $resource * @param AbstractDb|null $resourceCollection * @param array $data - * @since 2.2.0 */ public function __construct( Context $context, @@ -64,7 +61,6 @@ public function __construct( * * @return Value * @throws LocalizedException - * @since 2.2.0 */ public function afterSave() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php index 04202cdcda11c..4b125949948c6 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Enabled/SubscriptionHandler.php @@ -13,7 +13,6 @@ /** * Class for processing of activation/deactivation MBI subscription. - * @since 2.2.0 */ class SubscriptionHandler { @@ -42,7 +41,6 @@ class SubscriptionHandler * Max value for reserve counter of attempts to subscribe. * * @var int - * @since 2.2.0 */ private $attemptsInitValue = 24; @@ -50,7 +48,6 @@ class SubscriptionHandler * Service which allows to write values into config. * * @var WriterInterface - * @since 2.2.0 */ private $configWriter; @@ -58,7 +55,6 @@ class SubscriptionHandler * Flag Manager. * * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -66,13 +62,11 @@ class SubscriptionHandler * Model for handling Magento BI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var ReinitableConfigInterface - * @since 2.2.0 */ private $reinitableConfig; @@ -81,7 +75,6 @@ class SubscriptionHandler * @param FlagManager $flagManager * @param AnalyticsToken $analyticsToken * @param ReinitableConfigInterface $reinitableConfig - * @since 2.2.0 */ public function __construct( WriterInterface $configWriter, @@ -101,7 +94,6 @@ public function __construct( * Activate process of subscription handling if Analytics token is not received. * * @return bool - * @since 2.2.0 */ public function processEnabled() { @@ -118,7 +110,6 @@ public function processEnabled() * Set cron schedule setting into config for activation of subscription process. * * @return bool - * @since 2.2.0 */ private function setCronSchedule() { @@ -130,7 +121,6 @@ private function setCronSchedule() * Set flag as reserve counter of attempts subscription operation. * * @return bool - * @since 2.2.0 */ private function setAttemptsFlag() { @@ -145,7 +135,6 @@ private function setAttemptsFlag() * and interrupt subscription handling if Analytics token is not received. * * @return bool - * @since 2.2.0 */ public function processDisabled() { @@ -162,7 +151,6 @@ public function processDisabled() * Unset flag of attempts subscription operation. * * @return bool - * @since 2.2.0 */ private function unsetAttemptsFlag() { @@ -174,7 +162,6 @@ private function unsetAttemptsFlag() * Unset schedule of collection data cron. * * @return bool - * @since 2.2.0 */ private function disableCollectionData() { diff --git a/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php index 0fe9caa4ea0a0..1aabbb91ddf87 100644 --- a/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php +++ b/app/code/Magento/Analytics/Model/Config/Backend/Vertical.php @@ -9,7 +9,6 @@ /** * A backend model for verticals configuration. - * @since 2.2.0 */ class Vertical extends \Magento\Framework\App\Config\Value { @@ -21,7 +20,6 @@ class Vertical extends \Magento\Framework\App\Config\Value * * @return $this * @throws LocalizedException if the value of the selected vertical is empty. - * @since 2.2.0 */ public function beforeSave() { diff --git a/app/code/Magento/Analytics/Model/Config/Mapper.php b/app/code/Magento/Analytics/Model/Config/Mapper.php index d672248777ec5..504690b8e4763 100644 --- a/app/code/Magento/Analytics/Model/Config/Mapper.php +++ b/app/code/Magento/Analytics/Model/Config/Mapper.php @@ -8,7 +8,6 @@ /** * Transforms Analytics configuration data. - * @since 2.2.0 */ class Mapper { @@ -35,7 +34,6 @@ class Mapper * ], * ] * ]; - * @since 2.2.0 */ public function execute($configData) { diff --git a/app/code/Magento/Analytics/Model/Config/Reader.php b/app/code/Magento/Analytics/Model/Config/Reader.php index e5e120f95bbd6..8980e31627717 100644 --- a/app/code/Magento/Analytics/Model/Config/Reader.php +++ b/app/code/Magento/Analytics/Model/Config/Reader.php @@ -9,26 +9,22 @@ /** * Composite reader for config. - * @since 2.2.0 */ class Reader implements ReaderInterface { /** * @var ReaderInterface[] - * @since 2.2.0 */ private $readers; /** * @var Mapper - * @since 2.2.0 */ private $mapper; /** * @param Mapper $mapper * @param ReaderInterface[] $readers - * @since 2.2.0 */ public function __construct( Mapper $mapper, @@ -43,7 +39,6 @@ public function __construct( * * @param string|null $scope * @return array - * @since 2.2.0 */ public function read($scope = null) { diff --git a/app/code/Magento/Analytics/Model/Config/Source/Vertical.php b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php index 7aac0b070af4b..c9d9582ea7c7a 100644 --- a/app/code/Magento/Analytics/Model/Config/Source/Vertical.php +++ b/app/code/Magento/Analytics/Model/Config/Source/Vertical.php @@ -10,7 +10,6 @@ * * Prepares and provides options for a selector of verticals which is located * in the corresponding configuration menu of the Admin area. - * @since 2.2.0 */ class Vertical implements \Magento\Framework\Option\ArrayInterface { @@ -23,13 +22,11 @@ class Vertical implements \Magento\Framework\Option\ArrayInterface * It is supposed that the list may be changed in each Magento release. * * @var array - * @since 2.2.0 */ private $verticals; /** * @param array $verticals - * @since 2.2.0 */ public function __construct(array $verticals) { @@ -38,7 +35,6 @@ public function __construct(array $verticals) /** * {@inheritdoc} - * @since 2.2.0 */ public function toOptionArray() { diff --git a/app/code/Magento/Analytics/Model/ConfigInterface.php b/app/code/Magento/Analytics/Model/ConfigInterface.php index 2f84f9bffe8de..caaa2e100c1c7 100644 --- a/app/code/Magento/Analytics/Model/ConfigInterface.php +++ b/app/code/Magento/Analytics/Model/ConfigInterface.php @@ -8,7 +8,6 @@ /** * Interface for Analytics Config. - * @since 2.2.0 */ interface ConfigInterface { @@ -18,7 +17,6 @@ interface ConfigInterface * @param string|null $key * @param string|null $default * @return array - * @since 2.2.0 */ public function get($key = null, $default = null); } diff --git a/app/code/Magento/Analytics/Model/Connector.php b/app/code/Magento/Analytics/Model/Connector.php index 5b2fdb0af525b..23b0ffa213b6e 100644 --- a/app/code/Magento/Analytics/Model/Connector.php +++ b/app/code/Magento/Analytics/Model/Connector.php @@ -12,7 +12,6 @@ * A connector to external services. * * Aggregates and executes commands which perform requests to external services. - * @since 2.2.0 */ class Connector { @@ -24,20 +23,17 @@ class Connector * The list may be configured in each module via '/etc/di.xml'. * * @var string[] - * @since 2.2.0 */ private $commands; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @param array $commands * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( array $commands, @@ -53,7 +49,6 @@ public function __construct( * @param string $commandName * @return bool * @throws NotFoundException if the command is not found. - * @since 2.2.0 */ public function execute($commandName) { diff --git a/app/code/Magento/Analytics/Model/Connector/CommandInterface.php b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php index cf7fe4e24f721..7a8774fe3dba9 100644 --- a/app/code/Magento/Analytics/Model/Connector/CommandInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/CommandInterface.php @@ -8,7 +8,6 @@ /** * Introduces family of integration calls. * Each implementation represents call to external service. - * @since 2.2.0 */ interface CommandInterface { @@ -17,7 +16,6 @@ interface CommandInterface * Information about destination and arguments appears from config * * @return bool - * @since 2.2.0 */ public function execute(); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php b/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php index 0e7c6f24c2a52..c223bb1f3b07d 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/Client/Curl.php @@ -14,31 +14,26 @@ * A CURL HTTP client. * * Sends requests via a CURL adapter. - * @since 2.2.0 */ class Curl implements \Magento\Analytics\Model\Connector\Http\ClientInterface { /** * @var CurlFactory - * @since 2.2.0 */ private $curlFactory; /** * @var ResponseFactory - * @since 2.2.0 */ private $responseFactory; /** * @var ConverterInterface - * @since 2.2.0 */ private $converter; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; @@ -47,7 +42,6 @@ class Curl implements \Magento\Analytics\Model\Connector\Http\ClientInterface * @param ResponseFactory $responseFactory * @param ConverterInterface $converter * @param LoggerInterface $logger - * @since 2.2.0 */ public function __construct( CurlFactory $curlFactory, @@ -63,7 +57,6 @@ public function __construct( /** * {@inheritdoc} - * @since 2.2.0 */ public function request($method, $url, array $body = [], array $headers = [], $version = '1.1') { @@ -103,7 +96,6 @@ public function request($method, $url, array $body = [], array $headers = [], $v * @param array $headers * * @return array - * @since 2.2.0 */ private function applyContentTypeHeaderFromConverter(array $headers) { diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php index aa2a8ca2cbf1a..a1e1f057684f6 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ClientInterface.php @@ -9,7 +9,6 @@ * An interface for an HTTP client. * * Sends requests via a proper adapter. - * @since 2.2.0 */ interface ClientInterface { @@ -25,7 +24,6 @@ interface ClientInterface * @param string $version * * @return \Zend_Http_Response - * @since 2.2.0 */ public function request($method, $url, array $body = [], array $headers = [], $version = '1.1'); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php index 826332b0169ac..a6ce85cadc62f 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ConverterInterface.php @@ -7,7 +7,6 @@ /** * Represents converter interface for http request and response body. - * @since 2.2.0 */ interface ConverterInterface { @@ -15,7 +14,6 @@ interface ConverterInterface * @param string $body * * @return array - * @since 2.2.0 */ public function fromBody($body); @@ -23,13 +21,11 @@ public function fromBody($body); * @param array $data * * @return string - * @since 2.2.0 */ public function toBody(array $data); /** * @return string - * @since 2.2.0 */ public function getContentTypeHeader(); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php b/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php index 78d308305a5c8..4a0f27f245316 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/JsonConverter.php @@ -7,7 +7,6 @@ /** * Represents JSON converter for http request and response body. - * @since 2.2.0 */ class JsonConverter implements ConverterInterface { @@ -20,7 +19,6 @@ class JsonConverter implements ConverterInterface * @param string $body * * @return array - * @since 2.2.0 */ public function fromBody($body) { @@ -32,7 +30,6 @@ public function fromBody($body) * @param array $data * * @return string - * @since 2.2.0 */ public function toBody(array $data) { @@ -41,7 +38,6 @@ public function toBody(array $data) /** * @return string - * @since 2.2.0 */ public function getContentTypeHeader() { diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php b/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php index fe13cdfdde253..77d23b88529a3 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ResponseFactory.php @@ -7,7 +7,6 @@ /** * A factory for an HTTP response. - * @since 2.2.0 */ class ResponseFactory { @@ -16,7 +15,6 @@ class ResponseFactory * * @param string $response * @return \Zend_Http_Response - * @since 2.2.0 */ public function create($response) { diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php b/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php index 51faa8ecc8f31..4a6633f08da55 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ResponseHandlerInterface.php @@ -7,14 +7,12 @@ /** * Represents an interface for response handler which process response body. - * @since 2.2.0 */ interface ResponseHandlerInterface { /** * @param array $responseBody * @return bool|string - * @since 2.2.0 */ public function handleResponse(array $responseBody); } diff --git a/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php b/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php index 9041929ad1b33..ec198e4a3c40b 100644 --- a/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php +++ b/app/code/Magento/Analytics/Model/Connector/Http/ResponseResolver.php @@ -7,26 +7,22 @@ /** * Extract result from http response. Call response handler by status. - * @since 2.2.0 */ class ResponseResolver { /** * @var ConverterInterface - * @since 2.2.0 */ private $converter; /** * @var array - * @since 2.2.0 */ private $responseHandlers; /** * @param ConverterInterface $converter * @param ResponseHandlerInterface[] $responseHandlers - * @since 2.2.0 */ public function __construct(ConverterInterface $converter, array $responseHandlers = []) { @@ -38,7 +34,6 @@ public function __construct(ConverterInterface $converter, array $responseHandle * @param \Zend_Http_Response $response * * @return bool|string - * @since 2.2.0 */ public function getResult(\Zend_Http_Response $response) { diff --git a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php index a88b87a447072..f1a8ea6460f9d 100644 --- a/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php +++ b/app/code/Magento/Analytics/Model/Connector/NotifyDataChangedCommand.php @@ -14,43 +14,36 @@ /** * Command notifies MBI about that data collection was finished. - * @since 2.2.0 */ class NotifyDataChangedCommand implements CommandInterface { /** * @var string - * @since 2.2.0 */ private $notifyDataChangedUrlPath = 'analytics/url/notify_data_changed'; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; @@ -61,7 +54,6 @@ class NotifyDataChangedCommand implements CommandInterface * @param ScopeConfigInterface $config * @param ResponseResolver $responseResolver * @param LoggerInterface $logger - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -81,7 +73,6 @@ public function __construct( * Notify MBI about that data collection was finished * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php index f0577084cbff3..dfa283e10d070 100644 --- a/app/code/Magento/Analytics/Model/Connector/OTPRequest.php +++ b/app/code/Magento/Analytics/Model/Connector/OTPRequest.php @@ -19,7 +19,6 @@ * * OTP (One-Time Password) is a password that is valid for short period of time * and may be used only for one login session. - * @since 2.2.0 */ class OTPRequest { @@ -27,31 +26,26 @@ class OTPRequest * Resource for handling MBI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; @@ -60,7 +54,6 @@ class OTPRequest * an URL that provides an OTP. * * @var string - * @since 2.2.0 */ private $otpUrlConfigPath = 'analytics/url/otp'; @@ -70,7 +63,6 @@ class OTPRequest * @param ScopeConfigInterface $config * @param ResponseResolver $responseResolver * @param LoggerInterface $logger - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -92,7 +84,6 @@ public function __construct( * Returns received OTP or FALSE in case of failure. * * @return string|false - * @since 2.2.0 */ public function call() { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php index d385f466e2919..d9a672e81f43d 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/OTP.php @@ -9,7 +9,6 @@ /** * Fetches OTP from body. - * @since 2.2.0 */ class OTP implements ResponseHandlerInterface { @@ -17,7 +16,6 @@ class OTP implements ResponseHandlerInterface * @param array $responseBody * * @return bool|string - * @since 2.2.0 */ public function handleResponse(array $responseBody) { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php index e15dbe48a7597..c79630d6414d8 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/ReSignUp.php @@ -12,25 +12,21 @@ /** * Removes stored token and triggers subscription process. - * @since 2.2.0 */ class ReSignUp implements ResponseHandlerInterface { /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var SubscriptionHandler - * @since 2.2.0 */ private $subscriptionHandler; /** * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatusProvider; @@ -38,7 +34,6 @@ class ReSignUp implements ResponseHandlerInterface * @param AnalyticsToken $analyticsToken * @param SubscriptionHandler $subscriptionHandler * @param SubscriptionStatusProvider $subscriptionStatusProvider - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -52,7 +47,6 @@ public function __construct( /** * @inheritdoc - * @since 2.2.0 */ public function handleResponse(array $responseBody) { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php index 49ad1936a3975..b2261e418abc7 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/SignUp.php @@ -11,26 +11,22 @@ /** * Stores access token to MBI that received in body. - * @since 2.2.0 */ class SignUp implements ResponseHandlerInterface { /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var ConverterInterface - * @since 2.2.0 */ private $converter; /** * @param AnalyticsToken $analyticsToken * @param ConverterInterface $converter - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -42,7 +38,6 @@ public function __construct( /** * @inheritdoc - * @since 2.2.0 */ public function handleResponse(array $body) { diff --git a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php index 13a7eaa9b1fd8..73fc575ae2821 100644 --- a/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php +++ b/app/code/Magento/Analytics/Model/Connector/ResponseHandler/Update.php @@ -9,7 +9,6 @@ /** * Return positive answer that request was finished successfully. - * @since 2.2.0 */ class Update implements ResponseHandlerInterface { @@ -17,7 +16,6 @@ class Update implements ResponseHandlerInterface * @param array $responseBody * * @return bool|string - * @since 2.2.0 */ public function handleResponse(array $responseBody) { diff --git a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php index a52e79182ce0c..a1f23637e04b1 100644 --- a/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php +++ b/app/code/Magento/Analytics/Model/Connector/SignUpCommand.php @@ -17,49 +17,41 @@ * Class SignUpCommand * * SignUp merchant for Free Tier project - * @since 2.2.0 */ class SignUpCommand implements CommandInterface { /** * @var string - * @since 2.2.0 */ private $signUpUrlPath = 'analytics/url/signup'; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var IntegrationManager - * @since 2.2.0 */ private $integrationManager; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; @@ -72,7 +64,6 @@ class SignUpCommand implements CommandInterface * @param Http\ClientInterface $httpClient * @param LoggerInterface $logger * @param ResponseResolver $responseResolver - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -101,7 +92,6 @@ public function __construct( * This method returns true in case of success * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php index ff8ad2ec85a43..8f05f1107e87e 100644 --- a/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php +++ b/app/code/Magento/Analytics/Model/Connector/UpdateCommand.php @@ -17,49 +17,41 @@ /** * Class UpdateCommand * Command executes in case change store url - * @since 2.2.0 */ class UpdateCommand implements CommandInterface { /** * @var string - * @since 2.2.0 */ private $updateUrlPath = 'analytics/url/update'; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var Http\ClientInterface - * @since 2.2.0 */ private $httpClient; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var LoggerInterface - * @since 2.2.0 */ private $logger; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var ResponseResolver - * @since 2.2.0 */ private $responseResolver; @@ -70,7 +62,6 @@ class UpdateCommand implements CommandInterface * @param LoggerInterface $logger * @param FlagManager $flagManager * @param ResponseResolver $responseResolver - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -92,7 +83,6 @@ public function __construct( * Executes update request to MBI api in case store url was changed * * @return bool - * @since 2.2.0 */ public function execute() { diff --git a/app/code/Magento/Analytics/Model/Cryptographer.php b/app/code/Magento/Analytics/Model/Cryptographer.php index 848d2911e9a5e..6905eee372ae2 100644 --- a/app/code/Magento/Analytics/Model/Cryptographer.php +++ b/app/code/Magento/Analytics/Model/Cryptographer.php @@ -9,7 +9,6 @@ /** * Class for encrypting data. - * @since 2.2.0 */ class Cryptographer { @@ -17,7 +16,6 @@ class Cryptographer * Resource for handling MBI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -25,20 +23,17 @@ class Cryptographer * Cipher method for encryption. * * @var string - * @since 2.2.0 */ private $cipherMethod = 'AES-256-CBC'; /** * @var EncodedContextFactory - * @since 2.2.0 */ private $encodedContextFactory; /** * @param AnalyticsToken $analyticsToken * @param EncodedContextFactory $encodedContextFactory - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -54,7 +49,6 @@ public function __construct( * @param string $source * @return EncodedContext * @throws LocalizedException - * @since 2.2.0 */ public function encode($source) { @@ -91,7 +85,6 @@ public function encode($source) * * @return string * @throws LocalizedException - * @since 2.2.0 */ private function getKey() { @@ -106,7 +99,6 @@ private function getKey() * Return established cipher method. * * @return string - * @since 2.2.0 */ private function getCipherMethod() { @@ -117,7 +109,6 @@ private function getCipherMethod() * Return each time generated random initialization vector which depends on the cipher method. * * @return string - * @since 2.2.0 */ private function getInitializationVector() { @@ -130,7 +121,6 @@ private function getInitializationVector() * * @param string $cipherMethod * @return bool - * @since 2.2.0 */ private function validateCipherMethod($cipherMethod) { diff --git a/app/code/Magento/Analytics/Model/EncodedContext.php b/app/code/Magento/Analytics/Model/EncodedContext.php index bffbf29315c11..5fb2d0c15aef7 100644 --- a/app/code/Magento/Analytics/Model/EncodedContext.php +++ b/app/code/Magento/Analytics/Model/EncodedContext.php @@ -7,7 +7,6 @@ /** * Contain information about encrypted data. - * @since 2.2.0 */ class EncodedContext { @@ -15,7 +14,6 @@ class EncodedContext * Encrypted string. * * @var string - * @since 2.2.0 */ private $content; @@ -23,14 +21,12 @@ class EncodedContext * Initialization vector that was used for encryption. * * @var string - * @since 2.2.0 */ private $initializationVector; /** * @param string $content * @param string $initializationVector - * @since 2.2.0 */ public function __construct($content, $initializationVector = '') { @@ -40,7 +36,6 @@ public function __construct($content, $initializationVector = '') /** * @return string - * @since 2.2.0 */ public function getContent() { @@ -49,7 +44,6 @@ public function getContent() /** * @return string - * @since 2.2.0 */ public function getInitializationVector() { diff --git a/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php index 74cfd28365678..5d127037afea9 100644 --- a/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php +++ b/app/code/Magento/Analytics/Model/Exception/State/SubscriptionUpdateException.php @@ -10,7 +10,6 @@ /** * Analytics is in update subscription mode. - * @since 2.2.0 */ class SubscriptionUpdateException extends LocalizedException { diff --git a/app/code/Magento/Analytics/Model/ExportDataHandler.php b/app/code/Magento/Analytics/Model/ExportDataHandler.php index 37611df7e2ec8..b9d3b6340184b 100644 --- a/app/code/Magento/Analytics/Model/ExportDataHandler.php +++ b/app/code/Magento/Analytics/Model/ExportDataHandler.php @@ -14,7 +14,6 @@ /** * Class for the handling of a new data collection for MBI. - * @since 2.2.0 */ class ExportDataHandler implements ExportDataHandlerInterface { @@ -22,7 +21,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Subdirectory path for all temporary files. * * @var string - * @since 2.2.0 */ private $subdirectoryPath = 'analytics/'; @@ -30,19 +28,16 @@ class ExportDataHandler implements ExportDataHandlerInterface * Filename of archive with collected data. * * @var string - * @since 2.2.0 */ private $archiveName = 'data.tgz'; /** * @var Filesystem - * @since 2.2.0 */ private $filesystem; /** * @var Archive - * @since 2.2.0 */ private $archive; @@ -50,7 +45,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Resource for write data of reports into separate files. * * @var ReportWriterInterface - * @since 2.2.0 */ private $reportWriter; @@ -58,7 +52,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Resource for encrypting data. * * @var Cryptographer - * @since 2.2.0 */ private $cryptographer; @@ -66,7 +59,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * Resource for registration a new file. * * @var FileRecorder - * @since 2.2.0 */ private $fileRecorder; @@ -76,7 +68,6 @@ class ExportDataHandler implements ExportDataHandlerInterface * @param ReportWriterInterface $reportWriter * @param Cryptographer $cryptographer * @param FileRecorder $fileRecorder - * @since 2.2.0 */ public function __construct( Filesystem $filesystem, @@ -94,7 +85,6 @@ public function __construct( /** * @inheritdoc - * @since 2.2.0 */ public function prepareExportData() { @@ -127,7 +117,6 @@ public function prepareExportData() * Return relative path to a directory for temporary files with reports data. * * @return string - * @since 2.2.0 */ private function getTmpFilesDirRelativePath() { @@ -138,7 +127,6 @@ private function getTmpFilesDirRelativePath() * Return relative path to a directory for an archive. * * @return string - * @since 2.2.0 */ private function getArchiveRelativePath() { @@ -151,7 +139,6 @@ private function getArchiveRelativePath() * @param WriteInterface $directory * @param string $path * @return string - * @since 2.2.0 */ private function prepareDirectory(WriteInterface $directory, $path) { @@ -166,7 +153,6 @@ private function prepareDirectory(WriteInterface $directory, $path) * @param WriteInterface $directory * @param string $path * @return string - * @since 2.2.0 */ private function prepareFileDirectory(WriteInterface $directory, $path) { @@ -184,7 +170,6 @@ private function prepareFileDirectory(WriteInterface $directory, $path) * @param string $source * @param string $destination * @return bool - * @since 2.2.0 */ private function pack($source, $destination) { @@ -206,7 +191,6 @@ private function pack($source, $destination) * @param string $path * @return string * @throws LocalizedException If source is not exist. - * @since 2.2.0 */ private function validateSource(WriteInterface $directory, $path) { diff --git a/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php index c8af595c2aadf..65efb33659c89 100644 --- a/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php +++ b/app/code/Magento/Analytics/Model/ExportDataHandlerInterface.php @@ -7,7 +7,6 @@ /** * The interface represents the type of classes that handling of a new data collection for MBI. - * @since 2.2.0 */ interface ExportDataHandlerInterface { @@ -15,7 +14,6 @@ interface ExportDataHandlerInterface * Execute collecting new data for MBI. * * @return bool - * @since 2.2.0 */ public function prepareExportData(); } diff --git a/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php b/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php index 1f995fb92d27f..34941ac9ae2f2 100644 --- a/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php +++ b/app/code/Magento/Analytics/Model/ExportDataHandlerNotification.php @@ -7,19 +7,16 @@ /** * Class which add notification behaviour to classes that handling of a new data collection for MBI. - * @since 2.2.0 */ class ExportDataHandlerNotification implements ExportDataHandlerInterface { /** * @var ExportDataHandler - * @since 2.2.0 */ private $exportDataHandler; /** * @var Connector - * @since 2.2.0 */ private $analyticsConnector; @@ -28,7 +25,6 @@ class ExportDataHandlerNotification implements ExportDataHandlerInterface * * @param ExportDataHandlerInterface $exportDataHandler * @param Connector $connector - * @since 2.2.0 */ public function __construct(ExportDataHandler $exportDataHandler, Connector $connector) { @@ -41,7 +37,6 @@ public function __construct(ExportDataHandler $exportDataHandler, Connector $con * Execute notification command. * * @return bool - * @since 2.2.0 */ public function prepareExportData() { diff --git a/app/code/Magento/Analytics/Model/FileInfo.php b/app/code/Magento/Analytics/Model/FileInfo.php index edfac858d6f68..19bdaf21b2a20 100644 --- a/app/code/Magento/Analytics/Model/FileInfo.php +++ b/app/code/Magento/Analytics/Model/FileInfo.php @@ -7,7 +7,6 @@ /** * Contain information about encrypted file. - * @since 2.2.0 */ class FileInfo { @@ -15,7 +14,6 @@ class FileInfo * Initialization vector that was used for encryption. * * @var string - * @since 2.2.0 */ private $initializationVector; @@ -23,14 +21,12 @@ class FileInfo * Relative path to an encrypted file. * * @var string - * @since 2.2.0 */ private $path; /** * @param string $path * @param string $initializationVector - * @since 2.2.0 */ public function __construct($path = '', $initializationVector = '') { @@ -40,7 +36,6 @@ public function __construct($path = '', $initializationVector = '') /** * @return string - * @since 2.2.0 */ public function getPath() { @@ -49,7 +44,6 @@ public function getPath() /** * @return string - * @since 2.2.0 */ public function getInitializationVector() { diff --git a/app/code/Magento/Analytics/Model/FileInfoManager.php b/app/code/Magento/Analytics/Model/FileInfoManager.php index 204995e133d20..e37700e665420 100644 --- a/app/code/Magento/Analytics/Model/FileInfoManager.php +++ b/app/code/Magento/Analytics/Model/FileInfoManager.php @@ -10,19 +10,16 @@ /** * Manage saving and loading FileInfo object. - * @since 2.2.0 */ class FileInfoManager { /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; /** * @var FileInfoFactory - * @since 2.2.0 */ private $fileInfoFactory; @@ -30,7 +27,6 @@ class FileInfoManager * Flag code for a stored FileInfo object. * * @var string - * @since 2.2.0 */ private $flagCode = 'analytics_file_info'; @@ -38,7 +34,6 @@ class FileInfoManager * Parameters which have to be saved into encoded form. * * @var array - * @since 2.2.0 */ private $encodedParameters = [ 'initializationVector' @@ -47,7 +42,6 @@ class FileInfoManager /** * @param FlagManager $flagManager * @param FileInfoFactory $fileInfoFactory - * @since 2.2.0 */ public function __construct( FlagManager $flagManager, @@ -63,7 +57,6 @@ public function __construct( * @param FileInfo $fileInfo * @return bool * @throws LocalizedException - * @since 2.2.0 */ public function save(FileInfo $fileInfo) { @@ -91,7 +84,6 @@ public function save(FileInfo $fileInfo) * Load FileInfo object. * * @return FileInfo - * @since 2.2.0 */ public function load() { @@ -112,7 +104,6 @@ public function load() * * @param string $value * @return string - * @since 2.2.0 */ private function encodeValue($value) { @@ -124,7 +115,6 @@ private function encodeValue($value) * * @param string $value * @return string - * @since 2.2.0 */ private function decodeValue($value) { diff --git a/app/code/Magento/Analytics/Model/FileRecorder.php b/app/code/Magento/Analytics/Model/FileRecorder.php index 94e0c59d9321b..70438a98d56f1 100644 --- a/app/code/Magento/Analytics/Model/FileRecorder.php +++ b/app/code/Magento/Analytics/Model/FileRecorder.php @@ -11,7 +11,6 @@ /** * Class for the handling of registration a new file for MBI. - * @since 2.2.0 */ class FileRecorder { @@ -19,13 +18,11 @@ class FileRecorder * Resource for managing FileInfo object. * * @var FileInfoManager - * @since 2.2.0 */ private $fileInfoManager; /** * @var FileInfoFactory - * @since 2.2.0 */ private $fileInfoFactory; @@ -33,7 +30,6 @@ class FileRecorder * Subdirectory path for an encoded file. * * @var string - * @since 2.2.0 */ private $fileSubdirectoryPath = 'analytics/'; @@ -41,13 +37,11 @@ class FileRecorder * File name of an encoded file. * * @var string - * @since 2.2.0 */ private $encodedFileName = 'data.tgz'; /** * @var Filesystem - * @since 2.2.0 */ private $filesystem; @@ -55,7 +49,6 @@ class FileRecorder * @param FileInfoManager $fileInfoManager * @param FileInfoFactory $fileInfoFactory * @param Filesystem $filesystem - * @since 2.2.0 */ public function __construct( FileInfoManager $fileInfoManager, @@ -72,7 +65,6 @@ public function __construct( * * @param EncodedContext $encodedContext * @return bool - * @since 2.2.0 */ public function recordNewFile(EncodedContext $encodedContext) { @@ -92,7 +84,6 @@ public function recordNewFile(EncodedContext $encodedContext) * Return relative path to encoded file. * * @return string - * @since 2.2.0 */ private function getFileRelativePath() { @@ -106,7 +97,6 @@ private function getFileRelativePath() * @param EncodedContext $encodedContext * @param string $fileRelativePath * @return bool - * @since 2.2.0 */ private function registerFile(EncodedContext $encodedContext, $fileRelativePath) { @@ -127,7 +117,6 @@ private function registerFile(EncodedContext $encodedContext, $fileRelativePath) * @param FileInfo $fileInfo * @param WriteInterface $directory * @return bool - * @since 2.2.0 */ private function removeOldFile(FileInfo $fileInfo, WriteInterface $directory) { diff --git a/app/code/Magento/Analytics/Model/IntegrationManager.php b/app/code/Magento/Analytics/Model/IntegrationManager.php index b2694ac8241c1..61a40a955e026 100644 --- a/app/code/Magento/Analytics/Model/IntegrationManager.php +++ b/app/code/Magento/Analytics/Model/IntegrationManager.php @@ -18,25 +18,21 @@ * Manages the integration user at magento side. * User name stored in config. * User roles - * @since 2.2.0 */ class IntegrationManager { /** * @var SystemConfig - * @since 2.2.0 */ private $config; /** * @var IntegrationServiceInterface - * @since 2.2.0 */ private $integrationService; /** * @var OauthServiceInterface - * @since 2.2.0 */ private $oauthService; @@ -46,7 +42,6 @@ class IntegrationManager * @param SystemConfig $config * @param IntegrationServiceInterface $integrationService * @param OauthServiceInterface $oauthService - * @since 2.2.0 */ public function __construct( SystemConfig $config, @@ -63,7 +58,6 @@ public function __construct( * * @return bool * @throws NoSuchEntityException - * @since 2.2.0 */ public function activateIntegration() { @@ -83,7 +77,6 @@ public function activateIntegration() * This method execute Generate Token command and enable integration * * @return bool|\Magento\Integration\Model\Oauth\Token - * @since 2.2.0 */ public function generateToken() { @@ -99,7 +92,6 @@ public function generateToken() * Returns consumer Id for MA integration user * * @return \Magento\Integration\Model\Integration - * @since 2.2.0 */ private function generateIntegration() { @@ -117,7 +109,6 @@ private function generateIntegration() * * @param int $status * @return array - * @since 2.2.0 */ private function getIntegrationData($status = Integration::STATUS_INACTIVE) { diff --git a/app/code/Magento/Analytics/Model/Link.php b/app/code/Magento/Analytics/Model/Link.php index 34479e9ae4f61..4a40796df4fd0 100644 --- a/app/code/Magento/Analytics/Model/Link.php +++ b/app/code/Magento/Analytics/Model/Link.php @@ -11,19 +11,16 @@ * Class Link * * Represents link with collected data and initialized vector for decryption. - * @since 2.2.0 */ class Link implements LinkInterface { /** * @var string - * @since 2.2.0 */ private $url; /** * @var string - * @since 2.2.0 */ private $initializationVector; @@ -32,7 +29,6 @@ class Link implements LinkInterface * * @param string $url * @param string $initializationVector - * @since 2.2.0 */ public function __construct($url, $initializationVector) { @@ -42,7 +38,6 @@ public function __construct($url, $initializationVector) /** * @return string - * @since 2.2.0 */ public function getUrl() { @@ -51,7 +46,6 @@ public function getUrl() /** * @return string - * @since 2.2.0 */ public function getInitializationVector() { diff --git a/app/code/Magento/Analytics/Model/LinkProvider.php b/app/code/Magento/Analytics/Model/LinkProvider.php index 6d09e20fef1a4..2474653f4916c 100644 --- a/app/code/Magento/Analytics/Model/LinkProvider.php +++ b/app/code/Magento/Analytics/Model/LinkProvider.php @@ -13,25 +13,21 @@ /** * Provides link to file with collected report data. - * @since 2.2.0 */ class LinkProvider implements LinkProviderInterface { /** * @var LinkInterfaceFactory - * @since 2.2.0 */ private $linkFactory; /** * @var FileInfoManager - * @since 2.2.0 */ private $fileInfoManager; /** * @var StoreManagerInterface - * @since 2.2.0 */ private $storeManager; @@ -39,7 +35,6 @@ class LinkProvider implements LinkProviderInterface * @param LinkInterfaceFactory $linkInterfaceFactory * @param FileInfoManager $fileInfoManager * @param StoreManagerInterface $storeManager - * @since 2.2.0 */ public function __construct( LinkInterfaceFactory $linkFactory, @@ -56,7 +51,6 @@ public function __construct( * * @param FileInfo $fileInfo * @return string - * @since 2.2.0 */ private function getBaseUrl(FileInfo $fileInfo) { @@ -68,7 +62,6 @@ private function getBaseUrl(FileInfo $fileInfo) * * @param FileInfo $fileInfo * @return bool - * @since 2.2.0 */ private function isFileReady(FileInfo $fileInfo) { @@ -77,7 +70,6 @@ private function isFileReady(FileInfo $fileInfo) /** * @inheritdoc - * @since 2.2.0 */ public function get() { diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php index b831c4e20dc5f..c3ebf52da4b99 100644 --- a/app/code/Magento/Analytics/Model/NotificationTime.php +++ b/app/code/Magento/Analytics/Model/NotificationTime.php @@ -14,7 +14,6 @@ * * Manage access to notification time flag * - * @since 2.2.2 */ class NotificationTime { @@ -22,19 +21,16 @@ class NotificationTime /** * @var FlagManager - * @since 2.2.2 */ private $flagManager; /** * @var UserContextInterface - * @since 2.2.2 */ private $userContext; /** * @var DateTimeFactory - * @since 2.2.2 */ private $dateTimeFactory; @@ -44,7 +40,6 @@ class NotificationTime * @param FlagManager $flagManager * @param UserContextInterface $userContext * @param DateTimeFactory $dateTimeFactory - * @since 2.2.2 */ public function __construct( FlagManager $flagManager, @@ -60,7 +55,6 @@ public function __construct( * Stores last notification time * * @return bool - * @since 2.2.2 */ public function storeLastTimeNotificationForCurrentUser() { @@ -73,7 +67,6 @@ public function storeLastTimeNotificationForCurrentUser() * Returns last time when merchant was notified about Analytic services * * @return int - * @since 2.2.2 */ public function getLastTimeNotificationForCurrentUser() { @@ -84,7 +77,6 @@ public function getLastTimeNotificationForCurrentUser() * Remove last notification time flag. * * @return bool - * @since 2.2.2 */ public function unsetLastTimeNotificationValueForCurrentUser() { diff --git a/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php index e2bdf354b040c..174272614fb19 100644 --- a/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php +++ b/app/code/Magento/Analytics/Model/Plugin/BaseUrlConfigPlugin.php @@ -12,19 +12,16 @@ /** * Plugin on Base URL config value AfterSave method. - * @since 2.2.0 */ class BaseUrlConfigPlugin { /** * @var SubscriptionUpdateHandler - * @since 2.2.0 */ private $subscriptionUpdateHandler; /** * @param SubscriptionUpdateHandler $subscriptionUpdateHandler - * @since 2.2.0 */ public function __construct( SubscriptionUpdateHandler $subscriptionUpdateHandler @@ -39,7 +36,6 @@ public function __construct( * @param Value $result * @return Value * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function afterAfterSave( Value $subject, @@ -55,7 +51,6 @@ public function afterAfterSave( /** * @param Value $result * @return bool - * @since 2.2.0 */ private function isPluginApplicable(Value $result) { diff --git a/app/code/Magento/Analytics/Model/ProviderFactory.php b/app/code/Magento/Analytics/Model/ProviderFactory.php index 35af7d5ddaa1c..3a23430fca077 100644 --- a/app/code/Magento/Analytics/Model/ProviderFactory.php +++ b/app/code/Magento/Analytics/Model/ProviderFactory.php @@ -11,19 +11,16 @@ * Class ProviderFactory * * Factory for report providers - * @since 2.2.0 */ class ProviderFactory { /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( ObjectManagerInterface $objectManager @@ -34,7 +31,6 @@ public function __construct( /** * @param string $providerName * @return object - * @since 2.2.0 */ public function create($providerName) { diff --git a/app/code/Magento/Analytics/Model/ReportUrlProvider.php b/app/code/Magento/Analytics/Model/ReportUrlProvider.php index dfa27358e252b..e7fdf6f9e8132 100644 --- a/app/code/Magento/Analytics/Model/ReportUrlProvider.php +++ b/app/code/Magento/Analytics/Model/ReportUrlProvider.php @@ -13,7 +13,6 @@ /** * Provide URL on resource with reports. - * @since 2.2.0 */ class ReportUrlProvider { @@ -21,7 +20,6 @@ class ReportUrlProvider * Resource for handling MBI token value. * * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; @@ -29,19 +27,16 @@ class ReportUrlProvider * Resource which provide OTP. * * @var OTPRequest - * @since 2.2.0 */ private $otpRequest; /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $config; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -49,7 +44,6 @@ class ReportUrlProvider * Path to config value with URL which provide reports. * * @var string - * @since 2.2.0 */ private $urlReportConfigPath = 'analytics/url/report'; @@ -58,7 +52,6 @@ class ReportUrlProvider * @param OTPRequest $otpRequest * @param ScopeConfigInterface $config * @param FlagManager $flagManager - * @since 2.2.0 */ public function __construct( AnalyticsToken $analyticsToken, @@ -77,7 +70,6 @@ public function __construct( * * @return string * @throws SubscriptionUpdateException - * @since 2.2.0 */ public function getUrl() { diff --git a/app/code/Magento/Analytics/Model/ReportWriter.php b/app/code/Magento/Analytics/Model/ReportWriter.php index ae3522c6f4351..7128658947908 100644 --- a/app/code/Magento/Analytics/Model/ReportWriter.php +++ b/app/code/Magento/Analytics/Model/ReportWriter.php @@ -11,7 +11,6 @@ /** * Writes reports in files in csv format * @inheritdoc - * @since 2.2.0 */ class ReportWriter implements ReportWriterInterface { @@ -19,25 +18,21 @@ class ReportWriter implements ReportWriterInterface * File name for error reporting file in archive * * @var string - * @since 2.2.0 */ private $errorsFileName = 'errors.csv'; /** * @var Config - * @since 2.2.0 */ private $config; /** * @var ProviderFactory - * @since 2.2.0 */ private $providerFactory; /** * @var ReportValidator - * @since 2.2.0 */ private $reportValidator; @@ -47,7 +42,6 @@ class ReportWriter implements ReportWriterInterface * @param ConfigInterface $config * @param ReportValidator $reportValidator * @param ProviderFactory $providerFactory - * @since 2.2.0 */ public function __construct( ConfigInterface $config, @@ -61,7 +55,6 @@ public function __construct( /** * {@inheritdoc} - * @since 2.2.0 */ public function write(WriteInterface $directory, $path) { diff --git a/app/code/Magento/Analytics/Model/ReportWriterInterface.php b/app/code/Magento/Analytics/Model/ReportWriterInterface.php index bb7f8dfbe26a6..a611095a47ae4 100644 --- a/app/code/Magento/Analytics/Model/ReportWriterInterface.php +++ b/app/code/Magento/Analytics/Model/ReportWriterInterface.php @@ -14,7 +14,6 @@ * Executes export of collected data * Iterates registered providers @see etc/analytics.xml * Collects data (to TMP folder) - * @since 2.2.0 */ interface ReportWriterInterface { @@ -24,7 +23,6 @@ interface ReportWriterInterface * @param WriteInterface $directory * @param string $path * @return void - * @since 2.2.0 */ public function write(WriteInterface $directory, $path); } diff --git a/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php b/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php index eabeccd260966..a0800387d28f5 100644 --- a/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php +++ b/app/code/Magento/Analytics/Model/ReportXml/ModuleIterator.php @@ -9,13 +9,11 @@ /** * Class ModuleIterator - * @since 2.2.0 */ class ModuleIterator extends \IteratorIterator { /** * @var ModuleManager - * @since 2.2.0 */ private $moduleManager; @@ -24,7 +22,6 @@ class ModuleIterator extends \IteratorIterator * * @param ModuleManager $moduleManager * @param \Traversable $iterator - * @since 2.2.0 */ public function __construct( ModuleManager $moduleManager, @@ -38,7 +35,6 @@ public function __construct( * Returns module with module status * * @return array - * @since 2.2.0 */ public function current() { diff --git a/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php index e070e2c669ccf..0d226a9de7dc2 100644 --- a/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php +++ b/app/code/Magento/Analytics/Model/StoreConfigurationProvider.php @@ -15,25 +15,21 @@ /** * Class StoreConfigurationProvider * Provides config data report - * @since 2.2.0 */ class StoreConfigurationProvider { /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $scopeConfig; /** * @var string[] - * @since 2.2.0 */ private $configPaths; /** * @var StoreManagerInterface - * @since 2.2.0 */ private $storeManager; @@ -41,7 +37,6 @@ class StoreConfigurationProvider * @param ScopeConfigInterface $scopeConfig * @param StoreManagerInterface $storeManager * @param string[] $configPaths - * @since 2.2.0 */ public function __construct( ScopeConfigInterface $scopeConfig, @@ -57,7 +52,6 @@ public function __construct( * Generates report using config paths from di.xml * For each website and store * @return \IteratorIterator - * @since 2.2.0 */ public function getReport() { @@ -87,7 +81,6 @@ public function getReport() * @param string $scope * @param int $scopeId * @return array - * @since 2.2.0 */ private function generateReportForScope($scope, $scopeId) { diff --git a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php index 478e0ae4ccd63..1dd831a672faa 100644 --- a/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php +++ b/app/code/Magento/Analytics/Model/SubscriptionStatusProvider.php @@ -12,7 +12,6 @@ /** * Provider of subscription status. - * @since 2.2.0 */ class SubscriptionStatusProvider { @@ -38,19 +37,16 @@ class SubscriptionStatusProvider /** * @var ScopeConfigInterface - * @since 2.2.0 */ private $scopeConfig; /** * @var AnalyticsToken - * @since 2.2.0 */ private $analyticsToken; /** * @var FlagManager - * @since 2.2.0 */ private $flagManager; @@ -58,7 +54,6 @@ class SubscriptionStatusProvider * @param ScopeConfigInterface $scopeConfig * @param AnalyticsToken $analyticsToken * @param FlagManager $flagManager - * @since 2.2.0 */ public function __construct( ScopeConfigInterface $scopeConfig, @@ -80,7 +75,6 @@ public function __construct( * Failed - if subscription is enabled and token was not received after attempts ended. * * @return string - * @since 2.2.0 */ public function getStatus() { @@ -96,7 +90,6 @@ public function getStatus() * Retrieve status for subscription that enabled in config. * * @return string - * @since 2.2.0 */ public function getStatusForEnabledSubscription() { @@ -119,7 +112,6 @@ public function getStatusForEnabledSubscription() * Retrieve status for subscription that disabled in config. * * @return string - * @since 2.2.0 */ public function getStatusForDisabledSubscription() { diff --git a/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php index 688caedf8e864..9aaa2ebb3b56f 100644 --- a/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php +++ b/app/code/Magento/Analytics/Model/System/Message/NotificationAboutFailedSubscription.php @@ -11,26 +11,22 @@ /** * Represents an analytics notification about failed subscription. - * @since 2.2.0 */ class NotificationAboutFailedSubscription implements MessageInterface { /** * @var SubscriptionStatusProvider - * @since 2.2.0 */ private $subscriptionStatusProvider; /** * @var UrlInterface - * @since 2.2.0 */ private $urlBuilder; /** * @param SubscriptionStatusProvider $subscriptionStatusProvider * @param UrlInterface $urlBuilder - * @since 2.2.0 */ public function __construct(SubscriptionStatusProvider $subscriptionStatusProvider, UrlInterface $urlBuilder) { @@ -42,7 +38,6 @@ public function __construct(SubscriptionStatusProvider $subscriptionStatusProvid * @inheritdoc * * @codeCoverageIgnore - * @since 2.2.0 */ public function getIdentity() { @@ -51,7 +46,6 @@ public function getIdentity() /** * {@inheritdoc} - * @since 2.2.0 */ public function isDisplayed() { @@ -60,7 +54,6 @@ public function isDisplayed() /** * {@inheritdoc} - * @since 2.2.0 */ public function getText() { @@ -79,7 +72,6 @@ public function getText() * @inheritdoc * * @codeCoverageIgnore - * @since 2.2.0 */ public function getSeverity() { diff --git a/app/code/Magento/Analytics/ReportXml/Config.php b/app/code/Magento/Analytics/ReportXml/Config.php index 4176486fd0993..f50dcf941bf50 100644 --- a/app/code/Magento/Analytics/ReportXml/Config.php +++ b/app/code/Magento/Analytics/ReportXml/Config.php @@ -11,13 +11,11 @@ * Class Config * * Config of ReportXml - * @since 2.2.0 */ class Config implements ConfigInterface { /** * @var DataInterface - * @since 2.2.0 */ private $data; @@ -25,7 +23,6 @@ class Config implements ConfigInterface * Config constructor. * * @param DataInterface $data - * @since 2.2.0 */ public function __construct( DataInterface $data @@ -38,7 +35,6 @@ public function __construct( * * @param string $queryName * @return array - * @since 2.2.0 */ public function get($queryName) { diff --git a/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php index a479b70c91945..9e0b20a6ad414 100644 --- a/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php +++ b/app/code/Magento/Analytics/ReportXml/Config/Converter/Xml.php @@ -11,7 +11,6 @@ * A converter of reports configuration. * * Converts configuration data stored in XML format into corresponding PHP array. - * @since 2.2.0 */ class Xml implements ConverterInterface { @@ -20,7 +19,6 @@ class Xml implements ConverterInterface * * @param \DOMNode $source * @return array|string - * @since 2.2.0 */ private function convertNode(\DOMNode $source) { @@ -55,7 +53,6 @@ private function convertNode(\DOMNode $source) * * @param \DOMDocument $source * @return array - * @since 2.2.0 */ public function convert($source) { diff --git a/app/code/Magento/Analytics/ReportXml/Config/Mapper.php b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php index 8da73e257b825..4dda8f3c733a6 100644 --- a/app/code/Magento/Analytics/ReportXml/Config/Mapper.php +++ b/app/code/Magento/Analytics/ReportXml/Config/Mapper.php @@ -11,7 +11,6 @@ * Transforms configuration data to improve its usability. * * @see usage examples in \Magento\Analytics\ReportXml\Config\Reader - * @since 2.2.0 */ class Mapper { @@ -20,7 +19,6 @@ class Mapper * * @param array $configData * @return array - * @since 2.2.0 */ public function execute($configData) { diff --git a/app/code/Magento/Analytics/ReportXml/Config/Reader.php b/app/code/Magento/Analytics/ReportXml/Config/Reader.php index 8636ede7c6f08..3e0bc3cb5c796 100644 --- a/app/code/Magento/Analytics/ReportXml/Config/Reader.php +++ b/app/code/Magento/Analytics/ReportXml/Config/Reader.php @@ -11,7 +11,6 @@ * A composite reader of reports configuration. * * Reads configuration data using declared readers. - * @since 2.2.0 */ class Reader implements ReaderInterface { @@ -21,20 +20,17 @@ class Reader implements ReaderInterface * The list may be configured in each module via '/etc/di.xml'. * * @var ReaderInterface[] - * @since 2.2.0 */ private $readers; /** * @var Mapper - * @since 2.2.0 */ private $mapper; /** * @param Mapper $mapper * @param array $readers - * @since 2.2.0 */ public function __construct( Mapper $mapper, @@ -49,7 +45,6 @@ public function __construct( * * @param string|null $scope * @return array - * @since 2.2.0 */ public function read($scope = null) { diff --git a/app/code/Magento/Analytics/ReportXml/ConfigInterface.php b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php index b9271700f6758..ec03ddf429c06 100644 --- a/app/code/Magento/Analytics/ReportXml/ConfigInterface.php +++ b/app/code/Magento/Analytics/ReportXml/ConfigInterface.php @@ -10,7 +10,6 @@ * Interface ConfigInterface * * Interface for ReportXml Config - * @since 2.2.0 */ interface ConfigInterface { @@ -19,7 +18,6 @@ interface ConfigInterface * * @param string $queryName * @return array - * @since 2.2.0 */ public function get($queryName); } diff --git a/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php b/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php index 214d4a7d4cecd..e591ed2659651 100644 --- a/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php +++ b/app/code/Magento/Analytics/ReportXml/ConnectionFactory.php @@ -15,19 +15,16 @@ * * Creates connection instance for export according to existing one * This connection does not use buffered statement, also this connection is not persistent - * @since 2.2.0 */ class ConnectionFactory { /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; @@ -36,7 +33,6 @@ class ConnectionFactory * * @param ResourceConnection $resourceConnection * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection, @@ -51,7 +47,6 @@ public function __construct( * * @param string $connectionName * @return AdapterInterface - * @since 2.2.0 */ public function getConnection($connectionName) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php index e8c35ad46e2e5..083b4843c185a 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/AssemblerInterface.php @@ -13,7 +13,6 @@ * Introduces family of SQL assemblers * Each assembler populates SelectBuilder with config information * @see usage examples at \Magento\Analytics\ReportXml\QueryFactory - * @since 2.2.0 */ interface AssemblerInterface { @@ -23,7 +22,6 @@ interface AssemblerInterface * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig); } diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php index bcd9e99319564..251c43f5e1b71 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FilterAssembler.php @@ -14,19 +14,16 @@ * Class FilterAssembler * * Assembles WHERE conditions - * @since 2.2.0 */ class FilterAssembler implements AssemblerInterface { /** * @var ConditionResolver - * @since 2.2.0 */ private $conditionResolver; /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; @@ -35,7 +32,6 @@ class FilterAssembler implements AssemblerInterface * * @param ConditionResolver $conditionResolver * @param NameResolver $nameResolver - * @since 2.2.0 */ public function __construct( ConditionResolver $conditionResolver, @@ -51,7 +47,6 @@ public function __construct( * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php index 8b6f739e3ecdc..811119ace221b 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/FromAssembler.php @@ -13,25 +13,21 @@ /** * Assembles FROM condition - * @since 2.2.0 */ class FromAssembler implements AssemblerInterface { /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; /** * @var ColumnsResolver - * @since 2.2.0 */ private $columnsResolver; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; @@ -39,7 +35,6 @@ class FromAssembler implements AssemblerInterface * @param NameResolver $nameResolver * @param ColumnsResolver $columnsResolver * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( NameResolver $nameResolver, @@ -57,7 +52,6 @@ public function __construct( * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php index ec83019c39c31..f3c6540a25171 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php +++ b/app/code/Magento/Analytics/ReportXml/DB/Assembler/JoinAssembler.php @@ -16,31 +16,26 @@ * Class JoinAssembler * * Assembles JOIN conditions - * @since 2.2.0 */ class JoinAssembler implements AssemblerInterface { /** * @var ConditionResolver - * @since 2.2.0 */ private $conditionResolver; /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; /** * @var ColumnsResolver - * @since 2.2.0 */ private $columnsResolver; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; @@ -49,7 +44,6 @@ class JoinAssembler implements AssemblerInterface * @param ColumnsResolver $columnsResolver * @param NameResolver $nameResolver * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( ConditionResolver $conditionResolver, @@ -69,7 +63,6 @@ public function __construct( * @param SelectBuilder $selectBuilder * @param array $queryConfig * @return SelectBuilder - * @since 2.2.0 */ public function assemble(SelectBuilder $selectBuilder, $queryConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php index 5b9279175b5ff..e6474d4c5dc6d 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php +++ b/app/code/Magento/Analytics/ReportXml/DB/ColumnsResolver.php @@ -13,25 +13,21 @@ * Class ColumnsResolver * * Resolves columns names - * @since 2.2.0 */ class ColumnsResolver { /** * @var NameResolver - * @since 2.2.0 */ private $nameResolver; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private $connection; @@ -40,7 +36,6 @@ class ColumnsResolver * * @param NameResolver $nameResolver * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( NameResolver $nameResolver, @@ -54,7 +49,6 @@ public function __construct( * Returns connection * * @return \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private function getConnection() { @@ -70,7 +64,6 @@ private function getConnection() * @param SelectBuilder $selectBuilder * @param array $entityConfig * @return array - * @since 2.2.0 */ public function getColumns(SelectBuilder $selectBuilder, $entityConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php index 96a7b0b95cafd..773b96959e794 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php +++ b/app/code/Magento/Analytics/ReportXml/DB/ConditionResolver.php @@ -13,13 +13,11 @@ * Class ConditionResolver * * Mapper for WHERE conditions - * @since 2.2.0 */ class ConditionResolver { /** * @var array - * @since 2.2.0 */ private $conditionMap = [ 'eq' => '%1$s = %2$s', @@ -39,20 +37,17 @@ class ConditionResolver /** * @var \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private $connection; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * ConditionResolver constructor. * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection @@ -64,7 +59,6 @@ public function __construct( * Returns connection * * @return \Magento\Framework\DB\Adapter\AdapterInterface - * @since 2.2.0 */ private function getConnection() { @@ -80,7 +74,6 @@ private function getConnection() * @param string $condition * @param string $referencedEntity * @return mixed|null|string|\Zend_Db_Expr - * @since 2.2.0 */ private function getValue($condition, $referencedEntity) { @@ -114,7 +107,6 @@ private function getValue($condition, $referencedEntity) * @param array $condition * @param null|string $referencedEntity * @return string - * @since 2.2.0 */ private function getCondition(SelectBuilder $selectBuilder, $tableName, $condition, $referencedEntity = null) { @@ -141,7 +133,6 @@ private function getCondition(SelectBuilder $selectBuilder, $tableName, $conditi * @param string $aliasName * @param null|string $referencedAlias * @return array - * @since 2.2.0 */ public function getFilter(SelectBuilder $selectBuilder, $filterConfig, $aliasName, $referencedAlias = null) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php index fdea82ba25426..c9543002eb272 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php +++ b/app/code/Magento/Analytics/ReportXml/DB/NameResolver.php @@ -9,7 +9,6 @@ * Class NameResolver * * Resolver for source names - * @since 2.2.0 */ class NameResolver { @@ -18,7 +17,6 @@ class NameResolver * * @param array $elementConfig * @return string - * @since 2.2.0 */ public function getName($elementConfig) { @@ -30,7 +28,6 @@ public function getName($elementConfig) * * @param array $elementConfig * @return string - * @since 2.2.0 */ public function getAlias($elementConfig) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php index 1092d5fd1e4fc..21a641f0a71c7 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php +++ b/app/code/Magento/Analytics/ReportXml/DB/ReportValidator.php @@ -13,19 +13,16 @@ * Class ReportValidator * * Validates report definitions by doing query to storage with limit 0 - * @since 2.2.0 */ class ReportValidator { /** * @var ConnectionFactory - * @since 2.2.0 */ private $connectionFactory; /** * @var QueryFactory - * @since 2.2.0 */ private $queryFactory; @@ -36,7 +33,6 @@ class ReportValidator * * @param ConnectionFactory $connectionFactory * @param QueryFactory $queryFactory - * @since 2.2.0 */ public function __construct(ConnectionFactory $connectionFactory, QueryFactory $queryFactory) { @@ -51,7 +47,6 @@ public function __construct(ConnectionFactory $connectionFactory, QueryFactory $ * @param SearchCriteriaInterface $criteria * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function validate($name, SearchCriteriaInterface $criteria = null) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php index bb37af94c9419..4e5a1940773b1 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilder.php @@ -14,61 +14,51 @@ * * Responsible for Select object creation, works as a builder. Returns Select as result; * Used in SQL assemblers. - * @since 2.2.0 */ class SelectBuilder { /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var string - * @since 2.2.0 */ private $connectionName; /** * @var array - * @since 2.2.0 */ private $from; /** * @var array - * @since 2.2.0 */ private $group = []; /** * @var array - * @since 2.2.0 */ private $columns = []; /** * @var array - * @since 2.2.0 */ private $filters = []; /** * @var array - * @since 2.2.0 */ private $joins = []; /** * @var array - * @since 2.2.0 */ private $params = []; /** * @var array - * @since 2.2.0 */ private $having = []; @@ -76,7 +66,6 @@ class SelectBuilder * SelectBuilder constructor. * * @param ResourceConnection $resourceConnection - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection @@ -88,7 +77,6 @@ public function __construct( * Get join condition * * @return array - * @since 2.2.0 */ public function getJoins() { @@ -100,7 +88,6 @@ public function getJoins() * * @param array $joins * @return void - * @since 2.2.0 */ public function setJoins($joins) { @@ -111,7 +98,6 @@ public function setJoins($joins) * Get connection name * * @return string - * @since 2.2.0 */ public function getConnectionName() { @@ -123,7 +109,6 @@ public function getConnectionName() * * @param string $connectionName * @return void - * @since 2.2.0 */ public function setConnectionName($connectionName) { @@ -134,7 +119,6 @@ public function setConnectionName($connectionName) * Get columns * * @return array - * @since 2.2.0 */ public function getColumns() { @@ -146,7 +130,6 @@ public function getColumns() * * @param array $columns * @return void - * @since 2.2.0 */ public function setColumns($columns) { @@ -157,7 +140,6 @@ public function setColumns($columns) * Get filters * * @return array - * @since 2.2.0 */ public function getFilters() { @@ -169,7 +151,6 @@ public function getFilters() * * @param array $filters * @return void - * @since 2.2.0 */ public function setFilters($filters) { @@ -180,7 +161,6 @@ public function setFilters($filters) * Get from condition * * @return array - * @since 2.2.0 */ public function getFrom() { @@ -192,7 +172,6 @@ public function getFrom() * * @param array $from * @return void - * @since 2.2.0 */ public function setFrom($from) { @@ -205,7 +184,6 @@ public function setFrom($from) * @param Select $select * @param array $joinConfig * @return Select - * @since 2.2.0 */ private function processJoin(Select $select, $joinConfig) { @@ -227,7 +205,6 @@ private function processJoin(Select $select, $joinConfig) * Creates Select object * * @return Select - * @since 2.2.0 */ public function create() { @@ -251,7 +228,6 @@ public function create() * Returns group * * @return array - * @since 2.2.0 */ public function getGroup() { @@ -263,7 +239,6 @@ public function getGroup() * * @param array $group * @return void - * @since 2.2.0 */ public function setGroup($group) { @@ -274,7 +249,6 @@ public function setGroup($group) * Get parameters * * @return array - * @since 2.2.0 */ public function getParams() { @@ -286,7 +260,6 @@ public function getParams() * * @param array $params * @return void - * @since 2.2.0 */ public function setParams($params) { @@ -297,7 +270,6 @@ public function setParams($params) * Get having condition * * @return array - * @since 2.2.0 */ public function getHaving() { @@ -309,7 +281,6 @@ public function getHaving() * * @param array $having * @return void - * @since 2.2.0 */ public function setHaving($having) { diff --git a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php index 1866d9282c1e9..1d88d4618efc5 100644 --- a/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php +++ b/app/code/Magento/Analytics/ReportXml/DB/SelectBuilderFactory.php @@ -9,7 +9,6 @@ /** * Factory class for @see \Magento\Analytics\ReportXml\DB\SelectBuilder - * @since 2.2.0 */ class SelectBuilderFactory { @@ -17,7 +16,6 @@ class SelectBuilderFactory * Object Manager instance * * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; @@ -25,7 +23,6 @@ class SelectBuilderFactory * SelectBuilderFactory constructor. * * @param ObjectManagerInterface $objectManager - * @since 2.2.0 */ public function __construct( ObjectManagerInterface $objectManager @@ -38,7 +35,6 @@ public function __construct( * * @param array $data * @return SelectBuilder - * @since 2.2.0 */ public function create(array $data = []) { diff --git a/app/code/Magento/Analytics/ReportXml/IteratorFactory.php b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php index 195fad845623f..a196cef8b66dc 100644 --- a/app/code/Magento/Analytics/ReportXml/IteratorFactory.php +++ b/app/code/Magento/Analytics/ReportXml/IteratorFactory.php @@ -10,19 +10,16 @@ /** * Class IteratorFactory - * @since 2.2.0 */ class IteratorFactory { /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @var string - * @since 2.2.0 */ private $defaultIteratorName; @@ -31,7 +28,6 @@ class IteratorFactory * * @param ObjectManagerInterface $objectManager * @param string $defaultIteratorName - * @since 2.2.0 */ public function __construct( ObjectManagerInterface $objectManager, @@ -52,7 +48,6 @@ public function __construct( * @param \Traversable $result * @param string|null $iteratorName * @return \IteratorIterator - * @since 2.2.0 */ public function create(\Traversable $result, $iteratorName = null) { diff --git a/app/code/Magento/Analytics/ReportXml/Query.php b/app/code/Magento/Analytics/ReportXml/Query.php index 7e464a5ad46d1..46ec2fb494183 100644 --- a/app/code/Magento/Analytics/ReportXml/Query.php +++ b/app/code/Magento/Analytics/ReportXml/Query.php @@ -11,31 +11,26 @@ * Class Query * * Query object, contains SQL statement, information about connection, query arguments - * @since 2.2.0 */ class Query implements \JsonSerializable { /** * @var Select - * @since 2.2.0 */ private $select; /** * @var \Magento\Analytics\ReportXml\SelectHydrator - * @since 2.2.0 */ private $selectHydrator; /** * @var string - * @since 2.2.0 */ private $connectionName; /** * @var array - * @since 2.2.0 */ private $config; @@ -46,7 +41,6 @@ class Query implements \JsonSerializable * @param SelectHydrator $selectHydrator * @param string $connectionName * @param array $config - * @since 2.2.0 */ public function __construct( Select $select, @@ -62,7 +56,6 @@ public function __construct( /** * @return Select - * @since 2.2.0 */ public function getSelect() { @@ -71,7 +64,6 @@ public function getSelect() /** * @return string - * @since 2.2.0 */ public function getConnectionName() { @@ -80,7 +72,6 @@ public function getConnectionName() /** * @return array - * @since 2.2.0 */ public function getConfig() { diff --git a/app/code/Magento/Analytics/ReportXml/QueryFactory.php b/app/code/Magento/Analytics/ReportXml/QueryFactory.php index 37e6609553023..8ed7e767b28b3 100644 --- a/app/code/Magento/Analytics/ReportXml/QueryFactory.php +++ b/app/code/Magento/Analytics/ReportXml/QueryFactory.php @@ -14,43 +14,36 @@ * * Creates Query object according to configuration * Factory for @see \Magento\Analytics\ReportXml\Query - * @since 2.2.0 */ class QueryFactory { /** * @var Config - * @since 2.2.0 */ private $config; /** * @var SelectBuilderFactory - * @since 2.2.0 */ private $selectBuilderFactory; /** * @var DB\Assembler\AssemblerInterface[] - * @since 2.2.0 */ private $assemblers; /** * @var CacheInterface - * @since 2.2.0 */ private $queryCache; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; /** * @var SelectHydrator - * @since 2.2.0 */ private $selectHydrator; @@ -63,7 +56,6 @@ class QueryFactory * @param SelectBuilderFactory $selectBuilderFactory * @param Config $config * @param array $assemblers - * @since 2.2.0 */ public function __construct( CacheInterface $queryCache, @@ -86,7 +78,6 @@ public function __construct( * * @param string $queryConfig * @return string - * @since 2.2.0 */ private function getQueryConnectionName($queryConfig) { @@ -102,7 +93,6 @@ private function getQueryConnectionName($queryConfig) * * @param string $queryName * @return Query - * @since 2.2.0 */ private function constructQuery($queryName) { @@ -129,7 +119,6 @@ private function constructQuery($queryName) * * @param string $queryName * @return Query - * @since 2.2.0 */ public function create($queryName) { diff --git a/app/code/Magento/Analytics/ReportXml/ReportProvider.php b/app/code/Magento/Analytics/ReportXml/ReportProvider.php index 4edd1100c5325..3ebe5941108bc 100644 --- a/app/code/Magento/Analytics/ReportXml/ReportProvider.php +++ b/app/code/Magento/Analytics/ReportXml/ReportProvider.php @@ -12,25 +12,21 @@ * Class ReportProvider * * Providers for reports data - * @since 2.2.0 */ class ReportProvider { /** * @var QueryFactory - * @since 2.2.0 */ private $queryFactory; /** * @var ConnectionFactory - * @since 2.2.0 */ private $connectionFactory; /** * @var IteratorFactory - * @since 2.2.0 */ private $iteratorFactory; @@ -40,7 +36,6 @@ class ReportProvider * @param QueryFactory $queryFactory * @param ConnectionFactory $connectionFactory * @param IteratorFactory $iteratorFactory - * @since 2.2.0 */ public function __construct( QueryFactory $queryFactory, @@ -58,7 +53,6 @@ public function __construct( * * @param Query $query * @return string|null - * @since 2.2.0 */ private function getIteratorName(Query $query) { @@ -71,7 +65,6 @@ private function getIteratorName(Query $query) * * @param string $name * @return \IteratorIterator - * @since 2.2.0 */ public function getReport($name) { diff --git a/app/code/Magento/Analytics/ReportXml/SelectHydrator.php b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php index 9dd0f8327dd14..02cde2fd0598d 100644 --- a/app/code/Magento/Analytics/ReportXml/SelectHydrator.php +++ b/app/code/Magento/Analytics/ReportXml/SelectHydrator.php @@ -12,7 +12,6 @@ /** * Class SelectHydrator - * @since 2.2.0 */ class SelectHydrator { @@ -20,7 +19,6 @@ class SelectHydrator * Array of supported Select parts * * @var array - * @since 2.2.0 */ private $predefinedSelectParts = [ @@ -39,19 +37,16 @@ class SelectHydrator /** * @var array - * @since 2.2.0 */ private $selectParts; /** * @var ResourceConnection - * @since 2.2.0 */ private $resourceConnection; /** * @var ObjectManagerInterface - * @since 2.2.0 */ private $objectManager; @@ -59,7 +54,6 @@ class SelectHydrator * @param ResourceConnection $resourceConnection * @param ObjectManagerInterface $objectManager * @param array $selectParts - * @since 2.2.0 */ public function __construct( ResourceConnection $resourceConnection, @@ -73,7 +67,6 @@ public function __construct( /** * @return array - * @since 2.2.0 */ private function getSelectParts() { @@ -86,7 +79,6 @@ private function getSelectParts() * @param Select $select * @return array * @throws \Zend_Db_Select_Exception - * @since 2.2.0 */ public function extract(Select $select) { @@ -100,7 +92,6 @@ public function extract(Select $select) /** * @param array $selectParts * @return Select - * @since 2.2.0 */ public function recreate(array $selectParts) { @@ -124,7 +115,6 @@ public function recreate(array $selectParts) * @param Select $select * @param array $selectParts * @return Select - * @since 2.2.0 */ private function processColumns(Select $select, array &$selectParts) { diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php index 5a67a6d5e6765..aaa619bbb0caa 100644 --- a/app/code/Magento/Analytics/Setup/InstallData.php +++ b/app/code/Magento/Analytics/Setup/InstallData.php @@ -13,7 +13,6 @@ /** * @codeCoverageIgnore - * @since 2.2.0 */ class InstallData implements InstallDataInterface { @@ -21,7 +20,6 @@ class InstallData implements InstallDataInterface /** * {@inheritdoc} * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * @since 2.2.0 */ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { diff --git a/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php index eada5011a933f..87f5c7c5bc4fd 100644 --- a/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php +++ b/app/code/Magento/Analytics/Ui/DataProvider/DummyDataProvider.php @@ -12,7 +12,6 @@ /** * Class which serves as stub for degenerated UI component. - * @since 2.2.0 */ class DummyDataProvider implements DataProviderInterface { @@ -20,7 +19,6 @@ class DummyDataProvider implements DataProviderInterface * Search result object. * * @var SearchResultInterface - * @since 2.2.0 */ private $searchResult; @@ -28,7 +26,6 @@ class DummyDataProvider implements DataProviderInterface * Search criteria object. * * @var SearchCriteriaInterface - * @since 2.2.0 */ private $searchCriteria; @@ -36,7 +33,6 @@ class DummyDataProvider implements DataProviderInterface * Data collection. * * @var Collection - * @since 2.2.0 */ private $collection; @@ -44,7 +40,6 @@ class DummyDataProvider implements DataProviderInterface * Own name of this provider. * * @var string - * @since 2.2.0 */ private $name; @@ -52,7 +47,6 @@ class DummyDataProvider implements DataProviderInterface * Provider configuration data. * * @var array - * @since 2.2.0 */ private $data; @@ -62,7 +56,6 @@ class DummyDataProvider implements DataProviderInterface * @param SearchCriteriaInterface $searchCriteria * @param Collection $collection * @param array $data - * @since 2.2.0 */ public function __construct( $name, @@ -82,7 +75,6 @@ public function __construct( * Get Data Provider name * * @return string - * @since 2.2.0 */ public function getName() { @@ -93,7 +85,6 @@ public function getName() * Get config data * * @return mixed - * @since 2.2.0 */ public function getConfigData() { @@ -106,7 +97,6 @@ public function getConfigData() * @param mixed $config * * @return bool - * @since 2.2.0 */ public function setConfigData($config) { @@ -117,7 +107,6 @@ public function setConfigData($config) /** * @return array - * @since 2.2.0 */ public function getMeta() { @@ -130,7 +119,6 @@ public function getMeta() * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function getFieldMetaInfo($fieldSetName, $fieldName) { @@ -144,7 +132,6 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function getFieldSetMetaInfo($fieldSetName) { @@ -156,7 +143,6 @@ public function getFieldSetMetaInfo($fieldSetName) * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function getFieldsMetaInfo($fieldSetName) { @@ -167,7 +153,6 @@ public function getFieldsMetaInfo($fieldSetName) * Get primary field name * * @return string - * @since 2.2.0 */ public function getPrimaryFieldName() { @@ -178,7 +163,6 @@ public function getPrimaryFieldName() * Get field name in request * * @return string - * @since 2.2.0 */ public function getRequestFieldName() { @@ -189,7 +173,6 @@ public function getRequestFieldName() * Get data * * @return mixed - * @since 2.2.0 */ public function getData() { @@ -203,7 +186,6 @@ public function getData() * * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function addFilter(\Magento\Framework\Api\Filter $filter) { @@ -217,7 +199,6 @@ public function addFilter(\Magento\Framework\Api\Filter $filter) * * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function addOrder($field, $direction) { @@ -231,7 +212,6 @@ public function addOrder($field, $direction) * * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @since 2.2.0 */ public function setLimit($offset, $size) { @@ -241,7 +221,6 @@ public function setLimit($offset, $size) * Returns search criteria * * @return SearchCriteriaInterface - * @since 2.2.0 */ public function getSearchCriteria() { @@ -250,7 +229,6 @@ public function getSearchCriteria() /** * @return SearchResultInterface - * @since 2.2.0 */ public function getSearchResult() { From a1137d98a064ea23f5c86538d645245a5cef3218 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 5 Oct 2017 11:06:25 -0500 Subject: [PATCH 038/528] MAGETWO-80474: Update Advanced Reporting Configuration Page --- .../Block/Adminhtml/System/Config/Vertical.php | 5 ++++- .../System/Config/AdditionalCommentTest.php | 15 ++++++++------- .../System/Config/CollectionTimeLabelTest.php | 16 +++++++++------- .../Config/SubscriptionStatusLabelTest.php | 17 ++++++++--------- .../Adminhtml/System/Config/VerticalTest.php | 15 ++++++++------- .../Magento/Analytics/etc/adminhtml/system.xml | 4 ++-- 6 files changed, 39 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php index b7ec114e69563..6ba95bf76cde3 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -6,11 +6,12 @@ namespace Magento\Analytics\Block\Adminhtml\System\Config; /** - * Provides select with industry information + * Provides vertical select with additional information and style customization */ class Vertical extends \Magento\Config\Block\System\Config\Form\Field { /** + * @inheritdoc * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string */ @@ -22,6 +23,8 @@ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $ele } /** + * Decorates row HTML for custom element style + * * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @param string $html * @return string diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php index 744ba7466e593..cbf06264096ac 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/AdditionalCommentTest.php @@ -9,6 +9,7 @@ use Magento\Backend\Block\Template\Context; use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class AdditionalCommentTest extends \PHPUnit\Framework\TestCase { @@ -32,9 +33,6 @@ class AdditionalCommentTest extends \PHPUnit\Framework\TestCase */ private $formMock; - /** - * @return void - */ protected function setUp() { $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) @@ -48,12 +46,15 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->additionalComment = new AdditionalComment($this->contextMock); + $objectManager = new ObjectManager($this); + $this->additionalComment = $objectManager->getObject( + AdditionalComment::class, + [ + 'context' => $this->contextMock + ] + ); } - /** - * @return void - */ public function testRender() { $this->abstractElementMock->setForm($this->formMock); diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php index 74fbbf2e78a40..a652cf6b3d548 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -10,6 +10,7 @@ use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class CollectionTimeLabelTest extends \PHPUnit\Framework\TestCase { @@ -33,9 +34,6 @@ class CollectionTimeLabelTest extends \PHPUnit\Framework\TestCase */ private $abstractElementMock; - /** - * @return void - */ protected function setUp() { $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) @@ -55,12 +53,16 @@ protected function setUp() $this->contextMock->expects($this->any()) ->method('getLocaleDate') ->willReturn($this->timeZoneMock); - $this->collectionTimeLabel = new CollectionTimeLabel($this->contextMock); + + $objectManager = new ObjectManager($this); + $this->collectionTimeLabel = $objectManager->getObject( + CollectionTimeLabel::class, + [ + 'context' => $this->contextMock + ] + ); } - /** - * @return void - */ public function testRender() { $timeZone = "America/New_York"; diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php index 04728c403a861..09e753e4ac8aa 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/SubscriptionStatusLabelTest.php @@ -10,6 +10,7 @@ use Magento\Backend\Block\Template\Context; use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Class SignupTest @@ -41,9 +42,6 @@ class SubscriptionStatusLabelTest extends \PHPUnit\Framework\TestCase */ private $formMock; - /** - * @return void - */ protected function setUp() { $this->subscriptionStatusProviderMock = $this->getMockBuilder(SubscriptionStatusProvider::class) @@ -60,15 +58,16 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->subscriptionStatusLabel = new SubscriptionStatusLabel( - $this->contextMock, - $this->subscriptionStatusProviderMock + $objectManager = new ObjectManager($this); + $this->subscriptionStatusLabel = $objectManager->getObject( + SubscriptionStatusLabel::class, + [ + 'context' => $this->contextMock, + 'subscriptionStatusProvider' => $this->subscriptionStatusProviderMock + ] ); } - /** - * @return void - */ public function testRender() { $this->abstractElementMock->setForm($this->formMock); diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php index 331b487e5dd9d..abce48c36c86a 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/VerticalTest.php @@ -9,6 +9,7 @@ use Magento\Backend\Block\Template\Context; use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class VerticalTest extends \PHPUnit\Framework\TestCase { @@ -32,9 +33,6 @@ class VerticalTest extends \PHPUnit\Framework\TestCase */ private $formMock; - /** - * @return void - */ protected function setUp() { $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) @@ -48,12 +46,15 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->vertical = new Vertical($this->contextMock); + $objectManager = new ObjectManager($this); + $this->vertical = $objectManager->getObject( + Vertical::class, + [ + 'context' => $this->contextMock + ] + ); } - /** - * @return void - */ public function testRender() { $this->abstractElementMock->setForm($this->formMock); diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml index 3d87c24176c81..c3bf5c4b11d2f 100644 --- a/app/code/Magento/Analytics/etc/adminhtml/system.xml +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -28,7 +28,7 @@ Magento\Analytics\Block\Adminhtml\System\Config\CollectionTimeLabel Magento\Analytics\Model\Config\Backend\CollectionTime
- + Industry Data In order to personalize your Advanced Reporting experience, please select your industry. @@ -36,7 +36,7 @@ Magento\Analytics\Model\Config\Backend\Vertical Magento\Analytics\Block\Adminhtml\System\Config\Vertical - + Learn more about Date: Thu, 5 Oct 2017 11:44:44 -0500 Subject: [PATCH 039/528] MAGETWO-80474: Update Advanced Reporting Configuration Page --- .../Analytics/Block/Adminhtml/System/Config/Vertical.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php index 6ba95bf76cde3..99606e10f99d9 100644 --- a/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php +++ b/app/code/Magento/Analytics/Block/Adminhtml/System/Config/Vertical.php @@ -12,8 +12,6 @@ class Vertical extends \Magento\Config\Block\System\Config\Form\Field { /** * @inheritdoc - * @param \Magento\Framework\Data\Form\Element\AbstractElement $element - * @return string */ public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { From 7ddbd2b65762074b88c39c959247f9292a5d63a9 Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 5 Oct 2017 14:45:55 -0500 Subject: [PATCH 040/528] MAGETWO-80479: Update existing Advanced Reporting tests - Remove obsolete tests --- .../AssertConfigAnalyticsRestored.php | 54 ------------------- .../AssertDisableReportingInPopup.php | 49 ----------------- .../AssertEnableReportingInPopup.php | 42 --------------- .../Constraint/AssertSkipReportingInPopup.php | 42 --------------- .../AssertSubscriptionPopupNotExist.php | 39 -------------- .../app/Magento/Analytics/Test/etc/di.xml | 25 --------- 6 files changed, 251 deletions(-) delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php deleted file mode 100644 index e624b49ff38dc..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsRestored.php +++ /dev/null @@ -1,54 +0,0 @@ -run(); - - $configAnalytics->getAnalyticsForm()->analyticsToggle(); - $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); - $configAnalytics->getAnalyticsForm()->saveConfig(); - - \PHPUnit_Framework_Assert::assertTrue( - $systemConfigPage->getMessagesBlock()->assertSuccessMessage(), - 'Sending data to the Analytics is not saved.' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Sending data to the Analytics is saved.'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php deleted file mode 100644 index de1facb47230b..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertDisableReportingInPopup.php +++ /dev/null @@ -1,49 +0,0 @@ -open(); - $dashboard->getSubscriptionBlock()->enableCheckbox(); - $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); - $dashboard->getModalBlock()->dismissWarning(); - $dashboard->getSubscriptionBlock()->declineAdvancedReporting(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getSubscriptionBlock()->isVisible(), - 'Advanced Reporting was not disabled' - ); - $dashboard->getModalBlock()->acceptWarning(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getModalBlock()->isVisible(), - 'Advanced Reporting disabling was not confirmed' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Advanced Reporting was disabled'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php deleted file mode 100644 index 9205ee89f0913..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEnableReportingInPopup.php +++ /dev/null @@ -1,42 +0,0 @@ -open(); - $dashboard->getSubscriptionBlock()->enableCheckbox(); - $dashboard->getSubscriptionBlock()->acceptAdvancedReporting(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getSubscriptionBlock()->isVisible(), - 'Advanced Reporting was not enabled' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Advanced Reporting was enabled'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php deleted file mode 100644 index ddb3593537ad8..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSkipReportingInPopup.php +++ /dev/null @@ -1,42 +0,0 @@ -open(); - $dashboard->getSubscriptionBlock()->disableCheckbox(); - $dashboard->getSubscriptionBlock()->skipAdvancedReporting(); - \PHPUnit_Framework_Assert::assertFalse( - $dashboard->getSubscriptionBlock()->isVisible(), - 'Advanced Reporting was not skipped' - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return 'Advanced Reporting was skipped'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php deleted file mode 100644 index c2bb48f4bb2ec..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertSubscriptionPopupNotExist.php +++ /dev/null @@ -1,39 +0,0 @@ -getSubscriptionBlock()->isVisible(), - "Subscription form is visible on dashboard." - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return "Subscription form is absent on dashboard."; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml index 74b10cca43c1f..cc113f1768e2e 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -13,11 +13,6 @@ - - - S1 - - S1 @@ -28,24 +23,4 @@ S1 - - - S1 - - - - - S1 - - - - - S1 - - - - - S1 - - From 41410ac66c1391ca0adb565e78cc32c71b872e9e Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Thu, 5 Oct 2017 21:56:28 +0200 Subject: [PATCH 041/528] Add db-prefix from env conf --- setup/src/Magento/Setup/Model/Installer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php index 4a9bfd9063656..60cf85efc40ca 100644 --- a/setup/src/Magento/Setup/Model/Installer.php +++ b/setup/src/Magento/Setup/Model/Installer.php @@ -1010,6 +1010,7 @@ private function installOrderIncrementPrefix($orderIncrementPrefix) public function installAdminUser($data) { $this->assertDbConfigExists(); + $data += ['db-prefix' => $this->deploymentConfig->get(ConfigOptionsListConstants::CONFIG_PATH_DB_PREFIX)]; $setup = $this->setupFactory->create($this->context->getResources()); $adminAccount = $this->adminAccountFactory->create($setup->getConnection(), (array)$data); $adminAccount->save(); From 0c127edb4ab39cf296b8884bf588566c7f8148ad Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 5 Oct 2017 15:14:32 -0500 Subject: [PATCH 042/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Model/Condition/CanViewNotification.php | 18 ++- .../Analytics/Model/NotificationFlag.php | 75 +++++++++++ .../Analytics/Model/NotificationTime.php | 85 ------------ .../Condition/CanViewNotificationTest.php | 22 +-- .../Enabled/SubscriptionHandlerTest.php | 16 --- .../Test/Unit/Model/NotificationFlagTest.php | 107 +++++++++++++++ .../Test/Unit/Model/NotificationTimeTest.php | 126 ------------------ app/code/Magento/Analytics/etc/module.xml | 1 - .../layout/adminhtml_dashboard_index.xml | 2 +- .../web/css/source/_module.less | 6 +- .../web/images/advanced-reporting-badge.svg | 7 - .../web/images/analytics-icon.svg | 84 ++++++++++++ .../Mtf/App/State/NotificationTimeHandler.php | 56 -------- .../app/Magento/Analytics/Test/etc/di.xml | 22 --- .../Setup/Test/TestCase/UpgradeSystemTest.php | 13 -- .../js/modal/modal-component.test.js | 126 ------------------ 16 files changed, 289 insertions(+), 477 deletions(-) create mode 100644 app/code/Magento/Analytics/Model/NotificationFlag.php delete mode 100644 app/code/Magento/Analytics/Model/NotificationTime.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php delete mode 100644 app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/advanced-reporting-badge.svg create mode 100644 app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg delete mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php delete mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 88bc50e622f01..e66b9fa2d722d 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -6,7 +6,7 @@ namespace Magento\Analytics\Model\Condition; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; -use Magento\Analytics\Model\NotificationTime; +use Magento\Analytics\Model\NotificationFlag; /** * Class CanViewNotification @@ -22,19 +22,19 @@ class CanViewNotification implements VisibilityConditionInterface const NAME = 'can_view_notification'; /** - * @var NotificationTime + * @var NotificationFlag */ - private $notificationTime; + private $notificationFlag; /** * CanViewNotification constructor. * - * @param NotificationTime $notificationTime + * @param NotificationFlag $notificationFlag */ public function __construct( - NotificationTime $notificationTime + NotificationFlag $notificationFlag ) { - $this->notificationTime = $notificationTime; + $this->notificationFlag = $notificationFlag; } /** @@ -44,13 +44,11 @@ public function __construct( */ public function isVisible(array $arguments) { - $lastNotificationTime = $this->notificationTime->getLastTimeNotificationForCurrentUser(); - - if ($lastNotificationTime) { + if ($this->notificationFlag->hasNotificationValueForCurrentUser()) { return false; } - return $this->notificationTime->storeLastTimeNotificationForCurrentUser(); + return $this->notificationFlag->storeNotificationValueForCurrentUser(); } /** diff --git a/app/code/Magento/Analytics/Model/NotificationFlag.php b/app/code/Magento/Analytics/Model/NotificationFlag.php new file mode 100644 index 0000000000000..7f282934d6d28 --- /dev/null +++ b/app/code/Magento/Analytics/Model/NotificationFlag.php @@ -0,0 +1,75 @@ +flagManager = $flagManager; + $this->session = $session; + } + + /** + * Stores flag to indicate the user was notified about Analytic services + * + * @return bool + */ + public function storeNotificationValueForCurrentUser() + { + $flagCode = self::NOTIFICATION_SEEN . $this->session->getUser()->getId(); + return $this->flagManager->saveFlag($flagCode, 1); + } + + /** + * Returns the flag data if the user was notified about Analytic services + * + * @return bool + */ + public function hasNotificationValueForCurrentUser() + { + return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); + } + + /** + * Remove the notification seen flag + * + * @return bool + */ + public function unsetNotificationValueForCurrentUser() + { + return $this->flagManager->deleteFlag(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); + } +} diff --git a/app/code/Magento/Analytics/Model/NotificationTime.php b/app/code/Magento/Analytics/Model/NotificationTime.php deleted file mode 100644 index c3ebf52da4b99..0000000000000 --- a/app/code/Magento/Analytics/Model/NotificationTime.php +++ /dev/null @@ -1,85 +0,0 @@ -flagManager = $flagManager; - $this->userContext = $userContext; - $this->dateTimeFactory = $dateTimeFactory; - } - - /** - * Stores last notification time - * - * @return bool - */ - public function storeLastTimeNotificationForCurrentUser() - { - $flagCode = self::NOTIFICATION_TIME . $this->userContext->getUserId(); - $dateTime = $this->dateTimeFactory->create(); - return $this->flagManager->saveFlag($flagCode, $dateTime->getTimestamp()); - } - - /** - * Returns last time when merchant was notified about Analytic services - * - * @return int - */ - public function getLastTimeNotificationForCurrentUser() - { - return $this->flagManager->getFlagData(self::NOTIFICATION_TIME . $this->userContext->getUserId()); - } - - /** - * Remove last notification time flag. - * - * @return bool - */ - public function unsetLastTimeNotificationValueForCurrentUser() - { - return $this->flagManager->deleteFlag(self::NOTIFICATION_TIME . $this->userContext->getUserId()); - } -} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index b12325a0ee511..e7eafcdbe7024 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -8,7 +8,7 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Analytics\Model\NotificationTime; +use Magento\Analytics\Model\NotificationFlag; /** * Class CanViewNotificationTest @@ -16,9 +16,9 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase { /** - * @var NotificationTime|\PHPUnit_Framework_MockObject_MockObject + * @var NotificationFlag|\PHPUnit_Framework_MockObject_MockObject */ - private $notificationTimeMock; + private $notificationFlagMock; /** * @var CanViewNotification @@ -27,33 +27,33 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase public function setUp() { - $this->notificationTimeMock = $this->getMockBuilder(NotificationTime::class) + $this->notificationFlagMock = $this->getMockBuilder(NotificationFlag::class) ->disableOriginalConstructor() ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'notificationTime' => $this->notificationTimeMock + 'notificationFlag' => $this->notificationFlagMock ] ); } public function testUserShouldSeeNotification() { - $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotificationForCurrentUser') + $this->notificationFlagMock->expects($this->once()) + ->method('hasNotificationValueForCurrentUser') ->willReturn(false); - $this->notificationTimeMock->expects($this->once()) - ->method('storeLastTimeNotificationForCurrentUser') + $this->notificationFlagMock->expects($this->once()) + ->method('storeNotificationValueForCurrentUser') ->willReturn(true); $this->assertTrue($this->canViewNotification->isVisible([])); } public function testUserShouldNotSeeNotification() { - $this->notificationTimeMock->expects($this->once()) - ->method('getLastTimeNotificationForCurrentUser') + $this->notificationFlagMock->expects($this->once()) + ->method('hasNotificationValueForCurrentUser') ->willReturn(true); $this->assertFalse($this->canViewNotification->isVisible([])); } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php index ff3b807e5d8c5..82aa4dc72dfe0 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Config/Backend/Enabled/SubscriptionHandlerTest.php @@ -9,7 +9,6 @@ use Magento\Analytics\Model\AnalyticsToken; use Magento\Analytics\Model\Config\Backend\CollectionTime; use Magento\Analytics\Model\Config\Backend\Enabled\SubscriptionHandler; -use Magento\Analytics\Model\NotificationTime; use Magento\Framework\App\Config\Storage\WriterInterface; use Magento\Framework\FlagManager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; @@ -49,9 +48,6 @@ class SubscriptionHandlerTest extends \PHPUnit\Framework\TestCase */ private $subscriptionHandler; - /** - * @return void - */ protected function setUp() { $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) @@ -79,9 +75,6 @@ protected function setUp() ); } - /** - * @return void - */ public function testProcessEnabledTokenExist() { $this->tokenMock @@ -99,9 +92,6 @@ public function testProcessEnabledTokenExist() ); } - /** - * @return void - */ public function testProcessEnabledTokenDoesNotExist() { $this->tokenMock @@ -122,9 +112,6 @@ public function testProcessEnabledTokenDoesNotExist() ); } - /** - * @return void - */ public function testProcessDisabledTokenDoesNotExist() { $this->configWriterMock @@ -145,9 +132,6 @@ public function testProcessDisabledTokenDoesNotExist() ); } - /** - * @return void - */ public function testProcessDisabledTokenExists() { $this->configWriterMock diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php new file mode 100644 index 0000000000000..94816cb0965c5 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php @@ -0,0 +1,107 @@ +userId = 1; + + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods(['getUser', 'getId']) + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->notificationFlag = $objectManagerHelper->getObject( + NotificationFlag::class, + [ + 'flagManager' => $this->flagManagerMock, + 'session' => $this->sessionMock + ] + ); + } + + public function testStoreNotificationValueForCurrentUser() + { + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId, 1) + ->willReturn(true); + $this->assertTrue($this->notificationFlag->storeNotificationValueForCurrentUser()); + } + + public function testHasNotificationValueForCurrentUser() + { + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) + ->willReturn(true); + $this->assertTrue($this->notificationFlag->hasNotificationValueForCurrentUser()); + } + + public function testUnsetNotificationValueForCurrentUser() + { + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->flagManagerMock + ->expects($this->once()) + ->method('deleteFlag') + ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) + ->willReturn(true); + $this->assertTrue($this->notificationFlag->unsetNotificationValueForCurrentUser()); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php deleted file mode 100644 index e60407f9bf8dd..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationTimeTest.php +++ /dev/null @@ -1,126 +0,0 @@ -value = 10005000; - $this->userId = 1; - - $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) - ->disableOriginalConstructor() - ->getMock(); - $this->userContextInterfaceMock = $this->getMockBuilder(UserContextInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->dateTimeFactoryMock = $this->getMockBuilder(DateTimeFactory::class) - ->getMock(); - $this->dateTimeMock = $this->getMockBuilder(\DateTime::class) - ->getMock(); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->notificationTime = $objectManagerHelper->getObject( - NotificationTime::class, - [ - 'flagManager' => $this->flagManagerMock, - 'userContext' => $this->userContextInterfaceMock, - 'dateTimeFactory' => $this->dateTimeFactoryMock - ] - ); - } - - public function testStoreLastTimeNotificationForCurrentUser() - { - $this->userContextInterfaceMock->expects($this->once()) - ->method("getUserId") - ->willReturn(1); - $this->dateTimeFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->dateTimeMock); - $this->dateTimeMock->expects($this->once()) - ->method('getTimestamp') - ->willReturn(10005000); - - $this->flagManagerMock - ->expects($this->once()) - ->method('saveFlag') - ->with(NotificationTime::NOTIFICATION_TIME . $this->userId, $this->value) - ->willReturn(true); - $this->assertTrue($this->notificationTime->storeLastTimeNotificationForCurrentUser()); - } - - public function testGetLastTimeNotificationForCurrentUser() - { - $this->userContextInterfaceMock->expects($this->once()) - ->method("getUserId") - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('getFlagData') - ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) - ->willReturn(true); - $this->assertEquals($this->value, $this->notificationTime->getLastTimeNotificationForCurrentUser()); - } - - public function testUnsetLastTimeNotificationValueForCurrentUser() - { - $this->userContextInterfaceMock->expects($this->once()) - ->method("getUserId") - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('deleteFlag') - ->with(NotificationTime::NOTIFICATION_TIME . $this->userId) - ->willReturn(true); - $this->assertTrue($this->notificationTime->unsetLastTimeNotificationValueForCurrentUser()); - } -} diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml index 37d1a9e79ad70..32ee5d23a4d86 100644 --- a/app/code/Magento/Analytics/etc/module.xml +++ b/app/code/Magento/Analytics/etc/module.xml @@ -12,7 +12,6 @@ - diff --git a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml index 3bfb5ca595790..a8f62d6d891a9 100644 --- a/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/Analytics/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> - + - - diff --git a/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg new file mode 100644 index 0000000000000..fde91d775d444 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_Analytics/web/images/analytics-icon.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php b/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php deleted file mode 100644 index 0ea32df272729..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Analytics/Mtf/App/State/NotificationTimeHandler.php +++ /dev/null @@ -1,56 +0,0 @@ -configuration = $configuration; - } - - /** - * Cancel subscription for functional tests - * - * @param AbstractState $state - * @return bool - * @throws \Exception - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function execute(AbstractState $state) - { - $url = $_ENV['app_backend_url'] . 'analytics/subscription/postpone'; - $curl = new BackendDecorator(new CurlTransport(), $this->configuration); - $curl->write($url, []); - $response = $curl->read(); - $curl->close(); - if (isset($response['success'])) { - return $response['success']; - } - return false; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml index 74b10cca43c1f..946be3f01537a 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -6,13 +6,6 @@ */ --> - - - - Magento\Analytics\Mtf\App\State\NotificationTimeHandler - - - S1 @@ -33,19 +26,4 @@ S1 - - - S1 - - - - - S1 - - - - - S1 - - diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php index 395fa4cd4d81f..53c36e0a1e1b0 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/TestCase/UpgradeSystemTest.php @@ -30,11 +30,6 @@ class UpgradeSystemTest extends Injectable */ protected $adminDashboard; - /** - * @var \Magento\Analytics\Mtf\App\State\NotificationTimeHandler - */ - private $analyticsNotificationHandler; - /** * @var \Magento\Mtf\Util\Iterator\ApplicationState */ @@ -43,18 +38,15 @@ class UpgradeSystemTest extends Injectable /** * @param Dashboard $adminDashboard * @param SetupWizard $setupWizard - * @param \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler * @param \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator */ public function __inject( Dashboard $adminDashboard, SetupWizard $setupWizard, - \Magento\Analytics\Mtf\App\State\NotificationTimeHandler $analyticsNotificationHandler, \Magento\Mtf\Util\Iterator\ApplicationState $applicationStateIterator ) { $this->adminDashboard = $adminDashboard; $this->setupWizard = $setupWizard; - $this->analyticsNotificationHandler = $analyticsNotificationHandler; $this->applicationStateIterator = $applicationStateIterator; } @@ -141,11 +133,6 @@ public function test( $assertSuccessMessage->processAssert($this->setupWizard, $upgrade['package']); - // Disable promotion popup for Analytics module - $appStateMetadata = $this->applicationStateIterator->current(); - $appState = \Magento\Mtf\ObjectManager::getInstance()->get($appStateMetadata['class']); - $this->analyticsNotificationHandler->execute($appState); - // Check application version $this->adminDashboard->open(); $assertApplicationVersion->processAssert($this->adminDashboard, $version); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js deleted file mode 100644 index 9f691c8dc2d05..0000000000000 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Analytics/adminhtml/js/modal/modal-component.test.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -/* global jQuery */ -/* eslint-disable max-nested-callbacks */ -define([ - 'jquery', - 'squire' -], function ($, Squire) { - 'use strict'; - - var injector = new Squire(), - mocks = { - 'Magento_Ui/js/modal/alert': jasmine.createSpy(), - 'uiRegistry': jasmine.createSpy() - }, - obj; - - describe('Magento_Analytics/js/modal/modal-component', function () { - beforeEach(function (done) { - injector.mock(mocks); - injector.require(['Magento_Analytics/js/modal/modal-component'], function (Constr) { - obj = new Constr({ - provider: 'provName', - name: '', - index: '', - links: '', - listens: '', - - /** - * @return {Object} source - mock for form data - */ - form: function () { - return { - source: { - data: {} - } - }; - } - }); - done(); - }); - }); - describe('"sendPostponeRequest" method', function () { - it('should send a ajax request', function () { - jQuery.ajax = jasmine.createSpy().and.callFake(function () { - var d = $.Deferred(); - - d.resolve({ - 'success': true - }); - - return d.promise(); - }); - - obj.sendPostponeRequest({}); - - expect(jQuery.ajax).toHaveBeenCalled(); - }); - - it('should call "onError" method if ajax received error', function () { - spyOn(obj, 'onError'); - jQuery.ajax = jasmine.createSpy().and.callFake(function () { - var d = $.Deferred(); - - d.resolve({ - 'error': true - }); - - return d.promise(); - }); - - obj.sendPostponeRequest({}); - - expect(jQuery.ajax).toHaveBeenCalled(); - expect(obj.onError).toHaveBeenCalled(); - }); - - it('should call "onError" method if request failed', function () { - spyOn(obj, 'onError'); - jQuery.ajax = jasmine.createSpy().and.callFake(function () { - var d = $.Deferred(); - - d.reject(); - - return d.promise(); - }); - - obj.sendPostponeRequest({}); - - expect(jQuery.ajax).toHaveBeenCalled(); - expect(obj.onError).toHaveBeenCalled(); - }); - }); - - describe('"onError" method', function () { - var abortRequest = { - statusText: 'abort' - }, - errorRequest = { - error: true, - message: 'Error text' - }; - - it('should do nothing if request aborted', function () { - expect(obj.onError(abortRequest)).toBeUndefined(); - }); - - it('should show alert with error', function () { - obj.onError(errorRequest); - expect(mocks['Magento_Ui/js/modal/alert']).toHaveBeenCalled(); - }); - }); - - describe('"actionCancel" method', function () { - it('should call "sendPostponeRequest" and "closeModal" methods', function () { - spyOn(obj, 'sendPostponeRequest'); - spyOn(obj, 'closeModal'); - obj.actionCancel(); - expect(obj.sendPostponeRequest).toHaveBeenCalledWith(obj.postponeOptions); - expect(obj.closeModal).toHaveBeenCalled(); - }); - }); - }); -}); From d07813406ea5a8c870324c3b8c746b2a2c7a8b54 Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Thu, 5 Oct 2017 22:15:41 +0200 Subject: [PATCH 043/528] Add Guard Clause to check if invoice has been canceled previously and Tests --- .../Magento/Sales/Model/Order/Invoice.php | 3 + .../Test/Unit/Model/Order/InvoiceTest.php | 59 ++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Invoice.php b/app/code/Magento/Sales/Model/Order/Invoice.php index 014ad8fd5fe3a..3f2fa1f72f6e5 100644 --- a/app/code/Magento/Sales/Model/Order/Invoice.php +++ b/app/code/Magento/Sales/Model/Order/Invoice.php @@ -407,6 +407,9 @@ public function void() */ public function cancel() { + if (!$this->canCancel()) { + return $this; + } $order = $this->getOrder(); $order->getPayment()->cancelInvoice($this); foreach ($this->getAllItems() as $item) { diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php index 0962e32dfb6ed..143089f75f7f8 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php @@ -8,6 +8,7 @@ namespace Magento\Sales\Test\Unit\Model\Order; +use Magento\Sales\Api\Data\InvoiceInterface; use Magento\Sales\Model\Order\Invoice; use Magento\Sales\Model\ResourceModel\OrderFactory; use Magento\Sales\Model\Order; @@ -72,7 +73,7 @@ protected function setUp() ->setMethods( [ 'getPayment', '__wakeup', 'load', 'setHistoryEntityName', 'getStore', 'getBillingAddress', - 'getShippingAddress' + 'getShippingAddress', 'getConfig', ] ) ->getMock(); @@ -83,7 +84,7 @@ protected function setUp() $this->paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods( - ['canVoid', '__wakeup', 'canCapture', 'capture', 'pay'] + ['canVoid', '__wakeup', 'canCapture', 'capture', 'pay', 'cancelInvoice'] )->getMock(); $this->orderFactory = $this->createPartialMock(\Magento\Sales\Model\OrderFactory::class, ['create']); @@ -407,4 +408,58 @@ private function getOrderInvoiceCollection() return $collection; } + + /** + * Assert open invoice can be canceled, and its status changes + */ + public function testCancelOpenInvoice() + { + $orderConfigMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Config::class) + ->disableOriginalConstructor()->setMethods( + ['getStateDefaultStatus'] + )->getMock(); + $orderConfigMock->expects($this->once())->method('getStateDefaultStatus') + ->with(Order::STATE_PROCESSING) + ->willReturn(Order::STATE_PROCESSING); + $this->order->expects($this->once())->method('getPayment')->willReturn($this->paymentMock); + $this->order->expects($this->once())->method('getConfig')->willReturn($orderConfigMock); + $this->paymentMock->expects($this->once())->method('cancelInvoice')->willReturn($this->paymentMock); + $this->eventManagerMock->expects($this->once()) + ->method('dispatch') + ->with('sales_order_invoice_cancel'); + $this->model->setData(InvoiceInterface::ITEMS, []); + $this->model->setState(Invoice::STATE_OPEN); + $this->model->cancel(); + self::assertEquals(Invoice::STATE_CANCELED, $this->model->getState()); + } + + /** + * Assert open invoice can be canceled, and its status changes + * + * @param $initialInvoiceStatus + * @param $expectedInvoiceStatus + * @dataProvider getNotOpenedInvoiceStatuses + */ + public function testCannotCancelNotOpenedInvoice($initialInvoiceStatus, $expectedInvoiceStatus) + { + $this->order->expects($this->never())->method('getPayment'); + $this->paymentMock->expects($this->never())->method('cancelInvoice'); + $this->eventManagerMock->expects($this->never()) + ->method('dispatch') + ->with('sales_order_invoice_cancel'); + $this->model->setState($initialInvoiceStatus); + $this->model->cancel(); + self::assertEquals($expectedInvoiceStatus, $this->model->getState()); + } + + /** + * @return array + */ + public function getNotOpenedInvoiceStatuses() + { + return [ + [Invoice::STATE_PAID, Invoice::STATE_PAID], + [Invoice::STATE_CANCELED, Invoice::STATE_CANCELED], + ]; + } } From 97b336d375227fe8a184337cc0341283770affeb Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 5 Oct 2017 15:18:39 -0500 Subject: [PATCH 044/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../functional/tests/app/Magento/Analytics/Test/etc/di.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml index cc113f1768e2e..ac51a3e2b6dd8 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/di.xml @@ -6,13 +6,6 @@ */ --> - - - - Magento\Analytics\Mtf\App\State\NotificationTimeHandler - - - S1 From b65b73d0d3fbe1fd7c11d403fd664a271836bfda Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Thu, 5 Oct 2017 22:28:43 +0200 Subject: [PATCH 045/528] Fix Codacy Variable too long --- .../Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php index 143089f75f7f8..0517da8b85cf0 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/InvoiceTest.php @@ -437,10 +437,10 @@ public function testCancelOpenInvoice() * Assert open invoice can be canceled, and its status changes * * @param $initialInvoiceStatus - * @param $expectedInvoiceStatus + * @param $finalInvoiceStatus * @dataProvider getNotOpenedInvoiceStatuses */ - public function testCannotCancelNotOpenedInvoice($initialInvoiceStatus, $expectedInvoiceStatus) + public function testCannotCancelNotOpenedInvoice($initialInvoiceStatus, $finalInvoiceStatus) { $this->order->expects($this->never())->method('getPayment'); $this->paymentMock->expects($this->never())->method('cancelInvoice'); @@ -449,7 +449,7 @@ public function testCannotCancelNotOpenedInvoice($initialInvoiceStatus, $expecte ->with('sales_order_invoice_cancel'); $this->model->setState($initialInvoiceStatus); $this->model->cancel(); - self::assertEquals($expectedInvoiceStatus, $this->model->getState()); + self::assertEquals($finalInvoiceStatus, $this->model->getState()); } /** From 86032de8e54a0a8567dd8c503aa75ff38efbfa5c Mon Sep 17 00:00:00 2001 From: David Date: Fri, 6 Oct 2017 10:25:04 +0200 Subject: [PATCH 046/528] Use strict comparision instead of is_null --- lib/internal/Magento/Framework/View/Model/Layout/Merge.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/View/Model/Layout/Merge.php b/lib/internal/Magento/Framework/View/Model/Layout/Merge.php index 1bae54e8728d9..4d611c830e91a 100644 --- a/lib/internal/Magento/Framework/View/Model/Layout/Merge.php +++ b/lib/internal/Magento/Framework/View/Model/Layout/Merge.php @@ -799,7 +799,7 @@ private function getXmlErrors($libXmlErrors) protected function _getPhysicalTheme(\Magento\Framework\View\Design\ThemeInterface $theme) { $result = $theme; - while (!is_null($result) && $result->getId() && !$result->isPhysical()) { + while ($result !== null && $result->getId() && !$result->isPhysical()) { $result = $result->getParentTheme(); } if (!$result) { From ae0af893a3e39a4a98c12136dddad92de3eef93b Mon Sep 17 00:00:00 2001 From: Iurii Ivashchenko Date: Fri, 6 Oct 2017 16:44:27 +0300 Subject: [PATCH 047/528] MAGETWO-80209: [2.2.x] - Static versioning and styles minification break email fonts styles #8241 #10638 --- .../Test/Unit/Model/Template/FilterTest.php | 2 +- composer.json | 2 +- composer.lock | 114 +++++++++--------- .../PreProcessor/Adapter/CssInlinerTest.php | 8 +- .../Css/PreProcessor/Adapter/CssInliner.php | 8 +- 5 files changed, 65 insertions(+), 69 deletions(-) diff --git a/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php b/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php index 8bfa2fc7d64cc..2eb8f582c54fa 100644 --- a/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php +++ b/app/code/Magento/Email/Test/Unit/Model/Template/FilterTest.php @@ -369,7 +369,7 @@ public function applyInlineCssDataProvider() '

', 'p { color: #000 }', [ - '', + '', '

', ], ], diff --git a/composer.json b/composer.json index 106e1657cb8ff..f87dfae22c08d 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "composer/composer": "1.4.1", "monolog/monolog": "^1.17", "oyejorge/less.php": "~1.7.0", - "pelago/emogrifier": "0.1.1", + "pelago/emogrifier": "1.2.0", "tubalmartin/cssmin": "4.1.0", "magento/magento-composer-installer": ">=0.1.11", "braintree/braintree_php": "3.22.0", diff --git a/composer.lock b/composer.lock index 65b5d6f561190..abd5bde659598 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "0018e7db581f83ff881d4c21d19cda3b", + "content-hash": "2a0540e2c6b29c9b81806dcc434940ce", "packages": [ { "name": "braintree/braintree_php", @@ -493,16 +493,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.2", + "version": "5.2.4", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "b80053b620826810b38211b3c5f935ba9cddf6b3" + "reference": "7ccb0e67ea8ace0f84c40900ca3c8a234467628c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/b80053b620826810b38211b3c5f935ba9cddf6b3", - "reference": "b80053b620826810b38211b3c5f935ba9cddf6b3", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/7ccb0e67ea8ace0f84c40900ca3c8a234467628c", + "reference": "7ccb0e67ea8ace0f84c40900ca3c8a234467628c", "shasum": "" }, "require": { @@ -555,7 +555,7 @@ "json", "schema" ], - "time": "2017-10-03T00:49:49+00:00" + "time": "2017-10-04T20:57:36+00:00" }, { "name": "league/climate", @@ -958,27 +958,31 @@ }, { "name": "pelago/emogrifier", - "version": "v0.1.1", + "version": "V1.2.0", "source": { "type": "git", "url": "https://github.com/jjriv/emogrifier.git", - "reference": "ed72bcd6a3c7014862ff86d026193667a172fedf" + "reference": "a1db453bb504597d821efcc04b21c79a6021e00c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jjriv/emogrifier/zipball/ed72bcd6a3c7014862ff86d026193667a172fedf", - "reference": "ed72bcd6a3c7014862ff86d026193667a172fedf", + "url": "https://api.github.com/repos/jjriv/emogrifier/zipball/a1db453bb504597d821efcc04b21c79a6021e00c", + "reference": "a1db453bb504597d821efcc04b21c79a6021e00c", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": ">=5.4.0" + "php": ">=5.4.0,<=7.1.99" }, "require-dev": { - "phpunit/phpunit": "~4.6.0", - "squizlabs/php_codesniffer": "~2.3.0" + "phpunit/phpunit": "4.8.27", + "squizlabs/php_codesniffer": "2.6.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, "autoload": { "psr-4": { "Pelago\\": "Classes/" @@ -1010,7 +1014,7 @@ ], "description": "Converts CSS styles into inline style attributes in your HTML code", "homepage": "http://www.pelagodesign.com/sidecar/emogrifier/", - "time": "2015-05-15T11:37:51+00:00" + "time": "2017-03-02T12:51:48+00:00" }, { "name": "phpseclib/phpseclib", @@ -1478,16 +1482,16 @@ }, { "name": "symfony/console", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253" + "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c0807a2ca978e64d8945d373a9221a5c35d1a253", - "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253", + "url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853", + "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853", "shasum": "" }, "require": { @@ -1535,7 +1539,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-08-27T14:29:03+00:00" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "symfony/debug", @@ -1596,16 +1600,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d" + "reference": "7fe089232554357efb8d4af65ce209fc6e5a2186" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1377400fd641d7d1935981546aaef780ecd5bf6d", - "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7fe089232554357efb8d4af65ce209fc6e5a2186", + "reference": "7fe089232554357efb8d4af65ce209fc6e5a2186", "shasum": "" }, "require": { @@ -1652,20 +1656,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-06-02T07:47:27+00:00" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "symfony/filesystem", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb" + "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1", + "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1", "shasum": "" }, "require": { @@ -1701,20 +1705,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-10-03T13:33:10+00:00" }, { "name": "symfony/finder", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e" + "reference": "773e19a491d97926f236942484cb541560ce862d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", - "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", + "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d", + "reference": "773e19a491d97926f236942484cb541560ce862d", "shasum": "" }, "require": { @@ -1750,7 +1754,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-10-02T06:42:24+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -1813,16 +1817,16 @@ }, { "name": "symfony/process", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8" + "reference": "26c9fb02bf06bd6b90f661a5bd17e510810d0176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", - "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", + "url": "https://api.github.com/repos/symfony/process/zipball/26c9fb02bf06bd6b90f661a5bd17e510810d0176", + "reference": "26c9fb02bf06bd6b90f661a5bd17e510810d0176", "shasum": "" }, "require": { @@ -1858,7 +1862,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-07-03T08:04:30+00:00" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "tedivm/jshrink", @@ -5527,16 +5531,16 @@ }, { "name": "symfony/config", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "f9f19a39ee178f61bb2190f51ff7c517c2159315" + "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/f9f19a39ee178f61bb2190f51ff7c517c2159315", - "reference": "f9f19a39ee178f61bb2190f51ff7c517c2159315", + "url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd", + "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd", "shasum": "" }, "require": { @@ -5585,20 +5589,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-09-04T16:28:07+00:00" + "time": "2017-10-04T18:56:58+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "e593f06dd90a81c7b70ac1c49862a061b0ec06d2" + "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e593f06dd90a81c7b70ac1c49862a061b0ec06d2", - "reference": "e593f06dd90a81c7b70ac1c49862a061b0ec06d2", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1", + "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1", "shasum": "" }, "require": { @@ -5655,7 +5659,7 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-09-05T20:39:38+00:00" + "time": "2017-10-04T17:15:30+00:00" }, { "name": "symfony/polyfill-php54", @@ -5935,16 +5939,16 @@ }, { "name": "symfony/stopwatch", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "9a5610a8d6a50985a7be485c0ba745c22607beeb" + "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/9a5610a8d6a50985a7be485c0ba745c22607beeb", - "reference": "9a5610a8d6a50985a7be485c0ba745c22607beeb", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/170edf8b3247d7b6779eb6fa7428f342702ca184", + "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184", "shasum": "" }, "require": { @@ -5980,7 +5984,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-07-29T21:54:42+00:00" + "time": "2017-10-02T06:42:24+00:00" }, { "name": "theseer/fdomdocument", diff --git a/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/Adapter/CssInlinerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/Adapter/CssInlinerTest.php index f1468f718df61..63c14b4293f7b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/Adapter/CssInlinerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Css/PreProcessor/Adapter/CssInlinerTest.php @@ -76,12 +76,10 @@ public function testGetFilesEmogrifier($htmlFilePath, $cssFilePath, $cssExpected $emogrifier->setHtml($html); $result = $emogrifier->emogrify(); /** - * Tests a bug in the library where there's no spaces to CSS string before passing to Emogrifier - * to fix known parsing issue with library. - * This test should will fail when this bug is fixed in the library and we should fix the adapter. - * https://github.com/jjriv/emogrifier/issues/370 + * This test was implemented for the issue which existed in the older version of Emogrifier. + * Test was updated, as the library got updated as well. */ - $this->assertNotContains($cssExpected, $result); + $this->assertContains($cssExpected, $result); } /** diff --git a/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/CssInliner.php b/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/CssInliner.php index 342283c312293..7164e68c709fb 100644 --- a/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/CssInliner.php +++ b/lib/internal/Magento/Framework/Css/PreProcessor/Adapter/CssInliner.php @@ -41,13 +41,7 @@ public function setHtml($html) */ public function setCss($css) { - /** - * Adds space to CSS string before passing to Emogrifier to fix known parsing issue with library. - * https://github.com/jjriv/emogrifier/issues/370 - */ - $cssWithAddedSpaces = preg_replace('#([\{\}>])#i', ' $1 ', $css); - - $this->emogrifier->setCss($cssWithAddedSpaces); + $this->emogrifier->setCss($css); } /** From ae9f2050e0cb5dad500d39be9fd42e1116b9f60e Mon Sep 17 00:00:00 2001 From: marina Date: Fri, 6 Oct 2017 17:03:42 +0300 Subject: [PATCH 048/528] Check cart rule subselect conditions against quote item children too The subselect condition only checked the visible quote items and this proved to be a problem in the case of configurable and bundle products. The quote item children are now checked against the validation too, and an item will be considered valid and added to the subselect total if either it, or at least one of it's children is validated. In the case of bundle products, the children items data will be used and added to the subselect total, when the match is on a child item. In the case of configurable products, the parent item data will be used in the subselect total, just like for all the other product types. Resolves: #10477 --- .../Model/Rule/Condition/Product/Subselect.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Rule/Condition/Product/Subselect.php b/app/code/Magento/SalesRule/Model/Rule/Condition/Product/Subselect.php index 108cc341253ae..51b5aea31143f 100644 --- a/app/code/Magento/SalesRule/Model/Rule/Condition/Product/Subselect.php +++ b/app/code/Magento/SalesRule/Model/Rule/Condition/Product/Subselect.php @@ -145,8 +145,22 @@ public function validate(\Magento\Framework\Model\AbstractModel $model) $attr = $this->getAttribute(); $total = 0; foreach ($model->getQuote()->getAllVisibleItems() as $item) { - if (parent::validate($item)) { - $total += $item->getData($attr); + $hasValidChild = false; + $useChildrenTotal = ($item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_BUNDLE); + $childrenAttrTotal = 0; + $children = $item->getChildren(); + if (!empty($children)) { + foreach ($children as $child) { + if (parent::validate($child)) { + $hasValidChild = true; + if ($useChildrenTotal) { + $childrenAttrTotal += $child->getData($attr); + } + } + } + } + if ($hasValidChild || parent::validate($item)) { + $total += (($hasValidChild && $useChildrenTotal) ? $childrenAttrTotal : $item->getData($attr)); } } return $this->validateAttribute($total); From eefdc1cdb6c21298e135fbbf986cabf742647caa Mon Sep 17 00:00:00 2001 From: Romain Ruaud Date: Thu, 5 Oct 2017 16:15:21 +0200 Subject: [PATCH 049/528] Fixing keyboard submit of adminhtml suggest form. --- lib/web/mage/backend/suggest.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/web/mage/backend/suggest.js b/lib/web/mage/backend/suggest.js index 81bde35f9e12a..2ce3405783ea1 100644 --- a/lib/web/mage/backend/suggest.js +++ b/lib/web/mage/backend/suggest.js @@ -245,6 +245,20 @@ case keyCode.ENTER: case keyCode.NUMPAD_ENTER: + suggestList = event.currentTarget.parentNode.getElementsByTagName('ul')[0]; + hasSelectedItems = suggestList.getElementsByClassName('_active').length >= 0; + + if (hasSelectedItems) { + selectedItem = $(suggestList.getElementsByClassName('_active')[0]); + /* eslint-disable max-depth */ + if (selectedItem.find('a') && selectedItem.find('a').attr('href') !== undefined) { + window.location = selectedItem.find('a').attr('href'); + event.preventDefault(); + + return false; + } + /* eslint-enable max-depth */ + } if (this.isDropdownShown() && this._focused) { this._proxyEvents(event); From cad0c4528b91ee1c20f473235b054e5506e8d719 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Fri, 6 Oct 2017 11:49:03 -0500 Subject: [PATCH 050/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Model/Condition/CanViewNotification.php | 28 +++-- .../Analytics/Model/NotificationFlag.php | 75 ------------ .../Model/NotificationFlagManager.php | 56 +++++++++ .../Condition/CanViewNotificationTest.php | 49 +++++--- .../Model/NotificationFlagManagerTest.php | 67 +++++++++++ .../Test/Unit/Model/NotificationFlagTest.php | 107 ------------------ 6 files changed, 178 insertions(+), 204 deletions(-) delete mode 100644 app/code/Magento/Analytics/Model/NotificationFlag.php create mode 100644 app/code/Magento/Analytics/Model/NotificationFlagManager.php create mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php delete mode 100644 app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index e66b9fa2d722d..9f1e48fb2c8f7 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -5,8 +5,9 @@ */ namespace Magento\Analytics\Model\Condition; +use Magento\Backend\Model\Auth\Session; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; -use Magento\Analytics\Model\NotificationFlag; +use Magento\Analytics\Model\NotificationFlagManager; /** * Class CanViewNotification @@ -22,33 +23,42 @@ class CanViewNotification implements VisibilityConditionInterface const NAME = 'can_view_notification'; /** - * @var NotificationFlag + * @var NotificationFlagManager */ - private $notificationFlag; + private $notificationFlagManager; + + /** + * @var Session + */ + private $session; /** * CanViewNotification constructor. * - * @param NotificationFlag $notificationFlag + * @param NotificationFlagManager $notificationFlagManager + * @param Session $session */ public function __construct( - NotificationFlag $notificationFlag + NotificationFlagManager $notificationFlagManager, + Session $session ) { - $this->notificationFlag = $notificationFlag; + $this->notificationFlagManager = $notificationFlagManager; + $this->session = $session; } /** - * Validate if notification popup can be shown + * Validate if notification popup can be shown and set the notification flag * * @inheritdoc */ public function isVisible(array $arguments) { - if ($this->notificationFlag->hasNotificationValueForCurrentUser()) { + $userId = $this->session->getUser()->getId(); + if ($this->notificationFlagManager->isUserNotified($userId)) { return false; } - return $this->notificationFlag->storeNotificationValueForCurrentUser(); + return $this->notificationFlagManager->setNotifiedUser($userId); } /** diff --git a/app/code/Magento/Analytics/Model/NotificationFlag.php b/app/code/Magento/Analytics/Model/NotificationFlag.php deleted file mode 100644 index 7f282934d6d28..0000000000000 --- a/app/code/Magento/Analytics/Model/NotificationFlag.php +++ /dev/null @@ -1,75 +0,0 @@ -flagManager = $flagManager; - $this->session = $session; - } - - /** - * Stores flag to indicate the user was notified about Analytic services - * - * @return bool - */ - public function storeNotificationValueForCurrentUser() - { - $flagCode = self::NOTIFICATION_SEEN . $this->session->getUser()->getId(); - return $this->flagManager->saveFlag($flagCode, 1); - } - - /** - * Returns the flag data if the user was notified about Analytic services - * - * @return bool - */ - public function hasNotificationValueForCurrentUser() - { - return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); - } - - /** - * Remove the notification seen flag - * - * @return bool - */ - public function unsetNotificationValueForCurrentUser() - { - return $this->flagManager->deleteFlag(self::NOTIFICATION_SEEN . $this->session->getUser()->getId()); - } -} diff --git a/app/code/Magento/Analytics/Model/NotificationFlagManager.php b/app/code/Magento/Analytics/Model/NotificationFlagManager.php new file mode 100644 index 0000000000000..624e0ab6bcdd1 --- /dev/null +++ b/app/code/Magento/Analytics/Model/NotificationFlagManager.php @@ -0,0 +1,56 @@ +flagManager = $flagManager; + } + + /** + * Sets the flag to indicate the user was notified about Analytic services + * @param $userId + * @return bool + */ + public function setNotifiedUser($userId) + { + $flagCode = self::NOTIFICATION_SEEN . $userId; + return $this->flagManager->saveFlag($flagCode, 1); + } + + /** + * Returns the flag data if the user was notified about Analytic services + * @param $userId + * @return bool + */ + public function isUserNotified($userId) + { + return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index e7eafcdbe7024..d8882f1fe1887 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -8,7 +8,8 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Analytics\Model\NotificationFlag; +use Magento\Analytics\Model\notificationFlagManager; +use Magento\Backend\Model\Auth\Session; /** * Class CanViewNotificationTest @@ -16,44 +17,66 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase { /** - * @var NotificationFlag|\PHPUnit_Framework_MockObject_MockObject + * @var CanViewNotification */ - private $notificationFlagMock; + private $canViewNotification; /** - * @var CanViewNotification + * @var NotificationFlagManager|\PHPUnit_Framework_MockObject_MockObject */ - private $canViewNotification; + private $notificationFlagManagerMock; + + /** + * @var Session|\PHPUnit_Framework_MockObject_MockObject + */ + private $sessionMock; public function setUp() { - $this->notificationFlagMock = $this->getMockBuilder(NotificationFlag::class) + $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() + ->setMethods(['getUser', 'getId']) ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'notificationFlag' => $this->notificationFlagMock + 'notificationFlagManager' => $this->notificationFlagManagerMock, + 'session' => $this->sessionMock ] ); } public function testUserShouldSeeNotification() { - $this->notificationFlagMock->expects($this->once()) - ->method('hasNotificationValueForCurrentUser') + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->notificationFlagManagerMock->expects($this->once()) + ->method('isUserNotified') ->willReturn(false); - $this->notificationFlagMock->expects($this->once()) - ->method('storeNotificationValueForCurrentUser') + $this->notificationFlagManagerMock->expects($this->once()) + ->method('setNotifiedUser') ->willReturn(true); $this->assertTrue($this->canViewNotification->isVisible([])); } public function testUserShouldNotSeeNotification() { - $this->notificationFlagMock->expects($this->once()) - ->method('hasNotificationValueForCurrentUser') + $this->sessionMock->expects($this->once()) + ->method('getUser') + ->willReturnSelf(); + $this->sessionMock->expects($this->once()) + ->method('getId') + ->willReturn(1); + $this->notificationFlagManagerMock->expects($this->once()) + ->method('isUserNotified') ->willReturn(true); $this->assertFalse($this->canViewNotification->isVisible([])); } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php new file mode 100644 index 0000000000000..8438f86449153 --- /dev/null +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -0,0 +1,67 @@ +userId = 1; + $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + $this->notificationFlagManager = $objectManagerHelper->getObject( + NotificationFlagManager::class, + [ + 'flagManager' => $this->flagManagerMock + ] + ); + } + + public function testSetNotifiedUser() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('saveFlag') + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId, 1) + ->willReturn(true); + $this->assertTrue($this->notificationFlagManager->setNotifiedUser($this->userId)); + } + + public function testIsUserNotified() + { + $this->flagManagerMock + ->expects($this->once()) + ->method('getFlagData') + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId) + ->willReturn(true); + $this->assertTrue($this->notificationFlagManager->isUserNotified($this->userId)); + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php deleted file mode 100644 index 94816cb0965c5..0000000000000 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagTest.php +++ /dev/null @@ -1,107 +0,0 @@ -userId = 1; - - $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) - ->disableOriginalConstructor() - ->getMock(); - $this->sessionMock = $this->getMockBuilder(Session::class) - ->disableOriginalConstructor() - ->setMethods(['getUser', 'getId']) - ->getMock(); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->notificationFlag = $objectManagerHelper->getObject( - NotificationFlag::class, - [ - 'flagManager' => $this->flagManagerMock, - 'session' => $this->sessionMock - ] - ); - } - - public function testStoreNotificationValueForCurrentUser() - { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('saveFlag') - ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId, 1) - ->willReturn(true); - $this->assertTrue($this->notificationFlag->storeNotificationValueForCurrentUser()); - } - - public function testHasNotificationValueForCurrentUser() - { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('getFlagData') - ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) - ->willReturn(true); - $this->assertTrue($this->notificationFlag->hasNotificationValueForCurrentUser()); - } - - public function testUnsetNotificationValueForCurrentUser() - { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->flagManagerMock - ->expects($this->once()) - ->method('deleteFlag') - ->with(NotificationFlag::NOTIFICATION_SEEN . $this->userId) - ->willReturn(true); - $this->assertTrue($this->notificationFlag->unsetNotificationValueForCurrentUser()); - } -} From aabdf799f950072e141f77893059933e22f921d9 Mon Sep 17 00:00:00 2001 From: Joan He Date: Sat, 7 Oct 2017 07:54:34 -0500 Subject: [PATCH 051/528] Merge remote-tracking branch 'upstream/2.2-develop' into MAGETWO-71458-analytics # Conflicts: # composer.lock --- composer.lock | 94 +++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/composer.lock b/composer.lock index 5673d2620a94b..2d43d7ff9163a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "e9655626aff3d3314ffaab8bd609154c", - "content-hash": "bcd940e542a85144ed6e61f7ca9334d6", + "hash": "24aca194b219901b445f7acc8f3a1c16", + "content-hash": "a3dbf15e8a5ad7687ca8b391486311a0", "packages": [ { "name": "braintree/braintree_php", @@ -494,16 +494,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.2", + "version": "5.2.4", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "b80053b620826810b38211b3c5f935ba9cddf6b3" + "reference": "7ccb0e67ea8ace0f84c40900ca3c8a234467628c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/b80053b620826810b38211b3c5f935ba9cddf6b3", - "reference": "b80053b620826810b38211b3c5f935ba9cddf6b3", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/7ccb0e67ea8ace0f84c40900ca3c8a234467628c", + "reference": "7ccb0e67ea8ace0f84c40900ca3c8a234467628c", "shasum": "" }, "require": { @@ -556,7 +556,7 @@ "json", "schema" ], - "time": "2017-10-03 00:49:49" + "time": "2017-10-04 20:57:36" }, { "name": "league/climate", @@ -1479,16 +1479,16 @@ }, { "name": "symfony/console", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253" + "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c0807a2ca978e64d8945d373a9221a5c35d1a253", - "reference": "c0807a2ca978e64d8945d373a9221a5c35d1a253", + "url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853", + "reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853", "shasum": "" }, "require": { @@ -1536,7 +1536,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-08-27 14:29:03" + "time": "2017-10-01 21:00:16" }, { "name": "symfony/debug", @@ -1597,16 +1597,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d" + "reference": "7fe089232554357efb8d4af65ce209fc6e5a2186" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1377400fd641d7d1935981546aaef780ecd5bf6d", - "reference": "1377400fd641d7d1935981546aaef780ecd5bf6d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7fe089232554357efb8d4af65ce209fc6e5a2186", + "reference": "7fe089232554357efb8d4af65ce209fc6e5a2186", "shasum": "" }, "require": { @@ -1653,20 +1653,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-06-02 07:47:27" + "time": "2017-10-01 21:00:16" }, { "name": "symfony/filesystem", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb" + "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", - "reference": "b32a0e5f928d0fa3d1dd03c78d020777e50c10cb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1", + "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1", "shasum": "" }, "require": { @@ -1702,20 +1702,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-07-29 21:54:42" + "time": "2017-10-03 13:33:10" }, { "name": "symfony/finder", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e" + "reference": "773e19a491d97926f236942484cb541560ce862d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", - "reference": "b2260dbc80f3c4198f903215f91a1ac7fe9fe09e", + "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d", + "reference": "773e19a491d97926f236942484cb541560ce862d", "shasum": "" }, "require": { @@ -1751,7 +1751,7 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-07-29 21:54:42" + "time": "2017-10-02 06:42:24" }, { "name": "symfony/polyfill-mbstring", @@ -1814,16 +1814,16 @@ }, { "name": "symfony/process", - "version": "v2.8.27", + "version": "v2.8.28", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8" + "reference": "26c9fb02bf06bd6b90f661a5bd17e510810d0176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", - "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", + "url": "https://api.github.com/repos/symfony/process/zipball/26c9fb02bf06bd6b90f661a5bd17e510810d0176", + "reference": "26c9fb02bf06bd6b90f661a5bd17e510810d0176", "shasum": "" }, "require": { @@ -1859,7 +1859,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-07-03 08:04:30" + "time": "2017-10-01 21:00:16" }, { "name": "tedivm/jshrink", @@ -5528,16 +5528,16 @@ }, { "name": "symfony/config", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "f9f19a39ee178f61bb2190f51ff7c517c2159315" + "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/f9f19a39ee178f61bb2190f51ff7c517c2159315", - "reference": "f9f19a39ee178f61bb2190f51ff7c517c2159315", + "url": "https://api.github.com/repos/symfony/config/zipball/4ab62407bff9cd97c410a7feaef04c375aaa5cfd", + "reference": "4ab62407bff9cd97c410a7feaef04c375aaa5cfd", "shasum": "" }, "require": { @@ -5586,20 +5586,20 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-09-04 16:28:07" + "time": "2017-10-04 18:56:58" }, { "name": "symfony/dependency-injection", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "e593f06dd90a81c7b70ac1c49862a061b0ec06d2" + "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/e593f06dd90a81c7b70ac1c49862a061b0ec06d2", - "reference": "e593f06dd90a81c7b70ac1c49862a061b0ec06d2", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/8ebad929aee3ca185b05f55d9cc5521670821ad1", + "reference": "8ebad929aee3ca185b05f55d9cc5521670821ad1", "shasum": "" }, "require": { @@ -5656,7 +5656,7 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-09-05 20:39:38" + "time": "2017-10-04 17:15:30" }, { "name": "symfony/polyfill-php54", @@ -5936,16 +5936,16 @@ }, { "name": "symfony/stopwatch", - "version": "v3.3.9", + "version": "v3.3.10", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "9a5610a8d6a50985a7be485c0ba745c22607beeb" + "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/9a5610a8d6a50985a7be485c0ba745c22607beeb", - "reference": "9a5610a8d6a50985a7be485c0ba745c22607beeb", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/170edf8b3247d7b6779eb6fa7428f342702ca184", + "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184", "shasum": "" }, "require": { @@ -5981,7 +5981,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-07-29 21:54:42" + "time": "2017-10-02 06:42:24" }, { "name": "theseer/fdomdocument", From 17d37b2e362a75b69634ba9030ad37ef410713ab Mon Sep 17 00:00:00 2001 From: Juliano Vargas Date: Sun, 8 Oct 2017 21:32:11 +0100 Subject: [PATCH 052/528] Update Guest.php Bug fix ref: https://github.com/magento/magento2/issues/11275 --- app/code/Magento/Sales/Helper/Guest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Sales/Helper/Guest.php b/app/code/Magento/Sales/Helper/Guest.php index a80be58bc003e..dd8845008d79e 100644 --- a/app/code/Magento/Sales/Helper/Guest.php +++ b/app/code/Magento/Sales/Helper/Guest.php @@ -178,6 +178,9 @@ public function loadValidOrder(App\RequestInterface $request) public function getBreadcrumbs(\Magento\Framework\View\Result\Page $resultPage) { $breadcrumbs = $resultPage->getLayout()->getBlock('breadcrumbs'); + if (!$breadcrumbs) { + return; + } $breadcrumbs->addCrumb( 'home', [ From b6c78a4056be7c442cd2b88cee206561ccd2de6d Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Mon, 9 Oct 2017 17:40:49 +0200 Subject: [PATCH 053/528] Check if necessary send email to subscribers --- app/code/Magento/Newsletter/Model/Subscriber.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php index 7847098083949..8ffa6102f60ef 100644 --- a/app/code/Magento/Newsletter/Model/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/Subscriber.php @@ -393,10 +393,12 @@ public function randomSequence($length = 32) */ public function subscribe($email) { + $sendInformationEmail = false; $this->loadByEmail($email); if (!$this->getId()) { $this->setSubscriberConfirmCode($this->randomSequence()); + $sendInformationEmail = true; } $isConfirmNeed = $this->_scopeConfig->getValue( @@ -444,12 +446,14 @@ public function subscribe($email) try { /* Save model before sending out email */ $this->save(); - if ($isConfirmNeed === true - && $isOwnSubscribes === false - ) { - $this->sendConfirmationRequestEmail(); - } else { - $this->sendConfirmationSuccessEmail(); + if($sendInformationEmail) { + if ($isConfirmNeed === true + && $isOwnSubscribes === false + ) { + $this->sendConfirmationRequestEmail(); + } else { + $this->sendConfirmationSuccessEmail(); + } } return $this->getStatus(); } catch (\Exception $e) { From f5daa7fd4766ed937c0c7030d0fe69041221a554 Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Mon, 9 Oct 2017 20:06:02 +0200 Subject: [PATCH 054/528] Fix Code Style --- app/code/Magento/Newsletter/Model/Subscriber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php index 8ffa6102f60ef..7a55234302568 100644 --- a/app/code/Magento/Newsletter/Model/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/Subscriber.php @@ -446,7 +446,7 @@ public function subscribe($email) try { /* Save model before sending out email */ $this->save(); - if($sendInformationEmail) { + if ($sendInformationEmail) { if ($isConfirmNeed === true && $isOwnSubscribes === false ) { From 53f999eaec107586d3a7bdd1c02f0ede8c7ed753 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Mon, 9 Oct 2017 15:16:52 -0500 Subject: [PATCH 055/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Model/NotificationFlagManager.php | 6 +++- .../Condition/CanViewNotificationTest.php | 35 ++++++++++--------- .../Model/NotificationFlagManagerTest.php | 18 ++++------ 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Analytics/Model/NotificationFlagManager.php b/app/code/Magento/Analytics/Model/NotificationFlagManager.php index 624e0ab6bcdd1..6fdc88352ed00 100644 --- a/app/code/Magento/Analytics/Model/NotificationFlagManager.php +++ b/app/code/Magento/Analytics/Model/NotificationFlagManager.php @@ -51,6 +51,10 @@ public function setNotifiedUser($userId) */ public function isUserNotified($userId) { - return $this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId); + if ($this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId)) { + return true; + } + + return false; } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index d8882f1fe1887..45a30ea1113a7 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -50,34 +50,35 @@ public function setUp() ); } - public function testUserShouldSeeNotification() + public function isVisibleProvider() { - $this->sessionMock->expects($this->once()) - ->method('getUser') - ->willReturnSelf(); - $this->sessionMock->expects($this->once()) - ->method('getId') - ->willReturn(1); - $this->notificationFlagManagerMock->expects($this->once()) - ->method('isUserNotified') - ->willReturn(false); - $this->notificationFlagManagerMock->expects($this->once()) - ->method('setNotifiedUser') - ->willReturn(true); - $this->assertTrue($this->canViewNotification->isVisible([])); + return [ + [1, false, true], + [1, true, false] + ]; } - public function testUserShouldNotSeeNotification() + /** + * @dataProvider isVisibleProvider + * @param int $userId + * @param bool $isUserNotified + * @param bool $expected + */ + public function testIsVisible($userId, $isUserNotified, $expected) { $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); $this->sessionMock->expects($this->once()) ->method('getId') - ->willReturn(1); + ->willReturn($userId); $this->notificationFlagManagerMock->expects($this->once()) ->method('isUserNotified') + ->willReturn($isUserNotified); + $this->notificationFlagManagerMock->expects($this->any()) + ->method('setNotifiedUser') ->willReturn(true); - $this->assertFalse($this->canViewNotification->isVisible([])); + + $this->assertEquals($expected, $this->canViewNotification->isVisible([])); } } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 8438f86449153..3061ec98e6b1a 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -11,7 +11,7 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; /** - * Class NotificationFlagTest + * Class NotificationFlagManagerTest */ class NotificationFlagManagerTest extends \PHPUnit\Framework\TestCase { @@ -25,14 +25,8 @@ class NotificationFlagManagerTest extends \PHPUnit\Framework\TestCase */ private $notificationFlagManager; - /** - * @var int - */ - private $userId; - public function setUp() { - $this->userId = 1; $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) ->disableOriginalConstructor() ->getMock(); @@ -47,21 +41,23 @@ public function setUp() public function testSetNotifiedUser() { + $userId = 1; $this->flagManagerMock ->expects($this->once()) ->method('saveFlag') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId, 1) + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId, 1) ->willReturn(true); - $this->assertTrue($this->notificationFlagManager->setNotifiedUser($this->userId)); + $this->assertTrue($this->notificationFlagManager->setNotifiedUser($userId)); } public function testIsUserNotified() { + $userId = 1; $this->flagManagerMock ->expects($this->once()) ->method('getFlagData') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $this->userId) + ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId) ->willReturn(true); - $this->assertTrue($this->notificationFlagManager->isUserNotified($this->userId)); + $this->assertTrue($this->notificationFlagManager->isUserNotified($userId)); } } From 0888e8ce84d9f29c97e7c1997b7ff243990c5201 Mon Sep 17 00:00:00 2001 From: marina Date: Mon, 9 Oct 2017 23:57:23 +0300 Subject: [PATCH 056/528] Stop throwing exception in order to send sitemap errors by email --- app/code/Magento/Sitemap/Model/Observer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sitemap/Model/Observer.php b/app/code/Magento/Sitemap/Model/Observer.php index 3ae3061310a0b..54f91bebea744 100644 --- a/app/code/Magento/Sitemap/Model/Observer.php +++ b/app/code/Magento/Sitemap/Model/Observer.php @@ -113,7 +113,6 @@ public function scheduledGenerateSitemaps() $sitemap->generateXml(); } catch (\Exception $e) { $errors[] = $e->getMessage(); - throw $e; } } From 3fc3c1dc76bf643915b752dbe13b064e3cbc858e Mon Sep 17 00:00:00 2001 From: marina Date: Tue, 10 Oct 2017 00:06:27 +0300 Subject: [PATCH 057/528] Remove undefined _translateModel property The lines were a reminiscence from when the translation logic was in the core module. The logic was replaced with the correct use of the inlineTranslation property that is also present at the end of the method. --- app/code/Magento/Sitemap/Model/Observer.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Sitemap/Model/Observer.php b/app/code/Magento/Sitemap/Model/Observer.php index 54f91bebea744..840a6a1858fae 100644 --- a/app/code/Magento/Sitemap/Model/Observer.php +++ b/app/code/Magento/Sitemap/Model/Observer.php @@ -121,8 +121,7 @@ public function scheduledGenerateSitemaps() \Magento\Store\Model\ScopeInterface::SCOPE_STORE ) ) { - $translate = $this->_translateModel->getTranslateInline(); - $this->_translateModel->setTranslateInline(false); + $this->inlineTranslation->suspend(); $this->_transportBuilder->setTemplateIdentifier( $this->_scopeConfig->getValue( From ce4fb9740ec8a362f77110ff9755f871d5187fdd Mon Sep 17 00:00:00 2001 From: Thiago Lima Date: Tue, 10 Oct 2017 13:43:37 +0200 Subject: [PATCH 058/528] #11211 Fix Store View switcher --- app/code/Magento/Store/Model/Store.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 1d100da274465..f9db40c05a332 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1166,6 +1166,9 @@ public function getCurrentUrl($fromStore = true) if (!$this->isUseStoreInUrl()) { $storeParsedQuery['___store'] = $this->getCode(); } + if ($this->getCode() !== $this->_storeManager->getStore()->getCode()) { + $fromStore = true; + } if ($fromStore !== false) { $storeParsedQuery['___from_store'] = $fromStore === true ? $this->_storeManager->getStore()->getCode() : $fromStore; @@ -1175,9 +1178,14 @@ public function getCurrentUrl($fromStore = true) . '://' . $storeParsedUrl['host'] . (isset($storeParsedUrl['port']) ? ':' . $storeParsedUrl['port'] : '') - . $storeParsedUrl['path'] - . $requestString - . ($storeParsedQuery ? '?' . http_build_query($storeParsedQuery, '', '&') : ''); + . $storeParsedUrl['path']; + + //avoid query params duplication + if (!preg_match('/___store=(.*?)&___from_store=(.*?)/', $requestString)) { + $currentUrl .= $requestString; + } + + $currentUrl .= ($storeParsedQuery ? '?' . http_build_query($storeParsedQuery, '', '&') : ''); return $currentUrl; } From 6dfb610d611f6b22770f0f738951bdb89ca73734 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Tue, 10 Oct 2017 15:48:26 +0200 Subject: [PATCH 059/528] ADDED $sortByPostion flag to getChildren() --- .../Magento/Catalog/Model/ResourceModel/Category/Flat.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php index d7f8bd9d789a2..01e4b072b0367 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php @@ -602,9 +602,10 @@ public function isInRootCategoryList($category) * @param \Magento\Catalog\Model\Category $category * @param bool $recursive * @param bool $isActive + * @param bool $sortByPosition * @return array */ - public function getChildren($category, $recursive = true, $isActive = true) + public function getChildren($category, $recursive = true, $isActive = true, $sortByPosition = false) { $select = $this->getConnection()->select()->from( $this->getMainStoreTable($category->getStoreId()), @@ -619,6 +620,9 @@ public function getChildren($category, $recursive = true, $isActive = true) if ($isActive) { $select->where('is_active = ?', '1'); } + if ($sortByPosition) { + $select->order('position ASC'); + } $_categories = $this->getConnection()->fetchAll($select); $categoriesIds = []; foreach ($_categories as $_category) { From dd6e5a36e2a3bcc1167d12897686fdb9ce1caa3d Mon Sep 17 00:00:00 2001 From: David Angel Date: Tue, 10 Oct 2017 10:20:40 -0400 Subject: [PATCH 060/528] Update en_US.csv Use US English spelling for "Optimization". --- app/code/Magento/Cms/i18n/en_US.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Cms/i18n/en_US.csv b/app/code/Magento/Cms/i18n/en_US.csv index 983493bb7732a..e4989777593f8 100644 --- a/app/code/Magento/Cms/i18n/en_US.csv +++ b/app/code/Magento/Cms/i18n/en_US.csv @@ -133,7 +133,7 @@ Block,Block "Enable Page","Enable Page" Content,Content "Content Heading","Content Heading" -"Search Engine Optimisation","Search Engine Optimisation" +"Search Engine Optimization","Search Engine Optimization" "Meta Title","Meta Title" "Meta Keywords","Meta Keywords" "Meta Description","Meta Description" From 4092346a9505d190faf65930b63db881c3e3b5fd Mon Sep 17 00:00:00 2001 From: David Angel Date: Tue, 10 Oct 2017 10:23:02 -0400 Subject: [PATCH 061/528] Update cms_page_form.xml Use US English spelling for "Optimization". --- .../Magento/Cms/view/adminhtml/ui_component/cms_page_form.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_form.xml b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_form.xml index f8c4f07bd4336..5441481f6cea2 100644 --- a/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_form.xml +++ b/app/code/Magento/Cms/view/adminhtml/ui_component/cms_page_form.xml @@ -141,7 +141,7 @@
true - + From 84ff52beb4adb70024060179ddff3eb1776e47db Mon Sep 17 00:00:00 2001 From: David Angel Date: Tue, 10 Oct 2017 10:25:35 -0400 Subject: [PATCH 062/528] Update PageForm.xml Use US English spelling for "Optimization". --- .../app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml index 2ed1bdc790806..28de286b1411a 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Block/Adminhtml/Page/Edit/PageForm.xml @@ -68,7 +68,7 @@ \Magento\Backend\Test\Block\Widget\Tab - //div[div/strong/span[text()="Search Engine Optimisation"]] + //div[div/strong/span[text()="Search Engine Optimization"]] xpath From 3a42624692578139978e2fecbdceac96e88bcb65 Mon Sep 17 00:00:00 2001 From: Manu Gonzalez Rodriguez Date: Tue, 10 Oct 2017 17:40:45 +0200 Subject: [PATCH 063/528] Bug fix update attributes --- .../Magento/Framework/Data/Form/Element/Multiselect.php | 2 +- .../Data/Test/Unit/Form/Element/MultiselectTest.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php b/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php index 6e9b598cc8f4d..4a493d79128f9 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php @@ -57,7 +57,7 @@ public function getElementHtml() $this->addClass('select multiselect admin__control-multiselect'); $html = ''; if ($this->getCanBeEmpty()) { - $html .= ''; + $html .= ''; } if (!empty($this->_data['disabled'])) { $html .= ''; diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php index 62b3329b2c533..0750df0c3df03 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php @@ -27,10 +27,14 @@ protected function setUp() public function testHiddenFieldPresentInMultiSelect() { $fieldName = 'fieldName'; + $fieldId = 'fieldId'; $this->_model->setCanBeEmpty(true); $this->_model->setName($fieldName); + $this->_model->setId($fieldId); $elementHtml = $this->_model->getElementHtml(); - $this->assertContains('assertContains( + ' Date: Tue, 10 Oct 2017 17:43:06 +0200 Subject: [PATCH 064/528] getDateFormatWithLongYear --- app/code/Magento/Customer/Block/Widget/Dob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Block/Widget/Dob.php b/app/code/Magento/Customer/Block/Widget/Dob.php index f8ee8fddf2ea2..037d24d065708 100644 --- a/app/code/Magento/Customer/Block/Widget/Dob.php +++ b/app/code/Magento/Customer/Block/Widget/Dob.php @@ -228,7 +228,7 @@ public function getHtmlExtraParams() */ public function getDateFormat() { - return $this->_localeDate->getDateFormat(\IntlDateFormatter::SHORT); + return $this->_localeDate->getDateFormatWithLongYear(); } /** From ad8cb5ccd8ab29fddfae1448593efb47c044fe75 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 11:45:43 -0500 Subject: [PATCH 065/528] MAGETWO-80479: Update existing Advanced Reporting tests - Update naming --- .../AssertConfigAnalyticsDisabled.php | 11 +++++------ .../Constraint/AssertConfigAnalyticsEnabled.php | 11 +++++------ ...p => AssertConfigAnalyticsIndustryScope.php} | 10 +++++----- ...php => AssertEmptyIndustryCanNotBeSaved.php} | 10 +++++----- ...erticalIsSet.php => AssertIndustryIsSet.php} | 16 ++++++++-------- .../Analytics/Test/TestCase/InstallTest.xml | 17 +++++++++++++++++ ...{SetVerticalTest.php => SetIndustryTest.php} | 2 +- ...{SetVerticalTest.xml => SetIndustryTest.xml} | 6 +++--- 8 files changed, 49 insertions(+), 34 deletions(-) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertConfigAnalyticsVerticalScope.php => AssertConfigAnalyticsIndustryScope.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertEmptyVerticalCanNotBeSaved.php => AssertEmptyIndustryCanNotBeSaved.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertVerticalIsSet.php => AssertIndustryIsSet.php} (62%) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.php => SetIndustryTest.php} (95%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.xml => SetIndustryTest.xml} (89%) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php index daeed6a66cfa4..0f65835a32aa7 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is disabled in Stores>Configuration>General>Analytics->General menu. + * Assert Advanced Reporting service is disabled */ class AssertConfigAnalyticsDisabled extends AbstractConstraint { /** - * Assert Analytics is disabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is disabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,12 +27,12 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertFalse( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not disabled.' + 'Magento Advanced Reporting service is not disabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Disabled', - 'Magento Analytics status is not disabled.' + 'Magento Advanced Reporting service subscription status is not disabled.' ); } @@ -43,7 +43,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is disabled in Stores > Configuration > General > Analytics > General menu' - . ' and has Disabled status.'; + return 'Magento Advanced Reporting service is disabled and has Disabled status.'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php index eb699105e1906..8fd04e06b14bb 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting Service is enabled. */ class AssertConfigAnalyticsEnabled extends AbstractConstraint { /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is enabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,13 +27,13 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertTrue( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not enabled.' + 'Magento Advanced Reporting service is not enabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Pending', - 'Magento Analytics status is not pending.' + 'Magento Advanced Reporting service subscription status is not pending.' ); } @@ -44,7 +44,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is enabled and has Pending status in' - . ' Stores > Configuration > General > Analytics > General menu.'; + return 'Magento Advanced Reporting service is enabled and has Pending status'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php index 3793292653cbf..bb208dbb379c8 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting industry scope is website in Stores. */ -class AssertConfigAnalyticsVerticalScope extends AbstractConstraint +class AssertConfigAnalyticsIndustryScope extends AbstractConstraint { /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting industry scope is website in Stores. * * @param ConfigAnalytics $configAnalytics */ @@ -23,7 +23,7 @@ public function processAssert(ConfigAnalytics $configAnalytics) \PHPUnit_Framework_Assert::assertEquals( true, $configAnalytics->getAnalyticsForm()->getAnalyticsVerticalScope(), - 'Magento Analytics vertical scope is not website' + 'Magento Advanced Reporting industry scope is not website' ); } @@ -34,6 +34,6 @@ public function processAssert(ConfigAnalytics $configAnalytics) */ public function toString() { - return 'Magento Analytics vertical scope is website'; + return 'Magento Advanced Reporting industry scope is website'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php index 3cf503047e6ea..5e86c13b8bbae 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in advanced reporting configuration. */ -class AssertEmptyVerticalCanNotBeSaved extends AbstractConstraint +class AssertEmptyIndustryCanNotBeSaved extends AbstractConstraint { /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in Advanced Reporting configuration. * * @param ConfigAnalytics $configAnalytics * @param string $errorMessage @@ -25,7 +25,7 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) \PHPUnit_Framework_Assert::assertEquals( $errorMessage, $configAnalytics->getMessages()->getErrorMessage(), - 'There is no error message when saving empty vertical in configuration' + 'There is no error message when saving empty industry in configuration' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) public function toString() { return - 'Empty Magento Analytics vertical can not be saved'; + 'Empty Magento Advanced Reporting industry can not be saved'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php similarity index 62% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php index 514c83a30ff51..635c4b35324ed 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php @@ -9,23 +9,23 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set. */ -class AssertVerticalIsSet extends AbstractConstraint +class AssertIndustryIsSet extends AbstractConstraint { /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set * * @param ConfigAnalytics $configAnalytics - * @param string $vertical + * @param string $industry * @return void */ - public function processAssert(ConfigAnalytics $configAnalytics, $vertical) + public function processAssert(ConfigAnalytics $configAnalytics, $industry) { \PHPUnit_Framework_Assert::assertEquals( - $vertical, + $industry, $configAnalytics->getAnalyticsForm()->getAnalyticsVertical(), - $vertical . 'vertical is not selected' + $industry . 'industry is not selected' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $vertical) public function toString() { return - 'Proper Magento Analytics vertical is selected'; + 'Proper Magento Advanced Reporting industry is selected'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml new file mode 100644 index 0000000000000..5ce0a2f1556fd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml @@ -0,0 +1,17 @@ + + + + + + severity:S1 + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php similarity index 95% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php index a721774f4d22c..0ff682c09c662 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php @@ -18,7 +18,7 @@ * * @ZephyrId MAGETWO-63898 */ -class SetVerticalTest extends Injectable +class SetIndustryTest extends Injectable { /* tags */ const MVP = 'no'; diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml similarity index 89% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index 1db31781ccc2f..dd495fb2afe6b 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -6,16 +6,16 @@ */ --> - + Apps and Games - + --Please Select-- Please select a vertical. - + From b7f82b6861cbf2596cfb58f837660537f5450918 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 11:57:10 -0500 Subject: [PATCH 066/528] MAGETWO-80479: Update existing Advanced Reporting tests - Update naming --- .../Constraint/AssertConfigAnalyticsDisabled.php | 11 +++++------ .../Constraint/AssertConfigAnalyticsEnabled.php | 11 +++++------ ...hp => AssertConfigAnalyticsIndustryScope.php} | 10 +++++----- ....php => AssertEmptyIndustryCanNotBeSaved.php} | 10 +++++----- ...VerticalIsSet.php => AssertIndustryIsSet.php} | 16 ++++++++-------- .../{SetVerticalTest.php => SetIndustryTest.php} | 2 +- .../{SetVerticalTest.xml => SetIndustryTest.xml} | 8 ++++---- 7 files changed, 33 insertions(+), 35 deletions(-) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertConfigAnalyticsVerticalScope.php => AssertConfigAnalyticsIndustryScope.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertEmptyVerticalCanNotBeSaved.php => AssertEmptyIndustryCanNotBeSaved.php} (64%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/{AssertVerticalIsSet.php => AssertIndustryIsSet.php} (62%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.php => SetIndustryTest.php} (95%) rename dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/{SetVerticalTest.xml => SetIndustryTest.xml} (86%) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php index daeed6a66cfa4..0f65835a32aa7 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is disabled in Stores>Configuration>General>Analytics->General menu. + * Assert Advanced Reporting service is disabled */ class AssertConfigAnalyticsDisabled extends AbstractConstraint { /** - * Assert Analytics is disabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is disabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,12 +27,12 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertFalse( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not disabled.' + 'Magento Advanced Reporting service is not disabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Disabled', - 'Magento Analytics status is not disabled.' + 'Magento Advanced Reporting service subscription status is not disabled.' ); } @@ -43,7 +43,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is disabled in Stores > Configuration > General > Analytics > General menu' - . ' and has Disabled status.'; + return 'Magento Advanced Reporting service is disabled and has Disabled status.'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php index eb699105e1906..8fd04e06b14bb 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -10,12 +10,12 @@ use Magento\Mtf\Constraint\AbstractConstraint; /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting Service is enabled. */ class AssertConfigAnalyticsEnabled extends AbstractConstraint { /** - * Assert Analytics is enabled in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting service is enabled. * * @param ConfigAnalytics $configAnalytics * @param OpenAnalyticsConfigStep $openAnalyticsConfigStep @@ -27,13 +27,13 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon \PHPUnit_Framework_Assert::assertTrue( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), - 'Magento Analytics is not enabled.' + 'Magento Advanced Reporting service is not enabled.' ); \PHPUnit_Framework_Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Pending', - 'Magento Analytics status is not pending.' + 'Magento Advanced Reporting service subscription status is not pending.' ); } @@ -44,7 +44,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon */ public function toString() { - return 'Magento Analytics is enabled and has Pending status in' - . ' Stores > Configuration > General > Analytics > General menu.'; + return 'Magento Advanced Reporting service is enabled and has Pending status'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php index 3793292653cbf..bb208dbb379c8 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsVerticalScope.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsIndustryScope.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics > General menu. + * Assert Advanced Reporting industry scope is website in Stores. */ -class AssertConfigAnalyticsVerticalScope extends AbstractConstraint +class AssertConfigAnalyticsIndustryScope extends AbstractConstraint { /** - * Assert Analytics vertical scope is website in Stores > Configuration > General > Analytics menu. + * Assert Advanced Reporting industry scope is website in Stores. * * @param ConfigAnalytics $configAnalytics */ @@ -23,7 +23,7 @@ public function processAssert(ConfigAnalytics $configAnalytics) \PHPUnit_Framework_Assert::assertEquals( true, $configAnalytics->getAnalyticsForm()->getAnalyticsVerticalScope(), - 'Magento Analytics vertical scope is not website' + 'Magento Advanced Reporting industry scope is not website' ); } @@ -34,6 +34,6 @@ public function processAssert(ConfigAnalytics $configAnalytics) */ public function toString() { - return 'Magento Analytics vertical scope is website'; + return 'Magento Advanced Reporting industry scope is website'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php similarity index 64% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php index 3cf503047e6ea..5e86c13b8bbae 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyVerticalCanNotBeSaved.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertEmptyIndustryCanNotBeSaved.php @@ -9,12 +9,12 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in advanced reporting configuration. */ -class AssertEmptyVerticalCanNotBeSaved extends AbstractConstraint +class AssertEmptyIndustryCanNotBeSaved extends AbstractConstraint { /** - * Assert Analytics empty Vertical can not be saved in Stores > Configuration > General > Analytics > General menu. + * Assert empty industry can not be saved in Advanced Reporting configuration. * * @param ConfigAnalytics $configAnalytics * @param string $errorMessage @@ -25,7 +25,7 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) \PHPUnit_Framework_Assert::assertEquals( $errorMessage, $configAnalytics->getMessages()->getErrorMessage(), - 'There is no error message when saving empty vertical in configuration' + 'There is no error message when saving empty industry in configuration' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $errorMessage) public function toString() { return - 'Empty Magento Analytics vertical can not be saved'; + 'Empty Magento Advanced Reporting industry can not be saved'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php similarity index 62% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php index 514c83a30ff51..635c4b35324ed 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertVerticalIsSet.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertIndustryIsSet.php @@ -9,23 +9,23 @@ use Magento\Analytics\Test\Page\Adminhtml\ConfigAnalytics; /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set. */ -class AssertVerticalIsSet extends AbstractConstraint +class AssertIndustryIsSet extends AbstractConstraint { /** - * Assert Analytics Vertical is set in Stores > Configuration > General > Analytics > General menu. + * Assert Advance Reporting Industry is set * * @param ConfigAnalytics $configAnalytics - * @param string $vertical + * @param string $industry * @return void */ - public function processAssert(ConfigAnalytics $configAnalytics, $vertical) + public function processAssert(ConfigAnalytics $configAnalytics, $industry) { \PHPUnit_Framework_Assert::assertEquals( - $vertical, + $industry, $configAnalytics->getAnalyticsForm()->getAnalyticsVertical(), - $vertical . 'vertical is not selected' + $industry . 'industry is not selected' ); } @@ -37,6 +37,6 @@ public function processAssert(ConfigAnalytics $configAnalytics, $vertical) public function toString() { return - 'Proper Magento Analytics vertical is selected'; + 'Proper Magento Advanced Reporting industry is selected'; } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php similarity index 95% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php index a721774f4d22c..0ff682c09c662 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php @@ -18,7 +18,7 @@ * * @ZephyrId MAGETWO-63898 */ -class SetVerticalTest extends Injectable +class SetIndustryTest extends Injectable { /* tags */ const MVP = 'no'; diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml similarity index 86% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml rename to dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index 1db31781ccc2f..e44b83dbd55d1 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetVerticalTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -6,16 +6,16 @@ */ --> - + Apps and Games - - + + --Please Select-- Please select a vertical. - + From ff3b1fa67d34925eb22b4b72ba4a7b22cd7f7047 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 12:09:12 -0500 Subject: [PATCH 067/528] MAGETWO-80480: Automate function tests - automate MAGETWO-80760 --- ...onBlock.php => AdvancedReportingBlock.php} | 17 ++++---- .../AssertAdvancedReportingPopupExist.php | 39 +++++++++++++++++++ .../Test/Page/Adminhtml/Dashboard.xml | 2 +- .../Analytics/Test/TestCase/InstallTest.xml | 17 ++++++++ 4 files changed, 64 insertions(+), 11 deletions(-) rename dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/{SubscriptionBlock.php => AdvancedReportingBlock.php} (54%) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php similarity index 54% rename from dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php rename to dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php index e362d51790a76..5bd381dfe2b3d 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/SubscriptionBlock.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php @@ -5,30 +5,27 @@ */ namespace Magento\Analytics\Test\Block\Adminhtml\Dashboard\AdvancedReporting; -use Magento\Mtf\Client\Locator; use Magento\Ui\Test\Block\Adminhtml\Modal; /** - * Subscription block. + * Advanced Reporting block. */ -class SubscriptionBlock extends Modal +class AdvancedReportingBlock extends Modal { /** - * Close subscription pop-up button + * Close pop-up button * * @var string */ private $closeReportingButton = '[data-index="analytics_subscription_button_close"]'; /** - * Skip subscription popup. - * - * @return void + * @inheritdoc */ - public function skipAdvancedReporting() + public function isVisible() { $this->waitModalAnimationFinished(); - $this->_rootElement->find($this->closeReportingButton)->click(); - $this->waitForElementNotVisible($this->loadingMask); + return parent::isVisible() && $this->_rootElement->find($this->closeReportingButton)->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php new file mode 100644 index 0000000000000..cfb69094ce87c --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPopupExist.php @@ -0,0 +1,39 @@ +getAdvancedReportingBlock()->isVisible(), + "Advanced Reporting Popup is absent on dashboard." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Advanced Reporting Popup is visible on dashboard."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml index bc94ef7862ca7..e1631f20dd101 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Page/Adminhtml/Dashboard.xml @@ -7,7 +7,7 @@ --> - + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml new file mode 100644 index 0000000000000..5ce0a2f1556fd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/InstallTest.xml @@ -0,0 +1,17 @@ + + + + + + severity:S1 + + + + + + From d6ad3b0d1eed023f714387f112a8085d5615c848 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 13:00:09 -0500 Subject: [PATCH 068/528] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- ...ificationMenuAccessUserPermissionsTest.php | 37 +++++++++++++++++++ ...ificationMenuAccessUserPermissionsTest.xml | 15 ++++++++ .../Magento/Analytics/Test/etc/testcase.xml | 2 +- 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php new file mode 100644 index 0000000000000..2abbec4020e72 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.php @@ -0,0 +1,37 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml new file mode 100644 index 0000000000000..433e6b18b39e5 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -0,0 +1,15 @@ + + + + + + custom_admin_with_role_without_subscription_permissions + + + + diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml index 2de77423c0a74..dfdbdf0d7d761 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml @@ -6,7 +6,7 @@ */ --> - + From 941bca0dd10c51b6cc2168c16f342ce2e23e894d Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 10 Oct 2017 13:35:43 -0500 Subject: [PATCH 069/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Analytics/Test/Unit/Model/NotificationFlagManagerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 3061ec98e6b1a..43e160bfcbb22 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -45,7 +45,7 @@ public function testSetNotifiedUser() $this->flagManagerMock ->expects($this->once()) ->method('saveFlag') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId, 1) + ->with('analytics_notification_seen_admin_' . $userId, 1) ->willReturn(true); $this->assertTrue($this->notificationFlagManager->setNotifiedUser($userId)); } @@ -56,7 +56,7 @@ public function testIsUserNotified() $this->flagManagerMock ->expects($this->once()) ->method('getFlagData') - ->with(NotificationFlagManager::NOTIFICATION_SEEN . $userId) + ->with('analytics_notification_seen_admin_' . $userId) ->willReturn(true); $this->assertTrue($this->notificationFlagManager->isUserNotified($userId)); } From 9d6a8135a302457737a7e43d39756c4b23b2b33b Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 10 Oct 2017 13:58:40 -0500 Subject: [PATCH 070/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup --- .../Test/Unit/Model/NotificationFlagManagerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 43e160bfcbb22..0ac331c8d1015 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -8,7 +8,7 @@ use Magento\Analytics\Model\NotificationFlagManager; use Magento\Framework\FlagManager; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Class NotificationFlagManagerTest @@ -30,8 +30,8 @@ public function setUp() $this->flagManagerMock = $this->getMockBuilder(FlagManager::class) ->disableOriginalConstructor() ->getMock(); - $objectManagerHelper = new ObjectManagerHelper($this); - $this->notificationFlagManager = $objectManagerHelper->getObject( + $objectManager = new ObjectManager($this); + $this->notificationFlagManager = $objectManager->getObject( NotificationFlagManager::class, [ 'flagManager' => $this->flagManagerMock From 89a49fd8f7e4c4de84ac41026dbe93b4be9aac03 Mon Sep 17 00:00:00 2001 From: Manu Gonzalez Rodriguez Date: Tue, 10 Oct 2017 21:44:34 +0200 Subject: [PATCH 071/528] Code style revision --- .../Magento/Framework/Data/Form/Element/Multiselect.php | 4 +++- .../Framework/Data/Test/Unit/Form/Element/MultiselectTest.php | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php b/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php index 4a493d79128f9..03daa6c08fff4 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php @@ -57,7 +57,9 @@ public function getElementHtml() $this->addClass('select multiselect admin__control-multiselect'); $html = ''; if ($this->getCanBeEmpty()) { - $html .= ''; + $html .= ' + + '; } if (!empty($this->_data['disabled'])) { $html .= ''; diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php index 0750df0c3df03..6d1680a9f38a6 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php @@ -33,7 +33,8 @@ public function testHiddenFieldPresentInMultiSelect() $this->_model->setId($fieldId); $elementHtml = $this->_model->getElementHtml(); $this->assertContains( - ' Date: Tue, 10 Oct 2017 22:14:21 +0200 Subject: [PATCH 072/528] Refactoring DobTest --- .../Customer/Test/Unit/Block/Widget/DobTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php b/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php index ea4498591e086..74b2c119784e6 100644 --- a/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php +++ b/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php @@ -33,7 +33,7 @@ class DobTest extends \PHPUnit\Framework\TestCase const YEAR = '2014'; // Value of date('Y', strtotime(self::DATE)) - const DATE_FORMAT = 'M/d/yy'; + const DATE_FORMAT = 'M/d/Y'; /** Constants used by Dob::setDateInput($code, $html) */ const DAY_HTML = @@ -485,8 +485,8 @@ public function testGetHtmlExtraParamsWithoutRequiredOption() { $this->escaper->expects($this->any()) ->method('escapeHtml') - ->with('{"validate-date":{"dateFormat":"M\/d\/yy"}}') - ->will($this->returnValue('{"validate-date":{"dateFormat":"M\/d\/yy"}}')); + ->with('{"validate-date":{"dateFormat":"M\/d\/Y"}}') + ->will($this->returnValue('{"validate-date":{"dateFormat":"M\/d\/Y"}}')); $this->attribute->expects($this->once()) ->method("isRequired") @@ -494,7 +494,7 @@ public function testGetHtmlExtraParamsWithoutRequiredOption() $this->assertEquals( $this->_block->getHtmlExtraParams(), - 'data-validate="{"validate-date":{"dateFormat":"M\/d\/yy"}}"' + 'data-validate="{"validate-date":{"dateFormat":"M\/d\/Y"}}"' ); } @@ -506,14 +506,14 @@ public function testGetHtmlExtraParamsWithRequiredOption() $this->escaper->expects($this->any()) ->method('escapeHtml') - ->with('{"required":true,"validate-date":{"dateFormat":"M\/d\/yy"}}') - ->will($this->returnValue('{"required":true,"validate-date":{"dateFormat":"M\/d\/yy"}}')); + ->with('{"required":true,"validate-date":{"dateFormat":"M\/d\/Y"}}') + ->will($this->returnValue('{"required":true,"validate-date":{"dateFormat":"M\/d\/Y"}}')); $this->context->expects($this->any())->method('getEscaper')->will($this->returnValue($this->escaper)); $this->assertEquals( - 'data-validate="{"required":true,"validate-date":{"dateFormat":"M\/d\/yy"}}"', + 'data-validate="{"required":true,"validate-date":{"dateFormat":"M\/d\/Y"}}"', $this->_block->getHtmlExtraParams() ); } From 810aac28ffb49c7a90928e9cb94cb303d9627da0 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 15:40:13 -0500 Subject: [PATCH 073/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup - fix unit test --- .../Dashboard/AdvancedReporting/AdvancedReportingBlock.php | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php index 5bd381dfe2b3d..1d6ac74e7ffec 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Block/Adminhtml/Dashboard/AdvancedReporting/AdvancedReportingBlock.php @@ -26,6 +26,5 @@ public function isVisible() { $this->waitModalAnimationFinished(); return parent::isVisible() && $this->_rootElement->find($this->closeReportingButton)->isVisible(); - } } From 14d70f763ea2406cf60c94c0a969da4f08f100d3 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 15:41:10 -0500 Subject: [PATCH 074/528] MAGETWO-80480: Automate function tests - fix static test failure --- .../Test/Unit/Model/NotificationFlagManagerTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php index 0ac331c8d1015..e3be87843d131 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/NotificationFlagManagerTest.php @@ -42,8 +42,7 @@ public function setUp() public function testSetNotifiedUser() { $userId = 1; - $this->flagManagerMock - ->expects($this->once()) + $this->flagManagerMock->expects($this->once()) ->method('saveFlag') ->with('analytics_notification_seen_admin_' . $userId, 1) ->willReturn(true); @@ -53,8 +52,7 @@ public function testSetNotifiedUser() public function testIsUserNotified() { $userId = 1; - $this->flagManagerMock - ->expects($this->once()) + $this->flagManagerMock->expects($this->once()) ->method('getFlagData') ->with('analytics_notification_seen_admin_' . $userId) ->willReturn(true); From e26da7718370b17b94ea8ca42a1997bf29aba3d3 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 16:29:10 -0500 Subject: [PATCH 075/528] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- ...ginAgainAdvancedReportingPopupNotExist.php | 49 +++++++++++++++++++ ...ificationMenuAccessUserPermissionsTest.xml | 6 +++ 2 files changed, 55 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php new file mode 100644 index 0000000000000..65b706e7291fe --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php @@ -0,0 +1,49 @@ +objectManager->create( + \Magento\User\Test\TestStep\LogoutUserOnBackendStep::class + )->run(); + + + $this->objectManager->create( + \Magento\User\Test\TestStep\LoginUserOnBackendStep::class, + ['user' => $user] + )->run(); + \PHPUnit_Framework_Assert::assertFalse( + $dashboard->getAdvancedReportingBlock()->isVisible(), + "Advanced Reporting Popup is visible on dashboard." + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Advanced Reporting Popup is absent on dashboard."; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml index 433e6b18b39e5..57ca2a2473b32 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -10,6 +10,12 @@ custom_admin_with_role_without_subscription_permissions + + + + default + + From bc33fb4f6a4512ca2e07ac3b6bd7e9cd17f3fe1d Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 16:34:25 -0500 Subject: [PATCH 076/528] MAGETWO-80477: Update Advanced Reporting Subscription Popup - fix unit test --- .../Test/Unit/Model/Condition/CanViewNotificationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 45a30ea1113a7..c0941a5a94e9e 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -8,7 +8,7 @@ use Magento\Analytics\Model\Condition\CanViewNotification; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Analytics\Model\notificationFlagManager; +use Magento\Analytics\Model\NotificationFlagManager; use Magento\Backend\Model\Auth\Session; /** From 7bfa39a4c4d1b1b226c1781d5a37337973b10c6c Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 16:43:49 -0500 Subject: [PATCH 077/528] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- .../AssertLoginAgainAdvancedReportingPopupNotExist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php index 65b706e7291fe..cf22df718149b 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertLoginAgainAdvancedReportingPopupNotExist.php @@ -12,7 +12,7 @@ /** * Assert that Advanced Reporting Popup is absent on dashboard when admin user login again */ -class AssertAdvancedReportingPopupExist extends AbstractConstraint +class AssertLoginAgainAdvancedReportingPopupNotExist extends AbstractConstraint { /** * Assert that Advanced Reporting Popup is absent on dashboard when admin user login again @@ -26,11 +26,11 @@ public function processAssert(Dashboard $dashboard, User $user) \Magento\User\Test\TestStep\LogoutUserOnBackendStep::class )->run(); - $this->objectManager->create( \Magento\User\Test\TestStep\LoginUserOnBackendStep::class, ['user' => $user] )->run(); + \PHPUnit_Framework_Assert::assertFalse( $dashboard->getAdvancedReportingBlock()->isVisible(), "Advanced Reporting Popup is visible on dashboard." From 891e58fe0be4307c1485696f7ca33281e524c499 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 17:27:43 -0500 Subject: [PATCH 078/528] MAGETWO-80480: Automate function tests - automate MAGETWO-80786 --- ...ssertAdvancedReportingSectionInvisible.php | 40 +++++++++++++++++++ .../AssertAdvancedReportingSectionVisible.php | 40 +++++++++++++++++++ ...ificationMenuAccessUserPermissionsTest.xml | 2 + 3 files changed, 82 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php create mode 100644 dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php new file mode 100644 index 0000000000000..d154ee275710a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionInvisible.php @@ -0,0 +1,40 @@ +open(); + \PHPUnit_Framework_Assert::assertFalse( + in_array('Advanced Reporting', $configEdit->getTabs()->getSubTabsNames('General')), + 'Advanced Reporting section is visible.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting section is invisible.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php new file mode 100644 index 0000000000000..18ea93fee1ea3 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingSectionVisible.php @@ -0,0 +1,40 @@ +open(); + \PHPUnit_Framework_Assert::assertTrue( + in_array('Advanced Reporting', $configEdit->getTabs()->getSubTabsNames('General')), + 'Advanced Reporting section is not visible.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Advanced Reporting section is visible.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml index 57ca2a2473b32..0a827cacc984c 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -11,11 +11,13 @@ custom_admin_with_role_without_subscription_permissions + default + From db7dbd4f8d3a817224ad42f17793f2ecc0bb69a1 Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 10 Oct 2017 20:32:58 -0500 Subject: [PATCH 079/528] MAGETWO-80480: Automate function tests - fix function test failure --- .../app/Magento/Analytics/Test/TestCase/SetIndustryTest.php | 6 +++--- .../app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php index 0ff682c09c662..8b76df048b9a4 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.php @@ -28,13 +28,13 @@ class SetIndustryTest extends Injectable * Set analytics vertical test. * * @param ConfigAnalytics $configAnalytics - * @param string $vertical + * @param string $industry * @return void */ - public function test(ConfigAnalytics $configAnalytics, $vertical) + public function test(ConfigAnalytics $configAnalytics, $industry) { $configAnalytics->open(); - $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($vertical); + $configAnalytics->getAnalyticsForm()->setAnalyticsVertical($industry); $configAnalytics->getAnalyticsForm()->saveConfig(); } } diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index e44b83dbd55d1..bb21a2adf130c 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -8,12 +8,12 @@ - Apps and Games + Apps and Games - --Please Select-- + --Please Select-- Please select a vertical. From 4cdc13319ae5dccef8973ee04ac4bf2c5fe9f0a9 Mon Sep 17 00:00:00 2001 From: Tim Bezhashvyly Date: Wed, 11 Oct 2017 08:06:16 +0200 Subject: [PATCH 080/528] Issue #6924: Unmask exception message during product import Probably a typo. Exception message was passed as a exception description argument instead of exception message. Artefact of optional parameters. --- app/code/Magento/ImportExport/Model/Import.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/ImportExport/Model/Import.php b/app/code/Magento/ImportExport/Model/Import.php index 8da1bb1763ece..092b721b82435 100644 --- a/app/code/Magento/ImportExport/Model/Import.php +++ b/app/code/Magento/ImportExport/Model/Import.php @@ -567,7 +567,6 @@ public function validateSource(\Magento\ImportExport\Model\Import\AbstractSource ProcessingError::ERROR_LEVEL_CRITICAL, null, null, - null, $e->getMessage() ); } From f77dadbd3ad92610515b7fecd22f6217bb708df5 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Wed, 11 Oct 2017 10:38:56 +0200 Subject: [PATCH 081/528] ADDED $sortByPosition flag to Magento\Catalog\Model\Category ADDED test testGetChildrenSroted() to integration testsuite Magento\Catalog\Model\Category --- app/code/Magento/Catalog/Model/Category.php | 5 +++-- .../testsuite/Magento/Catalog/Model/CategoryTreeTest.php | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php index c4d6742a02dd3..28d55830a1342 100644 --- a/app/code/Magento/Catalog/Model/Category.php +++ b/app/code/Magento/Catalog/Model/Category.php @@ -780,11 +780,12 @@ public function getAllChildren($asArray = false) /** * Retrieve children ids comma separated * + * @param boolean $sortByPosition * @return string */ - public function getChildren() + public function getChildren($sortByPosition = false) { - return implode(',', $this->getResource()->getChildren($this, false)); + return implode(',', $this->getResource()->getChildren($this, false, true, $sortByPosition)); } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php index 5e9244367bb13..84ccb4f91d97a 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php @@ -128,6 +128,12 @@ public function testGetChildren() $this->assertEquals(array_diff([4, 13], explode(',', $this->_model->getChildren())), []); } + public function testGetChildrenSorted() + { + $this->_model->load(2); + $this->assertEquals(array_diff([3, 4, 5], explode(',', $this->_model->getChildren(true))), []); + } + public function testGetPathInStore() { $this->_model->load(5); From 64e6854dc15c280cdd8e845a17952df722730f35 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi Date: Wed, 11 Oct 2017 12:36:40 +0300 Subject: [PATCH 082/528] MAGETWO-80188: [2.2.x] - Prevent change log entry when nothing has changed #4893 --- .../Framework/Mview/View/Subscription.php | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/View/Subscription.php b/lib/internal/Magento/Framework/Mview/View/Subscription.php index f2019d6f8c3df..797968eae0eb1 100644 --- a/lib/internal/Magento/Framework/Mview/View/Subscription.php +++ b/lib/internal/Magento/Framework/Mview/View/Subscription.php @@ -10,6 +10,8 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Ddl\Trigger; +use Magento\Framework\DB\Ddl\TriggerFactory; +use Magento\Framework\Mview\ViewInterface; class Subscription implements SubscriptionInterface { @@ -21,12 +23,12 @@ class Subscription implements SubscriptionInterface protected $connection; /** - * @var \Magento\Framework\DB\Ddl\TriggerFactory + * @var TriggerFactory */ protected $triggerFactory; /** - * @var \Magento\Framework\Mview\View\CollectionInterface + * @var CollectionInterface */ protected $viewCollection; @@ -67,21 +69,21 @@ class Subscription implements SubscriptionInterface /** * @param ResourceConnection $resource - * @param \Magento\Framework\DB\Ddl\TriggerFactory $triggerFactory - * @param \Magento\Framework\Mview\View\CollectionInterface $viewCollection - * @param \Magento\Framework\Mview\ViewInterface $view + * @param TriggerFactory $triggerFactory + * @param CollectionInterface $viewCollection + * @param ViewInterface $view * @param string $tableName * @param string $columnName * @param array $ignoredUpdateColumns */ public function __construct( ResourceConnection $resource, - \Magento\Framework\DB\Ddl\TriggerFactory $triggerFactory, - \Magento\Framework\Mview\View\CollectionInterface $viewCollection, - \Magento\Framework\Mview\ViewInterface $view, + TriggerFactory $triggerFactory, + CollectionInterface $viewCollection, + ViewInterface $view, $tableName, $columnName, - $ignoredUpdateColumns = [] + array $ignoredUpdateColumns = [] ) { $this->connection = $resource->getConnection(); $this->triggerFactory = $triggerFactory; @@ -94,9 +96,9 @@ public function __construct( } /** - * Create subsciption + * Create subscription * - * @return \Magento\Framework\Mview\View\SubscriptionInterface + * @return SubscriptionInterface */ public function create() { @@ -113,7 +115,7 @@ public function create() // Add statements for linked views foreach ($this->getLinkedViews() as $view) { - /** @var \Magento\Framework\Mview\ViewInterface $view */ + /** @var ViewInterface $view */ $trigger->addStatement($this->buildStatement($event, $view->getChangelog())); } @@ -127,7 +129,7 @@ public function create() /** * Remove subscription * - * @return \Magento\Framework\Mview\View\SubscriptionInterface + * @return SubscriptionInterface */ public function remove() { @@ -142,7 +144,7 @@ public function remove() // Add statements for linked views foreach ($this->getLinkedViews() as $view) { - /** @var \Magento\Framework\Mview\ViewInterface $view */ + /** @var ViewInterface $view */ $trigger->addStatement($this->buildStatement($event, $view->getChangelog())); } @@ -165,10 +167,10 @@ public function remove() protected function getLinkedViews() { if (!$this->linkedViews) { - $viewList = $this->viewCollection->getViewsByStateMode(\Magento\Framework\Mview\View\StateInterface::MODE_ENABLED); + $viewList = $this->viewCollection->getViewsByStateMode(StateInterface::MODE_ENABLED); foreach ($viewList as $view) { - /** @var \Magento\Framework\Mview\ViewInterface $view */ + /** @var ViewInterface $view */ // Skip the current view if ($view->getId() == $this->getView()->getId()) { continue; @@ -189,10 +191,10 @@ protected function getLinkedViews() * Build trigger statement for INSERT, UPDATE, DELETE events * * @param string $event - * @param \Magento\Framework\Mview\View\ChangelogInterface $changelog + * @param ChangelogInterface $changelog * @return string */ - protected function buildStatement($event, $changelog) + protected function buildStatement(string $event, ChangelogInterface $changelog) { switch ($event) { case Trigger::EVENT_INSERT: @@ -259,7 +261,7 @@ private function getAfterEventTriggerName($event) /** * Retrieve View related to subscription * - * @return \Magento\Framework\Mview\ViewInterface + * @return ViewInterface * @codeCoverageIgnore */ public function getView() From fc4723441c7652917201cac2b4411639bf2acd76 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Wed, 11 Oct 2017 15:50:52 +0200 Subject: [PATCH 083/528] FIXED integration test ADDED $recursive and $isActive, flags to getChildren() --- app/code/Magento/Catalog/Model/Category.php | 6 ++++-- .../testsuite/Magento/Catalog/Model/CategoryTreeTest.php | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php index 28d55830a1342..7fc15928b784d 100644 --- a/app/code/Magento/Catalog/Model/Category.php +++ b/app/code/Magento/Catalog/Model/Category.php @@ -780,12 +780,14 @@ public function getAllChildren($asArray = false) /** * Retrieve children ids comma separated * + * @param boolean $recursive + * @param boolean $isActive * @param boolean $sortByPosition * @return string */ - public function getChildren($sortByPosition = false) + public function getChildren($recursive = true, $isActive = true, $sortByPosition = false) { - return implode(',', $this->getResource()->getChildren($this, false, true, $sortByPosition)); + return implode(',', $this->getResource()->getChildren($this, $recursive, $isActive, $sortByPosition)); } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php index 84ccb4f91d97a..8707c54865996 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php @@ -131,7 +131,9 @@ public function testGetChildren() public function testGetChildrenSorted() { $this->_model->load(2); - $this->assertEquals(array_diff([3, 4, 5], explode(',', $this->_model->getChildren(true))), []); + $unsorted = explode(',', $this->_model->getChildren()); + usort($unsorted); + $this->assertEquals(array_diff($unsorted, explode(',', $this->_model->getChildren(true, true, true))), []); } public function testGetPathInStore() From 4f4e95e99ed4761ea982660889f26f940c6123bb Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi Date: Wed, 11 Oct 2017 16:55:39 +0300 Subject: [PATCH 084/528] MAGETWO-80188: [2.2.x] - Prevent change log entry when nothing has changed #4893 --- lib/internal/Magento/Framework/Mview/View/Subscription.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Mview/View/Subscription.php b/lib/internal/Magento/Framework/Mview/View/Subscription.php index 797968eae0eb1..4f5c65c799be8 100644 --- a/lib/internal/Magento/Framework/Mview/View/Subscription.php +++ b/lib/internal/Magento/Framework/Mview/View/Subscription.php @@ -194,7 +194,7 @@ protected function getLinkedViews() * @param ChangelogInterface $changelog * @return string */ - protected function buildStatement(string $event, ChangelogInterface $changelog) + protected function buildStatement($event, $changelog) { switch ($event) { case Trigger::EVENT_INSERT: From 25e7e1432aad71d32cbc36289c8dc0c42611cb94 Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 11 Oct 2017 09:44:42 -0500 Subject: [PATCH 085/528] MAGETWO-80480: Automate function tests - address code review comments --- .../app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml index bb21a2adf130c..3a04420ca9d64 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/SetIndustryTest.xml @@ -6,13 +6,13 @@ */ --> - - + + Apps and Games - + --Please Select-- Please select a vertical. From 4ab424f4145ceed93f287f62eb96081604a9874b Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 11 Oct 2017 10:25:49 -0500 Subject: [PATCH 086/528] MAGETWO-80481: Update documents --- app/code/Magento/Analytics/README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Analytics/README.md b/app/code/Magento/Analytics/README.md index ee6d017a1f3ac..7ec64abcd9b86 100644 --- a/app/code/Magento/Analytics/README.md +++ b/app/code/Magento/Analytics/README.md @@ -1,4 +1,4 @@ -# Magento_Analytics module +# Magento_Analytics Module The Magento_Analytics module integrates your Magento instance with the [Magento Business Intelligence (MBI)](https://magento.com/products/business-intelligence) to use [Advanced Reporting](http://devdocs.magento.com/guides/v2.2/advanced-reporting/modules.html) functionality. @@ -20,6 +20,22 @@ Beyond the [usual module file structure](http://devdocs.magento.com/guides/v2.2/ [Report XML](http://devdocs.magento.com/guides/v2.2/advanced-reporting/report-xml.html) is a markup language used to build reports for Advanced Reporting. The language declares SQL queries using XML declaration. +## Subscription Process + +The subscription to the MBI service is enabled during the installation process of the Analytics module. Each administrator will be notified of these new features upon their initial login to the Admin Panel. + +## Analytics Settings + +Configuration settings for the Analytics module can be modified in the Admin Panel on the Stores > Configuration page under the General > Advanced Reporting tab. + +The following options can be adjusted: +* Advanced Reporting Service (Enabled/Disabled) + * Alters the status of the Advanced Reporting subscription +* Time of day to send data (Hour/Minute/Second in the store's time zone) + * Defines when the data collection process for the Advanced Reporting service occurs +* Industry + * Defines the industry of the store in order to create a personalized Advanced Reporting experience + ## Extensibility We do not recommend to extend the Magento_Analytics module. It introduces an API that is purposed to transfer the collected data. Note that the API cannot be used for other needs. From 6e0909ff4320d198cad853dd10c19588d3519994 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 11 Oct 2017 10:35:36 -0500 Subject: [PATCH 087/528] MAGETWO-81342: Update link URLs to subscription modal and configuration page --- .../Analytics/etc/adminhtml/system.xml | 3 +- app/code/Magento/Analytics/i18n/en_US.csv | 52 +++++++++---------- .../analytics_subscription_notification.xml | 3 +- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml index c3bf5c4b11d2f..889517e629e04 100644 --- a/app/code/Magento/Analytics/etc/adminhtml/system.xml +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -15,7 +15,8 @@ For more information, see our terms and conditions.]]> + "Go to Advanced Reporting" link.
For more information, see our + terms and conditions.]]> Magento\Config\Model\Config\Source\Enabledisable diff --git a/app/code/Magento/Analytics/i18n/en_US.csv b/app/code/Magento/Analytics/i18n/en_US.csv index 090534923e450..b1c7ffe45518f 100644 --- a/app/code/Magento/Analytics/i18n/en_US.csv +++ b/app/code/Magento/Analytics/i18n/en_US.csv @@ -34,13 +34,14 @@ API,API Configuration,Configuration "Business Intelligence","Business Intelligence" "BI Essentials","BI Essentials" -"This service provides a suite of dynamic reports based on your product, order and - customer data. All reports are accessed securely on a personalized dashboard dedicated to your reports - - separate from your Admin Panel.
For more information, view details or see our - terms and conditions.","This service provides a suite of dynamic reports based on your product, order and - customer data. All reports are accessed securely on a personalized dashboard dedicated to your reports - - separate from your Admin Panel.
For more information, view details or see our - terms and conditions." +"This service provides a dynamic suite of reports with rich insights about your business. + Your reports can be accessed securely on a personalized dashboard outside of the admin panel by clicking on the + ""Go to Advanced Reporting"" link.
For more information, see our + terms and conditions. + ","This service provides a dynamic suite of reports with rich insights about your business. + Your reports can be accessed securely on a personalized dashboard outside of the admin panel by clicking on the + ""Go to Advanced Reporting"" link.
For more information, see our + terms and conditions." "Advanced Reporting Service","Advanced Reporting Service" Industry,Industry "Time of day to send data","Time of day to send data" @@ -70,26 +71,22 @@ Industry,Industry "Technology B2B","Technology B2B" "Analytics Subscription","Analytics Subscription" "powered by Magento Business Intelligence","powered by Magento Business Intelligence" -"

When you turn on Advanced - Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example - of the new data and trend reports, listed by category, include:

    -
  • Order: Number of orders, total revenue, and AOV
  • Customer: - New registered accounts, unique customers, number of orders, AOV, revenue by email -
  • Product: Quantity sold, bestsellers by volume/revenue

A - personalized dashboard includes all reports - separate from your Admin Panel, yet still at your - fingertips.

We're excited to offer these valuable tools that can help your business become - more data-driven. For more information, view details or see our - terms and conditions.

- ","

When you turn on Advanced - Reporting, you'll have access to a suite of dynamic reports tailored to your business. Example - of the new data and trend reports, listed by category, include:

    -
  • Order: Number of orders, total revenue, and AOV
  • Customer: - New registered accounts, unique customers, number of orders, AOV, revenue by email -
  • Product: Quantity sold, bestsellers by volume/revenue

A - personalized dashboard includes all reports - separate from your Admin Panel, yet still at your - fingertips.

We're excited to offer these valuable tools that can help your business become - more data-driven. For more information, view details or see our - terms and conditions.

+"

Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy and + Terms + of Service. You may opt out at any time from the Stores Configuration page.

+ ","

Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy and + Terms + of Service. You may opt out at any time from the Stores Configuration page.

" "Are you sure you want to opt out?","Are you sure you want to opt out?" Cancel,Cancel @@ -101,3 +98,4 @@ Cancel,Cancel free of charge, in your Magento software. When you opt out, we collect no product, order, and customer data to generate our dynamic reports.

To opt in later: You can always turn on Advanced Reporting in you Admin Panel.

" +"In order to personalize your Advanced Reporting experience, please select your industry.","In order to personalize your Advanced Reporting experience, please select your industry." diff --git a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml index c26b4e15dfe17..93c8b7b8c5ef4 100644 --- a/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml +++ b/app/code/Magento/Analytics/view/adminhtml/ui_component/analytics_subscription_notification.xml @@ -63,7 +63,8 @@ business.


As part of the Advanced Reporting service, we may also use your customer data for such purposes as benchmarking, improving our products and services, and providing you with new and improved analytics.


By using Magento 2.2, you agree to the Advanced - Reporting Privacy Policy and Terms + Reporting Privacy Policy + and Terms of Service. You may opt out at any time from the Stores Configuration page.

]]> From 90a83477ab40a8f18dff8a26dc59495c54a01056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mateos?= Date: Wed, 11 Oct 2017 20:29:28 +0200 Subject: [PATCH 088/528] Save region correctly to save sales address from admin --- .../Adminhtml/Order/AddressSave.php | 101 ++++++++++++++++-- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php index db0c2b2f5991b..2e355a403824f 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php @@ -1,12 +1,34 @@ regionFactory = $regionFactory ?: ObjectManager::getInstance()->get(RegionFactory::class); + parent::__construct( + $context, + $coreRegistry, + $fileFactory, + $translateInline, + $resultPageFactory, + $resultJsonFactory, + $resultLayoutFactory, + $resultRawFactory, + $orderManagement, + $orderRepository, + $logger + ); + } + /** * Save order address * - * @return \Magento\Backend\Model\View\Result\Redirect + * @return Redirect */ public function execute() { $addressId = $this->getRequest()->getParam('address_id'); - /** @var $address \Magento\Sales\Api\Data\OrderAddressInterface|\Magento\Sales\Model\Order\Address */ + /** @var $address OrderAddressInterface|Address */ $address = $this->_objectManager->create( - \Magento\Sales\Api\Data\OrderAddressInterface::class + OrderAddressInterface::class )->load($addressId); $data = $this->getRequest()->getPostValue(); + $data = $this->updateRegionData($data); $resultRedirect = $this->resultRedirectFactory->create(); if ($data && $address->getId()) { $address->addData($data); @@ -41,7 +114,7 @@ public function execute() ); $this->messageManager->addSuccess(__('You updated the order address.')); return $resultRedirect->setPath('sales/*/view', ['order_id' => $address->getParentId()]); - } catch (\Magento\Framework\Exception\LocalizedException $e) { + } catch (LocalizedException $e) { $this->messageManager->addError($e->getMessage()); } catch (\Exception $e) { $this->messageManager->addException($e, __('We can\'t update the order address right now.')); @@ -51,4 +124,20 @@ public function execute() return $resultRedirect->setPath('sales/*/'); } } + + /** + * Update region data + * + * @param array $attributeValues + * @return array + */ + private function updateRegionData($attributeValues) + { + if (!empty($attributeValues['region_id'])) { + $newRegion = $this->regionFactory->create()->load($attributeValues['region_id']); + $attributeValues['region_code'] = $newRegion->getCode(); + $attributeValues['region'] = $newRegion->getDefaultName(); + } + return $attributeValues; + } } From 1e6dd015a0143b9310034c3b5cf757df786aa558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mateos?= Date: Wed, 11 Oct 2017 20:32:09 +0200 Subject: [PATCH 089/528] Change origin copyright --- .../Magento/Sales/Controller/Adminhtml/Order/AddressSave.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php index 2e355a403824f..583849bf12458 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php @@ -1,7 +1,7 @@ Date: Wed, 11 Oct 2017 20:36:47 +0200 Subject: [PATCH 090/528] Append shipment comment to shipment if appendComment is true --- .../Magento/Sales/Model/Order/ShipmentDocumentFactory.php | 5 +++++ .../Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php b/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php index 8e46f26f7d9fc..6d9bffdd00771 100644 --- a/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php +++ b/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php @@ -101,6 +101,11 @@ public function create( $appendComment, $comment->getIsVisibleOnFront() ); + + if ($appendComment) { + $shipment->setCustomerNote($comment->getComment()); + $shipment->setCustomerNoteNotify($appendComment); + } } return $shipment; diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php index 0d02c49b21c6b..e681edf3e542f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php @@ -92,7 +92,7 @@ protected function setUp() $this->shipmentMock = $this->getMockBuilder(ShipmentInterface::class) ->disableOriginalConstructor() - ->setMethods(['addComment', 'addTrack']) + ->setMethods(['addComment', 'addTrack', 'setCustomerNote', 'setCustomerNoteNotify']) ->getMockForAbstractClass(); $this->hydratorPoolMock = $this->getMockBuilder(HydratorPool::class) @@ -160,7 +160,7 @@ public function testCreate() if ($appendComment) { $comment = "New comment!"; $visibleOnFront = true; - $this->commentMock->expects($this->once()) + $this->commentMock->expects($this->exactly(2)) ->method('getComment') ->willReturn($comment); @@ -172,6 +172,10 @@ public function testCreate() ->method('addComment') ->with($comment, $appendComment, $visibleOnFront) ->willReturnSelf(); + + $this->shipmentMock->expects($this->once()) + ->method('setCustomerNoteNotify') + ->with(true); } $this->assertEquals( From 1743a36a424ded64043fbc6592956099ebb0eec2 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Wed, 11 Oct 2017 21:47:27 +0300 Subject: [PATCH 091/528] Sync billing with shipping address on Admin Order Page - Set customer address ID only if the address was selected in dropdown - Removed "old" billing address from quote if customer address doesn't specified --- .../Magento/Sales/Model/AdminOrder/Create.php | 52 ++++++++-------- .../adminhtml/web/order/create/scripts.js | 46 +++++++++------ .../Controller/Adminhtml/Order/CreateTest.php | 59 ++++++++++++++++++- 3 files changed, 114 insertions(+), 43 deletions(-) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index ccc5c134514f6..3d80713c51c08 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -10,6 +10,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Model\Metadata\Form as CustomerForm; +use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\Item; /** @@ -1449,32 +1450,35 @@ public function getBillingAddress() */ public function setBillingAddress($address) { - if (is_array($address)) { - $billingAddress = $this->_objectManager->create( - \Magento\Quote\Model\Quote\Address::class - )->setData( - $address - )->setAddressType( - \Magento\Quote\Model\Quote\Address::TYPE_BILLING - ); - $this->_setQuoteAddress($billingAddress, $address); - /** - * save_in_address_book is not a valid attribute and is filtered out by _setQuoteAddress, - * that is why it should be added after _setQuoteAddress call - */ - $saveInAddressBook = (int)(!empty($address['save_in_address_book'])); - $billingAddress->setData('save_in_address_book', $saveInAddressBook); - - if (!$this->getQuote()->isVirtual() && $this->getShippingAddress()->getSameAsBilling()) { - $shippingAddress = clone $billingAddress; - $shippingAddress->setSameAsBilling(true); - $shippingAddress->setSaveInAddressBook(false); - $address['save_in_address_book'] = 0; - $this->setShippingAddress($address); - } + if (!is_array($address)) { + return $this; + } + + $billingAddress = $this->_objectManager->create(Address::class) + ->setData($address) + ->setAddressType(Address::TYPE_BILLING); + + $this->_setQuoteAddress($billingAddress, $address); + + /** + * save_in_address_book is not a valid attribute and is filtered out by _setQuoteAddress, + * that is why it should be added after _setQuoteAddress call + */ + $saveInAddressBook = (int)(!empty($address['save_in_address_book'])); + $billingAddress->setData('save_in_address_book', $saveInAddressBook); + + $quote = $this->getQuote(); + if (!$quote->isVirtual() && $this->getShippingAddress()->getSameAsBilling()) { + $address['save_in_address_book'] = 0; + $this->setShippingAddress($address); + } - $this->getQuote()->setBillingAddress($billingAddress); + // not assigned billing address should be saved as new + // but if quote already has the billing address it won't be overridden + if (empty($billingAddress->getCustomerAddressId())) { + $quote->removeAddress($quote->getBillingAddress()->getId()); } + $quote->setBillingAddress($billingAddress); return $this; } diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 1c755b4e08a0d..302c615e68855 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -157,6 +157,7 @@ define([ } if(this.addresses[id]){ this.fillAddressFields(container, this.addresses[id]); + } else{ this.fillAddressFields(container, {}); @@ -190,43 +191,52 @@ define([ } }, - changeAddressField : function(event){ - var field = Event.element(event); - var re = /[^\[]*\[([^\]]*)_address\]\[([^\]]*)\](\[(\d)\])?/; - var matchRes = field.name.match(re); + /** + * Triggers on each form's element changes. + * + * @param {Object} event + */ + changeAddressField: function (event) { + var field = Event.element(event), + re = /[^\[]*\[([^\]]*)_address\]\[([^\]]*)\](\[(\d)\])?/, + matchRes = field.name.match(re), + type, + name, + data; if (!matchRes) { return; } - var type = matchRes[1]; - var name = matchRes[2]; - var data; + type = matchRes[1]; + name = matchRes[2]; - if(this.isBillingField(field.id)){ - data = this.serializeData(this.billingAddressContainer) - } - else{ - data = this.serializeData(this.shippingAddressContainer) + if (this.isBillingField(field.id)) { + data = this.serializeData(this.billingAddressContainer); + } else { + data = this.serializeData(this.shippingAddressContainer); } data = data.toObject(); - if( (type == 'billing' && this.shippingAsBilling) - || (type == 'shipping' && !this.shippingAsBilling) ) { + if (type === 'billing' && this.shippingAsBilling || type === 'shipping' && !this.shippingAsBilling) { data['reset_shipping'] = true; } - data['order['+type+'_address][customer_address_id]'] = $('order-'+type+'_address_customer_address_id').value; + data['order[' + type + '_address][customer_address_id]'] = null; + + if (name === 'customer_address_id') { + data['order[' + type + '_address][customer_address_id]'] = + $('order-' + type + '_address_customer_address_id').value; + } if (data['reset_shipping']) { this.resetShippingMethod(data); } else { this.saveData(data); - if (name == 'country_id' || name == 'customer_address_id') { + + if (name === 'country_id' || name === 'customer_address_id') { this.loadArea(['shipping_method', 'billing_method', 'totals', 'items'], true, data); } - // added for reloading of default sender and default recipient for giftmessages - //this.loadArea(['giftmessage'], true, data); } }, diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php index 5f3dbdabc640a..e071dde26a263 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php @@ -5,6 +5,10 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Backend\Model\Session\Quote; +use Magento\Quote\Api\CartRepositoryInterface; + /** * @magentoAppArea adminhtml * @magentoDbIsolation enabled @@ -158,7 +162,7 @@ public function testIndexAction() */ public function testGetAclResource($actionName, $reordered, $expectedResult) { - $this->_objectManager->get(\Magento\Backend\Model\Session\Quote::class)->setReordered($reordered); + $this->_objectManager->get(Quote::class)->setReordered($reordered); $orderController = $this->_objectManager->get( \Magento\Sales\Controller\Adminhtml\Order\Stub\OrderCreateStub::class ); @@ -229,4 +233,57 @@ public function testDeniedSaveAction() $this->dispatch('backend/sales/order_create/save'); $this->assertEquals('403', $this->getResponse()->getHttpResponseCode()); } + + /** + * Checks a case when shipping is the same as billing and billing address details was changed by request. + * Both billing and shipping addresses should be updated. + * + * @magentoAppArea adminhtml + * @magentoDataFixture Magento/Sales/_files/quote_with_customer.php + */ + public function testSyncBetweenQuoteAddresses() + { + /** @var CustomerRepositoryInterface $customerRepository */ + $customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); + $customer = $customerRepository->get('customer@example.com'); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->_objectManager->get(CartRepositoryInterface::class); + $quote = $quoteRepository->getActiveForCustomer($customer->getId()); + + $session = $this->_objectManager->get(Quote::class); + $session->setQuoteId($quote->getId()); + + $data = [ + 'firstname' => 'John', + 'lastname' => 'Doe', + 'street' => ['Soborna 23'], + 'city' => 'Kyiv', + 'country_id' => 'UA', + 'region' => 'Kyivska', + 'region_id' => 1 + ]; + $this->getRequest()->setPostValue( + [ + 'order' => ['billing_address' => $data], + 'reset_shipping' => 1, + 'customer_id' => $customer->getId(), + 'store_id' => 1, + 'json' => true + ] + ); + + $this->dispatch('backend/sales/order_create/loadBlock/block/shipping_address'); + self::assertEquals(200, $this->getResponse()->getHttpResponseCode()); + + $updatedQuote = $quoteRepository->get($quote->getId()); + + $billingAddress = $updatedQuote->getBillingAddress(); + self::assertEquals($data['region_id'], $billingAddress->getRegionId()); + self::assertEquals($data['country_id'], $billingAddress->getCountryId()); + + $shippingAddress = $updatedQuote->getShippingAddress(); + self::assertEquals($data['city'], $shippingAddress->getCity()); + self::assertEquals($data['street'], $shippingAddress->getStreet()); + } } From 51e0867597d4e0fc590afff51345fcd10ba12ef9 Mon Sep 17 00:00:00 2001 From: Javier Villanueva Date: Wed, 11 Oct 2017 21:39:12 +0100 Subject: [PATCH 092/528] Fix typo in design rule hint message --- .../Backend/view/adminhtml/web/template/dynamic-rows/grid.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html index 74621806fa5fb..891ad48b33eff 100644 --- a/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html +++ b/app/code/Magento/Backend/view/adminhtml/web/template/dynamic-rows/grid.html @@ -85,7 +85,7 @@
+ translate="'Search strings are either normal strings or regular expressions (PCRE). They are matched in the same order as entered.'">
: From 284f966dc87dce72c238b0e3af3ccb72bfed84c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Pihlstr=C3=B6m?= Date: Wed, 11 Oct 2017 23:46:34 +0200 Subject: [PATCH 093/528] delete url rewrites for products after an attribute set is deleted --- .../Eav/Model/AttributeSetRepository.php | 68 +++++++++++++++++++ app/code/Magento/CatalogUrlRewrite/etc/di.xml | 3 + 2 files changed, 71 insertions(+) create mode 100644 app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php diff --git a/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php new file mode 100644 index 0000000000000..efb9151770bc3 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php @@ -0,0 +1,68 @@ +urlPersist = $urlPersist; + $this->productCollection = $productCollection; + } + + /** + * Remove product url rewrites when an attribute set is deleted. + * + * @param \Magento\Eav\Model\AttributeSetRepository $subject + * @param callable $proceed + * @param AttributeSetInterface $attributeSet + */ + public function aroundDelete(\Magento\Eav\Model\AttributeSetRepository $subject, callable $proceed, + AttributeSetInterface $attributeSet) + { + // Get the product ids + $ids = $this->productCollection->addFieldToFilter('attribute_set_id', $attributeSet->getAttributeSetId()) + ->getAllIds(); + + // Delete the attribute set + $result = $proceed($attributeSet); + + // Delete the old product url rewrites + try + { + $this->urlPersist->deleteByData(['entity_id' => $ids, 'entity_type' => 'product']); + } + catch (\Exception $exception) + { + throw new CouldNotDeleteException(__('Could not delete the url rewrite(s): %1', $exception->getMessage())); + } + + return $result; + } +} \ No newline at end of file diff --git a/app/code/Magento/CatalogUrlRewrite/etc/di.xml b/app/code/Magento/CatalogUrlRewrite/etc/di.xml index 2d421417bfdc0..44f0764755005 100644 --- a/app/code/Magento/CatalogUrlRewrite/etc/di.xml +++ b/app/code/Magento/CatalogUrlRewrite/etc/di.xml @@ -31,4 +31,7 @@ + + + From 1645894da2b76f4e0f31e2c1aecedb3c7795dbbf Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 11 Oct 2017 22:29:54 -0500 Subject: [PATCH 094/528] MAGETWO-80480: Automate function tests - fix function test failures --- .../tests/app/Magento/Analytics/Test/Repository/Role.xml | 7 +++++++ .../TestCase/NotificationMenuAccessUserPermissionsTest.xml | 2 +- .../tests/app/Magento/Analytics/Test/etc/testcase.xml | 3 +-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml index 6d067a691d59d..77cc8b5fac038 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Repository/Role.xml @@ -13,6 +13,13 @@ %current_password% Magento_Backend::dashboard + Magento_Backend::stores + Magento_Config::config + Magento_Config::config_general + Magento_Backend::system + Magento_Backend::system_other_settings + Magento_AdminNotification::adminnotification + Magento_AdminNotification::show_list diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml index 0a827cacc984c..794f9e2d5da27 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NotificationMenuAccessUserPermissionsTest.xml @@ -14,7 +14,7 @@ - default + custom_admin_with_default_role diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml index dfdbdf0d7d761..ce1828c8adf5c 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/etc/testcase.xml @@ -8,7 +8,6 @@ - - + From 07a95ccfc3f42e88f3d2ddcef7bb1c9ce4c3e2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Pihlstr=C3=B6m?= Date: Thu, 12 Oct 2017 08:41:55 +0200 Subject: [PATCH 095/528] adjustments for style standard --- .../Eav/Model/AttributeSetRepository.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php index efb9151770bc3..96fc232829757 100644 --- a/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php +++ b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php @@ -8,7 +8,6 @@ namespace Magento\CatalogUrlRewrite\Plugin\Eav\Model; - use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\Eav\Api\Data\AttributeSetInterface; use Magento\UrlRewrite\Model\UrlPersistInterface; @@ -43,9 +42,11 @@ public function __construct(UrlPersistInterface $urlPersist, Collection $product * @param callable $proceed * @param AttributeSetInterface $attributeSet */ - public function aroundDelete(\Magento\Eav\Model\AttributeSetRepository $subject, callable $proceed, - AttributeSetInterface $attributeSet) - { + public function aroundDelete( + \Magento\Eav\Model\AttributeSetRepository $subject, + callable $proceed, + AttributeSetInterface $attributeSet + ) { // Get the product ids $ids = $this->productCollection->addFieldToFilter('attribute_set_id', $attributeSet->getAttributeSetId()) ->getAllIds(); @@ -54,15 +55,12 @@ public function aroundDelete(\Magento\Eav\Model\AttributeSetRepository $subject, $result = $proceed($attributeSet); // Delete the old product url rewrites - try - { + try { $this->urlPersist->deleteByData(['entity_id' => $ids, 'entity_type' => 'product']); - } - catch (\Exception $exception) - { + } catch (\Exception $exception) { throw new CouldNotDeleteException(__('Could not delete the url rewrite(s): %1', $exception->getMessage())); } return $result; } -} \ No newline at end of file +} From 9ee464c765ac843e10235db9e619cb66e8cbee1f Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Thu, 12 Oct 2017 09:55:57 +0200 Subject: [PATCH 096/528] Fix for #9566: Show the correct label in the admin --- app/code/Magento/Sales/Model/Order/Config.php | 8 +++- .../Magento/Sales/Model/Order/StatusTest.php | 48 +++++++++++++++++++ .../Magento/Sales/_files/order_status.php | 25 ++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php diff --git a/app/code/Magento/Sales/Model/Order/Config.php b/app/code/Magento/Sales/Model/Order/Config.php index 1c7514142678b..ae0ef0c828512 100644 --- a/app/code/Magento/Sales/Model/Order/Config.php +++ b/app/code/Magento/Sales/Model/Order/Config.php @@ -122,8 +122,14 @@ public function getStateDefaultStatus($state) */ public function getStatusLabel($code) { - $code = $this->maskStatusForArea($this->state->getAreaCode(), $code); + $area = $this->state->getAreaCode(); + $code = $this->maskStatusForArea($area, $code); $status = $this->orderStatusFactory->create()->load($code); + + if ($area == 'adminhtml') { + return $status->getLabel(); + } + return $status->getStoreLabel(); } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php new file mode 100644 index 0000000000000..d53ff46122f57 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php @@ -0,0 +1,48 @@ +get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $objectManager->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId('100000001'); + + $this->assertEquals('Example', $order->getStatusLabel()); + } + + /** + * In the frontend the store view specific label must be showed. + * + * @magentoDataFixture Magento/Sales/_files/order_status.php + */ + public function testTheStoreViewLabelIsUsedInTheFrontend() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('frontend'); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $objectManager->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId('100000001'); + + $this->assertEquals('Store view example', $order->getStatusLabel()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php new file mode 100644 index 0000000000000..e65dd6b682396 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_status.php @@ -0,0 +1,25 @@ +create( + \Magento\Sales\Model\Order\Status::class +); + +$data = [ + 'status' => 'example', + 'label' => 'Example', + 'store_labels' => [ + 1 => 'Store view example', + ] +]; + +$orderStatus->setData($data)->setStatus('example'); +$orderStatus->save(); + +$order->setStatus('example'); +$order->save(); From 9d593a4dbd55d6bd0343c3587c1b9bc3e1470d5e Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Thu, 12 Oct 2017 10:18:30 +0200 Subject: [PATCH 097/528] FIXED sort --- .../testsuite/Magento/Catalog/Model/CategoryTreeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php index 8707c54865996..8eeba1230f8b1 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTreeTest.php @@ -132,7 +132,7 @@ public function testGetChildrenSorted() { $this->_model->load(2); $unsorted = explode(',', $this->_model->getChildren()); - usort($unsorted); + sort($unsorted); $this->assertEquals(array_diff($unsorted, explode(',', $this->_model->getChildren(true, true, true))), []); } From 79693c8800f61780bcd44cf3fbbee92615f70514 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Thu, 12 Oct 2017 13:57:53 +0200 Subject: [PATCH 098/528] FIXED default getChildren() $recursive value --- app/code/Magento/Catalog/Model/Category.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php index 7fc15928b784d..ff840635e4c70 100644 --- a/app/code/Magento/Catalog/Model/Category.php +++ b/app/code/Magento/Catalog/Model/Category.php @@ -785,7 +785,7 @@ public function getAllChildren($asArray = false) * @param boolean $sortByPosition * @return string */ - public function getChildren($recursive = true, $isActive = true, $sortByPosition = false) + public function getChildren($recursive = false, $isActive = true, $sortByPosition = false) { return implode(',', $this->getResource()->getChildren($this, $recursive, $isActive, $sortByPosition)); } From 2fb5735a848b8730379a1e71e67518ce8fc1683a Mon Sep 17 00:00:00 2001 From: vzabaznov Date: Thu, 12 Oct 2017 17:16:36 +0300 Subject: [PATCH 099/528] MAGETWO-81801: Prepare code base 2.2.1 --- app/code/Magento/Deploy/Model/Filesystem.php | 80 +++----- .../Deploy/Test/Unit/Model/FilesystemTest.php | 189 ++++++++++++------ .../Controller/Adminhtml/History/Download.php | 2 +- .../Adminhtml/History/DownloadTest.php | 13 +- app/code/Magento/Store/etc/config.xml | 4 + .../Adminhtml/Downloadable/FileTest.php | 35 ---- 6 files changed, 172 insertions(+), 151 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php diff --git a/app/code/Magento/Deploy/Model/Filesystem.php b/app/code/Magento/Deploy/Model/Filesystem.php index 3dd28f4d3e820..0557914f48d24 100644 --- a/app/code/Magento/Deploy/Model/Filesystem.php +++ b/app/code/Magento/Deploy/Model/Filesystem.php @@ -5,17 +5,16 @@ */ namespace Magento\Deploy\Model; -use Symfony\Component\Console\Output\OutputInterface; -use Magento\Framework\App\State; -use Magento\Framework\App\DeploymentConfig\Writer; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Validator\Locale; use Magento\User\Model\ResourceModel\User\Collection as UserCollection; +use Symfony\Component\Console\Output\OutputInterface; /** * Generate static files, compile * - * Сlear generated/code, generated/metadata/, var/view_preprocessed and pub/static directories + * Clear generated/code, generated/metadata/, var/view_preprocessed and pub/static directories * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ @@ -50,21 +49,6 @@ class Filesystem */ const DEFAULT_THEME = 'Magento/blank'; - /** - * @var \Magento\Framework\App\DeploymentConfig\Writer - */ - private $writer; - - /** - * @var \Magento\Framework\App\DeploymentConfig\Reader - */ - private $reader; - - /** - * @var \Magento\Framework\ObjectManagerInterface - */ - private $objectManager; - /** * @var \Magento\Framework\Filesystem */ @@ -101,33 +85,35 @@ class Filesystem private $userCollection; /** - * @param \Magento\Framework\App\DeploymentConfig\Writer $writer - * @param \Magento\Framework\App\DeploymentConfig\Reader $reader - * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @var Locale + */ + private $locale; + + /** * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\Framework\App\Filesystem\DirectoryList $directoryList * @param \Magento\Framework\Filesystem\Driver\File $driverFile * @param \Magento\Store\Model\Config\StoreView $storeView * @param \Magento\Framework\ShellInterface $shell + * @param UserCollection $userCollection + * @param Locale $locale */ public function __construct( - \Magento\Framework\App\DeploymentConfig\Writer $writer, - \Magento\Framework\App\DeploymentConfig\Reader $reader, - \Magento\Framework\ObjectManagerInterface $objectManager, \Magento\Framework\Filesystem $filesystem, \Magento\Framework\App\Filesystem\DirectoryList $directoryList, \Magento\Framework\Filesystem\Driver\File $driverFile, \Magento\Store\Model\Config\StoreView $storeView, - \Magento\Framework\ShellInterface $shell + \Magento\Framework\ShellInterface $shell, + UserCollection $userCollection, + Locale $locale ) { - $this->writer = $writer; - $this->reader = $reader; - $this->objectManager = $objectManager; $this->filesystem = $filesystem; $this->directoryList = $directoryList; $this->driverFile = $driverFile; $this->storeView = $storeView; $this->shell = $shell; + $this->userCollection = $userCollection; + $this->locale = $locale; $this->functionCallPath = PHP_BINARY . ' -f ' . BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento '; } @@ -141,7 +127,7 @@ public function __construct( public function regenerateStatic( OutputInterface $output ) { - // Сlear generated/code, generated/metadata/, var/view_preprocessed and pub/static directories + // Clear generated/code, generated/metadata/, var/view_preprocessed and pub/static directories $this->cleanupFilesystem( [ DirectoryList::CACHE, @@ -193,7 +179,7 @@ protected function deployStaticContent( private function getAdminUserInterfaceLocales() { $locales = []; - foreach ($this->getUserCollection() as $user) { + foreach ($this->userCollection as $user) { $locales[] = $user->getInterfaceLocale(); } return $locales; @@ -203,6 +189,7 @@ private function getAdminUserInterfaceLocales() * Get used store and admin user locales * * @return array + * @throws \InvalidArgumentException if unknown locale is provided by the store configuration */ private function getUsedLocales() { @@ -210,25 +197,18 @@ private function getUsedLocales() $this->storeView->retrieveLocales(), $this->getAdminUserInterfaceLocales() ); - return array_unique($usedLocales); - } - - /** - * Get user collection - * - * @return UserCollection - * @deprecated 100.1.0 Added to not break backward compatibility of the constructor signature - * by injecting the new dependency directly. - * The method can be removed in a future major release, when constructor signature can be changed. - */ - private function getUserCollection() - { - if (!($this->userCollection instanceof UserCollection)) { - return \Magento\Framework\App\ObjectManager::getInstance()->get( - UserCollection::class - ); - } - return $this->userCollection; + return array_map( + function ($locale) { + if (!$this->locale->isValid($locale)) { + throw new \InvalidArgumentException( + $locale . + ' argument has invalid value, run info:language:list for list of available locales' + ); + } + return $locale; + }, + array_unique($usedLocales) + ); } /** diff --git a/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php b/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php index 673f31c04ffd3..d14c86c4a3264 100644 --- a/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php +++ b/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php @@ -5,47 +5,64 @@ */ namespace Magento\Deploy\Test\Unit\Model; +use Magento\Deploy\Model\Filesystem as DeployFilesystem; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\ShellInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Model\Config\StoreView; +use Magento\User\Model\ResourceModel\User\Collection; +use Magento\User\Model\User; +use PHPUnit_Framework_MockObject_MockObject as MockObject; +use Symfony\Component\Console\Output\OutputInterface; +use Magento\Framework\Validator\Locale; +use Magento\Framework\Setup\Lists; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class FilesystemTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Store\Model\Config\StoreView + * @var StoreView|MockObject */ - private $storeViewMock; + private $storeView; /** - * @var \Magento\Framework\ShellInterface + * @var ShellInterface|MockObject */ - private $shellMock; + private $shell; /** - * @var \Magento\User\Model\ResourceModel\User\Collection + * @var OutputInterface|MockObject */ - private $userCollectionMock; + private $output; /** - * @var \Symfony\Component\Console\Output\OutputInterface + * @var Filesystem|MockObject */ - private $outputMock; + private $filesystem; /** - * @var \Magento\Framework\Filesystem + * @var WriteInterface|MockObject */ - private $filesystemMock; + private $directoryWrite; /** - * @var \Magento\Framework\Filesystem\Directory\WriteInterface + * @var Collection|MockObject */ - private $directoryWriteMock; + private $userCollection; /** - * @var \Magento\Framework\ObjectManagerInterface + * @var ObjectManagerInterface|MockObject */ - private $objectManagerMock; + private $objectManager; /** - * @var \Magento\Deploy\Model\Filesystem + * @var DeployFilesystem */ - private $filesystem; + private $deployFilesystem; /** * @var string @@ -54,75 +71,127 @@ class FilesystemTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - - $this->storeViewMock = $this->createMock(\Magento\Store\Model\Config\StoreView::class); - $this->shellMock = $this->createMock(\Magento\Framework\ShellInterface::class); - $this->userCollectionMock = $this->createMock(\Magento\User\Model\ResourceModel\User\Collection::class); - $this->outputMock = $this->createMock(\Symfony\Component\Console\Output\OutputInterface::class); - $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class); - $this->filesystemMock = $this->createMock(\Magento\Framework\Filesystem::class); - $this->directoryWriteMock = $this->createMock(\Magento\Framework\Filesystem\Directory\WriteInterface::class); - $this->filesystemMock->expects($this->any()) - ->method('getDirectoryWrite') - ->willReturn($this->directoryWriteMock); - $this->filesystem = $objectManager->getObject( - \Magento\Deploy\Model\Filesystem::class, + $objectManager = new ObjectManager($this); + + $this->storeView = $this->createMock(StoreView::class); + $this->shell = $this->createMock(ShellInterface::class); + $this->output = $this->createMock(OutputInterface::class); + $this->objectManager = $this->createMock(ObjectManagerInterface::class); + $this->filesystem = $this->createMock(Filesystem::class); + $this->directoryWrite = $this->createMock(WriteInterface::class); + $this->filesystem->method('getDirectoryWrite') + ->willReturn($this->directoryWrite); + + $this->userCollection = $this->createMock(Collection::class); + + $lists = $this->getMockBuilder(Lists::class) + ->disableOriginalConstructor() + ->getMock(); + $lists->method('getLocaleList') + ->willReturn([ + 'fr_FR' => 'France', + 'de_DE' => 'Germany', + 'nl_NL' => 'Netherlands', + 'en_US' => 'USA' + ]); + $locale = $objectManager->getObject(Locale::class, ['lists' => $lists]); + + $this->deployFilesystem = $objectManager->getObject( + DeployFilesystem::class, [ - 'storeView' => $this->storeViewMock, - 'shell' => $this->shellMock, - 'filesystem' => $this->filesystemMock + 'storeView' => $this->storeView, + 'shell' => $this->shell, + 'filesystem' => $this->filesystem, + 'userCollection' => $this->userCollection, + 'locale' => $locale ] ); - $userCollection = new \ReflectionProperty(\Magento\Deploy\Model\Filesystem::class, 'userCollection'); - $userCollection->setAccessible(true); - $userCollection->setValue($this->filesystem, $this->userCollectionMock); - $this->cmdPrefix = PHP_BINARY . ' -f ' . BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento '; } public function testRegenerateStatic() { $storeLocales = ['fr_FR', 'de_DE', 'nl_NL']; - $adminUserInterfaceLocales = ['de_DE', 'en_US']; - $this->storeViewMock->expects($this->once()) - ->method('retrieveLocales') + $this->storeView->method('retrieveLocales') ->willReturn($storeLocales); - $userMock = $this->createMock(\Magento\User\Model\User::class); - $userMock->expects($this->once()) - ->method('getInterfaceLocale') - ->willReturn('en_US'); - $this->userCollectionMock->expects($this->once()) - ->method('getIterator') - ->willReturn(new \ArrayIterator([$userMock])); - - $usedLocales = array_unique( - array_merge($storeLocales, $adminUserInterfaceLocales) - ); - $staticContentDeployCmd = $this->cmdPrefix . 'setup:static-content:deploy -f ' - . implode(' ', $usedLocales); + $setupDiCompileCmd = $this->cmdPrefix . 'setup:di:compile'; - $this->shellMock->expects($this->at(0)) + $this->shell->expects(self::at(0)) ->method('execute') ->with($setupDiCompileCmd); - $this->shellMock->expects($this->at(1)) + + $this->initAdminLocaleMock('en_US'); + + $usedLocales = ['fr_FR', 'de_DE', 'nl_NL', 'en_US']; + $staticContentDeployCmd = $this->cmdPrefix . 'setup:static-content:deploy -f ' + . implode(' ', $usedLocales); + $this->shell->expects(self::at(1)) ->method('execute') ->with($staticContentDeployCmd); - $this->outputMock->expects($this->at(0)) + $this->output->expects(self::at(0)) ->method('writeln') ->with('Starting compilation'); - $this->outputMock->expects($this->at(2)) + $this->output->expects(self::at(2)) ->method('writeln') ->with('Compilation complete'); - $this->outputMock->expects($this->at(3)) + $this->output->expects(self::at(3)) ->method('writeln') ->with('Starting deployment of static content'); - $this->outputMock->expects($this->at(5)) + $this->output->expects(self::at(5)) ->method('writeln') ->with('Deployment of static content complete'); - $this->filesystem->regenerateStatic($this->outputMock); + $this->deployFilesystem->regenerateStatic($this->output); + } + + /** + * Checks a case when configuration contains incorrect locale code. + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage ;echo argument has invalid value, run info:language:list for list of available locales + */ + public function testGenerateStaticForNotAllowedStoreViewLocale() + { + $storeLocales = ['fr_FR', 'de_DE', ';echo']; + $this->storeView->method('retrieveLocales') + ->willReturn($storeLocales); + + $this->initAdminLocaleMock('en_US'); + + $this->deployFilesystem->regenerateStatic($this->output); + } + + /** + * Checks as case when admin locale is incorrect. + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage ;echo argument has invalid value, run info:language:list for list of available locales + */ + public function testGenerateStaticForNotAllowedAdminLocale() + { + $storeLocales = ['fr_FR', 'de_DE', 'en_US']; + $this->storeView->method('retrieveLocales') + ->willReturn($storeLocales); + + $this->initAdminLocaleMock(';echo'); + + $this->deployFilesystem->regenerateStatic($this->output); + } + + /** + * Initializes admin user locale. + * + * @param string $locale + */ + private function initAdminLocaleMock($locale) + { + /** @var User|MockObject $user */ + $user = $this->createMock(User::class); + $user->method('getInterfaceLocale') + ->willReturn($locale); + $this->userCollection->method('getIterator') + ->willReturn(new \ArrayIterator([$user])); } } diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php b/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php index 91cfbefbd57a2..e490ee4018376 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/History/Download.php @@ -39,7 +39,7 @@ public function __construct( */ public function execute() { - $fileName = $this->getRequest()->getParam('filename'); + $fileName = basename($this->getRequest()->getParam('filename')); /** @var \Magento\ImportExport\Helper\Report $reportHelper */ $reportHelper = $this->_objectManager->get(\Magento\ImportExport\Helper\Report::class); diff --git a/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/History/DownloadTest.php b/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/History/DownloadTest.php index 73b97dfc67751..3eb14e673f648 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/History/DownloadTest.php +++ b/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/History/DownloadTest.php @@ -72,8 +72,9 @@ class DownloadTest extends \PHPUnit\Framework\TestCase */ protected function setUp() { - $this->request = $this->createPartialMock(\Magento\Framework\App\Request\Http::class, ['getParam']); - $this->request->expects($this->any())->method('getParam')->with('filename')->willReturn('filename'); + $this->request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) + ->disableOriginalConstructor() + ->getMock(); $this->reportHelper = $this->createPartialMock( \Magento\ImportExport\Helper\Report::class, ['importFileExists', 'getReportSize', 'getReportOutput'] @@ -126,11 +127,12 @@ protected function setUp() } /** - * Test execute() + * Tests execute() */ public function testExecute() { - $this->reportHelper->expects($this->any())->method('importFileExists')->willReturn(true); + $this->reportHelper->expects($this->atLeastOnce())->method('importFileExists')->willReturn(true); + $this->resultRaw->expects($this->once())->method('setContents'); $this->downloadController->execute(); } @@ -140,7 +142,8 @@ public function testExecute() */ public function testExecuteFileNotFound() { - $this->reportHelper->expects($this->any())->method('importFileExists')->willReturn(false); + $this->request->method('getParam')->with('filename')->willReturn('filename'); + $this->reportHelper->method('importFileExists')->willReturn(false); $this->resultRaw->expects($this->never())->method('setContents'); $this->downloadController->execute(); } diff --git a/app/code/Magento/Store/etc/config.xml b/app/code/Magento/Store/etc/config.xml index 470337a97dcd9..bb5b23620df4b 100644 --- a/app/code/Magento/Store/etc/config.xml +++ b/app/code/Magento/Store/etc/config.xml @@ -115,6 +115,10 @@ php + php3 + php4 + php5 + php7 htaccess jsp pl diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php b/dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php deleted file mode 100644 index 4d19e973556c0..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php +++ /dev/null @@ -1,35 +0,0 @@ - [ - 'name' => 'sample.txt', - 'type' => 'text/plain', - 'tmp_name' => dirname(__DIR__) . '/_files/sample.tmp', - 'error' => 0, - 'size' => 0, - ], - ]; - - $this->dispatch('backend/admin/downloadable_file/upload/type/samples'); - $body = $this->getResponse()->getBody(); - $result = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Json\Helper\Data::class - )->jsonDecode( - $body - ); - $this->assertEquals(0, $result['error']); - } -} From 0edacbcac548b09d3e9a1e155688eeb3fe714d6b Mon Sep 17 00:00:00 2001 From: vzabaznov Date: Thu, 12 Oct 2017 19:24:36 +0300 Subject: [PATCH 100/528] MAGETWO-81820: Fix versions of packages into magento/framework composer.json --- lib/internal/Magento/Framework/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/composer.json b/lib/internal/Magento/Framework/composer.json index 55d6e55d4977f..7046122ec9f89 100644 --- a/lib/internal/Magento/Framework/composer.json +++ b/lib/internal/Magento/Framework/composer.json @@ -21,7 +21,7 @@ "lib-libxml": "*", "ext-xsl": "*", "symfony/process": "~2.1", - "colinmollenhour/php-redis-session-abstract": "~1.2.2", + "colinmollenhour/php-redis-session-abstract": "1.3.4", "composer/composer": "1.4.1", "monolog/monolog": "^1.17", "oyejorge/less.php": "~1.7.0", From d1e6f822ce8d28ef1a941e3e33262782386344a6 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Thu, 12 Oct 2017 21:04:50 +0300 Subject: [PATCH 101/528] Sync billing with shipping address on Admin Order Page - Fixed failed FAT --- app/code/Magento/Sales/Model/AdminOrder/Create.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 3d80713c51c08..8619165cde606 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -1477,6 +1477,7 @@ public function setBillingAddress($address) // but if quote already has the billing address it won't be overridden if (empty($billingAddress->getCustomerAddressId())) { $quote->removeAddress($quote->getBillingAddress()->getId()); + $billingAddress->setCustomerAddressId(null); } $quote->setBillingAddress($billingAddress); @@ -1779,6 +1780,7 @@ public function _prepareCustomer() $address = $this->getShippingAddress()->setCustomerId($this->getQuote()->getCustomer()->getId()); $this->setShippingAddress($address); } + $this->getBillingAddress()->setCustomerId($customer->getId()); $this->getQuote()->updateCustomerData($this->getQuote()->getCustomer()); $customer = $this->getQuote()->getCustomer(); From e2f23bd15de36394ac10e81d81c3bd8671574d6d Mon Sep 17 00:00:00 2001 From: peterjaap Date: Thu, 12 Oct 2017 20:52:06 +0200 Subject: [PATCH 102/528] Added carrier code to ID to distinguish shipping methods with the same method name but differing carrier code --- .../view/frontend/web/template/cart/shipping-rates.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/template/cart/shipping-rates.html b/app/code/Magento/Checkout/view/frontend/web/template/cart/shipping-rates.html index db2ff7df0e0b1..bdb3a9e8454fd 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/cart/shipping-rates.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/cart/shipping-rates.html @@ -24,10 +24,10 @@ checked: $parents[1].selectedShippingMethod, attr: { value: carrier_code + '_' + method_code, - id: 's_method_' + method_code + id: 's_method_' + carrier_code + '_' + method_code } "/> -
+ + + + actionCancel + + + + + + + + + +
+ + + + + + + advertisement-text + Advanced Reporting + provides you with a dynamic suite of reports with rich insights about the health of your + business.


As part of the Advanced Reporting service, we may also use your customer + data for such purposes as benchmarking, improving our products and services, and providing you + with new and improved analytics.


By using Magento 2.2, you agree to the Advanced + Reporting Privacy Policy + and Terms + of Service. You may opt out at any time from the Stores Configuration page.

]]> +
+
+
+
+ + + + + + + + + +
+
+ + + actionCancel + + + + + + + + + +
+ + + + + + + advertisement-text + Magento's 2.2.2 release offers a set of improvements that were developed using increased + quality standards. The release includes these features, among others: +

+
    +
  • GitHub Community Moderator Team
  • +
  • GitHub Community Videos
  • +
  • DevDocs Enhancements
  • +
+

Find the 2.2.2 details and future plans in the + Magento DevBlog. +

]]> +
+
+
+
+ + + + + + + +
+ + + actionCancel + + + + + + + + + +
+ + + + + + + advertisement-text + Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform + their online purchasing experience to achieve greater operational efficiency, improved customer + service, and sales growth. New capabilities include: +

+
    +
  • Company accounts with multiple tiers of buyers
  • +
  • Buyer roles and permissions
  • +
  • Custom catalogs and pricing
  • +
  • Quoting support
  • +
  • Rapid reorder experience
  • +
  • Payments on credit
  • +
]]> +
+
+
+
+ + + + + + + + + +
+
From 72c6debb03de2565cf5fba362b0f03ae14331d66 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 12 Oct 2017 17:09:51 -0500 Subject: [PATCH 109/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../layout/adminhtml_dashboard_index_test.xml | 80 ------------ .../ui_component/analytics_notification.xml | 116 ----------------- .../ui_component/b2b_notification.xml | 122 ------------------ .../developer_experience_notification.xml | 120 ----------------- 4 files changed, 438 deletions(-) delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml delete mode 100644 app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml diff --git a/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml b/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml deleted file mode 100644 index 72c562752516c..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/layout/adminhtml_dashboard_index_test.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - false - - 3333 - true - fieldset - advertisement_notification.advertisement_notification - advertisement_modal - advertisement-steps-wizard - data - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - product_attributes_listing.product_attributes_listing.product_attributes_columns.ids - advertisement_notification.advertisement_notification_data_source - data - - - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - - - advertisement_notification.advertisement_notification - advertisement_modal - data - - - - - - - - - diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml deleted file mode 100644 index 267ed8ac665e1..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/analytics_notification.xml +++ /dev/null @@ -1,116 +0,0 @@ - - -
- - - advertisement_notification.advertisement_notification_data_source - - Analytics Subscription - templates/form/collapsible - - - advertisement_notification - true - simple - data - - advertisement_notification.advertisement_notification_data_source - - - - - - Magento_Ui/js/form/provider - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - -
- - - - - - - advertisement-text - Advanced Reporting - provides you with a dynamic suite of reports with rich insights about the health of your - business.


As part of the Advanced Reporting service, we may also use your customer - data for such purposes as benchmarking, improving our products and services, and providing you - with new and improved analytics.


By using Magento 2.2, you agree to the Advanced - Reporting Privacy Policy - and Terms - of Service. You may opt out at any time from the Stores Configuration page.

]]> -
-
-
-
- - - - - - - - - -
-
-
diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml deleted file mode 100644 index 0cd28487b1063..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/b2b_notification.xml +++ /dev/null @@ -1,122 +0,0 @@ - - -
- - - advertisement_notification.advertisement_notification_data_source - - Analytics Subscription - templates/form/collapsible - - - advertisement_notification - true - simple - data - - advertisement_notification.advertisement_notification_data_source - - - - - - Magento_Ui/js/form/provider - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - -
- - - - - - - advertisement-text - Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform - their online purchasing experience to achieve greater operational efficiency, improved customer - service, and sales growth. New capabilities include: -

-
    -
  • Company accounts with multiple tiers of buyers
  • -
  • Buyer roles and permissions
  • -
  • Custom catalogs and pricing
  • -
  • Quoting support
  • -
  • Rapid reorder experience
  • -
  • Payments on credit
  • -
]]> -
-
-
-
- - - - - - - - - -
-
-
diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml deleted file mode 100644 index 39ce179fe7255..0000000000000 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/developer_experience_notification.xml +++ /dev/null @@ -1,120 +0,0 @@ - - -
- - - advertisement_notification.advertisement_notification_data_source - - Analytics Subscription - templates/form/collapsible - - - advertisement_notification - true - simple - data - - advertisement_notification.advertisement_notification_data_source - - - - - - Magento_Ui/js/form/provider - - - - - - false - - - - - - - actionCancel - true - - - - - - - - - -
- - - - - - - advertisement-text - Magento's 2.2.2 release offers a set of improvements that were developed using increased - quality standards. The release includes these features, among others: -

-
    -
  • GitHub Community Moderator Team
  • -
  • GitHub Community Videos
  • -
  • DevDocs Enhancements
  • -
-

Find the 2.2.2 details and future plans in the - Magento DevBlog. -

]]> -
-
-
-
- - - - - - - - - -
-
-
From 6862db093f0fa415ff15625924f3b56acd9ad9bf Mon Sep 17 00:00:00 2001 From: crissanclick Date: Fri, 13 Oct 2017 00:12:21 +0200 Subject: [PATCH 110/528] Clean config cache --- .../Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php | 4 ++-- .../Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php index 847f1312e8caf..90f1a0944bd05 100644 --- a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php +++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php @@ -51,8 +51,8 @@ public function execute() } // clear the block html cache - $this->_cacheTypeList->cleanType('block_html'); - $this->_eventManager->dispatch('adminhtml_cache_refresh_type', ['type' => 'block_html']); + $this->_cacheTypeList->cleanType('config') + $this->_eventManager->dispatch('adminhtml_cache_refresh_type', ['type' => 'config']); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); diff --git a/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php index 0f879a6e162f5..2035885f05e8f 100644 --- a/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php +++ b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php @@ -19,7 +19,7 @@ public function testExecute() ->getMock(); $cacheTypeList->expects($this->once()) ->method('cleanType') - ->with('block_html') + ->with('config') ->willReturn(null); $request = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) From 4c698c21d2f42acbfc35d84356ed27ff2821d45e Mon Sep 17 00:00:00 2001 From: crissanclick Date: Fri, 13 Oct 2017 00:12:53 +0200 Subject: [PATCH 111/528] Clean config cache --- .../Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php index 90f1a0944bd05..b623b6c6868e7 100644 --- a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php +++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php @@ -51,7 +51,7 @@ public function execute() } // clear the block html cache - $this->_cacheTypeList->cleanType('config') + $this->_cacheTypeList->cleanType('config'); $this->_eventManager->dispatch('adminhtml_cache_refresh_type', ['type' => 'config']); /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ From 4bf38e99db52ccdfe96d70bc6be424406f164b6d Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Thu, 12 Oct 2017 19:13:35 -0500 Subject: [PATCH 112/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Model/Condition/CanViewNotification.php | 20 ++++++++++++-- .../Condition/CanViewNotificationTest.php | 26 +++++++++++++++---- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 9f1e48fb2c8f7..1f4867d692693 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -6,6 +6,7 @@ namespace Magento\Analytics\Model\Condition; use Magento\Backend\Model\Auth\Session; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; use Magento\Analytics\Model\NotificationFlagManager; @@ -22,6 +23,11 @@ class CanViewNotification implements VisibilityConditionInterface */ const NAME = 'can_view_notification'; + /** + * Magento Version to only show Advertisement module notification content and hide Analytics notification + */ + const VERSION_TO_HIDE = '2.2.1-dev'; + /** * @var NotificationFlagManager */ @@ -32,18 +38,26 @@ class CanViewNotification implements VisibilityConditionInterface */ private $session; + /** + * @var ProductMetadataInterface + */ + private $productMetadataInterface; + /** * CanViewNotification constructor. * * @param NotificationFlagManager $notificationFlagManager * @param Session $session + * @param ProductMetadataInterface $productMetadataInterface */ public function __construct( NotificationFlagManager $notificationFlagManager, - Session $session + Session $session, + ProductMetadataInterface $productMetadataInterface ) { $this->notificationFlagManager = $notificationFlagManager; $this->session = $session; + $this->productMetadataInterface = $productMetadataInterface; } /** @@ -53,8 +67,10 @@ public function __construct( */ public function isVisible(array $arguments) { + $version = $this->productMetadataInterface->getVersion(); + $userId = $this->session->getUser()->getId(); - if ($this->notificationFlagManager->isUserNotified($userId)) { + if (!strcmp($version, self::VERSION_TO_HIDE) || $this->notificationFlagManager->isUserNotified($userId)) { return false; } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index c0941a5a94e9e..336e4da6d5b88 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -7,6 +7,7 @@ namespace Magento\Analytics\Test\Unit\Model\Condition; use Magento\Analytics\Model\Condition\CanViewNotification; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Analytics\Model\NotificationFlagManager; use Magento\Backend\Model\Auth\Session; @@ -31,6 +32,11 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase */ private $sessionMock; + /** + * @var ProductMetadataInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productMetadataInterfaceMock; + public function setUp() { $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) @@ -40,12 +46,16 @@ public function setUp() ->disableOriginalConstructor() ->setMethods(['getUser', 'getId']) ->getMock(); + $this->productMetadataInterfaceMock = $this->getMockBuilder(ProductMetadataInterface::class) + ->disableOriginalConstructor() + ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ 'notificationFlagManager' => $this->notificationFlagManagerMock, - 'session' => $this->sessionMock + 'session' => $this->sessionMock, + 'productMetadataInterface' => $this->productMetadataInterfaceMock ] ); } @@ -53,26 +63,32 @@ public function setUp() public function isVisibleProvider() { return [ - [1, false, true], - [1, true, false] + [1, "2.2.1", false, true], + [1, "2.2.1-dev", true, false], + [1, "2.2.1", true, false], + [1, "2.2.1-dev", false, false] ]; } /** * @dataProvider isVisibleProvider * @param int $userId + * @param string $version * @param bool $isUserNotified * @param bool $expected */ - public function testIsVisible($userId, $isUserNotified, $expected) + public function testIsVisible($userId, $version, $isUserNotified, $expected) { + $this->productMetadataInterfaceMock->expects($this->once()) + ->method('getVersion') + ->willReturn($version); $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); $this->sessionMock->expects($this->once()) ->method('getId') ->willReturn($userId); - $this->notificationFlagManagerMock->expects($this->once()) + $this->notificationFlagManagerMock->expects($this->any()) ->method('isUserNotified') ->willReturn($isUserNotified); $this->notificationFlagManagerMock->expects($this->any()) From 79e9054aa2fd66a6c804774617cd0f5d14ffc49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Mart=C3=ADnez?= Date: Fri, 13 Oct 2017 04:37:07 +0200 Subject: [PATCH 113/528] Support to manage multiple instances in the same crontab, based on installation directory --- app/code/Magento/Cron/etc/di.xml | 2 +- .../Framework/Crontab/CrontabManager.php | 51 +++++++++++++----- .../Crontab/Test/Unit/CrontabManagerTest.php | 52 +++++++++---------- 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/app/code/Magento/Cron/etc/di.xml b/app/code/Magento/Cron/etc/di.xml index d355debfa703b..a37f3760b70a5 100644 --- a/app/code/Magento/Cron/etc/di.xml +++ b/app/code/Magento/Cron/etc/di.xml @@ -43,7 +43,7 @@ - + Magento\Framework\App\Shell diff --git a/lib/internal/Magento/Framework/Crontab/CrontabManager.php b/lib/internal/Magento/Framework/Crontab/CrontabManager.php index cd0dcdaeaa6a1..1f079b766c22e 100644 --- a/lib/internal/Magento/Framework/Crontab/CrontabManager.php +++ b/lib/internal/Magento/Framework/Crontab/CrontabManager.php @@ -5,11 +5,11 @@ */ namespace Magento\Framework\Crontab; -use Magento\Framework\ShellInterface; -use Magento\Framework\Phrase; +use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem; -use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Phrase; +use Magento\Framework\ShellInterface; /** * Manager works with cron tasks @@ -38,6 +38,30 @@ public function __construct( $this->filesystem = $filesystem; } + /** + * @return string + */ + private function getTasksBlockStart() + { + $tasksBlockStart = self::TASKS_BLOCK_START; + if (defined('BP')) { + $tasksBlockStart .= ' ' . md5(BP); + } + return $tasksBlockStart; + } + + /** + * @return string + */ + private function getTasksBlockEnd() + { + $tasksBlockEnd = self::TASKS_BLOCK_END; + if (defined('BP')) { + $tasksBlockEnd .= ' ' . md5(BP); + } + return $tasksBlockEnd; + } + /** * {@inheritdoc} */ @@ -45,7 +69,7 @@ public function getTasks() { $this->checkSupportedOs(); $content = $this->getCrontabContent(); - $pattern = '!(' . self::TASKS_BLOCK_START . ')(.*?)(' . self::TASKS_BLOCK_END . ')!s'; + $pattern = '!(' . $this->getTasksBlockStart() . ')(.*?)(' . $this->getTasksBlockEnd() . ')!s'; if (preg_match($pattern, $content, $matches)) { $tasks = trim($matches[2], PHP_EOL); @@ -61,14 +85,14 @@ public function getTasks() */ public function saveTasks(array $tasks) { - $this->checkSupportedOs(); - $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); - $logDir = $this->filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath(); - if (!$tasks) { throw new LocalizedException(new Phrase('List of tasks is empty')); } + $this->checkSupportedOs(); + $baseDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT)->getAbsolutePath(); + $logDir = $this->filesystem->getDirectoryRead(DirectoryList::LOG)->getAbsolutePath(); + foreach ($tasks as $key => $task) { if (empty($task['expression'])) { $tasks[$key]['expression'] = '* * * * *'; @@ -114,11 +138,11 @@ public function removeTasks() private function generateSection($content, $tasks = []) { if ($tasks) { - $content .= self::TASKS_BLOCK_START . PHP_EOL; + $content .= $this->getTasksBlockStart() . PHP_EOL; foreach ($tasks as $task) { - $content .= $task['expression'] . ' ' . PHP_BINARY . ' '. $task['command'] . PHP_EOL; + $content .= $task['expression'] . ' ' . PHP_BINARY . ' ' . $task['command'] . PHP_EOL; } - $content .= self::TASKS_BLOCK_END . PHP_EOL; + $content .= $this->getTasksBlockEnd() . PHP_EOL; } return $content; @@ -133,7 +157,8 @@ private function generateSection($content, $tasks = []) private function cleanMagentoSection($content) { $content = preg_replace( - '!' . preg_quote(self::TASKS_BLOCK_START) . '.*?' . preg_quote(self::TASKS_BLOCK_END . PHP_EOL) . '!s', + '!' . preg_quote($this->getTasksBlockStart()) . '.*?' + . preg_quote($this->getTasksBlockEnd() . PHP_EOL) . '!s', '', $content ); @@ -192,7 +217,7 @@ private function checkSupportedOs() { if (stripos(PHP_OS, 'WIN') === 0) { throw new LocalizedException( - new Phrase('Your operation system is not supported to work with this command') + new Phrase('Your operating system is not supported to work with this command') ); } } diff --git a/lib/internal/Magento/Framework/Crontab/Test/Unit/CrontabManagerTest.php b/lib/internal/Magento/Framework/Crontab/Test/Unit/CrontabManagerTest.php index e4088b1e4befc..779bc7621be7c 100644 --- a/lib/internal/Magento/Framework/Crontab/Test/Unit/CrontabManagerTest.php +++ b/lib/internal/Magento/Framework/Crontab/Test/Unit/CrontabManagerTest.php @@ -5,15 +5,15 @@ */ namespace Magento\Framework\Crontab\Test\Unit; +use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Crontab\CrontabManager; use Magento\Framework\Crontab\CrontabManagerInterface; -use Magento\Framework\ShellInterface; -use Magento\Framework\Phrase; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem; -use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Filesystem\Directory\ReadInterface; use Magento\Framework\Filesystem\DriverPool; +use Magento\Framework\Phrase; +use Magento\Framework\ShellInterface; class CrontabManagerTest extends \PHPUnit\Framework\TestCase { @@ -87,17 +87,17 @@ public function getTasksDataProvider() return [ [ 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, 'tasks' => ['* * * * * /bin/php /var/www/magento/bin/magento cron:run'], ], [ 'content' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, 'tasks' => [ '* * * * * /bin/php /var/www/magento/bin/magento cron:run', '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run', @@ -165,17 +165,17 @@ public function removeTasksDataProvider() return [ [ 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL ], [ 'contentBefore' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL . '* * * * * /bin/php /var/www/magento/bin/magento setup:cron:run' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, 'contentAfter' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL ], [ @@ -198,14 +198,12 @@ public function testSaveTasksWithEmptyTasksList() { $baseDirMock = $this->getMockBuilder(ReadInterface::class) ->getMockForAbstractClass(); - $baseDirMock->expects($this->once()) - ->method('getAbsolutePath') - ->willReturn('/var/www/magento2/'); + $baseDirMock->expects($this->never()) + ->method('getAbsolutePath'); $logDirMock = $this->getMockBuilder(ReadInterface::class) ->getMockForAbstractClass(); - $logDirMock->expects($this->once()) - ->method('getAbsolutePath') - ->willReturn('/var/www/magento2/var/log/'); + $logDirMock->expects($this->never()) + ->method('getAbsolutePath'); $this->filesystemMock->expects($this->any()) ->method('getDirectoryRead') @@ -292,9 +290,9 @@ public function testSaveTasks($tasks, $content, $contentToSave) public function saveTasksDataProvider() { $content = '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * /bin/php /var/www/magento/bin/magento cron:run' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL; + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL; return [ [ @@ -303,9 +301,9 @@ public function saveTasksDataProvider() ], 'content' => $content, 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * ' . PHP_BINARY . ' run.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, ], [ 'tasks' => [ @@ -313,9 +311,9 @@ public function saveTasksDataProvider() ], 'content' => $content, 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '1 2 3 4 5 ' . PHP_BINARY . ' run.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, ], [ 'tasks' => [ @@ -323,10 +321,10 @@ public function saveTasksDataProvider() ], 'content' => $content, 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * ' . PHP_BINARY . ' /var/www/magento2/run.php >>' . ' /var/www/magento2/var/log/cron.log' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, ], [ 'tasks' => [ @@ -334,10 +332,10 @@ public function saveTasksDataProvider() ], 'content' => $content, 'contentToSave' => '* * * * * /bin/php /var/www/cron.php' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_START . PHP_EOL + . CrontabManagerInterface::TASKS_BLOCK_START . ' ' . md5(BP) . PHP_EOL . '* * * * * ' . PHP_BINARY . ' /var/www/magento2/run.php' . ' %% cron:run | grep -v \"Ran \'jobs\' by schedule\"' . PHP_EOL - . CrontabManagerInterface::TASKS_BLOCK_END . PHP_EOL, + . CrontabManagerInterface::TASKS_BLOCK_END . ' ' . md5(BP) . PHP_EOL, ], ]; } From 3c589eaf71a87c8de885976698f5c18dba49ee85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Jewu=C5=82a?= Date: Sun, 17 Sep 2017 12:00:43 +0200 Subject: [PATCH 114/528] #10765 add confirmation and lock_expires labels to customer grid CSV export --- .../Ui/Component/DataProvider/Document.php | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php index f5cd5cac62d86..6255dc2b9eeda 100644 --- a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php +++ b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php @@ -6,9 +6,12 @@ namespace Magento\Customer\Ui\Component\DataProvider; use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Model\AccountManagement; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Customer\Api\GroupRepositoryInterface; +use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; /** @@ -31,6 +34,21 @@ class Document extends \Magento\Framework\View\Element\UiComponent\DataProvider\ */ private static $websiteAttributeCode = 'website_id'; + /** + * @var string + */ + private static $websiteIdAttributeCode = 'original_website_id'; + + /** + * @var string + */ + private static $confirmationAttributeCode = 'confirmation'; + + /** + * @var string + */ + private static $accountLockAttributeCode = 'lock_expires'; + /** * @var CustomerMetadataInterface */ @@ -46,23 +64,31 @@ class Document extends \Magento\Framework\View\Element\UiComponent\DataProvider\ */ private $storeManager; + /** + * @var ScopeConfigInterface + */ + private $scopeConfig; + /** * Document constructor. * @param AttributeValueFactory $attributeValueFactory * @param GroupRepositoryInterface $groupRepository * @param CustomerMetadataInterface $customerMetadata * @param StoreManagerInterface $storeManager + * @param ScopeConfigInterface $scopeConfig */ public function __construct( AttributeValueFactory $attributeValueFactory, GroupRepositoryInterface $groupRepository, CustomerMetadataInterface $customerMetadata, - StoreManagerInterface $storeManager + StoreManagerInterface $storeManager, + ScopeConfigInterface $scopeConfig ) { parent::__construct($attributeValueFactory); $this->customerMetadata = $customerMetadata; $this->groupRepository = $groupRepository; $this->storeManager = $storeManager; + $this->scopeConfig = $scopeConfig; } /** @@ -80,6 +106,12 @@ public function getCustomAttribute($attributeCode) case self::$websiteAttributeCode: $this->setWebsiteValue(); break; + case self::$confirmationAttributeCode: + $this->setConfirmationValue(); + break; + case self::$accountLockAttributeCode: + $this->setAccountLockValue(); + break; } return parent::getCustomAttribute($attributeCode); } @@ -133,5 +165,47 @@ private function setWebsiteValue() $value = $this->getData(self::$websiteAttributeCode); $list = $this->storeManager->getWebsites(); $this->setCustomAttribute(self::$websiteAttributeCode, $list[$value]->getName()); + $this->setCustomAttribute(self::$websiteIdAttributeCode, $value); + } + + /** + * Update confirmation value + * Method set confirmation text value to match what is shown in grid + * @return void + */ + private function setConfirmationValue() + { + $value = $this->getData(self::$confirmationAttributeCode); + $websiteId = $this->getData(self::$websiteIdAttributeCode) ?: $this->getData(self::$websiteAttributeCode); + $isConfirmationRequired = (bool)$this->scopeConfig->getValue( + AccountManagement::XML_PATH_IS_CONFIRM, + ScopeInterface::SCOPE_WEBSITES, + $websiteId); + + $valueText = !$isConfirmationRequired ? + __('Confirmation Not Required') + : ($value === null ? __('Confirmed') : __('Confirmation Required')); + + $this->setCustomAttribute(self::$confirmationAttributeCode, $valueText); + } + + /** + * Update lock expires value + * Method set account lock text value to match what is shown in grid + * @return void + */ + private function setAccountLockValue() + { + $value = $this->getDataByPath(self::$accountLockAttributeCode); + + $valueText = __('Unlocked'); + if ($value !== null) { + $lockExpires = new \DateTime($value); + if ($lockExpires > new \DateTime()) { + $valueText = __('Locked'); + } + } + + $this->setCustomAttribute(self::$accountLockAttributeCode, $valueText); } } From 0637eed27ffeb02fe86a3d5173ce21d070d256fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Jewu=C5=82a?= Date: Sun, 17 Sep 2017 12:49:29 +0200 Subject: [PATCH 115/528] #10765 Add tests for added methods --- .../Component/DataProvider/DocumentTest.php | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php index e9c91d8305e90..ec14c43219449 100644 --- a/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php @@ -13,6 +13,8 @@ use Magento\Customer\Ui\Component\DataProvider\Document; use Magento\Framework\Api\AttributeValue; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Phrase; use Magento\Store\Api\Data\WebsiteInterface; use Magento\Store\Model\StoreManagerInterface; use PHPUnit_Framework_MockObject_MockObject as MockObject; @@ -44,6 +46,11 @@ class DocumentTest extends \PHPUnit\Framework\TestCase */ private $storeManager; + /** + * @var ScopeConfigInterface|MockObject + */ + private $scopeConfig; + /** * @var Document */ @@ -59,11 +66,14 @@ protected function setUp() $this->storeManager = $this->getMockForAbstractClass(StoreManagerInterface::class); + $this->scopeConfig = $this->getMockForAbstractClass(ScopeConfigInterface::class); + $this->document = new Document( $this->attributeValueFactory, $this->groupRepository, $this->customerMetadata, - $this->storeManager + $this->storeManager, + $this->scopeConfig ); } @@ -156,6 +166,42 @@ public function testGetWebsiteAttribute() static::assertEquals('Main Website', $attribute->getValue()); } + /** + * @covers \Magento\Customer\Ui\Component\DataProvider\Document::getCustomAttribute + */ + public function testGetConfirmationAttribute() + { + $websiteId = 1; + $this->document->setData('original_website_id', $websiteId); + + $this->scopeConfig->expects(static::once()) + ->method('getValue') + ->with() + ->willReturn(true); + + $this->document->setData('confirmation', null); + $attribute = $this->document->getCustomAttribute('confirmation'); + + $value = $attribute->getValue(); + static::assertInstanceOf(Phrase::class, $value); + static::assertEquals('Confirmed', (string)$value); + } + + + /** + * @covers \Magento\Customer\Ui\Component\DataProvider\Document::getCustomAttribute + */ + public function testGetAccountLockValue() + { + $this->document->setData('lock_expires', null); + + $attribute = $this->document->getCustomAttribute('lock_expires'); + + $value = $attribute->getValue(); + static::assertInstanceOf(Phrase::class, $value); + static::assertEquals('Unlocked', (string)$value); + } + /** * Create mock for attribute value factory * @return void From a5680e6ec9c458fc5f0c531bb1b472cf39f69096 Mon Sep 17 00:00:00 2001 From: Zefiryn Date: Sun, 17 Sep 2017 13:31:21 +0200 Subject: [PATCH 116/528] 10765 code refactoring --- .../Customer/Ui/Component/DataProvider/Document.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php index 6255dc2b9eeda..7d66e54bd8b81 100644 --- a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php +++ b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php @@ -11,6 +11,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Customer\Api\GroupRepositoryInterface; +use Magento\Framework\App\ObjectManager; use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; @@ -82,13 +83,13 @@ public function __construct( GroupRepositoryInterface $groupRepository, CustomerMetadataInterface $customerMetadata, StoreManagerInterface $storeManager, - ScopeConfigInterface $scopeConfig + ScopeConfigInterface $scopeConfig = null ) { parent::__construct($attributeValueFactory); $this->customerMetadata = $customerMetadata; $this->groupRepository = $groupRepository; $this->storeManager = $storeManager; - $this->scopeConfig = $scopeConfig; + $this->scopeConfig = $scopeConfig ? $scopeConfig : ObjectManager::getInstance()->create(ScopeConfigInterface::class); } /** @@ -182,9 +183,10 @@ private function setConfirmationValue() ScopeInterface::SCOPE_WEBSITES, $websiteId); - $valueText = !$isConfirmationRequired ? - __('Confirmation Not Required') - : ($value === null ? __('Confirmed') : __('Confirmation Required')); + $valueText = __('Confirmation Not Required'); + if ($isConfirmationRequired) { + $valueText = $value === null ? __('Confirmed') : __('Confirmation Required'); + } $this->setCustomAttribute(self::$confirmationAttributeCode, $valueText); } From 20c3b4e1448a3bb0d748890cf1b5bf3508073d90 Mon Sep 17 00:00:00 2001 From: Zefiryn Date: Sun, 17 Sep 2017 16:06:49 +0200 Subject: [PATCH 117/528] 10765 fix coding standards --- .../Test/Unit/Ui/Component/DataProvider/DocumentTest.php | 1 - .../Magento/Customer/Ui/Component/DataProvider/Document.php | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php index ec14c43219449..1d7905cca7941 100644 --- a/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/DataProvider/DocumentTest.php @@ -187,7 +187,6 @@ public function testGetConfirmationAttribute() static::assertEquals('Confirmed', (string)$value); } - /** * @covers \Magento\Customer\Ui\Component\DataProvider\Document::getCustomAttribute */ diff --git a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php index 7d66e54bd8b81..a9a5c5b17744e 100644 --- a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php +++ b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php @@ -89,7 +89,7 @@ public function __construct( $this->customerMetadata = $customerMetadata; $this->groupRepository = $groupRepository; $this->storeManager = $storeManager; - $this->scopeConfig = $scopeConfig ? $scopeConfig : ObjectManager::getInstance()->create(ScopeConfigInterface::class); + $this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->create(ScopeConfigInterface::class); } /** @@ -181,7 +181,8 @@ private function setConfirmationValue() $isConfirmationRequired = (bool)$this->scopeConfig->getValue( AccountManagement::XML_PATH_IS_CONFIRM, ScopeInterface::SCOPE_WEBSITES, - $websiteId); + $websiteId + ); $valueText = __('Confirmation Not Required'); if ($isConfirmationRequired) { From 720496ccfa3baedb8e0435df442bc32de19b2bcc Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Fri, 13 Oct 2017 12:34:15 +0200 Subject: [PATCH 118/528] Magento setup:install interactive shell --- .../Setup/Console/Command/InstallCommand.php | 111 +++++++++++++++++- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/InstallCommand.php b/setup/src/Magento/Setup/Console/Command/InstallCommand.php index b0ccbba8c296f..98423c26d39e2 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallCommand.php @@ -13,6 +13,9 @@ use Magento\Framework\Setup\ConsoleLogger; use Symfony\Component\Console\Input\InputOption; use Magento\Setup\Model\ConfigModel; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Helper\QuestionHelper; /** * Command to install Magento application @@ -35,6 +38,16 @@ class InstallCommand extends AbstractSetupCommand */ const INPUT_KEY_USE_SAMPLE_DATA = 'use-sample-data'; + /** + * Parameter indicating command for interactive setup + */ + const INPUT_KEY_INTERACTIVE_SETUP = 'interactive'; + + /** + * Parameter indicating command shortcut for interactive setup + */ + const INPUT_KEY_INTERACTIVE_SETUP_SHORTCUT = 'i'; + /** * Regex for sales_order_increment_prefix validation. */ @@ -109,7 +122,13 @@ protected function configure() null, InputOption::VALUE_NONE, 'Use sample data' - ) + ), + new InputOption( + self::INPUT_KEY_INTERACTIVE_SETUP, + self::INPUT_KEY_INTERACTIVE_SETUP_SHORTCUT, + InputOption::VALUE_NONE, + 'Interactive Magento instalation' + ), ]); $this->setName('setup:install') ->setDescription('Installs the Magento application') @@ -139,12 +158,17 @@ protected function initialize(InputInterface $input, OutputInterface $output) { $inputOptions = $input->getOptions(); - $configOptionsToValidate = []; - foreach ($this->configModel->getAvailableOptions() as $option) { - if (array_key_exists($option->getName(), $inputOptions)) { - $configOptionsToValidate[$option->getName()] = $inputOptions[$option->getName()]; + if ($inputOptions['interactive']) { + $configOptionsToValidate = $this->interactiveQuestions($input, $output); + } else { + $configOptionsToValidate = []; + foreach ($this->configModel->getAvailableOptions() as $option) { + if (array_key_exists($option->getName(), $inputOptions)) { + $configOptionsToValidate[$option->getName()] = $inputOptions[$option->getName()]; + } } } + $errors = $this->configModel->validate($configOptionsToValidate); $errors = array_merge($errors, $this->adminUser->validate($input)); $errors = array_merge($errors, $this->validate($input)); @@ -177,4 +201,81 @@ public function validate(InputInterface $input) } return $errors; } + + /** + * Runs interactive questions + * + * It will ask users for interactive questionst regarding setup configuration. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return string[] Array of inputs + */ + private function interactiveQuestions(InputInterface $input, OutputInterface $output) + { + $helper = $this->getHelper('question'); + $configOptionsToValidate = []; + foreach ($this->configModel->getAvailableOptions() as $option) { + + $configOptionsToValidate[$option->getName()] = $this->askQuestion($input, $output, $helper, $option); + + /*$question = new Question($option->getDescription() . '? ', $option->getDefault()); + $configOptionsToValidate[$option->getName()] = $helper->ask($input, $output, $question); + */ + } + return $configOptionsToValidate; + } + + /** + * Runs interactive questions + * + * It will ask users for interactive questionst regarding setup configuration. + * + * @param InputInterface $input + * @param OutputInterface $output + * @param QuestionHelper $helper + * @param Magento\Framework\Setup\Option\TextConfigOption|Magento\Framework\Setup\Option\FlagConfigOption\Magento\Framework\Setup\Option\SelectConfigOption $option + * @return string[] Array of inputs + */ + private function askQuestion(InputInterface $input, OutputInterface $output, QuestionHelper $helper, $option) + { + if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + if ($option->isValueRequired()) { + $question = new ChoiceQuestion( + $option->getDescription() . '? ', + $option->getSelectOptions(), + $option->getDefault() + ); + } else { + $question = new ChoiceQuestion( + $option->getDescription() . ' [optional]? ', + $option->getSelectOptions(), + $option->getDefault() + ); + } + $question->setValidator(function ($answer) use ($option) { + $option->validate($option->getSelectOptions()[$answer]); + return $answer; + }); + } else { + if ($option->isValueRequired()) { + $question = new Question( + $option->getDescription() . '? ', + $option->getDefault() + ); + } else { + $question = new Question( + $option->getDescription() . ' [optional]? ', + $option->getDefault() + ); + } + $question->setValidator(function ($answer) use ($option) { + $option->validate($answer); + return $answer; + }); + } + + $value = $helper->ask($input, $output, $question); + return $value; + } } From 2fd48e6a99da3f6283cbad36a9b730b7a23cf767 Mon Sep 17 00:00:00 2001 From: David Verholen Date: Fri, 13 Oct 2017 11:15:46 +0200 Subject: [PATCH 119/528] [BUGFIX][11022] include original search criteria #fixes 11022 --- .../Magento/Catalog/Model/Product/Attribute/SetRepository.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php index ab6cdb3b464a4..44e99d4f29926 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php @@ -62,6 +62,7 @@ public function save(\Magento\Eav\Api\Data\AttributeSetInterface $attributeSet) */ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria) { + $this->searchCriteriaBuilder->setFilterGroups($searchCriteria->getFilterGroups()); $this->searchCriteriaBuilder->addFilters( [ $this->filterBuilder @@ -71,6 +72,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr ->create(), ] ); + $this->searchCriteriaBuilder->setSortOrders((array)$searchCriteria->getSortOrders()); $this->searchCriteriaBuilder->setCurrentPage($searchCriteria->getCurrentPage()); $this->searchCriteriaBuilder->setPageSize($searchCriteria->getPageSize()); return $this->attributeSetRepository->getList($this->searchCriteriaBuilder->create()); From 0e4dd85af64b5d9ed035da373e80d6d3fb08e1f8 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Fri, 13 Oct 2017 13:22:45 +0200 Subject: [PATCH 120/528] ADDED user and adminUser questions Code cleanup --- .../Setup/Console/Command/InstallCommand.php | 66 ++++++++++++++----- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/InstallCommand.php b/setup/src/Magento/Setup/Console/Command/InstallCommand.php index 98423c26d39e2..467e94febef39 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallCommand.php @@ -215,13 +215,33 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou { $helper = $this->getHelper('question'); $configOptionsToValidate = []; + foreach ($this->configModel->getAvailableOptions() as $option) { + $configOptionsToValidate[$option->getName()] = $this->askQuestion( + $input, + $output, + $helper, + $option, + true + ); + } - $configOptionsToValidate[$option->getName()] = $this->askQuestion($input, $output, $helper, $option); + foreach ($this->userConfig->getOptionsList() as $option) { + $configOptionsToValidate[$option->getName()] = $this->askQuestion( + $input, + $output, + $helper, + $option + ); + } - /*$question = new Question($option->getDescription() . '? ', $option->getDefault()); - $configOptionsToValidate[$option->getName()] = $helper->ask($input, $output, $question); - */ + foreach ($this->adminUser->getOptionsList() as $option) { + $configOptionsToValidate[$option->getName()] = $this->askQuestion( + $input, + $output, + $helper, + $option + ); } return $configOptionsToValidate; } @@ -234,11 +254,17 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou * @param InputInterface $input * @param OutputInterface $output * @param QuestionHelper $helper - * @param Magento\Framework\Setup\Option\TextConfigOption|Magento\Framework\Setup\Option\FlagConfigOption\Magento\Framework\Setup\Option\SelectConfigOption $option + * @param TextConfigOption|FlagConfigOption\SelectConfigOption $option + * @param Boolean $validateInline * @return string[] Array of inputs */ - private function askQuestion(InputInterface $input, OutputInterface $output, QuestionHelper $helper, $option) - { + private function askQuestion( + InputInterface $input, + OutputInterface $output, + QuestionHelper $helper, + $option, + $validateInline = false + ) { if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { if ($option->isValueRequired()) { $question = new ChoiceQuestion( @@ -253,10 +279,6 @@ private function askQuestion(InputInterface $input, OutputInterface $output, Que $option->getDefault() ); } - $question->setValidator(function ($answer) use ($option) { - $option->validate($option->getSelectOptions()[$answer]); - return $answer; - }); } else { if ($option->isValueRequired()) { $question = new Question( @@ -269,13 +291,25 @@ private function askQuestion(InputInterface $input, OutputInterface $output, Que $option->getDefault() ); } - $question->setValidator(function ($answer) use ($option) { - $option->validate($answer); - return $answer; - }); + } + $question->setValidator(function ($answer) use ($option, $validateInline) { + $answer = trim($answer); + + if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + $answer = $option->getSelectOptions()[$answer]; + } + + if ($validateInline) { + $option->validate($answer); + } + + return $answer; + }); + $value = $helper->ask($input, $output, $question); + return $value; } -} +} \ No newline at end of file From 9d0befb24b4dd81f1568155b23ec9451fea290b8 Mon Sep 17 00:00:00 2001 From: Jeroen van Leusden Date: Fri, 13 Oct 2017 13:46:00 +0200 Subject: [PATCH 121/528] Translate order getCreatedAtFormatted() to store locale --- app/code/Magento/Sales/Model/Order.php | 20 +++++++++-- .../Sales/Test/Unit/Model/OrderTest.php | 34 ++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index 250aa510eafc6..50497e8d47ba1 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -7,6 +7,8 @@ use Magento\Directory\Model\Currency; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderStatusHistoryInterface; @@ -212,6 +214,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ protected $_currencyFactory; + /** + * @var \Magento\Eav\Model\Config + */ + private $_eavConfig; + /** * @var \Magento\Sales\Model\Order\Status\HistoryFactory */ @@ -267,6 +274,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ protected $timezone; + /** + * @var ResolverInterface + */ + private $localeResolver; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -295,6 +307,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data + * @param ResolverInterface $localeResolver * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -324,7 +337,8 @@ public function __construct( \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productListFactory, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + ResolverInterface $localeResolver = null ) { $this->_storeManager = $storeManager; $this->_orderConfig = $orderConfig; @@ -346,6 +360,8 @@ public function __construct( $this->_trackCollectionFactory = $trackCollectionFactory; $this->salesOrderCollectionFactory = $salesOrderCollectionFactory; $this->priceCurrency = $priceCurrency; + $this->localeResolver = $localeResolver ?: ObjectManager::getInstance()->get(ResolverInterface::class); + parent::__construct( $context, $registry, @@ -1830,7 +1846,7 @@ public function getCreatedAtFormatted($format) new \DateTime($this->getCreatedAt()), $format, $format, - null, + $this->localeResolver->getDefaultLocale(), $this->timezone->getConfigTimezone('store', $this->getStore()) ); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index dab92632426fa..fb1970638753f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -7,6 +7,8 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; +use Magento\Framework\Locale\ResolverInterface; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Model\Order; use Magento\Sales\Model\ResourceModel\Order\Status\History\CollectionFactory as HistoryCollectionFactory; @@ -73,6 +75,16 @@ class OrderTest extends \PHPUnit\Framework\TestCase */ protected $productCollectionFactoryMock; + /** + * @var ResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $localeResolver; + + /** + * @var TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $timezone; + protected function setUp() { $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -124,6 +136,8 @@ protected function setUp() true, ['round'] ); + $this->localeResolver = $this->createMock(ResolverInterface::class); + $this->timezone = $this->createMock(TimezoneInterface::class); $this->incrementId = '#00000001'; $this->eventManager = $this->createMock(\Magento\Framework\Event\Manager::class); $context = $this->createPartialMock(\Magento\Framework\Model\Context::class, ['getEventDispatcher']); @@ -138,7 +152,9 @@ protected function setUp() 'historyCollectionFactory' => $this->historyCollectionFactoryMock, 'salesOrderCollectionFactory' => $this->salesOrderCollectionFactoryMock, 'priceCurrency' => $this->priceCurrency, - 'productListFactory' => $this->productCollectionFactoryMock + 'productListFactory' => $this->productCollectionFactoryMock, + 'localeResolver' => $this->localeResolver, + 'timezone' => $this->timezone, ] ); } @@ -1044,6 +1060,22 @@ public function testResetOrderWillResetPayment() ); } + public function testGetCreatedAtFormattedUsesCorrectLocale() + { + $localeCode = 'nl_NL'; + + $this->localeResolver->expects($this->once())->method('getDefaultLocale')->willReturn($localeCode); + $this->timezone->expects($this->once())->method('formatDateTime') + ->with( + $this->anything(), + $this->anything(), + $this->anything(), + $localeCode + ); + + $this->order->getCreatedAtFormatted(\IntlDateFormatter::SHORT); + } + public function notInvoicingStatesProvider() { return [ From ce12a7439fe03a690a5d5acb76dde333118c3d80 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Fri, 13 Oct 2017 14:02:56 +0200 Subject: [PATCH 122/528] ADDED re-run command output FIXED phpcs validation --- .../Setup/Console/Command/InstallCommand.php | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/InstallCommand.php b/setup/src/Magento/Setup/Console/Command/InstallCommand.php index 467e94febef39..a2e8715b02233 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallCommand.php @@ -169,6 +169,14 @@ protected function initialize(InputInterface $input, OutputInterface $output) } } + if ($inputOptions['interactive']) { + $command = ''; + foreach ($configOptionsToValidate as $key => $value) { + $command .= " --{$key}={$value}"; + } + $output->writeln("Try re-running command: php bin/magento setup:install{$command}"); + } + $errors = $this->configModel->validate($configOptionsToValidate); $errors = array_merge($errors, $this->adminUser->validate($input)); $errors = array_merge($errors, $this->validate($input)); @@ -226,6 +234,8 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou ); } + $output->writeln(""); + foreach ($this->userConfig->getOptionsList() as $option) { $configOptionsToValidate[$option->getName()] = $this->askQuestion( $input, @@ -235,6 +245,8 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou ); } + $output->writeln(""); + foreach ($this->adminUser->getOptionsList() as $option) { $configOptionsToValidate[$option->getName()] = $this->askQuestion( $input, @@ -243,7 +255,17 @@ private function interactiveQuestions(InputInterface $input, OutputInterface $ou $option ); } - return $configOptionsToValidate; + + $output->writeln(""); + + $returnConfigOptionsToValidate = []; + foreach ($configOptionsToValidate as $key => $value) { + if ($value != '') { + $returnConfigOptionsToValidate[$key] = $value; + } + } + + return $returnConfigOptionsToValidate; } /** @@ -265,7 +287,7 @@ private function askQuestion( $option, $validateInline = false ) { - if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + if ($option instanceof \Magento\Framework\Setup\Option\SelectConfigOption) { if ($option->isValueRequired()) { $question = new ChoiceQuestion( $option->getDescription() . '? ', @@ -291,16 +313,20 @@ private function askQuestion( $option->getDefault() ); } - } $question->setValidator(function ($answer) use ($option, $validateInline) { - $answer = trim($answer); - if (get_class($option) === 'Magento\Framework\Setup\Option\SelectConfigOption') { + if ($option instanceof \Magento\Framework\Setup\Option\SelectConfigOption) { $answer = $option->getSelectOptions()[$answer]; } + if ($answer == null) { + $answer = ''; + } else { + $answer = trim($answer); + } + if ($validateInline) { $option->validate($answer); } @@ -312,4 +338,4 @@ private function askQuestion( return $value; } -} \ No newline at end of file +} From 1d998f9c45856497332daddd930786ee42d458cb Mon Sep 17 00:00:00 2001 From: Mayank Date: Fri, 13 Oct 2017 18:19:11 +0530 Subject: [PATCH 123/528] Magento 2.2.0 Product Repeat Isuue after filter on category listing page.Issue : #11139 --- .../Catalog/Block/Product/ProductList/Toolbar.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index f461b52515253..46080ab5c3330 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -192,7 +192,14 @@ public function setCollection($collection) $this->_collection->setPageSize($limit); } if ($this->getCurrentOrder()) { - $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection()); + if (($this->getCurrentOrder()) == 'position') { + $this->_collection->addAttributeToSort( + $this->getCurrentOrder(), + $this->getCurrentDirection() + )->addAttributeToSort('entity_id', $this->getCurrentDirection()); + } else { + $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection()); + } } return $this; } From 354800097cfb6909aacaa98d8b8df3dfec4f8f35 Mon Sep 17 00:00:00 2001 From: Lorenzo Stramaccia Date: Fri, 13 Oct 2017 13:25:27 +0200 Subject: [PATCH 124/528] FIX toolbar-amount placing --- .../luma/Magento_Catalog/web/css/source/module/_toolbar.less | 1 - 1 file changed, 1 deletion(-) diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less index 5c51938b23422..580abf264cadc 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less @@ -44,7 +44,6 @@ line-height: @toolbar-mode-icon-font-size + 2; margin: 0; padding: 7px 0; - position: absolute; text-align: left; top: 0; vertical-align: middle; From a85d164f6c08b1fc37fd4df1fbd3c4a8e871749d Mon Sep 17 00:00:00 2001 From: David Verholen Date: Fri, 13 Oct 2017 15:17:23 +0200 Subject: [PATCH 125/528] [BUGFIX][11022] return original search criteria in search result --- .../Model/Product/Attribute/SetRepository.php | 7 ++++++- .../Catalog/Api/AttributeSetRepositoryTest.php | 14 ++------------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php index 44e99d4f29926..dafa7581253fd 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php @@ -72,10 +72,15 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr ->create(), ] ); + $this->searchCriteriaBuilder->setSortOrders((array)$searchCriteria->getSortOrders()); $this->searchCriteriaBuilder->setCurrentPage($searchCriteria->getCurrentPage()); $this->searchCriteriaBuilder->setPageSize($searchCriteria->getPageSize()); - return $this->attributeSetRepository->getList($this->searchCriteriaBuilder->create()); + + $searchResult = $this->attributeSetRepository->getList($this->searchCriteriaBuilder->create()); + $searchResult->setSearchCriteria($searchCriteria); + + return $searchResult; } /** diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php index 5e640390c3231..4f917a9c9961a 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/AttributeSetRepositoryTest.php @@ -165,19 +165,9 @@ public function testGetList() { $searchCriteria = [ 'searchCriteria' => [ - 'filter_groups' => [ - [ - 'filters' => [ - [ - 'field' => 'entity_type_code', - 'value' => 'catalog_product', - 'condition_type' => 'eq', - ], - ], - ], - ], + 'filter_groups' => [], 'current_page' => 1, - 'page_size' => 2, + 'page_size' => 2 ], ]; From 3ec56ac9158f5d344c387f62315696360a12a60d Mon Sep 17 00:00:00 2001 From: David Verholen Date: Fri, 13 Oct 2017 15:18:40 +0200 Subject: [PATCH 126/528] [BUGFIX][11022] typecast filtergroups array --- .../Magento/Catalog/Model/Product/Attribute/SetRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php index dafa7581253fd..14774103b8cd2 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/SetRepository.php @@ -62,7 +62,7 @@ public function save(\Magento\Eav\Api\Data\AttributeSetInterface $attributeSet) */ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria) { - $this->searchCriteriaBuilder->setFilterGroups($searchCriteria->getFilterGroups()); + $this->searchCriteriaBuilder->setFilterGroups((array)$searchCriteria->getFilterGroups()); $this->searchCriteriaBuilder->addFilters( [ $this->filterBuilder From fb41335de5520b6669dde4091d63fb13d0890154 Mon Sep 17 00:00:00 2001 From: Ievgen Shakhsuvarov Date: Fri, 13 Oct 2017 16:26:23 +0300 Subject: [PATCH 127/528] magento/magento2#11363: Unmask exception message during product import - Test updated --- .../Magento/ImportExport/Model/ImportTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php b/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php index 5ba955430021f..332ca5fba75c7 100644 --- a/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php +++ b/dev/tests/integration/testsuite/Magento/ImportExport/Model/ImportTest.php @@ -135,6 +135,31 @@ public function testValidateSourceException() $this->_model->validateSource($source); } + public function testValidateSourceExceptionMessage() + { + $exceptionMessage = 'Test Exception Message.'; + + $validationStrategy = ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR; + $this->_model->setEntity('catalog_product'); + $this->_model->setData(\Magento\ImportExport\Model\Import::FIELD_NAME_VALIDATION_STRATEGY, $validationStrategy); + $this->_model->setData(\Magento\ImportExport\Model\Import::FIELD_NAME_ALLOWED_ERROR_COUNT, 0); + + /** @var \Magento\ImportExport\Model\Import\AbstractSource|\PHPUnit_Framework_MockObject_MockObject $source */ + $source = $this->getMockForAbstractClass( + \Magento\ImportExport\Model\Import\AbstractSource::class, + [['sku', 'name']] + ); + $source->expects($this->any())->method('_getNextRow')->willThrowException( + new \Exception($exceptionMessage) + ); + + $this->assertFalse($this->_model->validateSource($source)); + $this->assertEquals( + $exceptionMessage, + $this->_model->getErrorAggregator()->getAllErrors()[0]->getErrorMessage() + ); + } + public function testGetEntity() { $entityName = 'entity_name'; From 1530cbd5580880d30f966c003eb00c8d9ce8c7ae Mon Sep 17 00:00:00 2001 From: Lewis Voncken Date: Fri, 13 Oct 2017 14:35:12 +0000 Subject: [PATCH 128/528] [BUGFIX] Check if item exists because it is possible to delete the item in the submitBefore observer event --- app/code/Magento/Tax/Model/Plugin/OrderSave.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Tax/Model/Plugin/OrderSave.php b/app/code/Magento/Tax/Model/Plugin/OrderSave.php index 7203285248688..3c87086cdf585 100644 --- a/app/code/Magento/Tax/Model/Plugin/OrderSave.php +++ b/app/code/Magento/Tax/Model/Plugin/OrderSave.php @@ -163,7 +163,9 @@ protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order) if (isset($quoteItemId['id'])) { //This is a product item $item = $order->getItemByQuoteItemId($quoteItemId['id']); - $itemId = $item->getId(); + if ($item !== null && $item->getId()) { + $itemId = $item->getId(); + } } elseif (isset($quoteItemId['associated_item_id'])) { //This item is associated with a product item $item = $order->getItemByQuoteItemId($quoteItemId['associated_item_id']); From 0379ec65e08e2fb6e02739bc6149ecc4e6ab970b Mon Sep 17 00:00:00 2001 From: Lewis Voncken Date: Fri, 13 Oct 2017 14:42:29 +0000 Subject: [PATCH 129/528] [TASK] Use one reference in Customer Webapi: use one Customer Id reference --- app/code/Magento/Customer/Api/CustomerRepositoryInterface.php | 4 ++-- app/code/Magento/Customer/etc/webapi.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Api/CustomerRepositoryInterface.php b/app/code/Magento/Customer/Api/CustomerRepositoryInterface.php index a18540d8cf9d5..2133ae5a323b4 100644 --- a/app/code/Magento/Customer/Api/CustomerRepositoryInterface.php +++ b/app/code/Magento/Customer/Api/CustomerRepositoryInterface.php @@ -38,7 +38,7 @@ public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $pa public function get($email, $websiteId = null); /** - * Get customer by customer ID. + * Get customer by Customer ID. * * @param int $customerId * @return \Magento\Customer\Api\Data\CustomerInterface @@ -70,7 +70,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr public function delete(\Magento\Customer\Api\Data\CustomerInterface $customer); /** - * Delete customer by ID. + * Delete customer by Customer ID. * * @param int $customerId * @return bool true on success diff --git a/app/code/Magento/Customer/etc/webapi.xml b/app/code/Magento/Customer/etc/webapi.xml index cbcbbc8e71c72..c4a6b74815c67 100644 --- a/app/code/Magento/Customer/etc/webapi.xml +++ b/app/code/Magento/Customer/etc/webapi.xml @@ -128,7 +128,7 @@ - + From 57de356be55c7a99620952953032d764988acab0 Mon Sep 17 00:00:00 2001 From: Lewis Voncken Date: Fri, 13 Oct 2017 14:44:52 +0000 Subject: [PATCH 130/528] [TASK] Updated the Exception description for V1/customers/password --- app/code/Magento/Customer/Model/AccountManagement.php | 9 +++++++-- .../Customer/Test/Unit/Model/AccountManagementTest.php | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index b7b099ec45232..89f2cc8f0a4a2 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -526,8 +526,13 @@ public function initiatePasswordReset($email, $template, $websiteId = null) default: throw new InputException( __( - 'Invalid value of "%value" provided for the %fieldName field.', - ['value' => $template, 'fieldName' => 'email type'] + 'Invalid value of "%value" provided for the %fieldName field. Possible values are %template1 or %template2.', + [ + 'value' => $template, + 'fieldName' => 'template', + 'template1' => AccountManagement::EMAIL_REMINDER, + 'template2' => AccountManagement::EMAIL_RESET + ] ) ); } diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php index de9c0460ad29e..13fd1790cecdd 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php @@ -1158,7 +1158,7 @@ public function testInitiatePasswordResetEmailReset() /** * @expectedException \Magento\Framework\Exception\InputException - * @expectedExceptionMessage Invalid value of "" provided for the email type field + * @expectedExceptionMessage Invalid value of "" provided for the template field. Possible values are email_reminder or email_reset. */ public function testInitiatePasswordResetNoTemplate() { From 951f0a0b6b58282fc590eb71a8996b65e806360d Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 13 Oct 2017 11:06:18 -0500 Subject: [PATCH 131/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Model/Condition/CanViewNotification.php | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 1f4867d692693..62ac77a916917 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -6,7 +6,7 @@ namespace Magento\Analytics\Model\Condition; use Magento\Backend\Model\Auth\Session; -use Magento\Framework\App\ProductMetadataInterface; +use Magento\Framework\Module\ModuleListInterface; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; use Magento\Analytics\Model\NotificationFlagManager; @@ -23,11 +23,6 @@ class CanViewNotification implements VisibilityConditionInterface */ const NAME = 'can_view_notification'; - /** - * Magento Version to only show Advertisement module notification content and hide Analytics notification - */ - const VERSION_TO_HIDE = '2.2.1-dev'; - /** * @var NotificationFlagManager */ @@ -39,25 +34,24 @@ class CanViewNotification implements VisibilityConditionInterface private $session; /** - * @var ProductMetadataInterface + * @var ModuleListInterface */ - private $productMetadataInterface; + private $moduleList; /** * CanViewNotification constructor. * * @param NotificationFlagManager $notificationFlagManager * @param Session $session - * @param ProductMetadataInterface $productMetadataInterface */ public function __construct( NotificationFlagManager $notificationFlagManager, Session $session, - ProductMetadataInterface $productMetadataInterface + ModuleListInterface $moduleList ) { $this->notificationFlagManager = $notificationFlagManager; $this->session = $session; - $this->productMetadataInterface = $productMetadataInterface; + $this->moduleList = $moduleList; } /** @@ -67,10 +61,8 @@ public function __construct( */ public function isVisible(array $arguments) { - $version = $this->productMetadataInterface->getVersion(); - $userId = $this->session->getUser()->getId(); - if (!strcmp($version, self::VERSION_TO_HIDE) || $this->notificationFlagManager->isUserNotified($userId)) { + if ($this->moduleList->has('Magento_Advertisement') || $this->notificationFlagManager->isUserNotified($userId)) { return false; } From 8e843ade22f640c9626eca9ce1111bd2edef5a3b Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Fri, 13 Oct 2017 19:42:07 +0200 Subject: [PATCH 132/528] Rewrite to have one test using a dataprovider --- .../Magento/Sales/Model/Order/StatusTest.php | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php index d53ff46122f57..db3afa031b278 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php @@ -12,37 +12,38 @@ */ class StatusTest extends \PHPUnit\Framework\TestCase { - /** - * In the backend the regular label must be showed. - * - * @magentoDataFixture Magento/Sales/_files/order_status.php - */ - public function testTheLabelIsUsedInTheBackend() + public function theCorrectLabelIsUsedDependingOnTheAreaProvider() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); - - /** @var \Magento\Sales\Model\Order $order */ - $order = $objectManager->create(\Magento\Sales\Model\Order::class); - $order->loadByIncrementId('100000001'); - - $this->assertEquals('Example', $order->getStatusLabel()); + return [ + 'backend label' => [ + 'adminhtml', + 'Example', + ], + 'store view label' => [ + 'frontend', + 'Store view example', + ], + ]; } /** - * In the frontend the store view specific label must be showed. + * In the backend the regular label must be showed. + * + * @param $area + * @param $result * * @magentoDataFixture Magento/Sales/_files/order_status.php + * @dataProvider theCorrectLabelIsUsedDependingOnTheAreaProvider */ - public function testTheStoreViewLabelIsUsedInTheFrontend() + public function testTheCorrectLabelIsUsedDependingOnTheArea($area, $result) { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('frontend'); + $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); /** @var \Magento\Sales\Model\Order $order */ $order = $objectManager->create(\Magento\Sales\Model\Order::class); $order->loadByIncrementId('100000001'); - $this->assertEquals('Store view example', $order->getStatusLabel()); + $this->assertEquals('Example', $order->getStatusLabel()); } } From 3c3168bdfbe43379e485ff91e708a045dd767e67 Mon Sep 17 00:00:00 2001 From: marina Date: Fri, 13 Oct 2017 20:43:15 +0300 Subject: [PATCH 133/528] Update scheduledGenerateSitemaps unit test --- .../Sitemap/Test/Unit/Model/ObserverTest.php | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php index 92e6f4e2e2293..904360ffb3804 100644 --- a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php +++ b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php @@ -96,11 +96,11 @@ protected function setUp() ); } - /** - * @expectedException \Exception - */ - public function testScheduledGenerateSitemapsThrowsException() + public function testScheduledGenerateSitemapsSendsExceptionEmail() { + $exception = 'Sitemap Exception'; + $transport = $this->createMock(\Magento\Framework\Mail\TransportInterface::class); + $this->scopeConfigMock->expects($this->once())->method('isSetFlag')->willReturn(true); $this->collectionFactoryMock->expects($this->once()) @@ -111,7 +111,53 @@ public function testScheduledGenerateSitemapsThrowsException() ->method('getIterator') ->willReturn(new \ArrayIterator([$this->sitemapMock])); - $this->sitemapMock->expects($this->once())->method('generateXml')->willThrowException(new \Exception()); + $this->sitemapMock->expects($this->once())->method('generateXml')->willThrowException(new \Exception($exception)); + + $this->scopeConfigMock->expects($this->at(1)) + ->method('getValue') + ->with( + \Magento\Sitemap\Model\Observer::XML_PATH_ERROR_RECIPIENT, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ) + ->willReturn('error-recipient@example.com'); + + $this->inlineTranslationMock->expects($this->once()) + ->method('suspend'); + + $this->transportBuilderMock->expects($this->once()) + ->method('setTemplateIdentifier') + ->will($this->returnSelf()); + + $this->transportBuilderMock->expects($this->once()) + ->method('setTemplateOptions') + ->with([ + 'area' => \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE, + 'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID, + ]) + ->will($this->returnSelf()); + + $this->transportBuilderMock->expects($this->once()) + ->method('setTemplateVars') + ->with(['warnings' => $exception]) + ->will($this->returnSelf()); + + $this->transportBuilderMock->expects($this->once()) + ->method('setFrom') + ->will($this->returnSelf()); + + $this->transportBuilderMock->expects($this->once()) + ->method('addTo') + ->will($this->returnSelf()); + + $this->transportBuilderMock->expects($this->once()) + ->method('getTransport') + ->willReturn($transport); + + $transport->expects($this->once()) + ->method('sendMessage'); + + $this->inlineTranslationMock->expects($this->once()) + ->method('resume'); $this->observer->scheduledGenerateSitemaps(); } From 00f243c10573c1021cb8079cd582225db168f9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Mart=C3=ADnez?= Date: Fri, 13 Oct 2017 20:35:58 +0200 Subject: [PATCH 134/528] Rewrite PhpFormatter::format method, to avoid add extra spaces --- .../DeploymentConfig/Writer/PhpFormatter.php | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php index 4a40e19c818e7..e466bb40a2210 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php @@ -21,21 +21,48 @@ class PhpFormatter implements FormatterInterface public function format($data, array $comments = []) { if (!empty($comments) && is_array($data)) { - $elements = []; + return "formatData($data, $comments, ' ') . "\n);\n"; + } + return " $value) { - $comment = ' '; if (!empty($comments[$key])) { - $section = " * For the section: " . $key . "\n"; - $exportedComment = is_string($comments[$key]) - ? $comments[$key] - : var_export($comments[$key], true); - $comment = " /**\n" . $section . " * " . str_replace("\n", "\n * ", $exportedComment) . "\n */\n"; + $elements[] = $prefix . '/**'; + $elements[] = $prefix . ' * For the section: ' . $key; + + foreach (explode("\n", $comments[$key]) as $commentLine) { + $elements[] = $prefix . ' * ' . $commentLine; + } + + $elements[] = $prefix . " */"; + } + + if (is_array($value)) { + $elements[] = $prefix . var_export($key, true) . ' => '; + $elements[] = $prefix . 'array ('; + $elements[] = $this->formatData($value, [], ' ' . $prefix); + $elements[] = $prefix . '),'; + } else { + $elements[] = $prefix . var_export($key, true) . ' => ' . var_export($value, true) . ','; } - $space = is_array($value) ? " \n" : ' '; - $elements[] = $comment . var_export($key, true) . ' =>' . $space . var_export($value, true); } - return " Date: Fri, 13 Oct 2017 23:10:31 +0100 Subject: [PATCH 135/528] Reduce variable length name isConfirmationRequired -> isConfirmRequired Keep the variable name less than 20 chars --- .../Magento/Customer/Ui/Component/DataProvider/Document.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php index a9a5c5b17744e..6a197feb03c61 100644 --- a/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php +++ b/app/code/Magento/Customer/Ui/Component/DataProvider/Document.php @@ -178,14 +178,14 @@ private function setConfirmationValue() { $value = $this->getData(self::$confirmationAttributeCode); $websiteId = $this->getData(self::$websiteIdAttributeCode) ?: $this->getData(self::$websiteAttributeCode); - $isConfirmationRequired = (bool)$this->scopeConfig->getValue( + $isConfirmRequired = (bool)$this->scopeConfig->getValue( AccountManagement::XML_PATH_IS_CONFIRM, ScopeInterface::SCOPE_WEBSITES, $websiteId ); $valueText = __('Confirmation Not Required'); - if ($isConfirmationRequired) { + if ($isConfirmRequired) { $valueText = $value === null ? __('Confirmed') : __('Confirmation Required'); } From 6f9497afe5d6e23c9b26702e23f9b8a8047617a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Mart=C3=ADnez?= Date: Sat, 14 Oct 2017 01:26:43 +0200 Subject: [PATCH 136/528] Remove else statement as indicated by Codacy --- .../Framework/App/DeploymentConfig/Writer/PhpFormatter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php index e466bb40a2210..319269bd0011d 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php @@ -51,13 +51,13 @@ protected function formatData($data, $comments, $prefix = '') $elements[] = $prefix . " */"; } + $elements[] = $prefix . var_export($key, true) . ' => ' . + (!is_array($value) ? var_export($value, true) . ',' : ''); + if (is_array($value)) { - $elements[] = $prefix . var_export($key, true) . ' => '; $elements[] = $prefix . 'array ('; $elements[] = $this->formatData($value, [], ' ' . $prefix); $elements[] = $prefix . '),'; - } else { - $elements[] = $prefix . var_export($key, true) . ' => ' . var_export($value, true) . ','; } } return implode("\n", $elements); From 69bb06b5b4daec0e95031ba0d0b6dbf83605f629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mateos?= Date: Sat, 14 Oct 2017 01:36:40 +0200 Subject: [PATCH 137/528] Show product alerts in admin product detail --- .../Product/Form/Modifier/Alerts.php | 173 ++++++++++++++++++ app/code/Magento/Catalog/etc/adminhtml/di.xml | 4 + 2 files changed, 177 insertions(+) create mode 100644 app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php new file mode 100644 index 0000000000000..96e00a911610c --- /dev/null +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php @@ -0,0 +1,173 @@ +scopeConfig = $scopeConfig; + $this->layoutFactory = $layoutFactory; + } + + /** + * {@inheritdoc} + * @since 101.0.0 + */ + public function modifyData(array $data) + { + return $data; + } + + /** + * {@inheritdoc} + * @since 101.0.0 + */ + public function modifyMeta(array $meta) + { + if (!$this->canShowTab()) { + return $meta; + } + + $meta = array_replace_recursive( + $meta, + [ + 'alerts' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'additionalClasses' => 'admin__fieldset-section', + 'label' => __('Product Alerts'), + 'collapsible' => true, + 'componentType' => Fieldset::NAME, + 'dataScope' => static::DATA_SCOPE, + 'sortOrder' => + $this->getNextGroupSortOrder( + $meta, + self::$previousGroup, + self::$sortOrder + ), + ], + ], + ], + 'children' => [ + static::DATA_SCOPE_STOCK => $this->getAlertStockFieldset(), + static::DATA_SCOPE_PRICE => $this->getAlertPriceFieldset() + ], + ], + ] + ); + + return $meta; + } + + /** + * @return bool + */ + private function canShowTab() + { + $alertPriceAllow = $this->scopeConfig->getValue( + 'catalog/productalert/allow_price', + ScopeInterface::SCOPE_STORE + ); + $alertStockAllow = $this->scopeConfig->getValue( + 'catalog/productalert/allow_stock', + ScopeInterface::SCOPE_STORE + ); + + return ($alertPriceAllow || $alertStockAllow); + } + + /** + * Prepares config for the alert stock products fieldset + * @return array + */ + private function getAlertStockFieldset() + { + return [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'label' => __('Alert stock'), + 'componentType' => 'container', + 'component' => 'Magento_Ui/js/form/components/html', + 'additionalClasses' => 'admin__fieldset-note', + 'content' => + '

' . __('Alert Stock') . '

' . + $this->layoutFactory->create()->createBlock( + Stock::class + )->toHtml(), + ] + ] + ] + ]; + } + + /** + * Prepares config for the alert price products fieldset + * @return array + */ + private function getAlertPriceFieldset() + { + return [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'label' => __('Alert price'), + 'componentType' => 'container', + 'component' => 'Magento_Ui/js/form/components/html', + 'additionalClasses' => 'admin__fieldset-note', + 'content' => + '

' . __('Alert Price') . '

' . + $this->layoutFactory->create()->createBlock( + Price::class + )->toHtml(), + ] + ] + ] + ]; + } +} diff --git a/app/code/Magento/Catalog/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml index 790bd163a6f17..b97e6fc1aa318 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/di.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml @@ -143,6 +143,10 @@ Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Attributes 120 + + Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Alerts + 130 + Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\TierPrice 150 From 55d4a833476cceeac0f421c2a283704a15516534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Mart=C3=ADnez?= Date: Sat, 14 Oct 2017 04:51:07 +0200 Subject: [PATCH 138/528] Update unit tests --- .../Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php index d77edbf86aaad..fe57a5a7ad8f3 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/Writer/PhpFormatterTest.php @@ -5,7 +5,7 @@ */ namespace Magento\Framework\App\Test\Unit\DeploymentConfig\Writer; -use \Magento\Framework\App\DeploymentConfig\Writer\PhpFormatter; +use Magento\Framework\App\DeploymentConfig\Writer\PhpFormatter; class PhpFormatterTest extends \PHPUnit\Framework\TestCase { @@ -81,7 +81,7 @@ public function formatWithCommentDataProvider() ), ), 'ns3' => 'just text', - 'ns4' => 'just text' + 'ns4' => 'just text', ); TEXT; @@ -126,7 +126,7 @@ public function formatWithCommentDataProvider() * For the section: ns4 * comment for namespace 4 */ - 'ns4' => 'just text' + 'ns4' => 'just text', ); TEXT; From 80ed8330926834840848330dc55f40b41b740bd5 Mon Sep 17 00:00:00 2001 From: peterjaap Date: Sat, 14 Oct 2017 12:38:24 +0200 Subject: [PATCH 139/528] Added fix for issue 2991 to fetch billing and shipping addresses to enable getting a correct price through the (web) API after adding a product to an empty cart --- app/code/Magento/Quote/Model/QuoteManagement.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 49206ff924f13..6089e6b670513 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -232,6 +232,8 @@ public function createEmptyCart() $quote->setShippingAddress($this->quoteAddressFactory->create()); try { + $quote->getBillingAddress(); + $quote->getShippingAddress()->setCollectShippingRates(true); $this->quoteRepository->save($quote); } catch (\Exception $e) { throw new CouldNotSaveException(__('Cannot create quote')); From 24d6a578c7825b491cae179c9597b0476ee282bc Mon Sep 17 00:00:00 2001 From: peterjaap Date: Sat, 14 Oct 2017 12:38:24 +0200 Subject: [PATCH 140/528] Added fix for issue 2991 to fetch billing and shipping addresses to enable getting a correct price through the (web) API after adding a product to an empty cart --- app/code/Magento/Quote/Model/QuoteManagement.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 49206ff924f13..9b88d102b733f 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -232,6 +232,9 @@ public function createEmptyCart() $quote->setShippingAddress($this->quoteAddressFactory->create()); try { + $quote->getBillingAddress()->setCollectShippingRates(true); + $quote->getShippingAddress()->setCollectShippingRates(true); + $this->quoteRepository->save($quote); } catch (\Exception $e) { throw new CouldNotSaveException(__('Cannot create quote')); From 69ef9dab06e1971c3db82be80778ece254a50443 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Sat, 14 Oct 2017 13:08:37 +0200 Subject: [PATCH 141/528] Forgot to use the dataprovider variables --- .../testsuite/Magento/Sales/Model/Order/StatusTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php index db3afa031b278..e4b64e77d6e05 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/StatusTest.php @@ -38,12 +38,12 @@ public function theCorrectLabelIsUsedDependingOnTheAreaProvider() public function testTheCorrectLabelIsUsedDependingOnTheArea($area, $result) { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode('adminhtml'); + $objectManager->get(\Magento\Framework\App\State::class)->setAreaCode($area); /** @var \Magento\Sales\Model\Order $order */ $order = $objectManager->create(\Magento\Sales\Model\Order::class); $order->loadByIncrementId('100000001'); - $this->assertEquals('Example', $order->getStatusLabel()); + $this->assertEquals($result, $order->getStatusLabel()); } } From 168d8cb87ef550a89d9cb2ad6ed57efbe38718cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mateos?= Date: Sat, 14 Oct 2017 14:02:54 +0200 Subject: [PATCH 142/528] Improve PHP Code Sniffer --- .../Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php index 96e00a911610c..1f154d3204454 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Alerts.php @@ -38,8 +38,7 @@ class Alerts extends AbstractModifier * @var LayoutFactory */ private $layoutFactory; - - + /** * Alerts constructor. * @param ScopeConfigInterface $scopeConfig From 64943cd06e02b8993a86835985786dfcd33964f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20H=C3=BCnig?= Date: Sat, 14 Oct 2017 14:32:48 +0200 Subject: [PATCH 143/528] close #10810 Migrates Apache Access Syntax to 2.4 on Apaxhe >= 2.4 --- .htaccess | 162 ++++++++++++++---- app/.htaccess | 10 +- bin/.htaccess | 10 +- dev/.htaccess | 10 +- .../Composer/_files/testFromClone/.htaccess | 8 +- .../_files/testFromClone/cache/.htaccess | 8 +- .../_files/testFromCreateProject/.htaccess | 8 +- .../testFromCreateProject/cache/.htaccess | 8 +- .../Composer/_files/testSkeleton/.htaccess | 8 +- .../_files/testSkeleton/cache/.htaccess | 8 +- generated/.htaccess | 10 +- lib/.htaccess | 10 +- phpserver/.htaccess | 10 +- pub/.htaccess | 18 +- pub/media/customer/.htaccess | 10 +- pub/media/downloadable/.htaccess | 10 +- pub/media/import/.htaccess | 10 +- pub/media/theme_customization/.htaccess | 9 +- setup/config/.htaccess | 10 +- setup/performance-toolkit/.htaccess | 10 +- setup/src/.htaccess | 10 +- setup/view/.htaccess | 10 +- var/.htaccess | 10 +- vendor/.htaccess | 10 +- 24 files changed, 309 insertions(+), 78 deletions(-) diff --git a/.htaccess b/.htaccess index 90b9c16a5a8c0..54e4ed4800a21 100644 --- a/.htaccess +++ b/.htaccess @@ -203,76 +203,166 @@ RedirectMatch 403 /\.git - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + # For 404s and 403s that aren't handled by the application, show plain 404 response diff --git a/app/.htaccess b/app/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/app/.htaccess +++ b/app/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/bin/.htaccess b/bin/.htaccess index 896fbc5a341ea..707c26b075e16 100644 --- a/bin/.htaccess +++ b/bin/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all \ No newline at end of file + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/dev/.htaccess b/dev/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/dev/.htaccess +++ b/dev/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/.htaccess b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/.htaccess index 14249c50bd760..118789f3d955b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/.htaccess +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/.htaccess @@ -1 +1,7 @@ -Deny from all \ No newline at end of file + + deny from all + += 2.4> + Require all denied + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/cache/.htaccess b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/cache/.htaccess index 14249c50bd760..118789f3d955b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/cache/.htaccess +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromClone/cache/.htaccess @@ -1 +1,7 @@ -Deny from all \ No newline at end of file + + deny from all + += 2.4> + Require all denied + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/.htaccess b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/.htaccess index 14249c50bd760..118789f3d955b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/.htaccess +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/.htaccess @@ -1 +1,7 @@ -Deny from all \ No newline at end of file + + deny from all + += 2.4> + Require all denied + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/cache/.htaccess b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/cache/.htaccess index 14249c50bd760..118789f3d955b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/cache/.htaccess +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testFromCreateProject/cache/.htaccess @@ -1 +1,7 @@ -Deny from all \ No newline at end of file + + deny from all + += 2.4> + Require all denied + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/.htaccess b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/.htaccess index 14249c50bd760..118789f3d955b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/.htaccess +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/.htaccess @@ -1 +1,7 @@ -Deny from all \ No newline at end of file + + deny from all + += 2.4> + Require all denied + + diff --git a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/cache/.htaccess b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/cache/.htaccess index 14249c50bd760..118789f3d955b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/cache/.htaccess +++ b/dev/tests/integration/testsuite/Magento/Framework/Composer/_files/testSkeleton/cache/.htaccess @@ -1 +1,7 @@ -Deny from all \ No newline at end of file + + deny from all + += 2.4> + Require all denied + + diff --git a/generated/.htaccess b/generated/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/generated/.htaccess +++ b/generated/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/lib/.htaccess b/lib/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/lib/.htaccess +++ b/lib/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/phpserver/.htaccess b/phpserver/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/phpserver/.htaccess +++ b/phpserver/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/pub/.htaccess b/pub/.htaccess index bdae9be342d8d..9d79c1cc2b9a4 100644 --- a/pub/.htaccess +++ b/pub/.htaccess @@ -190,8 +190,13 @@ ## Deny access to release notes to prevent disclosure of the installed Magento version - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + # For 404s and 403s that aren't handled by the application, show plain 404 response @@ -207,8 +212,13 @@ ErrorDocument 403 /errors/404.php ########################################### ## Deny access to cron.php - order allow,deny - deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + diff --git a/pub/media/customer/.htaccess b/pub/media/customer/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/pub/media/customer/.htaccess +++ b/pub/media/customer/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/pub/media/downloadable/.htaccess b/pub/media/downloadable/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/pub/media/downloadable/.htaccess +++ b/pub/media/downloadable/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/pub/media/import/.htaccess b/pub/media/import/.htaccess index 93169e4eb44ff..707c26b075e16 100644 --- a/pub/media/import/.htaccess +++ b/pub/media/import/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/pub/media/theme_customization/.htaccess b/pub/media/theme_customization/.htaccess index ae8ddd114d94e..2b93da6b4c079 100644 --- a/pub/media/theme_customization/.htaccess +++ b/pub/media/theme_customization/.htaccess @@ -1,5 +1,10 @@ Options -Indexes - Order allow,deny - Deny from all + + order allow,deny + deny from all + + = 2.4> + Require all denied + diff --git a/setup/config/.htaccess b/setup/config/.htaccess index 281d5c33db37c..707c26b075e16 100644 --- a/setup/config/.htaccess +++ b/setup/config/.htaccess @@ -1,2 +1,8 @@ -order allow,deny -deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/setup/performance-toolkit/.htaccess b/setup/performance-toolkit/.htaccess index 281d5c33db37c..707c26b075e16 100644 --- a/setup/performance-toolkit/.htaccess +++ b/setup/performance-toolkit/.htaccess @@ -1,2 +1,8 @@ -order allow,deny -deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/setup/src/.htaccess b/setup/src/.htaccess index 281d5c33db37c..707c26b075e16 100644 --- a/setup/src/.htaccess +++ b/setup/src/.htaccess @@ -1,2 +1,8 @@ -order allow,deny -deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/setup/view/.htaccess b/setup/view/.htaccess index 281d5c33db37c..707c26b075e16 100644 --- a/setup/view/.htaccess +++ b/setup/view/.htaccess @@ -1,2 +1,8 @@ -order allow,deny -deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/var/.htaccess b/var/.htaccess index 896fbc5a341ea..707c26b075e16 100755 --- a/var/.htaccess +++ b/var/.htaccess @@ -1,2 +1,8 @@ -Order deny,allow -Deny from all \ No newline at end of file + + order allow,deny + deny from all + += 2.4> + Require all denied + + diff --git a/vendor/.htaccess b/vendor/.htaccess index cb24fd7fc0b3a..707c26b075e16 100644 --- a/vendor/.htaccess +++ b/vendor/.htaccess @@ -1,2 +1,8 @@ -Order allow,deny -Deny from all + + order allow,deny + deny from all + += 2.4> + Require all denied + + From ac0406cb7b2f09bbfe15bce9546d79eea57d546c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylvain=20Raye=CC=81?= Date: Sat, 14 Oct 2017 15:01:07 +0200 Subject: [PATCH 144/528] [ISSUE-11140][BUGFIX] Skip store code admin from being detected in case of store code in url configured --- app/code/Magento/Store/App/Request/PathInfoProcessor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Store/App/Request/PathInfoProcessor.php b/app/code/Magento/Store/App/Request/PathInfoProcessor.php index ebea50588f9e5..9a09b78129a54 100644 --- a/app/code/Magento/Store/App/Request/PathInfoProcessor.php +++ b/app/code/Magento/Store/App/Request/PathInfoProcessor.php @@ -6,6 +6,7 @@ namespace Magento\Store\App\Request; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Store\Model\Store; class PathInfoProcessor implements \Magento\Framework\App\Request\PathInfoProcessorInterface { @@ -42,7 +43,7 @@ public function process(\Magento\Framework\App\RequestInterface $request, $pathI } if ($store->isUseStoreInUrl()) { - if (!$request->isDirectAccessFrontendName($storeCode)) { + if (!$request->isDirectAccessFrontendName($storeCode) && $storeCode != Store::ADMIN_CODE ) { $this->storeManager->setCurrentStore($storeCode); $pathInfo = '/' . (isset($pathParts[1]) ? $pathParts[1] : ''); return $pathInfo; From c170b4f9da948de14520e1c0901782346afcb42b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylvain=20Raye=CC=81?= Date: Sat, 14 Oct 2017 15:46:01 +0200 Subject: [PATCH 145/528] [ISSUE-10811][BUGFIX] Update .htaccess.sample to replace FollowSymLinks with SymLinksIfOwnerMatch --- .htaccess.sample | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.htaccess.sample b/.htaccess.sample index 3b61bb672ec8a..01d64d13393a7 100644 --- a/.htaccess.sample +++ b/.htaccess.sample @@ -111,7 +111,9 @@ ############################################ ## enable rewrites - Options +FollowSymLinks + # Options +FollowSymLinks + # The following line has better security but add some performance overhead - see https://httpd.apache.org/docs/2.4/en/misc/perf-tuning.html + Options -FollowSymLinks +SymLinksIfOwnerMatch RewriteEngine on ############################################ From 0f4b69493b125c8113b43dac72db414e223a5d51 Mon Sep 17 00:00:00 2001 From: Gabriel Queiroz Silva Date: Thu, 12 Oct 2017 14:49:18 -0300 Subject: [PATCH 146/528] Allow setting of http response status code in a Redirection --- .../Framework/Controller/Result/Redirect.php | 18 +++++-- .../Test/Unit/Result/RedirectTest.php | 52 +++++++++++++------ 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/lib/internal/Magento/Framework/Controller/Result/Redirect.php b/lib/internal/Magento/Framework/Controller/Result/Redirect.php index d68caeb3e4409..120b18d873cff 100644 --- a/lib/internal/Magento/Framework/Controller/Result/Redirect.php +++ b/lib/internal/Magento/Framework/Controller/Result/Redirect.php @@ -9,6 +9,8 @@ use Magento\Framework\App; use Magento\Framework\App\Response\HttpInterface as HttpResponseInterface; use Magento\Framework\Controller\AbstractResult; +use Magento\Framework\App\Response\RedirectInterface; +use Magento\Framework\UrlInterface; /** * In many cases controller actions may result in a redirect @@ -18,13 +20,14 @@ */ class Redirect extends AbstractResult { + /** - * @var \Magento\Framework\App\Response\RedirectInterface + * @var RedirectInterface */ protected $redirect; /** - * @var \Magento\Framework\UrlInterface + * @var UrlInterface */ protected $urlBuilder; @@ -37,11 +40,11 @@ class Redirect extends AbstractResult * Constructor * * @param App\Response\RedirectInterface $redirect - * @param \Magento\Framework\UrlInterface $urlBuilder + * @param UrlInterface $urlBuilder */ public function __construct( App\Response\RedirectInterface $redirect, - \Magento\Framework\UrlInterface $urlBuilder + UrlInterface $urlBuilder ) { $this->redirect = $redirect; $this->urlBuilder = $urlBuilder; @@ -70,6 +73,7 @@ public function setRefererOrBaseUrl() } /** + * URL Setter * @param string $url * @return $this */ @@ -97,7 +101,11 @@ public function setPath($path, array $params = []) */ protected function render(HttpResponseInterface $response) { - $response->setRedirect($this->url); + if (empty($this->httpResponseCode)) { + $response->setRedirect($this->url); + } else { + $response->setRedirect($this->url, $this->httpResponseCode); + } return $this; } } diff --git a/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php b/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php index 0295f0713d429..65e7ee489e84c 100644 --- a/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php +++ b/lib/internal/Magento/Framework/Controller/Test/Unit/Result/RedirectTest.php @@ -6,10 +6,13 @@ namespace Magento\Framework\Controller\Test\Unit\Result; -use Magento\Framework\App\Response\HttpInterface as HttpResponseInterface; +use \PHPUnit\Framework\TestCase; +use \Magento\Framework\App\Response\HttpInterface as HttpResponseInterface; +use \Magento\Framework\App\Response\RedirectInterface; use \Magento\Framework\Controller\Result\Redirect; +use \Magento\Framework\UrlInterface; -class RedirectTest extends \PHPUnit\Framework\TestCase +class RedirectTest extends TestCase { /** @var \Magento\Framework\Controller\Result\Redirect */ protected $redirect; @@ -28,9 +31,9 @@ class RedirectTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->redirectInterface = $this->createMock(\Magento\Framework\App\Response\RedirectInterface::class); - $this->urlBuilder = $this->createMock(\Magento\Framework\UrlInterface::class); - $this->urlInterface = $this->createMock(\Magento\Framework\UrlInterface::class); + $this->redirectInterface = $this->createMock(RedirectInterface::class); + $this->urlBuilder = $this->createMock(UrlInterface::class); + $this->urlInterface = $this->createMock(UrlInterface::class); $this->response = $this->createMock(HttpResponseInterface::class); $this->redirect = new Redirect($this->redirectInterface, $this->urlInterface); } @@ -39,7 +42,7 @@ public function testSetRefererUrl() { $this->redirectInterface->expects($this->once())->method('getRefererUrl'); $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, + Redirect::class, $this->redirect->setRefererUrl() ); } @@ -48,7 +51,7 @@ public function testSetRefererOrBaseUrl() { $this->redirectInterface->expects($this->once())->method('getRedirectUrl'); $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, + Redirect::class, $this->redirect->setRefererOrBaseUrl() ); } @@ -56,7 +59,7 @@ public function testSetRefererOrBaseUrl() public function testSetUrl() { $url = 'http://test.com'; - $this->assertInstanceOf(\Magento\Framework\Controller\Result\Redirect::class, $this->redirect->setUrl($url)); + $this->assertInstanceOf(Redirect::class, $this->redirect->setUrl($url)); } public function testSetPath() @@ -67,17 +70,36 @@ public function testSetPath() $this->returnValue($params) ); $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, + Redirect::class, $this->redirect->setPath($path, $params) ); } - public function testRender() + public function httpRedirectResponseStatusCodes() { - $this->response->expects($this->once())->method('setRedirect'); - $this->assertInstanceOf( - \Magento\Framework\Controller\Result\Redirect::class, - $this->redirect->renderResult($this->response) - ); + return [ + [302, null], + [302, 302], + [303, 303] + ]; + } + + /** + * @param int $expectedStatusCode + * @param int|null $actualStatusCode + * @dataProvider httpRedirectResponseStatusCodes + */ + public function testRender($expectedStatusCode, $actualStatusCode) + { + $url = 'http://test.com'; + $this->redirect->setUrl($url); + $this->redirect->setHttpResponseCode($actualStatusCode); + + $this->response + ->expects($this->once()) + ->method('setRedirect') + ->with($url, $expectedStatusCode); + + $this->redirect->renderResult($this->response); } } From 14371f2c49710552d829f2752689a161650ad2ef Mon Sep 17 00:00:00 2001 From: Joan He Date: Sat, 14 Oct 2017 15:13:11 -0500 Subject: [PATCH 147/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 - fix modal enters from top of the window --- .../web/css/source/_module.less | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less index b6b3a635ae2cb..4689e8352e222 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less @@ -112,3 +112,26 @@ padding: 1.5rem 0 2rem 7rem; } } + +.lib-modal-popup() { + -webkit-transition: visibility 0s .5s, opacity .5s ease; + transition: visibility 0s .5s, opacity .5s ease; + + &._show { + visibility: visible; + opacity: 1; + -webkit-transition: opacity .5s ease; + transition: opacity .5s ease; + } + + .modal-inner-wrap { + -webkit-transform: translateX(0); + transform: translateX(0); + -webkit-transition: -webkit-transform 0s; + transition: transform 0s; + .lib-css(background-color, @modal__background-color); + .lib-css(box-shadow, @modal__box-shadow); + opacity: 1; + pointer-events: auto; + } +} \ No newline at end of file From 846f117afded21fdea34fc0b11fc395f65d2da78 Mon Sep 17 00:00:00 2001 From: peterjaap Date: Sun, 15 Oct 2017 10:39:21 +0200 Subject: [PATCH 148/528] Removed setCollectShippingRates() on ShippingAddress because that method does not exist for a billing address. Also removed getBillingAddress() call because the empty address is already created 3 lines above. --- app/code/Magento/Quote/Model/QuoteManagement.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 9b88d102b733f..72c1942159016 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -232,7 +232,6 @@ public function createEmptyCart() $quote->setShippingAddress($this->quoteAddressFactory->create()); try { - $quote->getBillingAddress()->setCollectShippingRates(true); $quote->getShippingAddress()->setCollectShippingRates(true); $this->quoteRepository->save($quote); From 6ebf3cecfd06658f4da6a695c56d06c57bb59d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylvain=20Ray=C3=A9?= Date: Sun, 15 Oct 2017 10:52:55 +0200 Subject: [PATCH 149/528] Update PathInfoProcessor.php Prevent PHPCBF Error --- app/code/Magento/Store/App/Request/PathInfoProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Store/App/Request/PathInfoProcessor.php b/app/code/Magento/Store/App/Request/PathInfoProcessor.php index 9a09b78129a54..a38ea6d1272e8 100644 --- a/app/code/Magento/Store/App/Request/PathInfoProcessor.php +++ b/app/code/Magento/Store/App/Request/PathInfoProcessor.php @@ -43,7 +43,7 @@ public function process(\Magento\Framework\App\RequestInterface $request, $pathI } if ($store->isUseStoreInUrl()) { - if (!$request->isDirectAccessFrontendName($storeCode) && $storeCode != Store::ADMIN_CODE ) { + if (!$request->isDirectAccessFrontendName($storeCode) && $storeCode != Store::ADMIN_CODE) { $this->storeManager->setCurrentStore($storeCode); $pathInfo = '/' . (isset($pathParts[1]) ? $pathParts[1] : ''); return $pathInfo; From 86f1419e2a3ef386f1ebe3b68b23ab3050c2f7bb Mon Sep 17 00:00:00 2001 From: marina Date: Sun, 15 Oct 2017 16:27:05 +0300 Subject: [PATCH 150/528] Fix code style --- app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php index 904360ffb3804..e099d5b902544 100644 --- a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php +++ b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php @@ -111,7 +111,9 @@ public function testScheduledGenerateSitemapsSendsExceptionEmail() ->method('getIterator') ->willReturn(new \ArrayIterator([$this->sitemapMock])); - $this->sitemapMock->expects($this->once())->method('generateXml')->willThrowException(new \Exception($exception)); + $this->sitemapMock->expects($this->once()) + ->method('generateXml') + ->willThrowException(new \Exception($exception)); $this->scopeConfigMock->expects($this->at(1)) ->method('getValue') From 16590f018ab3c110d6999ebb467cd18592287f1c Mon Sep 17 00:00:00 2001 From: marina Date: Sun, 15 Oct 2017 17:27:25 +0300 Subject: [PATCH 151/528] Add suppress warning for coupling between objects --- app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php index e099d5b902544..ac88f23ff9d69 100644 --- a/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php +++ b/app/code/Magento/Sitemap/Test/Unit/Model/ObserverTest.php @@ -7,6 +7,10 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +/** + * Class ObserverTest + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class ObserverTest extends \PHPUnit\Framework\TestCase { /** From a688b66caf37cf160df810deb88accc38fabc5ec Mon Sep 17 00:00:00 2001 From: Marc Rodriguez Date: Sun, 15 Oct 2017 16:54:51 +0200 Subject: [PATCH 152/528] FR#10231_22 Custom URL Rewrite Not working --- app/code/Magento/Store/etc/frontend/di.xml | 2 +- app/code/Magento/UrlRewrite/etc/frontend/di.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Store/etc/frontend/di.xml b/app/code/Magento/Store/etc/frontend/di.xml index fd42a0367aa93..c39d5df863939 100644 --- a/app/code/Magento/Store/etc/frontend/di.xml +++ b/app/code/Magento/Store/etc/frontend/di.xml @@ -18,7 +18,7 @@ Magento\Framework\App\Router\Base false - 20 + 30 Magento\Framework\App\Router\DefaultRouter diff --git a/app/code/Magento/UrlRewrite/etc/frontend/di.xml b/app/code/Magento/UrlRewrite/etc/frontend/di.xml index ff44acb434366..d46bb1c5d14a2 100644 --- a/app/code/Magento/UrlRewrite/etc/frontend/di.xml +++ b/app/code/Magento/UrlRewrite/etc/frontend/di.xml @@ -12,7 +12,7 @@ Magento\UrlRewrite\Controller\Router false - 40 + 20 From 63b549b5bb052bb4a0b0b57cf81c7591f53b56e2 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Fri, 13 Oct 2017 15:42:04 +0300 Subject: [PATCH 153/528] Sync billing with shipping address on Admin Order Page - Added validation for empty applied taxes to avoid exceptions during json decoding --- .../Magento/Quote/Model/Quote/Address.php | 3 +- .../Test/Unit/Model/Quote/AddressTest.php | 28 +++++++++---------- .../Magento/Sales/Model/AdminOrder/Create.php | 5 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 109ca91cb2ae8..87c5feaba8f2e 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -1170,7 +1170,8 @@ public function validateMinimumAmount() */ public function getAppliedTaxes() { - return $this->serializer->unserialize($this->getData('applied_taxes')); + $taxes = $this->getData('applied_taxes'); + return $taxes ? $this->serializer->unserialize($taxes) : []; } /** diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php index 1557fe420be02..d01ae7304bdc6 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/AddressTest.php @@ -9,7 +9,7 @@ namespace Magento\Quote\Test\Unit\Model\Quote; use Magento\Directory\Model\Currency; -use \Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\Address\Rate; use Magento\Quote\Model\ResourceModel\Quote\Address\Rate\CollectionFactory as RateCollectionFactory; use Magento\Quote\Model\ResourceModel\Quote\Address\Rate\Collection as RatesCollection; @@ -28,6 +28,7 @@ use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Api\Data\WebsiteInterface; use Magento\Quote\Model\Quote\Address\RateResult\AbstractResult; +use Magento\Framework\Serialize\Serializer\Json; /** * Test class for sales quote address model @@ -117,7 +118,7 @@ protected function setUp() $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->scopeConfig = $this->createMock(\Magento\Framework\App\Config::class); - $this->serializer = $this->createMock(\Magento\Framework\Serialize\Serializer\Json::class); + $this->serializer = new Json(); $this->requestFactory = $this->getMockBuilder(RateRequestFactory::class) ->disableOriginalConstructor() @@ -273,20 +274,17 @@ public function testValidateMiniumumAmountNegative() public function testSetAndGetAppliedTaxes() { $data = ['data']; - $result = json_encode($data); - - $this->serializer->expects($this->once()) - ->method('serialize') - ->with($data) - ->willReturn($result); - - $this->serializer->expects($this->once()) - ->method('unserialize') - ->with($result) - ->willReturn($data); + self::assertInstanceOf(Address::class, $this->address->setAppliedTaxes($data)); + self::assertEquals($data, $this->address->getAppliedTaxes()); + } - $this->assertInstanceOf(\Magento\Quote\Model\Quote\Address::class, $this->address->setAppliedTaxes($data)); - $this->assertEquals($data, $this->address->getAppliedTaxes()); + /** + * Checks a case, when applied taxes are not provided. + */ + public function testGetAppliedTaxesWithEmptyValue() + { + $this->address->setData('applied_taxes', null); + self::assertEquals([], $this->address->getAppliedTaxes()); } /** diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 8619165cde606..c8afc6d8a292b 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -10,6 +10,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Model\Metadata\Form as CustomerForm; +use Magento\Framework\App\ObjectManager; use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote\Item; @@ -324,7 +325,7 @@ public function __construct( $this->dataObjectHelper = $dataObjectHelper; $this->orderManagement = $orderManagement; $this->quoteFactory = $quoteFactory; - $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + $this->serializer = $serializer ?: ObjectManager::getInstance() ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($data); } @@ -1476,8 +1477,8 @@ public function setBillingAddress($address) // not assigned billing address should be saved as new // but if quote already has the billing address it won't be overridden if (empty($billingAddress->getCustomerAddressId())) { - $quote->removeAddress($quote->getBillingAddress()->getId()); $billingAddress->setCustomerAddressId(null); + $quote->getBillingAddress()->setCustomerAddressId(null); } $quote->setBillingAddress($billingAddress); From 42072dd20ac633ce678946586de6d73b83e9a43b Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Sun, 15 Oct 2017 21:21:59 +0300 Subject: [PATCH 154/528] solve the toolbar problem when this is removed from the layout, code format on construcor of the product list block class --- .../Catalog/Block/Product/ListProduct.php | 74 ++++++++++++++----- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 7289aa85ea016..83065e81c7c50 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -7,13 +7,18 @@ namespace Magento\Catalog\Block\Product; use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Block\Product\Context; use Magento\Catalog\Block\Product\ProductList\Toolbar; +use Magento\Catalog\Helper\Product\ProductList; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\ResourceModel\Product\Collection; use Magento\Eav\Model\Entity\Collection\AbstractCollection; +use Magento\Framework\Data\Helper\PostHelper; use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Url\Helper\Data; /** * Product list @@ -33,7 +38,7 @@ class ListProduct extends AbstractProduct implements IdentityInterface /** * Product Collection * - * @var AbstractCollection + * @var \Magento\Eav\Model\Entity\Collection\AbstractCollection */ protected $_productCollection; @@ -55,30 +60,39 @@ class ListProduct extends AbstractProduct implements IdentityInterface protected $urlHelper; /** - * @var CategoryRepositoryInterface + * @var \Magento\Catalog\Api\CategoryRepositoryInterface */ protected $categoryRepository; /** - * @param Context $context + * @var \Magento\Catalog\Helper\Product\ProductList + */ + protected $productListHelper; + + /** + * + * @param \Magento\Catalog\Helper\Product\ProductList $productListHelper + * @param \Magento\Catalog\Block\Product\Context $context * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver - * @param CategoryRepositoryInterface $categoryRepository + * @param \Magento\Catalog\Api\CategoryRepositoryInterface $categoryRepository * @param \Magento\Framework\Url\Helper\Data $urlHelper * @param array $data */ public function __construct( - \Magento\Catalog\Block\Product\Context $context, - \Magento\Framework\Data\Helper\PostHelper $postDataHelper, - \Magento\Catalog\Model\Layer\Resolver $layerResolver, + ProductList $productListHelper, + Context $context, + PostHelper $postDataHelper, + Resolver $layerResolver, CategoryRepositoryInterface $categoryRepository, - \Magento\Framework\Url\Helper\Data $urlHelper, + Data $urlHelper, array $data = [] ) { $this->_catalogLayer = $layerResolver->get(); $this->_postDataHelper = $postDataHelper; $this->categoryRepository = $categoryRepository; $this->urlHelper = $urlHelper; + $this->productListHelper = $productListHelper; parent::__construct( $context, $data @@ -137,7 +151,12 @@ public function getLoadedProductCollection() */ public function getMode() { - return $this->getChildBlock('toolbar')->getCurrentMode(); + if ($this->getChildBlock('toolbar')) { + return $this->getChildBlock('toolbar')->getCurrentMode(); + } + // if toolbar is removed from layout, use the general configuration for product list mode + // - config path catalog/frontend/list_mode + return $this->productListHelper->getDefaultViewMode($this->getModes()); } /** @@ -148,27 +167,43 @@ public function getMode() protected function _beforeToHtml() { $collection = $this->_getProductCollection(); - $this->configureToolbar($this->getToolbarBlock(), $collection); + + $this->addToobarBlock($collection); + $collection->load(); return parent::_beforeToHtml(); } + /** + * Add toolbar block to product listing + * + * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection + */ + private function addToobarBlock(Collection $collection) + { + $toolbar = $this->getToolbarBlock(); + if ($toolbar) { + $this->configureToolbar($toolbar, $collection); + } + } + /** * Retrieve Toolbar block * - * @return Toolbar + * @return Toolbar|false */ public function getToolbarBlock() { + $block = false; + $blockName = $this->getToolbarBlockName(); - if ($blockName) { - $block = $this->getLayout()->getBlock($blockName); - if ($block) { - return $block; - } + if (!$blockName) { + return $block; } - $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); + + $block = $this->getLayout()->getBlock($blockName); + return $block; } @@ -386,9 +421,8 @@ private function initializeProductCollection() if ($origCategory) { $layer->setCurrentCategory($origCategory); } - - $toolbar = $this->getToolbarBlock(); - $this->configureToolbar($toolbar, $collection); + + $this->addToobarBlock($collection); $this->_eventManager->dispatch( 'catalog_block_product_list_collection', From 906daf673c4dd55a7f0452fb1b58797abf217cc9 Mon Sep 17 00:00:00 2001 From: Mayank Date: Mon, 16 Oct 2017 10:14:36 +0530 Subject: [PATCH 155/528] Redundant round brackets removed from Magento 2.2.0 layer navigation return no products when 2 filters selected. --- app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php index 46080ab5c3330..df98969c262ce 100644 --- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php +++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php @@ -192,7 +192,7 @@ public function setCollection($collection) $this->_collection->setPageSize($limit); } if ($this->getCurrentOrder()) { - if (($this->getCurrentOrder()) == 'position') { + if ($this->getCurrentOrder() == 'position') { $this->_collection->addAttributeToSort( $this->getCurrentOrder(), $this->getCurrentDirection() From 9dbe44493b92407c9b02217966224cb021175c48 Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 08:49:07 +0300 Subject: [PATCH 156/528] Remove the product list helper from constructor for backward compatibility. Use the default toolbar to get current listing mode. Refactor the code. --- .../Catalog/Block/Product/ListProduct.php | 74 ++++++++++++------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 83065e81c7c50..0b197f93d4d35 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -9,7 +9,6 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Block\Product\Context; use Magento\Catalog\Block\Product\ProductList\Toolbar; -use Magento\Catalog\Helper\Product\ProductList; use Magento\Catalog\Model\Category; use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Product; @@ -65,13 +64,6 @@ class ListProduct extends AbstractProduct implements IdentityInterface protected $categoryRepository; /** - * @var \Magento\Catalog\Helper\Product\ProductList - */ - protected $productListHelper; - - /** - * - * @param \Magento\Catalog\Helper\Product\ProductList $productListHelper * @param \Magento\Catalog\Block\Product\Context $context * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver @@ -80,7 +72,6 @@ class ListProduct extends AbstractProduct implements IdentityInterface * @param array $data */ public function __construct( - ProductList $productListHelper, Context $context, PostHelper $postDataHelper, Resolver $layerResolver, @@ -92,7 +83,6 @@ public function __construct( $this->_postDataHelper = $postDataHelper; $this->categoryRepository = $categoryRepository; $this->urlHelper = $urlHelper; - $this->productListHelper = $productListHelper; parent::__construct( $context, $data @@ -154,9 +144,31 @@ public function getMode() if ($this->getChildBlock('toolbar')) { return $this->getChildBlock('toolbar')->getCurrentMode(); } - // if toolbar is removed from layout, use the general configuration for product list mode - // - config path catalog/frontend/list_mode - return $this->productListHelper->getDefaultViewMode($this->getModes()); + + return $this->getDefaultListingMode(); + } + + /** + * Get listing mode for products if toolbar is removed from layout. + * Use the general configuration for product list mode from config path catalog/frontend/list_mode as default value + // or mode data from block declaration from layout. + * + * @return string + */ + private function getDefaultListingMode() + { + // default Toolbar when the toolbar layout is not used + $defaultToolbar = $this->getToolbarBlock(); + $availableModes = $defaultToolbar->getModes(); + + // layout config mode + $mode = $this->getData('mode'); + if (!$mode && !isset($availableModes[$mode])) { + // default config mode + $mode = $defaultToolbar->getCurrentMode(); + } + + return $mode; } /** @@ -168,7 +180,7 @@ protected function _beforeToHtml() { $collection = $this->_getProductCollection(); - $this->addToobarBlock($collection); + $this->addToolbarBlock($collection); $collection->load(); @@ -176,33 +188,41 @@ protected function _beforeToHtml() } /** - * Add toolbar block to product listing + * Add toolbar block from product listing layout * * @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ - private function addToobarBlock(Collection $collection) + private function addToolbarBlock(Collection $collection) { - $toolbar = $this->getToolbarBlock(); - if ($toolbar) { - $this->configureToolbar($toolbar, $collection); + $toolbarLayout = false; + + $blockName = $this->getToolbarBlockName(); + + if ($blockName) { + $toolbarLayout = $this->getLayout()->getBlock($blockName); + } + + if ($toolbarLayout) { + $this->configureToolbar($toolbarLayout, $collection); } } /** - * Retrieve Toolbar block + * Retrieve Toolbar block from layout or a default Toolbar * - * @return Toolbar|false + * @return Toolbar */ public function getToolbarBlock() { - $block = false; - $blockName = $this->getToolbarBlockName(); - if (!$blockName) { - return $block; + + if ($blockName) { + $block = $this->getLayout()->getBlock($blockName); } - $block = $this->getLayout()->getBlock($blockName); + if (!$block) { + $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); + } return $block; } @@ -422,7 +442,7 @@ private function initializeProductCollection() $layer->setCurrentCategory($origCategory); } - $this->addToobarBlock($collection); + $this->addToolbarBlock($collection); $this->_eventManager->dispatch( 'catalog_block_product_list_collection', From 49fdfaee640a79ef6278e9df247a07217d9d597c Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 10:56:16 +0300 Subject: [PATCH 157/528] refactor the code on get toolbar block from layout, fix condition on using the mode layout configuration --- .../Catalog/Block/Product/ListProduct.php | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 0b197f93d4d35..abcc106337617 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -163,7 +163,8 @@ private function getDefaultListingMode() // layout config mode $mode = $this->getData('mode'); - if (!$mode && !isset($availableModes[$mode])) { + + if (!$mode || !isset($availableModes[$mode])) { // default config mode $mode = $defaultToolbar->getCurrentMode(); } @@ -194,13 +195,7 @@ protected function _beforeToHtml() */ private function addToolbarBlock(Collection $collection) { - $toolbarLayout = false; - - $blockName = $this->getToolbarBlockName(); - - if ($blockName) { - $toolbarLayout = $this->getLayout()->getBlock($blockName); - } + $toolbarLayout = $this->getToolbarFromLayout(); if ($toolbarLayout) { $this->configureToolbar($toolbarLayout, $collection); @@ -214,11 +209,7 @@ private function addToolbarBlock(Collection $collection) */ public function getToolbarBlock() { - $blockName = $this->getToolbarBlockName(); - - if ($blockName) { - $block = $this->getLayout()->getBlock($blockName); - } + $block = $this->getToolbarFromLayout(); if (!$block) { $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); @@ -227,6 +218,24 @@ public function getToolbarBlock() return $block; } + /** + * Get toolbar block from layout + * + * @return bool|Toolbar + */ + private function getToolbarFromLayout() + { + $blockName = $this->getToolbarBlockName(); + + $toolbarLayout = false; + + if ($blockName) { + $toolbarLayout = $this->getLayout()->getBlock($blockName); + } + + return $toolbarLayout; + } + /** * Retrieve additional blocks html * From d06d1dcb06ec8f67c6a7ff9f8e9f708596589299 Mon Sep 17 00:00:00 2001 From: Eugene Tulika Date: Wed, 27 Sep 2017 10:21:19 -0500 Subject: [PATCH 158/528] MAGETWO-77226: Add VAT number to email source variables #10996 --- app/code/Magento/Email/Model/Source/Variables.php | 1 + app/code/Magento/Email/Test/Unit/Model/Source/VariablesTest.php | 1 + app/code/Magento/Email/i18n/en_US.csv | 1 + 3 files changed, 3 insertions(+) diff --git a/app/code/Magento/Email/Model/Source/Variables.php b/app/code/Magento/Email/Model/Source/Variables.php index 0d2a52d5c87d9..4ee08b0698ec2 100644 --- a/app/code/Magento/Email/Model/Source/Variables.php +++ b/app/code/Magento/Email/Model/Source/Variables.php @@ -47,6 +47,7 @@ public function __construct() ['value' => 'general/store_information/city', 'label' => __('City')], ['value' => 'general/store_information/street_line1', 'label' => __('Street Address 1')], ['value' => 'general/store_information/street_line2', 'label' => __('Street Address 2')], + ['value' => 'general/store_information/merchant_vat_number', 'label' => __('VAT Number')], ]; } diff --git a/app/code/Magento/Email/Test/Unit/Model/Source/VariablesTest.php b/app/code/Magento/Email/Test/Unit/Model/Source/VariablesTest.php index b6d618d383d9b..1f4a1040f4450 100644 --- a/app/code/Magento/Email/Test/Unit/Model/Source/VariablesTest.php +++ b/app/code/Magento/Email/Test/Unit/Model/Source/VariablesTest.php @@ -53,6 +53,7 @@ protected function setup() ['value' => 'general/store_information/city', 'label' => __('City')], ['value' => 'general/store_information/street_line1', 'label' => __('Street Address 1')], ['value' => 'general/store_information/street_line2', 'label' => __('Street Address 2')], + ['value' => 'general/store_information/merchant_vat_number', 'label' => __('VAT Number')], ]; } diff --git a/app/code/Magento/Email/i18n/en_US.csv b/app/code/Magento/Email/i18n/en_US.csv index d4a8de010dab3..8eed4b5c662b5 100644 --- a/app/code/Magento/Email/i18n/en_US.csv +++ b/app/code/Magento/Email/i18n/en_US.csv @@ -54,6 +54,7 @@ Region/State,Region/State City,City "Street Address 1","Street Address 1" "Street Address 2","Street Address 2" +"VAT Number","VAT Number" "Store Contact Information","Store Contact Information" %1,%1 "Template Variables","Template Variables" From b6ed2d9b31de64b234540abfd28f55485c4556bd Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 13:03:51 +0300 Subject: [PATCH 159/528] Update the toolbar test with product list collection. The toolbar HTML depends on product collection. Because you can remove the toolbar from layout, there is no reason for parent class to add the product collection to default toolbar if the toolbar is never used. That is why the test toolbar coverage needs to include a product collection before checking the toolbar HTML. --- .../testsuite/Magento/Catalog/Block/Product/ListTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php index 17c0f451f9083..43240824d43a5 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php @@ -62,6 +62,9 @@ public function testToolbarCoverage() /* In order to initialize toolbar collection block toHtml should be called before toolbar toHtml */ $this->assertEmpty($parent->toHtml(), 'Block HTML'); /* Template not specified */ $this->assertEquals('grid', $parent->getMode(), 'Default Mode'); /* default mode */ + + /* In order to use toolbar html you need a collection to be set to toolbar block */ + $parent->getToolbarBlock()->setCollection($parent->getLoadedProductCollection()); $this->assertNotEmpty($parent->getToolbarHtml(), 'Toolbar HTML'); /* toolbar for one simple product */ } From 9cd20c03f9c4f3d7dd79865addf8dac9aa6139db Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 15:46:14 +0300 Subject: [PATCH 160/528] Update the toolbar coverage test to use the a layout toolbar declaration present in default layout. Remove the previews correction made because it's not solve the problem where is checking if the toolbar HTML is not empty. --- .../testsuite/Magento/Catalog/Block/Product/ListTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php index 43240824d43a5..8773256b85785 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php @@ -55,6 +55,9 @@ public function testToolbarCoverage() $parent = $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ListProduct::class, 'parent'); /* Prepare toolbar block */ + $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, 'product_list_toolbar'); + $parent->setToolbarBlockName('product_list_toolbar'); + $toolbar = $parent->getToolbarBlock(); $this->assertInstanceOf(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, $toolbar, 'Default Toolbar'); @@ -62,9 +65,6 @@ public function testToolbarCoverage() /* In order to initialize toolbar collection block toHtml should be called before toolbar toHtml */ $this->assertEmpty($parent->toHtml(), 'Block HTML'); /* Template not specified */ $this->assertEquals('grid', $parent->getMode(), 'Default Mode'); /* default mode */ - - /* In order to use toolbar html you need a collection to be set to toolbar block */ - $parent->getToolbarBlock()->setCollection($parent->getLoadedProductCollection()); $this->assertNotEmpty($parent->getToolbarHtml(), 'Toolbar HTML'); /* toolbar for one simple product */ } From 221c593768ef67158740d143ceb55ef8b7f75436 Mon Sep 17 00:00:00 2001 From: Jeroen Date: Mon, 16 Oct 2017 17:13:40 +0200 Subject: [PATCH 161/528] Add "optional" translation --- app/code/Magento/Checkout/i18n/en_US.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Checkout/i18n/en_US.csv b/app/code/Magento/Checkout/i18n/en_US.csv index 8f84275b5488d..53e6ef67d68cd 100644 --- a/app/code/Magento/Checkout/i18n/en_US.csv +++ b/app/code/Magento/Checkout/i18n/en_US.csv @@ -176,3 +176,4 @@ Payment,Payment "Not yet calculated","Not yet calculated" "We received your order!","We received your order!" "Thank you for your purchase!","Thank you for your purchase!" +"optional", "optional" From 84b0872d076bcb310f1febb550fb08addcac75ad Mon Sep 17 00:00:00 2001 From: Raul E Watson Date: Mon, 16 Oct 2017 14:17:22 +0100 Subject: [PATCH 162/528] MAGETWO-75743: Fix for #9783 Multiple parameters in widget.xml not allowed --- .../Magento/Widget/Model/Config/Converter.php | 23 ++++++++++++++----- app/code/Magento/Widget/etc/widget.xsd | 4 ++-- app/code/Magento/Widget/etc/widget_file.xsd | 4 ++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Widget/Model/Config/Converter.php b/app/code/Magento/Widget/Model/Config/Converter.php index 010c46da56950..40718a5a5db9c 100644 --- a/app/code/Magento/Widget/Model/Config/Converter.php +++ b/app/code/Magento/Widget/Model/Config/Converter.php @@ -222,7 +222,7 @@ protected function _convertDepends($source) { $depends = []; foreach ($source->childNodes as $childNode) { - if ($childNode->nodeName == '#text') { + if ($childNode->nodeName === '#text') { continue; } if ($childNode->nodeName !== 'parameter') { @@ -231,12 +231,23 @@ protected function _convertDepends($source) ); } $parameterAttributes = $childNode->attributes; - $depends[$parameterAttributes->getNamedItem( - 'name' - )->nodeValue] = [ - 'value' => $parameterAttributes->getNamedItem('value')->nodeValue, - ]; + $dependencyName = $parameterAttributes->getNamedItem('name')->nodeValue; + $dependencyValue = $parameterAttributes->getNamedItem('value')->nodeValue; + + if (!isset($depends[$dependencyName])) { + $depends[$dependencyName] = [ + 'value' => $dependencyValue, + ]; + + continue; + } else if (!isset($depends[$dependencyName]['values'])) { + $depends[$dependencyName]['values'] = [$depends[$dependencyName]['value']]; + unset($depends[$dependencyName]['value']); + } + + $depends[$dependencyName]['values'][] = $dependencyValue; } + return $depends; } diff --git a/app/code/Magento/Widget/etc/widget.xsd b/app/code/Magento/Widget/etc/widget.xsd index caaeec8ac4b84..70c9ec8e3514f 100644 --- a/app/code/Magento/Widget/etc/widget.xsd +++ b/app/code/Magento/Widget/etc/widget.xsd @@ -212,8 +212,8 @@ List of parameters this parameter depends on. - + - + diff --git a/app/code/Magento/Widget/etc/widget_file.xsd b/app/code/Magento/Widget/etc/widget_file.xsd index 6ebf7a201212e..afdd506f3ba24 100644 --- a/app/code/Magento/Widget/etc/widget_file.xsd +++ b/app/code/Magento/Widget/etc/widget_file.xsd @@ -212,8 +212,8 @@ List of parameters this parameter depends on. - + - + From 2adefdff73c62d829d1969b3abc988992bd3da39 Mon Sep 17 00:00:00 2001 From: Marius Grad Date: Mon, 16 Oct 2017 19:26:15 +0300 Subject: [PATCH 163/528] fix static line limit test --- .../testsuite/Magento/Catalog/Block/Product/ListTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php index 8773256b85785..f68e509e4a8dd 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php @@ -55,7 +55,8 @@ public function testToolbarCoverage() $parent = $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ListProduct::class, 'parent'); /* Prepare toolbar block */ - $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, 'product_list_toolbar'); + $this->_getLayout() + ->createBlock(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, 'product_list_toolbar'); $parent->setToolbarBlockName('product_list_toolbar'); $toolbar = $parent->getToolbarBlock(); From 393baced51fc97dff2cb6093eb493ac3e681941a Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Mon, 16 Oct 2017 21:00:30 +0200 Subject: [PATCH 164/528] Changed logic to get customer subscriber status --- .../Magento/Newsletter/Model/Subscriber.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php index 7a55234302568..9e021a21d23b3 100644 --- a/app/code/Magento/Newsletter/Model/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/Subscriber.php @@ -393,12 +393,14 @@ public function randomSequence($length = 32) */ public function subscribe($email) { - $sendInformationEmail = false; $this->loadByEmail($email); + if ($this->getId() && $this->getStatus() == self::STATUS_SUBSCRIBED) { + return $this->getStatus(); + } + if (!$this->getId()) { $this->setSubscriberConfirmCode($this->randomSequence()); - $sendInformationEmail = true; } $isConfirmNeed = $this->_scopeConfig->getValue( @@ -446,14 +448,12 @@ public function subscribe($email) try { /* Save model before sending out email */ $this->save(); - if ($sendInformationEmail) { - if ($isConfirmNeed === true - && $isOwnSubscribes === false - ) { - $this->sendConfirmationRequestEmail(); - } else { - $this->sendConfirmationSuccessEmail(); - } + if ($isConfirmNeed === true + && $isOwnSubscribes === false + ) { + $this->sendConfirmationRequestEmail(); + } else { + $this->sendConfirmationSuccessEmail(); } return $this->getStatus(); } catch (\Exception $e) { From bd95e4ec5b909f491afb2b1567fefebdc819b63c Mon Sep 17 00:00:00 2001 From: Joshua Warren Date: Mon, 16 Oct 2017 15:39:02 -0500 Subject: [PATCH 165/528] Ensure that the database is cleared and Magento reinstalled when TESTS_CLEANUP is set to enabled --- .../framework/Magento/TestFramework/Application.php | 5 +++-- dev/tests/integration/framework/bootstrap.php | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/framework/Magento/TestFramework/Application.php b/dev/tests/integration/framework/Magento/TestFramework/Application.php index 2f4395b161a69..8a630a730718f 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Application.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Application.php @@ -438,7 +438,7 @@ public function cleanup() * @return void * @throws \Magento\Framework\Exception\LocalizedException */ - public function install() + public function install($cleanup) { $dirs = \Magento\Framework\App\Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS; $this->_ensureDirExists($this->installDir); @@ -453,8 +453,9 @@ public function install() $installParams = $this->getInstallCliParams(); // performance optimization: restore DB from last good dump to make installation on top of it (much faster) + // do not restore from the database if the cleanup option is set to ensure we have a clean DB to test on $db = $this->getDbInstance(); - if ($db->isDbDumpExists()) { + if ($db->isDbDumpExists() && !$cleanup) { $db->restoreFromDbDump(); } diff --git a/dev/tests/integration/framework/bootstrap.php b/dev/tests/integration/framework/bootstrap.php index 13008938147b5..4e14c8113a708 100644 --- a/dev/tests/integration/framework/bootstrap.php +++ b/dev/tests/integration/framework/bootstrap.php @@ -74,7 +74,7 @@ $application->cleanup(); } if (!$application->isInstalled()) { - $application->install(); + $application->install($settings->getAsBoolean('TESTS_CLEANUP')); } $application->initialize([]); From 03c6d2042cbba31758d309a83fd3250b6b01fe1a Mon Sep 17 00:00:00 2001 From: Kirill Morozov Date: Mon, 16 Oct 2017 16:56:19 -0400 Subject: [PATCH 166/528] MAGETWO-81245: Handling all setProductsFilter items in array as arguments --- .../ResourceModel/Stock/Item/StockItemCriteriaMapper.php | 5 +---- .../ResourceModel/Stock/Status/StockStatusCriteriaMapper.php | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item/StockItemCriteriaMapper.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item/StockItemCriteriaMapper.php index 21b6dfefeb1f5..43e7a6f7861ea 100644 --- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item/StockItemCriteriaMapper.php +++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item/StockItemCriteriaMapper.php @@ -99,12 +99,9 @@ public function mapWebsiteFilter($website) /** * @inheritdoc */ - public function mapProductsFilter($products) + public function mapProductsFilter(...$products) { $productIds = []; - if (!is_array($products)) { - $products = [$products]; - } foreach ($products as $product) { if ($product instanceof \Magento\Catalog\Model\Product) { $productIds[] = $product->getId(); diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status/StockStatusCriteriaMapper.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status/StockStatusCriteriaMapper.php index 820ccc7ff5cfb..419faa227bf17 100644 --- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status/StockStatusCriteriaMapper.php +++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status/StockStatusCriteriaMapper.php @@ -56,12 +56,9 @@ public function mapWebsiteFilter($website) * @param int|array|\Magento\Catalog\Model\Product|\Magento\Catalog\Model\Product[] $products * @return void */ - public function mapProductsFilter($products) + public function mapProductsFilter(...$products) { $productIds = []; - if (!is_array($products)) { - $products = [$products]; - } foreach ($products as $product) { if ($product instanceof \Magento\Catalog\Model\Product) { $productIds[] = $product->getId(); From 2b78a06446478b300fd24877ac11129141a2ca55 Mon Sep 17 00:00:00 2001 From: Eugene Tulika Date: Mon, 16 Oct 2017 17:43:42 -0400 Subject: [PATCH 167/528] MAGETWO-81675: Save region correctly to save sales address from admin --- .../Magento/Sales/Controller/Adminhtml/Order/AddressSave.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php index 583849bf12458..dc994e554b394 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php @@ -13,7 +13,7 @@ use Magento\Sales\Api\OrderRepositoryInterface; use Magento\Sales\Api\Data\OrderAddressInterface; use Magento\Sales\Controller\Adminhtml\Order; -use Magento\Sales\Model\Order\Address; +use Magento\Sales\Model\Order\Address as AddressModel; use Psr\Log\LoggerInterface; use Magento\Framework\Registry; use Magento\Framework\App\Response\Http\FileFactory; @@ -95,7 +95,7 @@ public function __construct( public function execute() { $addressId = $this->getRequest()->getParam('address_id'); - /** @var $address OrderAddressInterface|Address */ + /** @var $address OrderAddressInterface|AddressModel */ $address = $this->_objectManager->create( OrderAddressInterface::class )->load($addressId); From ba63d94066e2ab612297a920c134f1da8e89d65a Mon Sep 17 00:00:00 2001 From: Max Chadwick Date: Sat, 14 Oct 2017 14:31:38 -0400 Subject: [PATCH 168/528] Retain additional cron history by default There's no reason the clear the history out so fast other than to make it impossible to audit, if / when you have an issue. --- app/code/Magento/Cron/etc/cron_groups.xml | 4 ++-- app/code/Magento/Indexer/etc/cron_groups.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Cron/etc/cron_groups.xml b/app/code/Magento/Cron/etc/cron_groups.xml index a72bd6fdac10c..a01426eab723e 100644 --- a/app/code/Magento/Cron/etc/cron_groups.xml +++ b/app/code/Magento/Cron/etc/cron_groups.xml @@ -11,8 +11,8 @@ 20 15 10 - 60 - 600 + 10080 + 10080 0 diff --git a/app/code/Magento/Indexer/etc/cron_groups.xml b/app/code/Magento/Indexer/etc/cron_groups.xml index ad1513abe69ad..7afabee1949c0 100644 --- a/app/code/Magento/Indexer/etc/cron_groups.xml +++ b/app/code/Magento/Indexer/etc/cron_groups.xml @@ -11,8 +11,8 @@ 4 2 10 - 60 - 600 + 10080 + 10080 1 From 10b57f46398d6a85afee751ab1c7c9f1b7d31d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20M=C3=BCnch?= Date: Tue, 17 Oct 2017 09:36:48 +0200 Subject: [PATCH 169/528] Add interaction to admin:user:create command --- .../Command/AdminUserCreateCommand.php | 101 +++++++++++++++++- .../Command/AdminUserCreateCommandTest.php | 75 ++++++++++++- 2 files changed, 170 insertions(+), 6 deletions(-) diff --git a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php index 940bcbbd6d7f1..4ad8e7c229bfd 100644 --- a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php +++ b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php @@ -6,13 +6,14 @@ namespace Magento\Setup\Console\Command; -use Magento\Setup\Model\AdminAccount; use Magento\Framework\Setup\ConsoleLogger; +use Magento\Setup\Model\AdminAccount; use Magento\Setup\Model\InstallerFactory; use Magento\User\Model\UserValidationRules; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\Question; class AdminUserCreateCommand extends AbstractSetupCommand { @@ -50,6 +51,98 @@ protected function configure() parent::configure(); } + /** + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + /** @var \Symfony\Component\Console\Helper\QuestionHelper $questionHelper */ + $questionHelper = $this->getHelper('question'); + + if (!$input->getOption(AdminAccount::KEY_USER)) { + $question = new Question('Admin user: ', ''); + $this->addNotEmptyValidator($question); + + $input->setOption( + AdminAccount::KEY_USER, + $questionHelper->ask($input, $output, $question) + ); + } + + if (!$input->getOption(AdminAccount::KEY_PASSWORD)) { + $question = new Question('Admin password: ', ''); + $question->setHidden(true); + + $question->setValidator(function ($value) use ($output) { + $user = new \Magento\Framework\DataObject(); + $user->setPassword($value); + + $validator = new \Magento\Framework\Validator\DataObject(); + $this->validationRules->addPasswordRules($validator); + + $validator->isValid($user); + foreach ($validator->getMessages() as $message) { + throw new \Exception($message); + } + + return $value; + }); + + $input->setOption( + AdminAccount::KEY_PASSWORD, + $questionHelper->ask($input, $output, $question) + ); + } + + if (!$input->getOption(AdminAccount::KEY_EMAIL)) { + $question = new Question('Admin email: ', ''); + $this->addNotEmptyValidator($question); + + $input->setOption( + AdminAccount::KEY_EMAIL, + $questionHelper->ask($input, $output, $question) + ); + } + + if (!$input->getOption(AdminAccount::KEY_FIRST_NAME)) { + $question = new Question('Admin first name: ', ''); + $this->addNotEmptyValidator($question); + + $input->setOption( + AdminAccount::KEY_FIRST_NAME, + $questionHelper->ask($input, $output, $question) + ); + } + + if (!$input->getOption(AdminAccount::KEY_LAST_NAME)) { + $question = new Question('Admin last name: ', ''); + $this->addNotEmptyValidator($question); + + $input->setOption( + AdminAccount::KEY_LAST_NAME, + $questionHelper->ask($input, $output, $question) + ); + } + } + + /** + * @param \Symfony\Component\Console\Question\Question $question + * @return void + */ + private function addNotEmptyValidator(Question $question) + { + $question->setValidator(function ($value) { + if (trim($value) == '') { + throw new \Exception('The value cannot be empty'); + } + + return $value; + }); + } + /** * {@inheritdoc} */ @@ -57,7 +150,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $errors = $this->validate($input); if ($errors) { - $output->writeln('' . implode('' . PHP_EOL . '', $errors) . ''); + $output->writeln('' . implode('' . PHP_EOL . '', $errors) . ''); // we must have an exit code higher than zero to indicate something was wrong return \Magento\Framework\Console\Cli::RETURN_FAILURE; } @@ -113,7 +206,7 @@ public function validate(InputInterface $input) ? '' : $input->getOption(AdminAccount::KEY_PASSWORD) ); - $validator = new \Magento\Framework\Validator\DataObject; + $validator = new \Magento\Framework\Validator\DataObject(); $this->validationRules->addUserInfoRules($validator); $this->validationRules->addPasswordRules($validator); diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/AdminUserCreateCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/AdminUserCreateCommandTest.php index 1cfd0c9494a51..d244f48d4e1ea 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/AdminUserCreateCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/AdminUserCreateCommandTest.php @@ -5,14 +5,21 @@ */ namespace Magento\Setup\Test\Unit\Console\Command; -use Magento\Setup\Model\AdminAccount; use Magento\Setup\Console\Command\AdminUserCreateCommand; +use Magento\Setup\Model\AdminAccount; use Magento\Setup\Mvc\Bootstrap\InitParamListener; use Magento\User\Model\UserValidationRules; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Tester\CommandTester; class AdminUserCreateCommandTest extends \PHPUnit\Framework\TestCase { + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Symfony\Component\Console\Helper\QuestionHelper + */ + private $questionHelperMock; + /** * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Model\InstallerFactory */ @@ -27,6 +34,10 @@ public function setUp() { $this->installerFactoryMock = $this->createMock(\Magento\Setup\Model\InstallerFactory::class); $this->command = new AdminUserCreateCommand($this->installerFactoryMock, new UserValidationRules()); + + $this->questionHelperMock = $this->getMockBuilder(QuestionHelper::class) + ->setMethods(['ask']) + ->getMock(); } public function testExecute() @@ -50,10 +61,70 @@ public function testExecute() $installerMock = $this->createMock(\Magento\Setup\Model\Installer::class); $installerMock->expects($this->once())->method('installAdminUser')->with($data); $this->installerFactoryMock->expects($this->once())->method('create')->willReturn($installerMock); - $commandTester->execute($options); + $commandTester->execute($options, ['interactive' => false]); $this->assertEquals('Created Magento administrator user named user' . PHP_EOL, $commandTester->getDisplay()); } + public function testInteraction() + { + $application = new Application(); + $application->add($this->command); + + $this->questionHelperMock->expects($this->at(0)) + ->method('ask') + ->will($this->returnValue('admin')); + + $this->questionHelperMock->expects($this->at(1)) + ->method('ask') + ->will($this->returnValue('Password123')); + + $this->questionHelperMock->expects($this->at(2)) + ->method('ask') + ->will($this->returnValue('john.doe@example.com')); + + $this->questionHelperMock->expects($this->at(3)) + ->method('ask') + ->will($this->returnValue('John')); + + $this->questionHelperMock->expects($this->at(4)) + ->method('ask') + ->will($this->returnValue('Doe')); + + // We override the standard helper with our mock + $this->command->getHelperSet()->set($this->questionHelperMock, 'question'); + + $installerMock = $this->createMock(\Magento\Setup\Model\Installer::class); + + $expectedData = [ + 'admin-user' => 'admin', + 'admin-password' => 'Password123', + 'admin-email' => 'john.doe@example.com', + 'admin-firstname' => 'John', + 'admin-lastname' => 'Doe', + 'magento-init-params' => null, + 'help' => false, + 'quiet' => false, + 'verbose' => false, + 'version' => false, + 'ansi' => false, + 'no-ansi' => false, + 'no-interaction' => false, + ]; + + $installerMock->expects($this->once())->method('installAdminUser')->with($expectedData); + $this->installerFactoryMock->expects($this->once())->method('create')->willReturn($installerMock); + + $commandTester = new CommandTester($this->command); + $commandTester->execute([ + 'command' => $this->command->getName(), + ]); + + $this->assertEquals( + 'Created Magento administrator user named admin' . PHP_EOL, + $commandTester->getDisplay() + ); + } + public function testGetOptionsList() { /* @var $argsList \Symfony\Component\Console\Input\InputArgument[] */ From 3574bb598ba1ef279fe45d61ee342c0fb4b192e0 Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Tue, 17 Oct 2017 20:10:53 +0200 Subject: [PATCH 170/528] Remove Where part from SelectCountSql --- .../Reports/Model/ResourceModel/Review/Customer/Collection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php b/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php index a832823967647..c25fe3c6508ed 100644 --- a/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php +++ b/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php @@ -117,6 +117,7 @@ public function getSelectCountSql() $countSelect->reset(\Magento\Framework\DB\Select::LIMIT_COUNT); $countSelect->reset(\Magento\Framework\DB\Select::LIMIT_OFFSET); $countSelect->reset(\Magento\Framework\DB\Select::COLUMNS); + $countSelect->reset(\Magento\Framework\DB\Select::WHERE); $countSelect->columns(new \Zend_Db_Expr('COUNT(DISTINCT detail.customer_id)')); From cefb25a91d060f61074919b95c7909a8618fe134 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 17 Oct 2017 15:16:15 -0500 Subject: [PATCH 171/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Model/Condition/CanViewNotification.php | 4 ++- .../Condition/CanViewNotificationTest.php | 32 +++++++++---------- .../web/css/source/_module.less | 17 +++++----- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php index 62ac77a916917..7ec0cd3cefc08 100644 --- a/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Analytics/Model/Condition/CanViewNotification.php @@ -43,6 +43,7 @@ class CanViewNotification implements VisibilityConditionInterface * * @param NotificationFlagManager $notificationFlagManager * @param Session $session + * @param ModuleListInterface $moduleList */ public function __construct( NotificationFlagManager $notificationFlagManager, @@ -62,7 +63,8 @@ public function __construct( public function isVisible(array $arguments) { $userId = $this->session->getUser()->getId(); - if ($this->moduleList->has('Magento_Advertisement') || $this->notificationFlagManager->isUserNotified($userId)) { + if ($this->moduleList->has('Magento_Advertisement') + || $this->notificationFlagManager->isUserNotified($userId)) { return false; } diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 336e4da6d5b88..ba45d5a3eb0da 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -7,10 +7,10 @@ namespace Magento\Analytics\Test\Unit\Model\Condition; use Magento\Analytics\Model\Condition\CanViewNotification; -use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Analytics\Model\NotificationFlagManager; use Magento\Backend\Model\Auth\Session; +use Magento\Framework\Module\ModuleListInterface; /** * Class CanViewNotificationTest @@ -33,21 +33,21 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase private $sessionMock; /** - * @var ProductMetadataInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ModuleListInterface|\PHPUnit_Framework_MockObject_MockObject */ - private $productMetadataInterfaceMock; + private $moduleListMock; public function setUp() { $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) ->disableOriginalConstructor() ->getMock(); - $this->sessionMock = $this->getMockBuilder(Session::class) + $this->moduleListMock = $this->getMockBuilder(ModuleListInterface::class) ->disableOriginalConstructor() - ->setMethods(['getUser', 'getId']) ->getMock(); - $this->productMetadataInterfaceMock = $this->getMockBuilder(ProductMetadataInterface::class) + $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() + ->setMethods(['getUser', 'getId']) ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( @@ -55,7 +55,7 @@ public function setUp() [ 'notificationFlagManager' => $this->notificationFlagManagerMock, 'session' => $this->sessionMock, - 'productMetadataInterface' => $this->productMetadataInterfaceMock + 'moduleList' => $this->moduleListMock ] ); } @@ -63,28 +63,28 @@ public function setUp() public function isVisibleProvider() { return [ - [1, "2.2.1", false, true], - [1, "2.2.1-dev", true, false], - [1, "2.2.1", true, false], - [1, "2.2.1-dev", false, false] + [1, false, false, true], // No Ad Module, Has not seen before, should see popup + [1, true, false, false], // Has Ad Module, Has not seen before, should not see popup + [1, false, true, false], // No Ad Module, Has seen before, should not see popup + [1, true, true, false] // Has Ad Module, Has seen before, should not see popup ]; } /** * @dataProvider isVisibleProvider * @param int $userId - * @param string $version + * @param bool $hasNotificationModule * @param bool $isUserNotified * @param bool $expected */ - public function testIsVisible($userId, $version, $isUserNotified, $expected) + public function testIsVisible($userId, $hasNotificationModule, $isUserNotified, $expected) { - $this->productMetadataInterfaceMock->expects($this->once()) - ->method('getVersion') - ->willReturn($version); $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); + $this->moduleListMock->expects($this->once()) + ->method('has') + ->willReturn($hasNotificationModule); $this->sessionMock->expects($this->once()) ->method('getId') ->willReturn($userId); diff --git a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less index 4689e8352e222..49e0e17a2cb0d 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Advertisement/web/css/source/_module.less @@ -30,7 +30,6 @@ .advertisement-text { line-height: @line-height__l; - height: 32rem; ul { margin: 2rem 0 2rem 0; @@ -47,16 +46,16 @@ } } -.advertisement-modal { - .advertisement-text { - height: 35.5rem; - } -} - -.advertisement-button-next { +.advertisement-button-next, .advertisement-button-back { display: inline-block; vertical-align: top; float: right; + position: absolute; + bottom: 4rem; +} + +.advertisement-button-next { + right: 4rem; } .analytics-highlight { @@ -134,4 +133,4 @@ opacity: 1; pointer-events: auto; } -} \ No newline at end of file +} From 58f37f7b4d95ed0ea3097d5dc167ab86ad625d26 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 17 Oct 2017 15:18:38 -0500 Subject: [PATCH 172/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Test/Unit/Model/Condition/CanViewNotificationTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index ba45d5a3eb0da..0af3ae1ff21e2 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -63,10 +63,10 @@ public function setUp() public function isVisibleProvider() { return [ - [1, false, false, true], // No Ad Module, Has not seen before, should see popup - [1, true, false, false], // Has Ad Module, Has not seen before, should not see popup - [1, false, true, false], // No Ad Module, Has seen before, should not see popup - [1, true, true, false] // Has Ad Module, Has seen before, should not see popup + [1, false, false, true], + [1, true, false, false], + [1, false, true, false], + [1, true, true, false] ]; } From c2f3a9bfea102f2900991e5b544b3b10b6f16d65 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Tue, 17 Oct 2017 15:23:54 -0500 Subject: [PATCH 173/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../Unit/Model/Condition/CanViewNotificationTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php index 0af3ae1ff21e2..ccf3f1efa599b 100644 --- a/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -42,13 +42,13 @@ public function setUp() $this->notificationFlagManagerMock = $this->getMockBuilder(NotificationFlagManager::class) ->disableOriginalConstructor() ->getMock(); - $this->moduleListMock = $this->getMockBuilder(ModuleListInterface::class) - ->disableOriginalConstructor() - ->getMock(); $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() ->setMethods(['getUser', 'getId']) ->getMock(); + $this->moduleListMock = $this->getMockBuilder(ModuleListInterface::class) + ->disableOriginalConstructor() + ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, @@ -82,12 +82,12 @@ public function testIsVisible($userId, $hasNotificationModule, $isUserNotified, $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); - $this->moduleListMock->expects($this->once()) - ->method('has') - ->willReturn($hasNotificationModule); $this->sessionMock->expects($this->once()) ->method('getId') ->willReturn($userId); + $this->moduleListMock->expects($this->once()) + ->method('has') + ->willReturn($hasNotificationModule); $this->notificationFlagManagerMock->expects($this->any()) ->method('isUserNotified') ->willReturn($isUserNotified); From a872f4061695b91e923d1c1abb87a0a50e18c77d Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Wed, 18 Oct 2017 15:18:48 +0300 Subject: [PATCH 174/528] MAGETWO-81153: Backward incompatible changes of 2.2.1 release --- app/code/Magento/Customer/Helper/Address.php | 39 +----- .../Customer/Helper/AttributeChecker.php | 71 +++++++++++ .../Customer/Test/Unit/Helper/AddressTest.php | 69 ----------- .../Test/Unit/Helper/AttributeCheckerTest.php | 112 ++++++++++++++++++ 4 files changed, 184 insertions(+), 107 deletions(-) create mode 100644 app/code/Magento/Customer/Helper/AttributeChecker.php create mode 100644 app/code/Magento/Customer/Test/Unit/Helper/AttributeCheckerTest.php diff --git a/app/code/Magento/Customer/Helper/Address.php b/app/code/Magento/Customer/Helper/Address.php index 8dac704aaa085..c74c62dc6d98c 100644 --- a/app/code/Magento/Customer/Helper/Address.php +++ b/app/code/Magento/Customer/Helper/Address.php @@ -8,9 +8,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Api\CustomerMetadataInterface; use Magento\Customer\Api\Data\AttributeMetadataInterface; -use Magento\Customer\Model\Metadata\AttributeResolver; use Magento\Directory\Model\Country\Format; -use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\NoSuchEntityException; /** @@ -95,11 +93,6 @@ class Address extends \Magento\Framework\App\Helper\AbstractHelper */ protected $_addressConfig; - /** - * @var AttributeResolver - */ - private $attributeResolver; - /** * @param \Magento\Framework\App\Helper\Context $context * @param \Magento\Framework\View\Element\BlockFactory $blockFactory @@ -107,7 +100,6 @@ class Address extends \Magento\Framework\App\Helper\AbstractHelper * @param CustomerMetadataInterface $customerMetadataService * @param AddressMetadataInterface $addressMetadataService * @param \Magento\Customer\Model\Address\Config $addressConfig - * @param AttributeResolver|null $attributeResolver */ public function __construct( \Magento\Framework\App\Helper\Context $context, @@ -115,15 +107,13 @@ public function __construct( \Magento\Store\Model\StoreManagerInterface $storeManager, CustomerMetadataInterface $customerMetadataService, AddressMetadataInterface $addressMetadataService, - \Magento\Customer\Model\Address\Config $addressConfig, - AttributeResolver $attributeResolver = null + \Magento\Customer\Model\Address\Config $addressConfig ) { $this->_blockFactory = $blockFactory; $this->_storeManager = $storeManager; $this->_customerMetadataService = $customerMetadataService; $this->_addressMetadataService = $addressMetadataService; $this->_addressConfig = $addressConfig; - $this->attributeResolver = $attributeResolver ?: ObjectManager::getInstance()->get(AttributeResolver::class); parent::__construct($context); } @@ -401,31 +391,4 @@ public function isAttributeVisible($code) } return false; } - - /** - * Checks whether it is allowed to show an attribute on the form - * - * This check relies on the attribute's property 'getUsedInForms' which contains a list of forms - * where allowed to render specified attribute. - * - * @param string $attributeCode - * @param string $formName - * @return bool - */ - public function isAttributeAllowedOnForm($attributeCode, $formName) - { - $isAllowed = false; - $attributeMetadata = $this->_addressMetadataService->getAttributeMetadata($attributeCode); - if ($attributeMetadata) { - /** @var \Magento\Customer\Model\Attribute $attribute */ - $attribute = $this->attributeResolver->getModelByAttribute( - \Magento\Customer\Api\AddressMetadataManagementInterface::ENTITY_TYPE_ADDRESS, - $attributeMetadata - ); - $usedInForms = $attribute->getUsedInForms(); - $isAllowed = in_array($formName, $usedInForms, true); - } - - return $isAllowed; - } } diff --git a/app/code/Magento/Customer/Helper/AttributeChecker.php b/app/code/Magento/Customer/Helper/AttributeChecker.php new file mode 100644 index 0000000000000..d8766a67c8b21 --- /dev/null +++ b/app/code/Magento/Customer/Helper/AttributeChecker.php @@ -0,0 +1,71 @@ +addressMetadata = $addressMetadata; + $this->attributeResolver = $attributeResolver; + parent::__construct($context); + } + + /** + * Checks whether it is allowed to show an attribute on the form + * + * This check relies on the attribute's property 'getUsedInForms' which contains a list of forms + * where allowed to render specified attribute. + * + * @param string $attributeCode + * @param string $formName + * @return bool + */ + public function isAttributeAllowedOnForm($attributeCode, $formName) + { + $isAllowed = false; + $attributeMetadata = $this->addressMetadata->getAttributeMetadata($attributeCode); + if ($attributeMetadata) { + /** @var Attribute $attribute */ + $attribute = $this->attributeResolver->getModelByAttribute( + AddressMetadataManagementInterface::ENTITY_TYPE_ADDRESS, + $attributeMetadata + ); + $usedInForms = $attribute->getUsedInForms(); + $isAllowed = in_array($formName, $usedInForms, true); + } + + return $isAllowed; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php b/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php index 7b42e8b7774c8..50785247d7965 100644 --- a/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php +++ b/app/code/Magento/Customer/Test/Unit/Helper/AddressTest.php @@ -7,7 +7,6 @@ namespace Magento\Customer\Test\Unit\Helper; use Magento\Customer\Api\AddressMetadataInterface; -use Magento\Customer\Api\AddressMetadataManagementInterface; use Magento\Customer\Api\CustomerMetadataInterface; /** @@ -36,9 +35,6 @@ class AddressTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Customer\Model\Address\Config|\PHPUnit_Framework_MockObject_MockObject */ protected $addressConfig; - /** @var \Magento\Customer\Model\Metadata\AttributeResolver|\PHPUnit_Framework_MockObject_MockObject */ - protected $attributeResolver; - /** @var \PHPUnit_Framework_MockObject_MockObject|AddressMetadataInterface */ private $addressMetadataService; @@ -55,7 +51,6 @@ protected function setUp() $this->customerMetadataService = $arguments['customerMetadataService']; $this->addressConfig = $arguments['addressConfig']; $this->addressMetadataService = $arguments['addressMetadataService']; - $this->attributeResolver = $arguments['attributeResolver']; $this->helper = $objectManagerHelper->getObject($className, $arguments); } @@ -408,68 +403,4 @@ public function isAttributeVisibleDataProvider() ['invalid_code', false], ]; } - - /** - * @dataProvider attributeOnFormDataProvider - * @param bool $isAllowed - * @param bool $isMetadataExists - * @param string $attributeCode - * @param string $formName - * @param array $attributeFormsList - */ - public function testIsAttributeAllowedOnForm( - $isAllowed, - $isMetadataExists, - $attributeCode, - $formName, - array $attributeFormsList - ) { - $attributeMetadata = null; - if ($isMetadataExists) { - $attributeMetadata = $this->getMockBuilder(\Magento\Customer\Api\Data\AttributeMetadataInterface::class) - ->getMockForAbstractClass(); - $attribute = $this->getMockBuilder(\Magento\Customer\Model\Attribute::class) - ->disableOriginalConstructor() - ->getMock(); - $this->attributeResolver->expects($this->once()) - ->method('getModelByAttribute') - ->with(AddressMetadataManagementInterface::ENTITY_TYPE_ADDRESS, $attributeMetadata) - ->willReturn($attribute); - $attribute->expects($this->once()) - ->method('getUsedInForms') - ->willReturn($attributeFormsList); - } - $this->addressMetadataService->expects($this->once()) - ->method('getAttributeMetadata') - ->with($attributeCode) - ->willReturn($attributeMetadata); - $this->assertEquals($isAllowed, $this->helper->isAttributeAllowedOnForm($attributeCode, $formName)); - } - - public function attributeOnFormDataProvider() - { - return [ - 'metadata not exists' => [ - 'isAllowed' => false, - 'isMetadataExists' => false, - 'attributeCode' => 'attribute_code', - 'formName' => 'form_name', - 'attributeFormsList' => [], - ], - 'form not in the list' => [ - 'isAllowed' => false, - 'isMetadataExists' => true, - 'attributeCode' => 'attribute_code', - 'formName' => 'form_name', - 'attributeFormsList' => ['form_1', 'form_2'], - ], - 'allowed' => [ - 'isAllowed' => true, - 'isMetadataExists' => true, - 'attributeCode' => 'attribute_code', - 'formName' => 'form_name', - 'attributeFormsList' => ['form_name', 'form_1', 'form_2'], - ], - ]; - } } diff --git a/app/code/Magento/Customer/Test/Unit/Helper/AttributeCheckerTest.php b/app/code/Magento/Customer/Test/Unit/Helper/AttributeCheckerTest.php new file mode 100644 index 0000000000000..3ec2ded413bbb --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Helper/AttributeCheckerTest.php @@ -0,0 +1,112 @@ +context = $this->getMockBuilder(Context::class) + ->disableOriginalConstructor() + ->getMock(); + $this->addressMetadataService = $this->getMockForAbstractClass(AddressMetadataInterface::class); + $this->attributeResolver = $this->getMockBuilder(AttributeResolver::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new AttributeChecker( + $this->context, + $this->addressMetadataService, + $this->attributeResolver + ); + } + + /** + * @param bool $isAllowed + * @param bool $isMetadataExists + * @param string $attributeCode + * @param string $formName + * @param array $attributeFormsList + * + * @dataProvider attributeOnFormDataProvider + */ + public function testIsAttributeAllowedOnForm( + $isAllowed, + $isMetadataExists, + $attributeCode, + $formName, + array $attributeFormsList + ) { + $attributeMetadata = null; + if ($isMetadataExists) { + $attributeMetadata = $this->getMockForAbstractClass(AttributeMetadataInterface::class); + $attribute = $this->getMockBuilder(Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $this->attributeResolver->expects($this->once()) + ->method('getModelByAttribute') + ->with(AddressMetadataManagementInterface::ENTITY_TYPE_ADDRESS, $attributeMetadata) + ->willReturn($attribute); + $attribute->expects($this->once()) + ->method('getUsedInForms') + ->willReturn($attributeFormsList); + } + $this->addressMetadataService->expects($this->once()) + ->method('getAttributeMetadata') + ->with($attributeCode) + ->willReturn($attributeMetadata); + + $this->assertEquals($isAllowed, $this->model->isAttributeAllowedOnForm($attributeCode, $formName)); + } + + public function attributeOnFormDataProvider() + { + return [ + 'metadata not exists' => [ + 'isAllowed' => false, + 'isMetadataExists' => false, + 'attributeCode' => 'attribute_code', + 'formName' => 'form_name', + 'attributeFormsList' => [], + ], + 'form not in the list' => [ + 'isAllowed' => false, + 'isMetadataExists' => true, + 'attributeCode' => 'attribute_code', + 'formName' => 'form_name', + 'attributeFormsList' => ['form_1', 'form_2'], + ], + 'allowed' => [ + 'isAllowed' => true, + 'isMetadataExists' => true, + 'attributeCode' => 'attribute_code', + 'formName' => 'form_name', + 'attributeFormsList' => ['form_name', 'form_1', 'form_2'], + ], + ]; + } +} From 00c922a076640407941ae9fd4b13d5af4457d1a0 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 18 Oct 2017 09:50:47 -0500 Subject: [PATCH 175/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- .../{DummyDataProvider.php => DataProvider.php} | 8 ++++---- app/code/Magento/Advertisement/composer.json | 1 - app/code/Magento/Advertisement/etc/module.xml | 1 - .../adminhtml/ui_component/advertisement_notification.xml | 2 +- composer.json | 1 + 5 files changed, 6 insertions(+), 7 deletions(-) rename app/code/Magento/Advertisement/Ui/DataProvider/{DummyDataProvider.php => DataProvider.php} (95%) diff --git a/app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php b/app/code/Magento/Advertisement/Ui/DataProvider/DataProvider.php similarity index 95% rename from app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php rename to app/code/Magento/Advertisement/Ui/DataProvider/DataProvider.php index 7af053190645a..60d374dd6606c 100644 --- a/app/code/Magento/Advertisement/Ui/DataProvider/DummyDataProvider.php +++ b/app/code/Magento/Advertisement/Ui/DataProvider/DataProvider.php @@ -11,9 +11,9 @@ use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; /** - * Class which serves as stub for degenerated UI component. + * Data Provider for the Advertisement Notification UI component. */ -class DummyDataProvider implements DataProviderInterface +class DataProvider implements DataProviderInterface { /** * Search result object. @@ -156,7 +156,7 @@ public function getFieldsMetaInfo($fieldSetName) */ public function getPrimaryFieldName() { - return ''; + return 'advertisement_notification'; } /** @@ -166,7 +166,7 @@ public function getPrimaryFieldName() */ public function getRequestFieldName() { - return ''; + return 'advertisement_notification'; } /** diff --git a/app/code/Magento/Advertisement/composer.json b/app/code/Magento/Advertisement/composer.json index 93660553a3cff..f878bf9f91098 100644 --- a/app/code/Magento/Advertisement/composer.json +++ b/app/code/Magento/Advertisement/composer.json @@ -4,7 +4,6 @@ "require": { "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", "magento/module-backend": "100.2.*", - "magento/module-store": "100.2.*", "magento/framework": "100.2.*" }, "type": "magento2-module", diff --git a/app/code/Magento/Advertisement/etc/module.xml b/app/code/Magento/Advertisement/etc/module.xml index 119951fcc66a8..5db6c24c13cb6 100644 --- a/app/code/Magento/Advertisement/etc/module.xml +++ b/app/code/Magento/Advertisement/etc/module.xml @@ -9,7 +9,6 @@ - diff --git a/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml index 98d94eaef6ef0..cb57f3d7eadb6 100644 --- a/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml +++ b/app/code/Magento/Advertisement/view/adminhtml/ui_component/advertisement_notification.xml @@ -28,7 +28,7 @@ Magento_Ui/js/form/provider - + false diff --git a/composer.json b/composer.json index ca0e2b7f7f681..37e9c3d481d81 100644 --- a/composer.json +++ b/composer.json @@ -85,6 +85,7 @@ "magento/module-marketplace": "100.2.0", "magento/module-admin-notification": "100.2.0", "magento/module-advanced-pricing-import-export": "100.2.0", + "magento/module-advertisement": "100.2.0-dev", "magento/module-analytics": "100.2.0-dev", "magento/module-authorization": "100.2.0", "magento/module-authorizenet": "100.2.0", From 0f682c5f1dca5142b32e9b887b4e6dda192e5f80 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 18 Oct 2017 11:16:27 -0500 Subject: [PATCH 176/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- app/code/Magento/Advertisement/composer.json | 2 +- composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Advertisement/composer.json b/app/code/Magento/Advertisement/composer.json index f878bf9f91098..307b862a0b649 100644 --- a/app/code/Magento/Advertisement/composer.json +++ b/app/code/Magento/Advertisement/composer.json @@ -7,7 +7,7 @@ "magento/framework": "100.2.*" }, "type": "magento2-module", - "version": "100.2.0-dev", + "version": "100.2.0", "license": [ "OSL-3.0", "AFL-3.0" diff --git a/composer.json b/composer.json index 37e9c3d481d81..b4104c3a4f046 100644 --- a/composer.json +++ b/composer.json @@ -85,7 +85,7 @@ "magento/module-marketplace": "100.2.0", "magento/module-admin-notification": "100.2.0", "magento/module-advanced-pricing-import-export": "100.2.0", - "magento/module-advertisement": "100.2.0-dev", + "magento/module-advertisement": "100.2.0", "magento/module-analytics": "100.2.0-dev", "magento/module-authorization": "100.2.0", "magento/module-authorizenet": "100.2.0", From 7b7c78126b3ed70173aca807b4c14b5799f6a19d Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Wed, 18 Oct 2017 11:35:38 -0500 Subject: [PATCH 177/528] MAGETWO-80484: Create a module can have all the content in prototype if it is 2.2.2 --- composer.lock | 352 +++++++++++++++++++++++++------------------------- 1 file changed, 177 insertions(+), 175 deletions(-) diff --git a/composer.lock b/composer.lock index 52d00b3c5f544..11affe4e33322 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "0b1cc5912e2f422e953f6c4730434184", - "content-hash": "f42e69962756dd0af696c5611435ceec", + "content-hash": "ceca746323861f0ac218785a26d12193", "packages": [ { "name": "braintree/braintree_php", @@ -52,7 +51,7 @@ } ], "description": "Braintree PHP Client Library", - "time": "2017-02-16 19:59:04" + "time": "2017-02-16T19:59:04+00:00" }, { "name": "colinmollenhour/cache-backend-file", @@ -88,7 +87,7 @@ ], "description": "The stock Zend_Cache_Backend_File backend has extremely poor performance for cleaning by tags making it become unusable as the number of cached items increases. This backend makes many changes resulting in a huge performance boost, especially for tag cleaning.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_File", - "time": "2016-05-02 16:24:47" + "time": "2016-05-02T16:24:47+00:00" }, { "name": "colinmollenhour/cache-backend-redis", @@ -124,7 +123,7 @@ ], "description": "Zend_Cache backend using Redis with full support for tags.", "homepage": "https://github.com/colinmollenhour/Cm_Cache_Backend_Redis", - "time": "2017-03-25 04:54:24" + "time": "2017-03-25T04:54:24+00:00" }, { "name": "colinmollenhour/credis", @@ -164,7 +163,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2017-07-05 15:32:38" + "time": "2017-07-05T15:32:38+00:00" }, { "name": "colinmollenhour/php-redis-session-abstract", @@ -201,7 +200,7 @@ ], "description": "A Redis-based session handler with optimistic locking", "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", - "time": "2017-03-22 16:13:03" + "time": "2017-03-22T16:13:03+00:00" }, { "name": "composer/ca-bundle", @@ -260,7 +259,7 @@ "ssl", "tls" ], - "time": "2017-09-11 07:24:36" + "time": "2017-09-11T07:24:36+00:00" }, { "name": "composer/composer", @@ -337,7 +336,7 @@ "dependency", "package" ], - "time": "2017-03-10 08:29:45" + "time": "2017-03-10T08:29:45+00:00" }, { "name": "composer/semver", @@ -399,7 +398,7 @@ "validation", "versioning" ], - "time": "2016-08-30 16:08:34" + "time": "2016-08-30T16:08:34+00:00" }, { "name": "composer/spdx-licenses", @@ -460,7 +459,7 @@ "spdx", "validator" ], - "time": "2017-04-03 19:08:52" + "time": "2017-04-03T19:08:52+00:00" }, { "name": "container-interop/container-interop", @@ -491,7 +490,7 @@ ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "homepage": "https://github.com/container-interop/container-interop", - "time": "2017-02-14 19:40:03" + "time": "2017-02-14T19:40:03+00:00" }, { "name": "justinrainbow/json-schema", @@ -557,7 +556,7 @@ "json", "schema" ], - "time": "2017-10-10 13:22:37" + "time": "2017-10-10T13:22:37+00:00" }, { "name": "league/climate", @@ -606,7 +605,7 @@ "php", "terminal" ], - "time": "2015-01-18 14:31:58" + "time": "2015-01-18T14:31:58+00:00" }, { "name": "magento/composer", @@ -642,7 +641,7 @@ "AFL-3.0" ], "description": "Magento composer library helps to instantiate Composer application and run composer commands.", - "time": "2017-04-24 09:57:02" + "time": "2017-04-24T09:57:02+00:00" }, { "name": "magento/magento-composer-installer", @@ -721,7 +720,7 @@ "composer-installer", "magento" ], - "time": "2016-10-06 16:05:07" + "time": "2016-10-06T16:05:07+00:00" }, { "name": "magento/zendframework1", @@ -768,7 +767,7 @@ "ZF1", "framework" ], - "time": "2017-06-21 14:56:23" + "time": "2017-06-21T14:56:23+00:00" }, { "name": "monolog/monolog", @@ -846,7 +845,7 @@ "logging", "psr-3" ], - "time": "2017-06-19 01:22:40" + "time": "2017-06-19T01:22:40+00:00" }, { "name": "oyejorge/less.php", @@ -908,7 +907,7 @@ "php", "stylesheet" ], - "time": "2017-03-28 22:19:25" + "time": "2017-03-28T22:19:25+00:00" }, { "name": "paragonie/random_compat", @@ -956,7 +955,7 @@ "pseudorandom", "random" ], - "time": "2017-09-27 21:40:39" + "time": "2017-09-27T21:40:39+00:00" }, { "name": "pelago/emogrifier", @@ -1012,7 +1011,7 @@ ], "description": "Converts CSS styles into inline style attributes in your HTML code", "homepage": "http://www.pelagodesign.com/sidecar/emogrifier/", - "time": "2015-05-15 11:37:51" + "time": "2015-05-15T11:37:51+00:00" }, { "name": "phpseclib/phpseclib", @@ -1104,7 +1103,7 @@ "x.509", "x509" ], - "time": "2017-06-05 06:31:10" + "time": "2017-06-05T06:31:10+00:00" }, { "name": "psr/container", @@ -1153,7 +1152,7 @@ "container-interop", "psr" ], - "time": "2017-02-14 16:28:37" + "time": "2017-02-14T16:28:37+00:00" }, { "name": "psr/log", @@ -1200,7 +1199,7 @@ "psr", "psr-3" ], - "time": "2016-10-10 12:19:37" + "time": "2016-10-10T12:19:37+00:00" }, { "name": "ramsey/uuid", @@ -1282,7 +1281,7 @@ "identifier", "uuid" ], - "time": "2017-03-26 20:37:53" + "time": "2017-03-26T20:37:53+00:00" }, { "name": "seld/cli-prompt", @@ -1330,7 +1329,7 @@ "input", "prompt" ], - "time": "2017-03-18 11:32:45" + "time": "2017-03-18T11:32:45+00:00" }, { "name": "seld/jsonlint", @@ -1379,7 +1378,7 @@ "parser", "validator" ], - "time": "2017-06-18 15:11:04" + "time": "2017-06-18T15:11:04+00:00" }, { "name": "seld/phar-utils", @@ -1423,7 +1422,7 @@ "keywords": [ "phra" ], - "time": "2015-10-13 18:44:15" + "time": "2015-10-13T18:44:15+00:00" }, { "name": "sjparkinson/static-review", @@ -1476,7 +1475,7 @@ } ], "description": "An extendable framework for version control hooks.", - "time": "2014-09-22 08:40:36" + "time": "2014-09-22T08:40:36+00:00" }, { "name": "symfony/console", @@ -1537,7 +1536,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2017-10-01 21:00:16" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "symfony/debug", @@ -1594,7 +1593,7 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2016-07-30 07:22:48" + "time": "2016-07-30T07:22:48+00:00" }, { "name": "symfony/event-dispatcher", @@ -1654,7 +1653,7 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-10-01 21:00:16" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "symfony/filesystem", @@ -1703,7 +1702,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-10-03 13:33:10" + "time": "2017-10-03T13:33:10+00:00" }, { "name": "symfony/finder", @@ -1752,20 +1751,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2017-10-02 06:42:24" + "time": "2017-10-02T06:42:24+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803" + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803", - "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", + "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296", "shasum": "" }, "require": { @@ -1777,7 +1776,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -1811,7 +1810,7 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/process", @@ -1860,7 +1859,7 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-10-01 21:00:16" + "time": "2017-10-01T21:00:16+00:00" }, { "name": "tedivm/jshrink", @@ -1906,7 +1905,7 @@ "javascript", "minifier" ], - "time": "2015-07-04 07:35:09" + "time": "2015-07-04T07:35:09+00:00" }, { "name": "tubalmartin/cssmin", @@ -1959,7 +1958,7 @@ "minify", "yui" ], - "time": "2017-05-16 13:45:26" + "time": "2017-05-16T13:45:26+00:00" }, { "name": "zendframework/zend-captcha", @@ -2016,31 +2015,31 @@ "captcha", "zf2" ], - "time": "2017-02-23 08:09:44" + "time": "2017-02-23T08:09:44+00:00" }, { "name": "zendframework/zend-code", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-code.git", - "reference": "2899c17f83a7207f2d7f53ec2f421204d3beea27" + "reference": "02944646c109fa53b6b6ab8b5269bb080fcdf5b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-code/zipball/2899c17f83a7207f2d7f53ec2f421204d3beea27", - "reference": "2899c17f83a7207f2d7f53ec2f421204d3beea27", + "url": "https://api.github.com/repos/zendframework/zend-code/zipball/02944646c109fa53b6b6ab8b5269bb080fcdf5b4", + "reference": "02944646c109fa53b6b6ab8b5269bb080fcdf5b4", "shasum": "" }, "require": { - "php": "^5.6 || 7.0.0 - 7.0.4 || ^7.0.6", + "php": "^7.1", "zendframework/zend-eventmanager": "^2.6 || ^3.0" }, "require-dev": { "doctrine/annotations": "~1.0", "ext-phar": "*", - "phpunit/phpunit": "^4.8.21", - "squizlabs/php_codesniffer": "^2.5", + "phpunit/phpunit": "^6.2.3", + "zendframework/zend-coding-standard": "^1.0.0", "zendframework/zend-stdlib": "^2.7 || ^3.0" }, "suggest": { @@ -2050,8 +2049,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev", - "dev-develop": "3.2-dev" + "dev-master": "3.2-dev", + "dev-develop": "3.3-dev" } }, "autoload": { @@ -2069,7 +2068,7 @@ "code", "zf2" ], - "time": "2016-10-24 13:23:32" + "time": "2017-07-23T13:06:00+00:00" }, { "name": "zendframework/zend-config", @@ -2125,7 +2124,7 @@ "config", "zf2" ], - "time": "2016-02-04 23:01:10" + "time": "2016-02-04T23:01:10+00:00" }, { "name": "zendframework/zend-console", @@ -2177,7 +2176,7 @@ "console", "zf2" ], - "time": "2016-02-09 17:15:12" + "time": "2016-02-09T17:15:12+00:00" }, { "name": "zendframework/zend-crypt", @@ -2227,7 +2226,7 @@ "crypt", "zf2" ], - "time": "2016-02-03 23:46:30" + "time": "2016-02-03T23:46:30+00:00" }, { "name": "zendframework/zend-db", @@ -2284,7 +2283,7 @@ "db", "zf2" ], - "time": "2016-08-09 19:28:55" + "time": "2016-08-09T19:28:55+00:00" }, { "name": "zendframework/zend-di", @@ -2331,7 +2330,7 @@ "di", "zf2" ], - "time": "2016-04-25 20:58:11" + "time": "2016-04-25T20:58:11+00:00" }, { "name": "zendframework/zend-escaper", @@ -2375,7 +2374,7 @@ "escaper", "zf2" ], - "time": "2016-06-30 19:48:38" + "time": "2016-06-30T19:48:38+00:00" }, { "name": "zendframework/zend-eventmanager", @@ -2422,7 +2421,7 @@ "eventmanager", "zf2" ], - "time": "2016-02-18 20:49:05" + "time": "2016-02-18T20:49:05+00:00" }, { "name": "zendframework/zend-filter", @@ -2482,7 +2481,7 @@ "filter", "zf2" ], - "time": "2017-05-17 20:56:17" + "time": "2017-05-17T20:56:17+00:00" }, { "name": "zendframework/zend-form", @@ -2559,39 +2558,39 @@ "form", "zf2" ], - "time": "2017-05-18 14:59:53" + "time": "2017-05-18T14:59:53+00:00" }, { "name": "zendframework/zend-http", - "version": "2.6.0", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/zendframework/zend-http.git", - "reference": "09f4d279f46d86be63171ff62ee0f79eca878678" + "reference": "78aa510c0ea64bfb2aa234f50c4f232c9531acfa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-http/zipball/09f4d279f46d86be63171ff62ee0f79eca878678", - "reference": "09f4d279f46d86be63171ff62ee0f79eca878678", + "url": "https://api.github.com/repos/zendframework/zend-http/zipball/78aa510c0ea64bfb2aa234f50c4f232c9531acfa", + "reference": "78aa510c0ea64bfb2aa234f50c4f232c9531acfa", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "zendframework/zend-loader": "^2.5", - "zendframework/zend-stdlib": "^2.5 || ^3.0", - "zendframework/zend-uri": "^2.5", - "zendframework/zend-validator": "^2.5" + "php": "^5.6 || ^7.0", + "zendframework/zend-loader": "^2.5.1", + "zendframework/zend-stdlib": "^3.1 || ^2.7.7", + "zendframework/zend-uri": "^2.5.2", + "zendframework/zend-validator": "^2.10.1" }, "require-dev": { - "phpunit/phpunit": "^4.0", + "phpunit/phpunit": "^6.4.1 || ^5.7.15", "zendframework/zend-coding-standard": "~1.0.0", - "zendframework/zend-config": "^2.5" + "zendframework/zend-config": "^3.1 || ^2.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.6-dev", - "dev-develop": "2.7-dev" + "dev-master": "2.7-dev", + "dev-develop": "2.8-dev" } }, "autoload": { @@ -2606,10 +2605,13 @@ "description": "provides an easy interface for performing Hyper-Text Transfer Protocol (HTTP) requests", "homepage": "https://github.com/zendframework/zend-http", "keywords": [ + "ZendFramework", "http", - "zf2" + "http client", + "zend", + "zf" ], - "time": "2017-01-31 14:41:02" + "time": "2017-10-13T12:06:24+00:00" }, { "name": "zendframework/zend-hydrator", @@ -2667,7 +2669,7 @@ "hydrator", "zf2" ], - "time": "2016-02-18 22:38:26" + "time": "2016-02-18T22:38:26+00:00" }, { "name": "zendframework/zend-i18n", @@ -2734,7 +2736,7 @@ "i18n", "zf2" ], - "time": "2017-05-17 17:00:12" + "time": "2017-05-17T17:00:12+00:00" }, { "name": "zendframework/zend-inputfilter", @@ -2789,7 +2791,7 @@ "inputfilter", "zf2" ], - "time": "2017-05-18 14:20:56" + "time": "2017-05-18T14:20:56+00:00" }, { "name": "zendframework/zend-json", @@ -2844,7 +2846,7 @@ "json", "zf2" ], - "time": "2016-02-04 21:20:26" + "time": "2016-02-04T21:20:26+00:00" }, { "name": "zendframework/zend-loader", @@ -2888,7 +2890,7 @@ "loader", "zf2" ], - "time": "2015-06-03 14:05:47" + "time": "2015-06-03T14:05:47+00:00" }, { "name": "zendframework/zend-log", @@ -2959,7 +2961,7 @@ "logging", "zf2" ], - "time": "2017-05-17 16:03:26" + "time": "2017-05-17T16:03:26+00:00" }, { "name": "zendframework/zend-math", @@ -3009,7 +3011,7 @@ "math", "zf2" ], - "time": "2016-04-07 16:29:53" + "time": "2016-04-07T16:29:53+00:00" }, { "name": "zendframework/zend-modulemanager", @@ -3067,7 +3069,7 @@ "modulemanager", "zf2" ], - "time": "2017-07-11 19:39:57" + "time": "2017-07-11T19:39:57+00:00" }, { "name": "zendframework/zend-mvc", @@ -3154,7 +3156,7 @@ "mvc", "zf2" ], - "time": "2016-02-23 15:24:59" + "time": "2016-02-23T15:24:59+00:00" }, { "name": "zendframework/zend-serializer", @@ -3211,7 +3213,7 @@ "serializer", "zf2" ], - "time": "2016-06-21 17:01:55" + "time": "2016-06-21T17:01:55+00:00" }, { "name": "zendframework/zend-server", @@ -3257,7 +3259,7 @@ "server", "zf2" ], - "time": "2016-06-20 22:27:55" + "time": "2016-06-20T22:27:55+00:00" }, { "name": "zendframework/zend-servicemanager", @@ -3309,7 +3311,7 @@ "servicemanager", "zf2" ], - "time": "2016-12-19 19:14:29" + "time": "2016-12-19T19:14:29+00:00" }, { "name": "zendframework/zend-session", @@ -3375,7 +3377,7 @@ "session", "zf2" ], - "time": "2017-06-19 21:31:39" + "time": "2017-06-19T21:31:39+00:00" }, { "name": "zendframework/zend-soap", @@ -3427,7 +3429,7 @@ "soap", "zf2" ], - "time": "2016-04-21 16:06:27" + "time": "2016-04-21T16:06:27+00:00" }, { "name": "zendframework/zend-stdlib", @@ -3486,7 +3488,7 @@ "stdlib", "zf2" ], - "time": "2016-04-12 21:17:31" + "time": "2016-04-12T21:17:31+00:00" }, { "name": "zendframework/zend-text", @@ -3533,7 +3535,7 @@ "text", "zf2" ], - "time": "2016-02-08 19:03:52" + "time": "2016-02-08T19:03:52+00:00" }, { "name": "zendframework/zend-uri", @@ -3580,7 +3582,7 @@ "uri", "zf2" ], - "time": "2016-02-17 22:38:51" + "time": "2016-02-17T22:38:51+00:00" }, { "name": "zendframework/zend-validator", @@ -3651,7 +3653,7 @@ "validator", "zf2" ], - "time": "2017-08-22 14:19:23" + "time": "2017-08-22T14:19:23+00:00" }, { "name": "zendframework/zend-view", @@ -3738,38 +3740,38 @@ "view", "zf2" ], - "time": "2017-03-21 15:05:56" + "time": "2017-03-21T15:05:56+00:00" } ], "packages-dev": [ { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -3794,7 +3796,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14 21:17:01" + "time": "2017-07-22T11:58:36+00:00" }, { "name": "friendsofphp/php-cs-fixer", @@ -3864,7 +3866,7 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2017-03-31 12:59:38" + "time": "2017-03-31T12:59:38+00:00" }, { "name": "ircmaxell/password-compat", @@ -3906,7 +3908,7 @@ "hashing", "password" ], - "time": "2014-11-20 16:49:30" + "time": "2014-11-20T16:49:30+00:00" }, { "name": "lusitanian/oauth", @@ -3973,7 +3975,7 @@ "oauth", "security" ], - "time": "2016-07-12 22:15:40" + "time": "2016-07-12T22:15:40+00:00" }, { "name": "myclabs/deep-copy", @@ -4015,7 +4017,7 @@ "object", "object graph" ], - "time": "2017-04-12 18:52:22" + "time": "2017-04-12T18:52:22+00:00" }, { "name": "pdepend/pdepend", @@ -4055,7 +4057,7 @@ "BSD-3-Clause" ], "description": "Official version of pdepend to be handled with Composer", - "time": "2017-01-19 14:23:36" + "time": "2017-01-19T14:23:36+00:00" }, { "name": "phar-io/manifest", @@ -4110,7 +4112,7 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-03-05 18:14:27" + "time": "2017-03-05T18:14:27+00:00" }, { "name": "phar-io/version", @@ -4157,7 +4159,7 @@ } ], "description": "Library for handling version information and constraints", - "time": "2017-03-05 17:38:23" + "time": "2017-03-05T17:38:23+00:00" }, { "name": "phpdocumentor/reflection-common", @@ -4211,7 +4213,7 @@ "reflection", "static analysis" ], - "time": "2017-09-11 18:02:19" + "time": "2017-09-11T18:02:19+00:00" }, { "name": "phpdocumentor/reflection-docblock", @@ -4256,7 +4258,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-08-30 18:51:59" + "time": "2017-08-30T18:51:59+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -4303,7 +4305,7 @@ "email": "me@mikevanriel.com" } ], - "time": "2017-07-14 14:27:02" + "time": "2017-07-14T14:27:02+00:00" }, { "name": "phpmd/phpmd", @@ -4369,7 +4371,7 @@ "phpmd", "pmd" ], - "time": "2017-01-20 14:41:10" + "time": "2017-01-20T14:41:10+00:00" }, { "name": "phpspec/prophecy", @@ -4432,7 +4434,7 @@ "spy", "stub" ], - "time": "2017-09-04 11:05:03" + "time": "2017-09-04T11:05:03+00:00" }, { "name": "phpunit/php-code-coverage", @@ -4496,7 +4498,7 @@ "testing", "xunit" ], - "time": "2017-08-03 12:40:43" + "time": "2017-08-03T12:40:43+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4543,7 +4545,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03 07:40:28" + "time": "2016-10-03T07:40:28+00:00" }, { "name": "phpunit/php-text-template", @@ -4584,7 +4586,7 @@ "keywords": [ "template" ], - "time": "2015-06-21 13:50:34" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", @@ -4633,7 +4635,7 @@ "keywords": [ "timer" ], - "time": "2017-02-26 11:10:40" + "time": "2017-02-26T11:10:40+00:00" }, { "name": "phpunit/php-token-stream", @@ -4682,7 +4684,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20 05:47:52" + "time": "2017-08-20T05:47:52+00:00" }, { "name": "phpunit/phpunit", @@ -4766,7 +4768,7 @@ "testing", "xunit" ], - "time": "2017-08-03 13:59:28" + "time": "2017-08-03T13:59:28+00:00" }, { "name": "phpunit/phpunit-mock-objects", @@ -4825,7 +4827,7 @@ "mock", "xunit" ], - "time": "2017-08-03 14:08:16" + "time": "2017-08-03T14:08:16+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -4870,7 +4872,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04 06:30:41" + "time": "2017-03-04T06:30:41+00:00" }, { "name": "sebastian/comparator", @@ -4934,7 +4936,7 @@ "compare", "equality" ], - "time": "2017-03-03 06:26:08" + "time": "2017-03-03T06:26:08+00:00" }, { "name": "sebastian/diff", @@ -4986,7 +4988,7 @@ "keywords": [ "diff" ], - "time": "2017-05-22 07:24:03" + "time": "2017-05-22T07:24:03+00:00" }, { "name": "sebastian/environment", @@ -5036,7 +5038,7 @@ "environment", "hhvm" ], - "time": "2017-07-01 08:51:00" + "time": "2017-07-01T08:51:00+00:00" }, { "name": "sebastian/exporter", @@ -5103,7 +5105,7 @@ "export", "exporter" ], - "time": "2017-04-03 13:19:02" + "time": "2017-04-03T13:19:02+00:00" }, { "name": "sebastian/finder-facade", @@ -5142,7 +5144,7 @@ ], "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.", "homepage": "https://github.com/sebastianbergmann/finder-facade", - "time": "2016-02-17 07:02:23" + "time": "2016-02-17T07:02:23+00:00" }, { "name": "sebastian/global-state", @@ -5193,7 +5195,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27 15:39:26" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", @@ -5240,7 +5242,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03 12:35:26" + "time": "2017-08-03T12:35:26+00:00" }, { "name": "sebastian/object-reflector", @@ -5285,7 +5287,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29 09:07:27" + "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/phpcpd", @@ -5336,7 +5338,7 @@ ], "description": "Copy/Paste Detector (CPD) for PHP code.", "homepage": "https://github.com/sebastianbergmann/phpcpd", - "time": "2016-04-17 19:32:49" + "time": "2016-04-17T19:32:49+00:00" }, { "name": "sebastian/recursion-context", @@ -5389,7 +5391,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03 06:23:57" + "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", @@ -5431,7 +5433,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2015-07-28 20:34:47" + "time": "2015-07-28T20:34:47+00:00" }, { "name": "sebastian/version", @@ -5474,7 +5476,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03 07:35:21" + "time": "2016-10-03T07:35:21+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -5525,7 +5527,7 @@ "phpcs", "standards" ], - "time": "2017-06-14 01:23:49" + "time": "2017-06-14T01:23:49+00:00" }, { "name": "symfony/config", @@ -5587,7 +5589,7 @@ ], "description": "Symfony Config Component", "homepage": "https://symfony.com", - "time": "2017-10-04 18:56:58" + "time": "2017-10-04T18:56:58+00:00" }, { "name": "symfony/dependency-injection", @@ -5657,20 +5659,20 @@ ], "description": "Symfony DependencyInjection Component", "homepage": "https://symfony.com", - "time": "2017-10-04 17:15:30" + "time": "2017-10-04T17:15:30+00:00" }, { "name": "symfony/polyfill-php54", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php54.git", - "reference": "b7763422a5334c914ef0298ed21b253d25913a6e" + "reference": "d7810a14b2c6c1aff415e1bb755f611b3d5327bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/b7763422a5334c914ef0298ed21b253d25913a6e", - "reference": "b7763422a5334c914ef0298ed21b253d25913a6e", + "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/d7810a14b2c6c1aff415e1bb755f611b3d5327bc", + "reference": "d7810a14b2c6c1aff415e1bb755f611b3d5327bc", "shasum": "" }, "require": { @@ -5679,7 +5681,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5715,20 +5717,20 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-php55", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "29b1381d66f16e0581aab0b9f678ccf073288f68" + "reference": "b64e7f0c37ecf144ecc16668936eef94e628fbfd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/29b1381d66f16e0581aab0b9f678ccf073288f68", - "reference": "29b1381d66f16e0581aab0b9f678ccf073288f68", + "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/b64e7f0c37ecf144ecc16668936eef94e628fbfd", + "reference": "b64e7f0c37ecf144ecc16668936eef94e628fbfd", "shasum": "" }, "require": { @@ -5738,7 +5740,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5771,20 +5773,20 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "b6482e68974486984f59449ecea1fbbb22ff840f" + "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/b6482e68974486984f59449ecea1fbbb22ff840f", - "reference": "b6482e68974486984f59449ecea1fbbb22ff840f", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff", + "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff", "shasum": "" }, "require": { @@ -5794,7 +5796,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5830,20 +5832,20 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "8abc9097f5001d310f0edba727469c988acc6ea7" + "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/8abc9097f5001d310f0edba727469c988acc6ea7", - "reference": "8abc9097f5001d310f0edba727469c988acc6ea7", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/6de4f4884b97abbbed9f0a84a95ff2ff77254254", + "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254", "shasum": "" }, "require": { @@ -5852,7 +5854,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -5885,20 +5887,20 @@ "portable", "shim" ], - "time": "2017-07-11 13:25:55" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/polyfill-xml", - "version": "v1.5.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-xml.git", - "reference": "7d536462e554da7b05600a926303bf9b99153275" + "reference": "d7bcb5c3bb1832c532379df50825c08f43a64134" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-xml/zipball/7d536462e554da7b05600a926303bf9b99153275", - "reference": "7d536462e554da7b05600a926303bf9b99153275", + "url": "https://api.github.com/repos/symfony/polyfill-xml/zipball/d7bcb5c3bb1832c532379df50825c08f43a64134", + "reference": "d7bcb5c3bb1832c532379df50825c08f43a64134", "shasum": "" }, "require": { @@ -5908,7 +5910,7 @@ "type": "metapackage", "extra": { "branch-alias": { - "dev-master": "1.5-dev" + "dev-master": "1.6-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -5933,7 +5935,7 @@ "portable", "shim" ], - "time": "2017-06-14 15:44:48" + "time": "2017-10-11T12:05:26+00:00" }, { "name": "symfony/stopwatch", @@ -5982,7 +5984,7 @@ ], "description": "Symfony Stopwatch Component", "homepage": "https://symfony.com", - "time": "2017-10-02 06:42:24" + "time": "2017-10-02T06:42:24+00:00" }, { "name": "theseer/fdomdocument", @@ -6022,7 +6024,7 @@ ], "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.", "homepage": "https://github.com/theseer/fDOMDocument", - "time": "2017-06-30 11:53:12" + "time": "2017-06-30T11:53:12+00:00" }, { "name": "theseer/tokenizer", @@ -6062,7 +6064,7 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07 12:08:54" + "time": "2017-04-07T12:08:54+00:00" }, { "name": "webmozart/assert", @@ -6112,7 +6114,7 @@ "check", "validate" ], - "time": "2016-11-23 20:04:58" + "time": "2016-11-23T20:04:58+00:00" } ], "aliases": [], From b1a0181d4148c6f994ad85c7e2f4f8b762fc6a3f Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Wed, 18 Oct 2017 19:42:43 +0300 Subject: [PATCH 178/528] Sync billing with shipping address on Admin Order Page - Fixed skipped 'Same as billing' checkbox --- .../Magento/Sales/view/adminhtml/web/order/create/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 302c615e68855..8e25584627d3b 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -223,6 +223,7 @@ define([ } data['order[' + type + '_address][customer_address_id]'] = null; + data['shipping_as_billing'] = jQuery('[name="shipping_same_as_billing"]').is(':checked') ? 1 : 0; if (name === 'customer_address_id') { data['order[' + type + '_address][customer_address_id]'] = From ed52dc9b33ac855df73075334b26b657a87e2489 Mon Sep 17 00:00:00 2001 From: Todd Christensen Date: Wed, 18 Oct 2017 18:20:47 -0700 Subject: [PATCH 179/528] Correct flat indexing with staging and > 500 cats. Previously, the array was prefilled with entity_id values to ensure those categories were indexed. Unfortunately, when using row_id, it was using entity_ids. When chunking at 500, this could cause an overlapping row to be processed twice (the second time with missing non-static attributes), and cause a duplicate key error. --- .../Indexer/Category/Flat/AbstractAction.php | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php index 24d81f0054c5a..c5efbc619694a 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/AbstractAction.php @@ -369,9 +369,11 @@ protected function getAttributeValues($entityIds, $storeId) } $values = []; - foreach ($entityIds as $entityId) { - $values[$entityId] = []; + $linkIds = $this->getLinkIds($entityIds); + foreach ($linkIds as $linkId) { + $values[$linkId] = []; } + $attributes = $this->getAttributes(); $attributesType = ['varchar', 'int', 'decimal', 'text', 'datetime']; foreach ($attributesType as $type) { @@ -385,9 +387,36 @@ protected function getAttributeValues($entityIds, $storeId) } } } + return $values; } + /** + * Translate entity ids into link ids + * + * Used for rows with no EAV attributes set. + * + * @param array $entityIds + * @return array + */ + private function getLinkIds(array $entityIds) + { + $linkField = $this->getCategoryMetadata()->getLinkField(); + if ($linkField === 'entity_id') { + return $entityIds; + } + + $select = $this->connection->select()->from( + ['e' => $this->connection->getTableName($this->getTableName('catalog_category_entity'))], + [$linkField] + )->where( + 'e.entity_id IN (?)', + $entityIds + ); + + return $this->connection->fetchCol($select); + } + /** * Return attribute values for given entities and store of specific attribute type * From 9380c95ba8a12eac0f57b92a682b932b1ceb6a1f Mon Sep 17 00:00:00 2001 From: Anton Evers Date: Thu, 19 Oct 2017 13:14:58 +0600 Subject: [PATCH 180/528] Even existing credit memos should be refundable if their state is open Credit memos can have the state open: `\Magento\Sales\Model\Order\Creditmemo::STATE_OPEN`. This means that it is possible to have a creditmemo with an ID which still has to be refunded. I'm creating a module that introduces a validation step for refund payments before the actual refund can take place. It uses the open state of credit memos to wait for approval and then refunds the creditmemo. Right now the credit memo is not refundable once it has an ID. I think this is incorrect in case of open credit memos. --- app/code/Magento/Sales/Model/Service/CreditmemoService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Service/CreditmemoService.php b/app/code/Magento/Sales/Model/Service/CreditmemoService.php index 2f08c26de9058..c7541e6cb7e48 100644 --- a/app/code/Magento/Sales/Model/Service/CreditmemoService.php +++ b/app/code/Magento/Sales/Model/Service/CreditmemoService.php @@ -195,7 +195,7 @@ public function refund( */ protected function validateForRefund(\Magento\Sales\Api\Data\CreditmemoInterface $creditmemo) { - if ($creditmemo->getId()) { + if ($creditmemo->getId() && $creditmemo->getState() !== \Magento\Sales\Model\Order\Creditmemo::STATE_OPEN) { throw new \Magento\Framework\Exception\LocalizedException( __('We cannot register an existing credit memo.') ); From 3b50751687f873a645b914194228e0006fa1cb1b Mon Sep 17 00:00:00 2001 From: Oleksii Korshenko Date: Wed, 18 Oct 2017 14:58:47 -0400 Subject: [PATCH 181/528] MAGETWO-82202: ProductRepository sku cache is corrupted when cacheLimit is reached #11537 --- app/code/Magento/Catalog/Model/ProductRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php index 4a72539e982f2..4927a19146723 100644 --- a/app/code/Magento/Catalog/Model/ProductRepository.php +++ b/app/code/Magento/Catalog/Model/ProductRepository.php @@ -312,7 +312,7 @@ private function cacheProduct($cacheKey, \Magento\Catalog\Api\Data\ProductInterf if ($this->cacheLimit && count($this->instances) > $this->cacheLimit) { $offset = round($this->cacheLimit / -2); $this->instancesById = array_slice($this->instancesById, $offset, null, true); - $this->instances = array_slice($this->instances, $offset); + $this->instances = array_slice($this->instances, $offset, null, true); } } From 8f50585d954c7e5f617050ba8367f373c00ead8a Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko Date: Thu, 19 Oct 2017 13:44:51 +0300 Subject: [PATCH 182/528] MAGETWO-66532: [FT] Magento\UrlRewrite\Test\TestCase\CreateProductWithSeveralWebsitesUrlRewriteTest randomly fails on Jenkins --- .../TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml index 91de39b384c35..98e3f9e38382d 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductWithSeveralWebsitesUrlRewriteTest.xml @@ -8,7 +8,6 @@ - stable:no simple-product-%isolation% Simple Product %isolation% simple_sku_%isolation% From 56f5cfc590bcf9f10ad5f63d671891ef1f37722d Mon Sep 17 00:00:00 2001 From: Ievgen Shakhsuvarov Date: Fri, 1 Sep 2017 11:32:12 +0300 Subject: [PATCH 183/528] Travis CI functional tests maintenance for 2.2-develop --- .travis.yml | 7 +- .../InjectableTests/travis_acceptance.xml | 27 ++++++++ .../InjectableTests/travis_acceptance_1.xml | 67 ------------------- .../InjectableTests/travis_acceptance_2.xml | 67 ------------------- dev/travis/before_script.sh | 2 +- 5 files changed, 30 insertions(+), 140 deletions(-) create mode 100644 dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance.xml delete mode 100644 dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml delete mode 100644 dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_2.xml diff --git a/.travis.yml b/.travis.yml index 42c2bcab0c901..9adce44fe6734 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,8 +29,7 @@ env: - TEST_SUITE=integration INTEGRATION_INDEX=1 - TEST_SUITE=integration INTEGRATION_INDEX=2 - TEST_SUITE=integration INTEGRATION_INDEX=3 - - TEST_SUITE=functional ACCEPTANCE_INDEX=1 - - TEST_SUITE=functional ACCEPTANCE_INDEX=2 + - TEST_SUITE=functional matrix: exclude: - php: 7.0 @@ -40,9 +39,7 @@ matrix: - php: 7.0 env: TEST_SUITE=js GRUNT_COMMAND=static - php: 7.0 - env: TEST_SUITE=functional ACCEPTANCE_INDEX=1 - - php: 7.0 - env: TEST_SUITE=functional ACCEPTANCE_INDEX=2 + env: TEST_SUITE=functional cache: apt: true directories: diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance.xml new file mode 100644 index 0000000000000..3eec40244c7ec --- /dev/null +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml deleted file mode 100644 index 716a6dd89a61f..0000000000000 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_1.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_2.xml b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_2.xml deleted file mode 100644 index ce3f79f2923d9..0000000000000 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests/travis_acceptance_2.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dev/travis/before_script.sh b/dev/travis/before_script.sh index e72e01dfaccd3..0e8cc26e154df 100755 --- a/dev/travis/before_script.sh +++ b/dev/travis/before_script.sh @@ -126,7 +126,7 @@ case $TEST_SUITE in cp ./phpunit.xml.dist ./phpunit.xml sed -e "s?127.0.0.1?${MAGENTO_HOST_NAME}?g" --in-place ./phpunit.xml - sed -e "s?basic?travis_acceptance_${ACCEPTANCE_INDEX}?g" --in-place ./phpunit.xml + sed -e "s?basic?travis_acceptance?g" --in-place ./phpunit.xml cp ./.htaccess.sample ./.htaccess cd ./utils php -f mtf troubleshooting:check-all From 09c6b1eaf04b6c9f17447ccfb3c6deb206985c38 Mon Sep 17 00:00:00 2001 From: Cristian Sanclemente Date: Thu, 19 Oct 2017 15:49:16 +0200 Subject: [PATCH 184/528] get language code --- lib/internal/Magento/Framework/View/Page/Config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/View/Page/Config.php b/lib/internal/Magento/Framework/View/Page/Config.php index 248841e47499d..6fadc91bd73ee 100644 --- a/lib/internal/Magento/Framework/View/Page/Config.php +++ b/lib/internal/Magento/Framework/View/Page/Config.php @@ -173,7 +173,7 @@ public function __construct( $this->setElementAttribute( self::ELEMENT_TYPE_HTML, self::HTML_ATTRIBUTE_LANG, - str_replace('_', '-', $this->localeResolver->getLocale()) + strstr($this->localeResolver->getLocale(), '_', true) ); } From 7b0e90ae0f095685935c41670e268ded0870707e Mon Sep 17 00:00:00 2001 From: Brett Date: Thu, 19 Oct 2017 12:24:23 -0400 Subject: [PATCH 185/528] Fix "pattern" UI Component validation Convert `param` string to regular expression using constructor and test on the `RegExp` object. --- app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js index 76b00f56e780c..01a1575541408 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js @@ -360,7 +360,7 @@ define([ ], 'pattern': [ function (value, param) { - return param.test(value); + return new RegExp(param).test(value); }, $.mage.__('Invalid format.') ], From 4fbceeb70cf7c91e5104c3d5721549a8729d227b Mon Sep 17 00:00:00 2001 From: Danny Verkade Date: Thu, 19 Oct 2017 22:20:59 +0200 Subject: [PATCH 186/528] Changed typo where a string to be translated used double space "configure your" --- app/code/Magento/Paypal/i18n/en_US.csv | 2 +- .../templates/system/config/payflowlink/advanced.phtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Paypal/i18n/en_US.csv b/app/code/Magento/Paypal/i18n/en_US.csv index 164feea71511f..797edbf8bfa1e 100644 --- a/app/code/Magento/Paypal/i18n/en_US.csv +++ b/app/code/Magento/Paypal/i18n/en_US.csv @@ -367,7 +367,7 @@ expires,expires here,here " to learn more."," to learn more." "Important: ","Important: " -"To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.","To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website." +"To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.","To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website." "Once you log into your PayPal Advanced account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below","Once you log into your PayPal Advanced account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below" "To use PayPal Payflow Link, you must configure your PayPal Payflow Link account on the PayPal website.","To use PayPal Payflow Link, you must configure your PayPal Payflow Link account on the PayPal website." "Once you log into your PayPal Payflow Link account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below","Once you log into your PayPal Payflow Link account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below" diff --git a/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml b/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml index 2339b9ca38534..127d5bd14db42 100644 --- a/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml +++ b/app/code/Magento/Paypal/view/adminhtml/templates/system/config/payflowlink/advanced.phtml @@ -12,7 +12,7 @@

escapeHtml(__('Important: ')) ?> - escapeHtml(__('To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.')) ?> + escapeHtml(__('To use PayPal Payments Advanced, you must configure your PayPal Payments Advanced account on the PayPal website.')) ?> escapeHtml(__('Once you log into your PayPal Advanced account, navigate to the Service Settings - Hosted Checkout Pages - Set Up menu and set the options described below')) ?>

    From beccd7dd47b6d8421cb50863acb476d9b9bcec4b Mon Sep 17 00:00:00 2001 From: Thiago Lima Date: Fri, 20 Oct 2017 10:37:38 +0200 Subject: [PATCH 187/528] #11211 Fix Store View switcher, update integration test --- .../integration/testsuite/Magento/Store/Model/StoreTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php index e62436460998f..67fe8d1dedea9 100644 --- a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php +++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php @@ -274,7 +274,7 @@ public function testGetCurrentUrl() $this->model->load('admin'); $this->model->expects($this->any())->method('getUrl')->will($this->returnValue('http://localhost/index.php')); $this->assertStringEndsWith('default', $this->model->getCurrentUrl()); - $this->assertStringEndsNotWith('default', $this->model->getCurrentUrl(false)); + $this->assertStringEndsWith('default', $this->model->getCurrentUrl(false)); } /** From 48cdd0a4d289466c4c7b0f9873a66f7c27b2f370 Mon Sep 17 00:00:00 2001 From: Iurii Ivashchenko Date: Wed, 18 Oct 2017 19:25:26 +0300 Subject: [PATCH 188/528] MAGETWO-75517: L4 randomly failed on testReturnAction --- .../Magento/Paypal/Controller/ExpressTest.php | 2 + .../Paypal/_files/configurable_attribute.php | 62 ++++++++ .../Paypal/_files/product_configurable.php | 143 ++++++++++++++++++ .../_files/quote_express_configurable.php | 8 +- 4 files changed, 211 insertions(+), 4 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Paypal/_files/configurable_attribute.php create mode 100644 dev/tests/integration/testsuite/Magento/Paypal/_files/product_configurable.php diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php index 157999224d7b8..95e3abbfe6ff1 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php @@ -142,6 +142,8 @@ public function testStartActionCustomerToQuote() * Test return action with configurable product. * * @magentoDataFixture Magento/Paypal/_files/quote_express_configurable.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled */ public function testReturnAction() { diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/configurable_attribute.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/configurable_attribute.php new file mode 100644 index 0000000000000..12f63993cb2d3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/configurable_attribute.php @@ -0,0 +1,62 @@ +get(\Magento\Eav\Model\Config::class); +$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable'); + +$eavConfig->clear(); + +/** @var $installer \Magento\Catalog\Setup\CategorySetup */ +$installer = Bootstrap::getObjectManager()->create(\Magento\Catalog\Setup\CategorySetup::class); + +if (!$attribute->getId()) { + + /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ + $attribute = Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class + ); + + /** @var AttributeRepositoryInterface $attributeRepository */ + $attributeRepository = Bootstrap::getObjectManager()->create(AttributeRepositoryInterface::class); + + $attribute->setData( + [ + 'attribute_code' => 'test_configurable', + 'entity_type_id' => $installer->getEntityTypeId('catalog_product'), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'select', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 0, + 'used_in_product_listing' => 0, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Test Configurable'], + 'backend_type' => 'int', + 'option' => [ + 'value' => ['option_0' => ['Option 1'], 'option_1' => ['Option 2']], + 'order' => ['option_0' => 1, 'option_1' => 2], + ], + ] + ); + + $attributeRepository->save($attribute); + + /* Assign attribute to attribute set */ + $installer->addAttributeToGroup('catalog_product', 'Default', 'General', $attribute->getId()); +} + +$eavConfig->clear(); diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/product_configurable.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/product_configurable.php new file mode 100644 index 0000000000000..7851abd965d8c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/product_configurable.php @@ -0,0 +1,143 @@ +reinitialize(); + +require __DIR__ . '/configurable_attribute.php'; + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = Bootstrap::getObjectManager() + ->create(ProductRepositoryInterface::class); + +/** @var $installer CategorySetup */ +$installer = Bootstrap::getObjectManager()->create(CategorySetup::class); + +/* Create simple products per each option value*/ +/** @var AttributeOptionInterface[] $options */ +$options = $attribute->getOptions(); + +$attributeValues = []; +$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default'); +$associatedProductIds = []; +$productIds = [101, 201]; +array_shift($options); //remove the first option which is empty + +foreach ($options as $option) { + /** @var $product Product */ + $product = Bootstrap::getObjectManager()->create(Product::class); + $productId = array_shift($productIds); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setId($productId) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Option' . $option->getLabel()) + ->setSku('simple_' . $productId) + ->setPrice($productId) + ->setTestConfigurable($option->getValue()) + ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData([ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1 + ]); + + $product = $productRepository->save($product); + + /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */ + $stockItem = Bootstrap::getObjectManager()->create(\Magento\CatalogInventory\Model\Stock\Item::class); + $stockItem->load($productId, 'product_id'); + + if (!$stockItem->getProductId()) { + $stockItem->setProductId($productId); + } + $stockItem->setUseConfigManageStock(1); + $stockItem->setQty(1000); + $stockItem->setIsQtyDecimal(0); + $stockItem->setIsInStock(1); + $stockItem->save(); + + $attributeValues[] = [ + 'label' => 'test', + 'attribute_id' => $attribute->getId(), + 'value_index' => $option->getValue(), + ]; + $associatedProductIds[] = $product->getId(); +} + +/** @var $product Product */ +$product = Bootstrap::getObjectManager()->create(Product::class); + +/** @var Factory $optionsFactory */ +$optionsFactory = Bootstrap::getObjectManager()->create(Factory::class); + +$configurableAttributesData = [ + [ + 'attribute_id' => $attribute->getId(), + 'code' => $attribute->getAttributeCode(), + 'label' => $attribute->getStoreLabel(), + 'position' => '0', + 'values' => $attributeValues, + ], +]; + +$configurableOptions = $optionsFactory->create($configurableAttributesData); + +$extensionConfigurableAttributes = $product->getExtensionAttributes(); +$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions); +$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds); + +$product->setExtensionAttributes($extensionConfigurableAttributes); + +// Remove any previously created product with the same id. +/** @var \Magento\Framework\Registry $registry */ +$registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $productToDelete = $productRepository->getById(1); + $productRepository->delete($productToDelete); + + /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource */ + $itemResource = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\ResourceModel\Quote\Item::class); + $itemResource->getConnection()->delete( + $itemResource->getMainTable(), + 'product_id = ' . $productToDelete->getId() + ); +} catch (\Exception $e) { + // Nothing to remove +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +$product->setTypeId(Configurable::TYPE_CODE) + ->setId(100) + ->setAttributeSetId($attributeSetId) + ->setWebsiteIds([1]) + ->setName('Configurable Product') + ->setSku('configurable_express') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData([ + 'use_config_manage_stock' => 1, + 'is_in_stock' => 1 + ]); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_express_configurable.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_express_configurable.php index b3f14b188a32a..cf90172368d5c 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_express_configurable.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/quote_express_configurable.php @@ -11,7 +11,7 @@ use Magento\Quote\Model\Quote\Address\Rate; use Magento\TestFramework\Helper\Bootstrap; -require __DIR__ . '/../../../Magento/ConfigurableProduct/_files/product_configurable.php'; +require __DIR__ . '/product_configurable.php'; /** @var $objectManager \Magento\TestFramework\ObjectManager */ $objectManager = Bootstrap::getObjectManager(); @@ -19,7 +19,7 @@ /** @var $product \Magento\Catalog\Model\Product */ /** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ $productRepository = $objectManager->create(ProductRepositoryInterface::class); -$product = $productRepository->get('configurable'); +$product = $productRepository->get('configurable_express'); /** @var $options Collection */ $options = $objectManager->create(Collection::class); @@ -27,8 +27,8 @@ $requestInfo = new \Magento\Framework\DataObject( [ - 'product' => 2, - 'selected_configurable_option' => 2, + 'product' => 1, + 'selected_configurable_option' => 1, 'qty' => 1, 'super_attribute' => [ $attribute->getId() => $option->getId() From 41d67c236d4ca8a5313a8c0149965c972c5ced6b Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Fri, 20 Oct 2017 13:08:41 +0300 Subject: [PATCH 189/528] MAGETWO-81915: Magento 2.1.3 to 2.2.1 upgrade issue - Add correct processing for a case when design/theme/theme_id is empty --- .../Model/Config/Processor/DesignTheme.php | 4 +-- .../Config/Processor/DesignThemeTest.php | 18 ++++++++++++- .../Config/Processor/DesignThemeTest.php | 27 +++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Theme/Model/Config/Processor/DesignThemeTest.php diff --git a/app/code/Magento/Theme/Model/Config/Processor/DesignTheme.php b/app/code/Magento/Theme/Model/Config/Processor/DesignTheme.php index 258be67979ed2..d9d2c0e041e99 100644 --- a/app/code/Magento/Theme/Model/Config/Processor/DesignTheme.php +++ b/app/code/Magento/Theme/Model/Config/Processor/DesignTheme.php @@ -72,8 +72,8 @@ public function process(array $config) private function changeThemeFullPathToIdentifier($configItems) { $theme = null; - if ($this->arrayManager->exists(DesignInterface::XML_PATH_THEME_ID, $configItems)) { - $themeIdentifier = $this->arrayManager->get(DesignInterface::XML_PATH_THEME_ID, $configItems); + $themeIdentifier = $this->arrayManager->get(DesignInterface::XML_PATH_THEME_ID, $configItems); + if (!empty($themeIdentifier)) { if (!is_numeric($themeIdentifier)) { // workaround for case when db is not available try { diff --git a/app/code/Magento/Theme/Test/Unit/Model/Config/Processor/DesignThemeTest.php b/app/code/Magento/Theme/Test/Unit/Model/Config/Processor/DesignThemeTest.php index 1f3ab5642f471..bb2160f1e293d 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Config/Processor/DesignThemeTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Config/Processor/DesignThemeTest.php @@ -5,7 +5,6 @@ */ namespace Magento\Theme\Test\Unit\Model\Config\Processor; -use Magento\Config\App\Config\Source\DumpConfigSourceAggregated; use Magento\Framework\Stdlib\ArrayManager; use Magento\Framework\View\Design\Theme\ListInterface; use Magento\Theme\Model\Config\Processor\DesignTheme; @@ -78,6 +77,7 @@ private function prepareThemeMock() /** * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function getDumpConfigDataProvider() { @@ -163,6 +163,22 @@ public function getDumpConfigDataProvider() ], ], ], + [ + [ + 'websites' => [ + 'base' => [ + 'design' => ['theme' => ['theme_id' => '']], + ], + ], + ], + [ + 'websites' => [ + 'base' => [ + 'design' => ['theme' => ['theme_id' => '']], + ], + ], + ], + ], ]; } } diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Config/Processor/DesignThemeTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Config/Processor/DesignThemeTest.php new file mode 100644 index 0000000000000..01c8ebca57ac2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Config/Processor/DesignThemeTest.php @@ -0,0 +1,27 @@ +create(DesignTheme::class); + + $config = [ + 'default' => [ + 'design' => ['theme' => ['theme_id' => '']], + ], + ]; + + $this->assertEquals($config, $designTheme->process($config)); + } +} From 25ee497ea3a621e98b1d3428baa7a533c97257dd Mon Sep 17 00:00:00 2001 From: Kostyantyn Alexeyev Date: Fri, 20 Oct 2017 13:17:27 +0300 Subject: [PATCH 190/528] MAGETWO-81318: [2.2.x] B2B functional test fail Magento\Customer\Test\TestCase\CreateExistingCustomerBackendEntity.test with data set "CreateExistingCustomerBackendEntity1_0" --- .../Test/TestCase/CreateExistingCustomerBackendEntity.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.xml index 4692d21575813..5990157d6c5ea 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.xml +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/CreateExistingCustomerBackendEntity.xml @@ -8,7 +8,6 @@ - stable:no default From e5f160a12d1e0b59f30ed4504e0e852db2f32e02 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Fri, 20 Oct 2017 13:55:03 +0300 Subject: [PATCH 191/528] MAGETWO-82060: Incorrect products displayed after changing categories and running partial reindex --- .../Indexer/Category/Product/Action/Full.php | 26 ++- .../Model/Indexer/Product/CategoryTest.php | 209 ++++++++++++++++++ .../indexer_catalog_category_rollback.php | 2 +- .../indexer_catalog_product_categories.php | 56 +++++ ...er_catalog_product_categories_rollback.php | 26 +++ 5 files changed, 314 insertions(+), 5 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php index ae0c3554c0d32..f5e1596f23ce7 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php @@ -52,7 +52,6 @@ class Full extends \Magento\Catalog\Model\Indexer\Category\Product\AbstractActio * @param \Magento\Framework\Indexer\BatchSizeManagementInterface|null $batchSizeManagement * @param \Magento\Framework\Indexer\BatchProviderInterface|null $batchProvider * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool - * @param \Magento\Indexer\Model\Indexer\StateFactory|null $stateFactory * @param int|null $batchRowsCount * @param ActiveTableSwitcher|null $activeTableSwitcher */ @@ -87,6 +86,20 @@ public function __construct( $this->activeTableSwitcher = $activeTableSwitcher ?: $objectManager->get(ActiveTableSwitcher::class); } + /** + * Clear the table we'll be writing de-normalized data into + * to prevent archived data getting in the way of actual data. + * + * @return void + */ + private function clearCurrentTable() + { + $this->connection->delete( + $this->activeTableSwitcher + ->getAdditionalTableName($this->getMainTable()) + ); + } + /** * Refresh entities index * @@ -94,6 +107,7 @@ public function __construct( */ public function execute() { + $this->clearCurrentTable(); $this->reindex(); $this->activeTableSwitcher->switchTable($this->connection, [$this->getMainTable()]); return $this; @@ -103,6 +117,7 @@ public function execute() * Return select for remove unnecessary data * * @return \Magento\Framework\DB\Select + * @deprecated Not needed anymore. */ protected function getSelectUnnecessaryData() { @@ -127,12 +142,15 @@ protected function getSelectUnnecessaryData() * Remove unnecessary data * * @return void + * + * @deprecated Not needed anymore. */ protected function removeUnnecessaryData() { - $this->connection->query( - $this->connection->deleteFromSelect($this->getSelectUnnecessaryData(), $this->getMainTable()) - ); + //Called for backwards compatibility. + $this->getSelectUnnecessaryData(); + //This method is useless, + //left it here just in case somebody's using it in child classes. } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php new file mode 100644 index 0000000000000..cea50218638cb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php @@ -0,0 +1,209 @@ +indexer = Bootstrap::getObjectManager()->create( + Indexer::class + ); + $this->indexer->load('catalog_product_category'); + /** @var ProductResource $productResource */ + $this->productResource = Bootstrap::getObjectManager()->get( + ProductResource::class + ); + } + + /** + * Check that given product is only visible in given categories. + * + * @param Product $product + * @param Category[] $categoriesIn Categories the product is supposed + * to be in. + * @param Category[] $categories Whole list of categories. + * + * @return void + */ + private function assertProductIn( + Product $product, + array $categoriesIn, + array $categories + ) { + foreach ($categories as $category) { + $visible = in_array($category, $categoriesIn, true); + $this->assertEquals( + $visible, + (bool)$this->productResource->canBeShowInCategory( + $product, + $category->getId() + ), + 'Product "' .$product->getName() .'" is' + .($visible? '' : ' not') .' supposed to be in category "' + .$category->getName() .'"' + ); + } + } + + /** + * @magentoAppArea adminhtml + */ + public function testReindexAll() + { + //Category #1 is base category for this case, Category #2 is non-anchor + //sub-category of Category #1, Category #3 is anchor sub-category of + //Category #2, Category #4 is anchor sub-category of Category #1 + //Products are not yet assigned to categories + $categories = $this->loadCategories(4); + $products = $this->loadProducts(3); + + //Leaving Product #1 unassigned, Product #2 is assigned to Category #3, + //Product #3 assigned to Category #3 and #4. + $products[0]->setCategoryIds(null); + $this->productResource->save($products[0]); + $products[1]->setCategoryIds([$categories[2]->getId()]); + $this->productResource->save($products[1]); + $products[2]->setCategoryIds([ + $categories[2]->getId(), + $categories[3]->getId(), + ]); + $this->productResource->save($products[2]); + //Reindexing + $this->clearIndex(); + $this->indexer->reindexAll(); + + //Checking that Category #1 shows only Product #2 and #3 since + //Product #1 is not assigned to any category, Product #2 is assigned to + //it's sub-subcategory and Product #3 is assigned to a sub-subcategory + //and a subcategory. + //Category #2 doesn't have any products on display because while it's + //sub-category has products it's a non-anchor category. + //Category #3 has 2 products directly assigned to it. + //Category #4 only has 1 product directly assigned to it. + $this->assertProductIn($products[0], [], $categories); + $this->assertProductIn( + $products[1], + [$categories[0],$categories[2]], + $categories + ); + $this->assertProductIn( + $products[2], + [$categories[0], $categories[2], $categories[3]], + $categories + ); + + //Reassigning products a bit + $products[0]->setCategoryIds([$categories[0]->getId()]); + $this->productResource->save($products[0]); + $products[1]->setCategoryIds([]); + $this->productResource->save($products[1]); + $products[2]->setCategoryIds([ + $categories[1]->getId(), + $categories[2]->getId(), + $categories[3]->getId(), + ]); + $this->productResource->save($products[2]); + //Reindexing + $this->clearIndex(); + $this->indexer->reindexAll(); + //Checking that Category #1 now also shows Product #1 because it was + //directly assigned to it and not showing Product #2 because it was + //unassigned from Category #3. + //Category #2 now shows Product #3 because it was directly assigned + //to it. + //Category #3 now shows only Product #3 because Product #2 + //was unassigned. + //Category #4 still shows only Product #3. + $this->assertProductIn($products[0], [$categories[0]], $categories); + $this->assertProductIn($products[1], [], $categories); + $this->assertProductIn($products[2], $categories, $categories); + + $this->clearIndex(); + } + + /** + * Load categories from the fixture. + * + * @param int $limit + * @param int $offset + * @return Category[] + */ + private function loadCategories(int $limit, int $offset = 0): array + { + /** @var Category $category */ + $category = Bootstrap::getObjectManager()->create( + Category::class + ); + + $result = $category + ->getCollection() + ->addAttributeToSelect('name') + ->getItems(); + $result = array_slice($result, 2); + + return array_slice($result, $offset, $limit); + } + + /** + * Load products from the fixture. + * + * @param int $limit + * @param int $offset + * @return Product[] + */ + private function loadProducts(int $limit, int $offset = 0): array + { + /** @var Product[] $result */ + $result = []; + $ids = range($offset + 1, $offset + $limit); + foreach ($ids as $id) { + /** @var \Magento\Catalog\Model\Product $product */ + $product = Bootstrap::getObjectManager()->create( + Product::class + ); + $result[] = $product->load($id); + } + + return $result; + } + + /** + * Clear index data. + */ + private function clearIndex() + { + $this->productResource->getConnection()->delete( + $this->productResource->getTable('catalog_category_product_index') + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php index faa4fd6f4575e..51a8fc6b7e978 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php @@ -16,7 +16,7 @@ /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ $collection = $objectManager->create(\Magento\Catalog\Model\ResourceModel\Category\Collection::class); $collection - ->addAttributeToFilter('level', 2) + ->addAttributeToFilter('level', ['gteq' => 2]) ->load() ->delete(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php new file mode 100644 index 0000000000000..075422d5f0d78 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php @@ -0,0 +1,56 @@ +create(\Magento\Catalog\Model\Category::class); +$categoryFirst->setName('Category 1') + ->setPath('1/2') + ->setLevel(2) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setDefaultSortBy('name') + ->setIsAnchor(true) + ->save(); + +/** @var \Magento\Catalog\Model\Category $categorySecond */ +$categorySecond = $objectManager->create(\Magento\Catalog\Model\Category::class); +$categorySecond->setName('Category 2') + ->setPath($categoryFirst->getPath()) + ->setLevel(3) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setDefaultSortBy('name') + ->setIsAnchor(false) + ->save(); + +/** @var \Magento\Catalog\Model\Category $categoryThird */ +$categoryThird = $objectManager->create(\Magento\Catalog\Model\Category::class); +$categoryThird->setName('Category 3') + ->setPath($categorySecond->getPath()) + ->setLevel(4) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setDefaultSortBy('name') + ->setIsAnchor(true) + ->save(); + +/** @var \Magento\Catalog\Model\Category $categoryFourth */ +$categoryFourth = $objectManager->create(\Magento\Catalog\Model\Category::class); +$categoryFourth->setName('Category 4') + ->setPath($categoryFirst->getPath()) + ->setLevel(3) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(2) + ->setDefaultSortBy('name') + ->setIsAnchor(true) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php new file mode 100644 index 0000000000000..755f324b18cb2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php @@ -0,0 +1,26 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ +$collection = $objectManager->create( + \Magento\Catalog\Model\ResourceModel\Category\Collection::class +); +$collection + ->addAttributeToFilter('level', ['gteq' => 2]) + ->load() + ->delete(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From fea77c70d62e9c9259596dd0a96a4993f200380b Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Wed, 18 Oct 2017 12:04:49 +0300 Subject: [PATCH 192/528] Checkout place order exception when using a new address - Added doc block parsing for interceptors --- app/code/Magento/Quote/Model/Quote.php | 2 +- .../Magento/Quote/Model/QuoteTest.php | 2 +- .../Reflection/Test/Unit/Fixture/TSample.php | 25 +++++++ .../Test/Unit/Fixture/TSampleInterface.php | 21 ++++++ .../Test/Unit/TypeProcessorTest.php | 34 ++++++++- .../Framework/Reflection/TypeProcessor.php | 73 ++++++++++++++----- 6 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php create mode 100644 lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSampleInterface.php diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index bf2c6bbc57d95..7741d3b0f7657 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -1057,7 +1057,7 @@ public function addCustomerAddress(\Magento\Customer\Api\Data\AddressInterface $ public function updateCustomerData(\Magento\Customer\Api\Data\CustomerInterface $customer) { $quoteCustomer = $this->getCustomer(); - $this->dataObjectHelper->mergeDataObjects(get_class($quoteCustomer), $quoteCustomer, $customer); + $this->dataObjectHelper->mergeDataObjects(CustomerInterface::class, $quoteCustomer, $customer); $this->setCustomer($quoteCustomer); return $this; } diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php index 258b14bf6e0d3..ecd8b62b122d4 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php @@ -393,7 +393,7 @@ protected function _getCustomerDataArray() \Magento\Customer\Model\Data\Customer::DOB => '2014-02-03 00:00:00', \Magento\Customer\Model\Data\Customer::EMAIL => 'qa@example.com', \Magento\Customer\Model\Data\Customer::FIRSTNAME => 'Joe', - \Magento\Customer\Model\Data\Customer::GENDER => 'Male', + \Magento\Customer\Model\Data\Customer::GENDER => 0, \Magento\Customer\Model\Data\Customer::GROUP_ID => \Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID, \Magento\Customer\Model\Data\Customer::ID => 1, diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php new file mode 100644 index 0000000000000..1d78f9ed0a7d8 --- /dev/null +++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/Fixture/TSample.php @@ -0,0 +1,25 @@ +assertEquals("resNameMethodName", $this->_typeProcessor->getOperationName("resName", "methodName")); } + + /** + * Checks a case when method has only `@inheritdoc` annotation. + */ + public function testGetReturnTypeWithInheritDocBlock() + { + $expected = [ + 'type' => 'string', + 'isRequired' => true, + 'description' => null, + 'parameterCount' => 0 + ]; + + $classReflection = new ClassReflection(TSample::class); + $methodReflection = $classReflection->getMethod('getPropertyName'); + + self::assertEquals($expected, $this->_typeProcessor->getGetterReturnType($methodReflection)); + } + + /** + * Checks a case when method and parent interface don't have `@return` annotation. + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Getter return type must be specified using @return annotation. See Magento\Framework\Reflection\Test\Unit\Fixture\TSample::getName() + */ + public function testGetReturnTypeWithoutReturnTag() + { + $classReflection = new ClassReflection(TSample::class); + $methodReflection = $classReflection->getMethod('getName'); + $this->_typeProcessor->getGetterReturnType($methodReflection); + } } diff --git a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php index 5d6054056d35e..74c1bc95b208b 100644 --- a/lib/internal/Magento/Framework/Reflection/TypeProcessor.php +++ b/lib/internal/Magento/Framework/Reflection/TypeProcessor.php @@ -8,6 +8,7 @@ use Magento\Framework\Exception\SerializationException; use Magento\Framework\Phrase; use Zend\Code\Reflection\ClassReflection; +use Zend\Code\Reflection\DocBlock\Tag\ReturnTag; use Zend\Code\Reflection\DocBlockReflection; use Zend\Code\Reflection\MethodReflection; use Zend\Code\Reflection\ParameterReflection; @@ -16,6 +17,7 @@ * Type processor of config reader properties * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) this suppress MUST be removed after removing deprecated methods. */ class TypeProcessor { @@ -275,22 +277,7 @@ protected function dataObjectGetterDescriptionToFieldDescription($shortDescripti */ public function getGetterReturnType($methodReflection) { - $methodDocBlock = $methodReflection->getDocBlock(); - if (!$methodDocBlock) { - throw new \InvalidArgumentException( - "Each getter must have description with @return annotation. " - . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()" - ); - } - $returnAnnotations = $methodDocBlock->getTags('return'); - if (empty($returnAnnotations)) { - throw new \InvalidArgumentException( - "Getter return type must be specified using @return annotation. " - . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()" - ); - } - /** @var \Zend\Code\Reflection\DocBlock\Tag\ReturnTag $returnAnnotation */ - $returnAnnotation = current($returnAnnotations); + $returnAnnotation = $this->getMethodReturnAnnotation($methodReflection); $types = $returnAnnotation->getTypes(); $returnType = current($types); $nullable = in_array('null', $types); @@ -362,7 +349,7 @@ public function isTypeSimple($type) self::NORMALIZED_INT_TYPE, self::NORMALIZED_FLOAT_TYPE, self::NORMALIZED_DOUBLE_TYPE, - self::NORMALIZED_BOOLEAN_TYPE + self::NORMALIZED_BOOLEAN_TYPE, ] ); } @@ -708,4 +695,56 @@ private function getNormalizedType($type) } return $type; } + + /** + * Parses `return` annotation from reflection method. + * + * @param MethodReflection $methodReflection + * @return ReturnTag + * @throws \InvalidArgumentException if doc block is empty or `@return` annotation doesn't exist + */ + private function getMethodReturnAnnotation(MethodReflection $methodReflection) + { + $methodName = $methodReflection->getName(); + $returnAnnotations = $this->getReturnFromDocBlock($methodReflection); + if (empty($returnAnnotations)) { + // method can inherit doc block from implemented interface, like for interceptors + $implemented = $methodReflection->getDeclaringClass()->getInterfaces(); + /** @var ClassReflection $parentClassReflection */ + foreach ($implemented as $parentClassReflection) { + if ($parentClassReflection->hasMethod($methodName)) { + $returnAnnotations = $this->getReturnFromDocBlock( + $parentClassReflection->getMethod($methodName) + ); + break; + } + } + // throw an exception if even implemented interface doesn't have return annotations + if (empty($returnAnnotations)) { + throw new \InvalidArgumentException( + "Getter return type must be specified using @return annotation. " + . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodName}()" + ); + } + } + return $returnAnnotations; + } + + /** + * Parses `return` annotation from doc block. + * + * @param MethodReflection $methodReflection + * @return ReturnTag + */ + private function getReturnFromDocBlock(MethodReflection $methodReflection) + { + $methodDocBlock = $methodReflection->getDocBlock(); + if (!$methodDocBlock) { + throw new \InvalidArgumentException( + "Each getter must have a doc block. " + . "See {$methodReflection->getDeclaringClass()->getName()}::{$methodReflection->getName()}()" + ); + } + return current($methodDocBlock->getTags('return')); + } } From 0e2912d08a581a6fb33a5c3d1eba964445047a76 Mon Sep 17 00:00:00 2001 From: Yevhen Miroshnychenko Date: Fri, 20 Oct 2017 17:29:54 +0300 Subject: [PATCH 193/528] MAGETWO-81905: Cannot upgrade to 2.2.1-develop from 2.1.9 if DB was split --- app/code/Magento/Quote/Setup/UpgradeSchema.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Quote/Setup/UpgradeSchema.php b/app/code/Magento/Quote/Setup/UpgradeSchema.php index e4912892dbe17..1bb20a669bdf2 100644 --- a/app/code/Magento/Quote/Setup/UpgradeSchema.php +++ b/app/code/Magento/Quote/Setup/UpgradeSchema.php @@ -48,17 +48,17 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con } //drop foreign key for single DB case if (version_compare($context->getVersion(), '2.0.3', '<') - && $setup->tableExists($setup->getTable('quote_item')) + && $setup->tableExists($setup->getTable('quote_item', self::$connectionName)) ) { - $setup->getConnection()->dropForeignKey( - $setup->getTable('quote_item'), + $setup->getConnection(self::$connectionName)->dropForeignKey( + $setup->getTable('quote_item', self::$connectionName), $setup->getFkName('quote_item', 'product_id', 'catalog_product_entity', 'entity_id') ); } if (version_compare($context->getVersion(), '2.0.5', '<')) { - $connection = $setup->getConnection(); + $connection = $setup->getConnection(self::$connectionName); $connection->modifyColumn( - $setup->getTable('quote_address'), + $setup->getTable('quote_address', self::$connectionName), 'shipping_method', [ 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, From 72cf40179b42b0afd02ebb10592297585a12855f Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Fri, 20 Oct 2017 17:46:16 +0300 Subject: [PATCH 194/528] MAGETWO-82060: Incorrect products displayed after changing categories and running partial reindex --- .../Model/Indexer/Product/CategoryTest.php | 209 ------------------ .../indexer_catalog_category_rollback.php | 2 +- .../indexer_catalog_product_categories.php | 56 ----- ...er_catalog_product_categories_rollback.php | 26 --- 4 files changed, 1 insertion(+), 292 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php delete mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php delete mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php deleted file mode 100644 index cea50218638cb..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php +++ /dev/null @@ -1,209 +0,0 @@ -indexer = Bootstrap::getObjectManager()->create( - Indexer::class - ); - $this->indexer->load('catalog_product_category'); - /** @var ProductResource $productResource */ - $this->productResource = Bootstrap::getObjectManager()->get( - ProductResource::class - ); - } - - /** - * Check that given product is only visible in given categories. - * - * @param Product $product - * @param Category[] $categoriesIn Categories the product is supposed - * to be in. - * @param Category[] $categories Whole list of categories. - * - * @return void - */ - private function assertProductIn( - Product $product, - array $categoriesIn, - array $categories - ) { - foreach ($categories as $category) { - $visible = in_array($category, $categoriesIn, true); - $this->assertEquals( - $visible, - (bool)$this->productResource->canBeShowInCategory( - $product, - $category->getId() - ), - 'Product "' .$product->getName() .'" is' - .($visible? '' : ' not') .' supposed to be in category "' - .$category->getName() .'"' - ); - } - } - - /** - * @magentoAppArea adminhtml - */ - public function testReindexAll() - { - //Category #1 is base category for this case, Category #2 is non-anchor - //sub-category of Category #1, Category #3 is anchor sub-category of - //Category #2, Category #4 is anchor sub-category of Category #1 - //Products are not yet assigned to categories - $categories = $this->loadCategories(4); - $products = $this->loadProducts(3); - - //Leaving Product #1 unassigned, Product #2 is assigned to Category #3, - //Product #3 assigned to Category #3 and #4. - $products[0]->setCategoryIds(null); - $this->productResource->save($products[0]); - $products[1]->setCategoryIds([$categories[2]->getId()]); - $this->productResource->save($products[1]); - $products[2]->setCategoryIds([ - $categories[2]->getId(), - $categories[3]->getId(), - ]); - $this->productResource->save($products[2]); - //Reindexing - $this->clearIndex(); - $this->indexer->reindexAll(); - - //Checking that Category #1 shows only Product #2 and #3 since - //Product #1 is not assigned to any category, Product #2 is assigned to - //it's sub-subcategory and Product #3 is assigned to a sub-subcategory - //and a subcategory. - //Category #2 doesn't have any products on display because while it's - //sub-category has products it's a non-anchor category. - //Category #3 has 2 products directly assigned to it. - //Category #4 only has 1 product directly assigned to it. - $this->assertProductIn($products[0], [], $categories); - $this->assertProductIn( - $products[1], - [$categories[0],$categories[2]], - $categories - ); - $this->assertProductIn( - $products[2], - [$categories[0], $categories[2], $categories[3]], - $categories - ); - - //Reassigning products a bit - $products[0]->setCategoryIds([$categories[0]->getId()]); - $this->productResource->save($products[0]); - $products[1]->setCategoryIds([]); - $this->productResource->save($products[1]); - $products[2]->setCategoryIds([ - $categories[1]->getId(), - $categories[2]->getId(), - $categories[3]->getId(), - ]); - $this->productResource->save($products[2]); - //Reindexing - $this->clearIndex(); - $this->indexer->reindexAll(); - //Checking that Category #1 now also shows Product #1 because it was - //directly assigned to it and not showing Product #2 because it was - //unassigned from Category #3. - //Category #2 now shows Product #3 because it was directly assigned - //to it. - //Category #3 now shows only Product #3 because Product #2 - //was unassigned. - //Category #4 still shows only Product #3. - $this->assertProductIn($products[0], [$categories[0]], $categories); - $this->assertProductIn($products[1], [], $categories); - $this->assertProductIn($products[2], $categories, $categories); - - $this->clearIndex(); - } - - /** - * Load categories from the fixture. - * - * @param int $limit - * @param int $offset - * @return Category[] - */ - private function loadCategories(int $limit, int $offset = 0): array - { - /** @var Category $category */ - $category = Bootstrap::getObjectManager()->create( - Category::class - ); - - $result = $category - ->getCollection() - ->addAttributeToSelect('name') - ->getItems(); - $result = array_slice($result, 2); - - return array_slice($result, $offset, $limit); - } - - /** - * Load products from the fixture. - * - * @param int $limit - * @param int $offset - * @return Product[] - */ - private function loadProducts(int $limit, int $offset = 0): array - { - /** @var Product[] $result */ - $result = []; - $ids = range($offset + 1, $offset + $limit); - foreach ($ids as $id) { - /** @var \Magento\Catalog\Model\Product $product */ - $product = Bootstrap::getObjectManager()->create( - Product::class - ); - $result[] = $product->load($id); - } - - return $result; - } - - /** - * Clear index data. - */ - private function clearIndex() - { - $this->productResource->getConnection()->delete( - $this->productResource->getTable('catalog_category_product_index') - ); - } -} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php index 51a8fc6b7e978..faa4fd6f4575e 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php @@ -16,7 +16,7 @@ /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ $collection = $objectManager->create(\Magento\Catalog\Model\ResourceModel\Category\Collection::class); $collection - ->addAttributeToFilter('level', ['gteq' => 2]) + ->addAttributeToFilter('level', 2) ->load() ->delete(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php deleted file mode 100644 index 075422d5f0d78..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php +++ /dev/null @@ -1,56 +0,0 @@ -create(\Magento\Catalog\Model\Category::class); -$categoryFirst->setName('Category 1') - ->setPath('1/2') - ->setLevel(2) - ->setAvailableSortBy('name') - ->setIsActive(true) - ->setPosition(1) - ->setDefaultSortBy('name') - ->setIsAnchor(true) - ->save(); - -/** @var \Magento\Catalog\Model\Category $categorySecond */ -$categorySecond = $objectManager->create(\Magento\Catalog\Model\Category::class); -$categorySecond->setName('Category 2') - ->setPath($categoryFirst->getPath()) - ->setLevel(3) - ->setAvailableSortBy('name') - ->setIsActive(true) - ->setPosition(1) - ->setDefaultSortBy('name') - ->setIsAnchor(false) - ->save(); - -/** @var \Magento\Catalog\Model\Category $categoryThird */ -$categoryThird = $objectManager->create(\Magento\Catalog\Model\Category::class); -$categoryThird->setName('Category 3') - ->setPath($categorySecond->getPath()) - ->setLevel(4) - ->setAvailableSortBy('name') - ->setIsActive(true) - ->setPosition(1) - ->setDefaultSortBy('name') - ->setIsAnchor(true) - ->save(); - -/** @var \Magento\Catalog\Model\Category $categoryFourth */ -$categoryFourth = $objectManager->create(\Magento\Catalog\Model\Category::class); -$categoryFourth->setName('Category 4') - ->setPath($categoryFirst->getPath()) - ->setLevel(3) - ->setAvailableSortBy('name') - ->setIsActive(true) - ->setPosition(2) - ->setDefaultSortBy('name') - ->setIsAnchor(true) - ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php deleted file mode 100644 index 755f324b18cb2..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php +++ /dev/null @@ -1,26 +0,0 @@ -get(\Magento\Framework\Registry::class); - -$registry->unregister('isSecureArea'); -$registry->register('isSecureArea', true); - -/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ -$collection = $objectManager->create( - \Magento\Catalog\Model\ResourceModel\Category\Collection::class -); -$collection - ->addAttributeToFilter('level', ['gteq' => 2]) - ->load() - ->delete(); - -$registry->unregister('isSecureArea'); -$registry->register('isSecureArea', false); From fa83cae933095b1935e74a7a07b4b1e6fb9d5e4b Mon Sep 17 00:00:00 2001 From: Dmytro Voskoboinikov Date: Fri, 20 Oct 2017 19:16:01 +0300 Subject: [PATCH 195/528] MAGETWO-82060: Incorrect products displayed after changing categories and running partial reindex --- .../Model/Indexer/Product/CategoryTest.php | 209 ++++++++++++++++++ .../indexer_catalog_category_rollback.php | 2 +- .../indexer_catalog_product_categories.php | 56 +++++ ...er_catalog_product_categories_rollback.php | 26 +++ 4 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php new file mode 100644 index 0000000000000..cea50218638cb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/CategoryTest.php @@ -0,0 +1,209 @@ +indexer = Bootstrap::getObjectManager()->create( + Indexer::class + ); + $this->indexer->load('catalog_product_category'); + /** @var ProductResource $productResource */ + $this->productResource = Bootstrap::getObjectManager()->get( + ProductResource::class + ); + } + + /** + * Check that given product is only visible in given categories. + * + * @param Product $product + * @param Category[] $categoriesIn Categories the product is supposed + * to be in. + * @param Category[] $categories Whole list of categories. + * + * @return void + */ + private function assertProductIn( + Product $product, + array $categoriesIn, + array $categories + ) { + foreach ($categories as $category) { + $visible = in_array($category, $categoriesIn, true); + $this->assertEquals( + $visible, + (bool)$this->productResource->canBeShowInCategory( + $product, + $category->getId() + ), + 'Product "' .$product->getName() .'" is' + .($visible? '' : ' not') .' supposed to be in category "' + .$category->getName() .'"' + ); + } + } + + /** + * @magentoAppArea adminhtml + */ + public function testReindexAll() + { + //Category #1 is base category for this case, Category #2 is non-anchor + //sub-category of Category #1, Category #3 is anchor sub-category of + //Category #2, Category #4 is anchor sub-category of Category #1 + //Products are not yet assigned to categories + $categories = $this->loadCategories(4); + $products = $this->loadProducts(3); + + //Leaving Product #1 unassigned, Product #2 is assigned to Category #3, + //Product #3 assigned to Category #3 and #4. + $products[0]->setCategoryIds(null); + $this->productResource->save($products[0]); + $products[1]->setCategoryIds([$categories[2]->getId()]); + $this->productResource->save($products[1]); + $products[2]->setCategoryIds([ + $categories[2]->getId(), + $categories[3]->getId(), + ]); + $this->productResource->save($products[2]); + //Reindexing + $this->clearIndex(); + $this->indexer->reindexAll(); + + //Checking that Category #1 shows only Product #2 and #3 since + //Product #1 is not assigned to any category, Product #2 is assigned to + //it's sub-subcategory and Product #3 is assigned to a sub-subcategory + //and a subcategory. + //Category #2 doesn't have any products on display because while it's + //sub-category has products it's a non-anchor category. + //Category #3 has 2 products directly assigned to it. + //Category #4 only has 1 product directly assigned to it. + $this->assertProductIn($products[0], [], $categories); + $this->assertProductIn( + $products[1], + [$categories[0],$categories[2]], + $categories + ); + $this->assertProductIn( + $products[2], + [$categories[0], $categories[2], $categories[3]], + $categories + ); + + //Reassigning products a bit + $products[0]->setCategoryIds([$categories[0]->getId()]); + $this->productResource->save($products[0]); + $products[1]->setCategoryIds([]); + $this->productResource->save($products[1]); + $products[2]->setCategoryIds([ + $categories[1]->getId(), + $categories[2]->getId(), + $categories[3]->getId(), + ]); + $this->productResource->save($products[2]); + //Reindexing + $this->clearIndex(); + $this->indexer->reindexAll(); + //Checking that Category #1 now also shows Product #1 because it was + //directly assigned to it and not showing Product #2 because it was + //unassigned from Category #3. + //Category #2 now shows Product #3 because it was directly assigned + //to it. + //Category #3 now shows only Product #3 because Product #2 + //was unassigned. + //Category #4 still shows only Product #3. + $this->assertProductIn($products[0], [$categories[0]], $categories); + $this->assertProductIn($products[1], [], $categories); + $this->assertProductIn($products[2], $categories, $categories); + + $this->clearIndex(); + } + + /** + * Load categories from the fixture. + * + * @param int $limit + * @param int $offset + * @return Category[] + */ + private function loadCategories(int $limit, int $offset = 0): array + { + /** @var Category $category */ + $category = Bootstrap::getObjectManager()->create( + Category::class + ); + + $result = $category + ->getCollection() + ->addAttributeToSelect('name') + ->getItems(); + $result = array_slice($result, 2); + + return array_slice($result, $offset, $limit); + } + + /** + * Load products from the fixture. + * + * @param int $limit + * @param int $offset + * @return Product[] + */ + private function loadProducts(int $limit, int $offset = 0): array + { + /** @var Product[] $result */ + $result = []; + $ids = range($offset + 1, $offset + $limit); + foreach ($ids as $id) { + /** @var \Magento\Catalog\Model\Product $product */ + $product = Bootstrap::getObjectManager()->create( + Product::class + ); + $result[] = $product->load($id); + } + + return $result; + } + + /** + * Clear index data. + */ + private function clearIndex() + { + $this->productResource->getConnection()->delete( + $this->productResource->getTable('catalog_category_product_index') + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php index faa4fd6f4575e..51a8fc6b7e978 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_category_rollback.php @@ -16,7 +16,7 @@ /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ $collection = $objectManager->create(\Magento\Catalog\Model\ResourceModel\Category\Collection::class); $collection - ->addAttributeToFilter('level', 2) + ->addAttributeToFilter('level', ['gteq' => 2]) ->load() ->delete(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php new file mode 100644 index 0000000000000..075422d5f0d78 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories.php @@ -0,0 +1,56 @@ +create(\Magento\Catalog\Model\Category::class); +$categoryFirst->setName('Category 1') + ->setPath('1/2') + ->setLevel(2) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setDefaultSortBy('name') + ->setIsAnchor(true) + ->save(); + +/** @var \Magento\Catalog\Model\Category $categorySecond */ +$categorySecond = $objectManager->create(\Magento\Catalog\Model\Category::class); +$categorySecond->setName('Category 2') + ->setPath($categoryFirst->getPath()) + ->setLevel(3) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setDefaultSortBy('name') + ->setIsAnchor(false) + ->save(); + +/** @var \Magento\Catalog\Model\Category $categoryThird */ +$categoryThird = $objectManager->create(\Magento\Catalog\Model\Category::class); +$categoryThird->setName('Category 3') + ->setPath($categorySecond->getPath()) + ->setLevel(4) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setDefaultSortBy('name') + ->setIsAnchor(true) + ->save(); + +/** @var \Magento\Catalog\Model\Category $categoryFourth */ +$categoryFourth = $objectManager->create(\Magento\Catalog\Model\Category::class); +$categoryFourth->setName('Category 4') + ->setPath($categoryFirst->getPath()) + ->setLevel(3) + ->setAvailableSortBy('name') + ->setIsActive(true) + ->setPosition(2) + ->setDefaultSortBy('name') + ->setIsAnchor(true) + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php new file mode 100644 index 0000000000000..755f324b18cb2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/indexer_catalog_product_categories_rollback.php @@ -0,0 +1,26 @@ +get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ +$collection = $objectManager->create( + \Magento\Catalog\Model\ResourceModel\Category\Collection::class +); +$collection + ->addAttributeToFilter('level', ['gteq' => 2]) + ->load() + ->delete(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From 163ae73e533eaad61caaa36170612e808a7ff11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Mart=C3=ADnez?= Date: Fri, 20 Oct 2017 18:31:21 +0200 Subject: [PATCH 196/528] Update doc blocks --- .../App/DeploymentConfig/Writer/PhpFormatter.php | 8 ++++---- .../Unit/DeploymentConfig/Writer/PhpFormatterTest.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php index 319269bd0011d..b419b3827e5ff 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Writer/PhpFormatter.php @@ -21,7 +21,7 @@ class PhpFormatter implements FormatterInterface public function format($data, array $comments = []) { if (!empty($comments) && is_array($data)) { - return "formatData($data, $comments, ' ') . "\n);\n"; + return "formatData($data, $comments) . "\n);\n"; } return " Date: Fri, 20 Oct 2017 18:56:35 +0200 Subject: [PATCH 197/528] check subject and attribute set before continuing with interceptor --- .../Plugin/Eav/Model/AttributeSetRepository.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php index 96fc232829757..99370c9e48de8 100644 --- a/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php +++ b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php @@ -47,6 +47,11 @@ public function aroundDelete( callable $proceed, AttributeSetInterface $attributeSet ) { + if (!isset($subject) || !$attributeSet->getAttributeSetId()) + { + return false; + } + // Get the product ids $ids = $this->productCollection->addFieldToFilter('attribute_set_id', $attributeSet->getAttributeSetId()) ->getAllIds(); From 1b3f6aec94444d7e60e27e3cbba40614a6556a7c Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 20 Oct 2017 12:23:03 -0500 Subject: [PATCH 198/528] MAGETWO-82125: Display advertisement popup at the 1st time per admin login --- .../Model/AdvertisementFlagManager.php | 60 ---------- .../Model/Condition/CanViewNotification.php | 34 ++++-- .../Model/ResourceModel/Viewer/Logger.php | 106 ++++++++++++++++++ .../Advertisement/Model/Viewer/Log.php | 26 +++++ .../Advertisement/Setup/InstallSchema.php | 69 ++++++++++++ .../Model/AdvertisementFlagManagerTest.php | 61 ---------- .../Condition/CanViewNotificationTest.php | 83 +++++++++----- app/code/Magento/Advertisement/etc/module.xml | 2 +- .../Model/ResourceModel/Viewer/LoggerTest.php | 62 ++++++++++ 9 files changed, 343 insertions(+), 160 deletions(-) delete mode 100644 app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php create mode 100644 app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php create mode 100644 app/code/Magento/Advertisement/Model/Viewer/Log.php create mode 100644 app/code/Magento/Advertisement/Setup/InstallSchema.php delete mode 100644 app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php diff --git a/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php b/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php deleted file mode 100644 index 88a95f5df63b1..0000000000000 --- a/app/code/Magento/Advertisement/Model/AdvertisementFlagManager.php +++ /dev/null @@ -1,60 +0,0 @@ -flagManager = $flagManager; - } - - /** - * Sets the flag to indicate the user was notified about Analytic services - * @param $userId - * @return bool - */ - public function setNotifiedUser($userId) - { - $flagCode = self::NOTIFICATION_SEEN . $userId; - return $this->flagManager->saveFlag($flagCode, 1); - } - - /** - * Returns the flag data if the user was notified about Analytic services - * @param $userId - * @return bool - */ - public function isUserNotified($userId) - { - if ($this->flagManager->getFlagData(self::NOTIFICATION_SEEN . $userId)) { - return true; - } - - return false; - } -} diff --git a/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php index 1bd28ce95e0a3..b54f4fe928fb6 100644 --- a/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php +++ b/app/code/Magento/Advertisement/Model/Condition/CanViewNotification.php @@ -5,9 +5,10 @@ */ namespace Magento\Advertisement\Model\Condition; +use Magento\Advertisement\Model\ResourceModel\Viewer\Logger; use Magento\Backend\Model\Auth\Session; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\View\Layout\Condition\VisibilityConditionInterface; -use Magento\Advertisement\Model\AdvertisementFlagManager; /** * Class CanViewNotification @@ -23,27 +24,34 @@ class CanViewNotification implements VisibilityConditionInterface const NAME = 'can_view_notification'; /** - * @var AdvertisementFlagManager + * @var Logger */ - private $advertisementFlagManager; + private $viewerLogger; /** * @var Session */ private $session; + /** + * @var ProductMetadataInterface + */ + private $productMetadata; + /** * CanViewNotification constructor. * - * @param AdvertisementFlagManager $advertisementFlagManager + * @param Logger $viewerLogger * @param Session $session */ public function __construct( - AdvertisementFlagManager $advertisementFlagManager, - Session $session + Logger $viewerLogger, + Session $session, + ProductMetadataInterface $productMetadata ) { - $this->advertisementFlagManager = $advertisementFlagManager; + $this->viewerLogger = $viewerLogger; $this->session = $session; + $this->productMetadata = $productMetadata; } /** @@ -54,11 +62,17 @@ public function __construct( public function isVisible(array $arguments) { $userId = $this->session->getUser()->getId(); - if ($this->advertisementFlagManager->isUserNotified($userId)) { + $viewerLog = $this->viewerLogger->get($userId); + $version = $this->productMetadata->getVersion(); + if ($viewerLog == null + || $viewerLog->getLastViewVersion() == null + || $viewerLog->getLastViewVersion() < $version + ) { + $this->viewerLogger->log($userId, $version); + return true; + } else { return false; } - - return $this->advertisementFlagManager->setNotifiedUser($userId); } /** diff --git a/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php new file mode 100644 index 0000000000000..a38b888de4d64 --- /dev/null +++ b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php @@ -0,0 +1,106 @@ +resource = $resource; + $this->logFactory = $logFactory; + } + + /** + * Save (insert new or update existing) log. + * + * @param int $viewerId + * @param string $lastViewVersion + * @return $this + */ + public function log($viewerId, $lastViewVersion) + { + /** @var \Magento\Framework\DB\Adapter\AdapterInterface $connection */ + $connection = $this->resource->getConnection(ResourceConnection::DEFAULT_CONNECTION); + + $connection->insertOnDuplicate( + $this->resource->getTableName(self::TABLE_NAME ), + [ + 'viewer_id' => $viewerId, + 'last_view_version' => $lastViewVersion + ], + ['viewer_id', 'last_view_version'] + ); + + return $this; + } + + /** + * Get log by viewer Id. + * + * @param int $viewerId + * @return Log|null + */ + public function get($viewerId) + { + $data = $this->loadLogData($viewerId); + if (is_array($data)) { + return $this->logFactory->create(['data' => $data]); + } else { + return null; + } + } + + /** + * Load advertisement viewer log data by viewer id + * + * @param int $viewerId + * @return array + */ + private function loadLogData($viewerId) + { + $connection = $this->resource->getConnection(); + + $select = $connection->select() + ->from( + $this->resource->getTableName(self::TABLE_NAME) + )->where( + 'viewer_id = ?', + $viewerId + )->order( + 'id DESC' + )->limit(1); + + return $connection->fetchRow($select); + } +} diff --git a/app/code/Magento/Advertisement/Model/Viewer/Log.php b/app/code/Magento/Advertisement/Model/Viewer/Log.php new file mode 100644 index 0000000000000..fa19461f63a25 --- /dev/null +++ b/app/code/Magento/Advertisement/Model/Viewer/Log.php @@ -0,0 +1,26 @@ +getData('id'); + } + + public function getViewerId() + { + return $this->getData('viewer_id'); + } + + public function getLastViewVersion() + { + return $this->getData('last_view_version'); + } +} diff --git a/app/code/Magento/Advertisement/Setup/InstallSchema.php b/app/code/Magento/Advertisement/Setup/InstallSchema.php new file mode 100644 index 0000000000000..1bc1d433d84e8 --- /dev/null +++ b/app/code/Magento/Advertisement/Setup/InstallSchema.php @@ -0,0 +1,69 @@ +startSetup(); + + /** + * Create table 'advertisement_viewer_log' + */ + $table = $setup->getConnection()->newTable( + $setup->getTable('advertisement_viewer_log') + )->addColumn( + 'id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], + 'Log ID' + )->addColumn( + 'viewer_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false], + 'Viewer admin user ID' + )->addColumn( + 'last_view_version', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 10, + ['nullable' => true], + 'Viewer last view on product version' + )->addIndex( + $setup->getIdxName( + 'advertisement_viewer_log', + ['viewer_id'], + \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE + ), + ['viewer_id'], + ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] + )->addForeignKey( + $setup->getFkName('advertisement_viewer_log', 'viewer_id', 'admin_user', 'user_id'), + 'viewer_id', + $setup->getTable('admin_user'), + 'user_id', + Table::ACTION_CASCADE + )->setComment( + 'Advertisement Viewer Log Table' + ); + $setup->getConnection()->createTable($table); + + $setup->endSetup(); + } +} diff --git a/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php b/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php deleted file mode 100644 index ddcbdbd6c1a0b..0000000000000 --- a/app/code/Magento/Advertisement/Test/Unit/Model/AdvertisementFlagManagerTest.php +++ /dev/null @@ -1,61 +0,0 @@ -flagManagerMock = $this->getMockBuilder(FlagManager::class) - ->disableOriginalConstructor() - ->getMock(); - $objectManager = new ObjectManager($this); - $this->advertisementFlagManager = $objectManager->getObject( - AdvertisementFlagManager::class, - [ - 'flagManager' => $this->flagManagerMock - ] - ); - } - - public function testSetNotifiedUser() - { - $userId = 1; - $this->flagManagerMock->expects($this->once()) - ->method('saveFlag') - ->with('advertisement_notification_seen_admin_' . $userId, 1) - ->willReturn(true); - $this->assertTrue($this->advertisementFlagManager->setNotifiedUser($userId)); - } - - public function testIsUserNotified() - { - $userId = 1; - $this->flagManagerMock->expects($this->once()) - ->method('getFlagData') - ->with('advertisement_notification_seen_admin_' . $userId) - ->willReturn(true); - $this->assertTrue($this->advertisementFlagManager->isUserNotified($userId)); - } -} diff --git a/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php b/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php index 3fe6b6609bd5c..ecf283662959e 100644 --- a/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php +++ b/app/code/Magento/Advertisement/Test/Unit/Model/Condition/CanViewNotificationTest.php @@ -7,8 +7,10 @@ namespace Magento\Advertisement\Test\Unit\Model\Condition; use Magento\Advertisement\Model\Condition\CanViewNotification; +use Magento\Advertisement\Model\ResourceModel\Viewer\Logger; +use Magento\Advertisement\Model\Viewer\Log; +use Magento\Framework\App\ProductMetadataInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Advertisement\Model\AdvertisementFlagManager; use Magento\Backend\Model\Auth\Session; /** @@ -22,9 +24,14 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase private $canViewNotification; /** - * @var AdvertisementFlagManager|\PHPUnit_Framework_MockObject_MockObject + * @var Logger|\PHPUnit_Framework_MockObject_MockObject */ - private $advertisementFlagManagerMock; + private $viewerLoggerMock; + + /** + * @var ProductMetadataInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $productMetadataMock; /** * @var Session|\PHPUnit_Framework_MockObject_MockObject @@ -33,52 +40,72 @@ class CanViewNotificationTest extends \PHPUnit\Framework\TestCase public function setUp() { - $this->advertisementFlagManagerMock = $this->getMockBuilder(AdvertisementFlagManager::class) - ->disableOriginalConstructor() - ->getMock(); $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() ->setMethods(['getUser', 'getId']) ->getMock(); + $this->viewerLoggerMock = $this->getMockBuilder(Logger::class) + ->disableOriginalConstructor() + ->getMock(); + $this->productMetadataMock = $this->getMockBuilder(ProductMetadataInterface::class) + ->disableOriginalConstructor() + ->getMock(); $objectManager = new ObjectManager($this); $this->canViewNotification = $objectManager->getObject( CanViewNotification::class, [ - 'advertisementFlagManager' => $this->advertisementFlagManagerMock, - 'session' => $this->sessionMock + 'viewerLogger' => $this->viewerLoggerMock, + 'session' => $this->sessionMock, + 'productMetadata' => $this->productMetadataMock, ] ); } - public function isVisibleProvider() - { - return [ - [1, false, true], - [1, true, false] - ]; - } - /** - * @dataProvider isVisibleProvider - * @param int $userId - * @param bool $isUserNotified * @param bool $expected + * @param string $variableName + * @param int $callNum + * @param string $version + * @param string $lastViewVersion + * @dataProvider isVisibleProvider */ - public function testIsVisible($userId, $isUserNotified, $expected) + public function testIsVisible($expected, $variableName, $callNum, $version, $lastViewVersion = null) { $this->sessionMock->expects($this->once()) ->method('getUser') ->willReturnSelf(); $this->sessionMock->expects($this->once()) ->method('getId') - ->willReturn($userId); - $this->advertisementFlagManagerMock->expects($this->once()) - ->method('isUserNotified') - ->willReturn($isUserNotified); - $this->advertisementFlagManagerMock->expects($this->any()) - ->method('setNotifiedUser') - ->willReturn(true); - + ->willReturn(1); + $this->productMetadataMock->expects($this->once()) + ->method('getVersion') + ->willReturn($version); + $viewerLogMock = $this->getMockBuilder(Log::class) + ->disableOriginalConstructor() + ->getMock(); + $viewerLogMock->expects($this->any()) + ->method('getLastViewVersion') + ->willReturn($lastViewVersion); + $viewerLogNull = null; + $this->viewerLoggerMock->expects($this->once()) + ->method('get') + ->with(1) + ->willReturn($$variableName); + $this->viewerLoggerMock->expects($this->exactly($callNum)) + ->method('log') + ->with(1, $version); $this->assertEquals($expected, $this->canViewNotification->isVisible([])); } + + public function isVisibleProvider() + { + return [ + [true, 'viewerLogNull', 1, '2.2.1-dev'], + [true, 'viewerLogMock', 1, '2.2.1-dev', null], + [true, 'viewerLogMock', 1, '2.2.1-dev', '2.2.1'], + [true, 'viewerLogMock', 1, '2.2.1-dev', '2.2.0'], + [true, 'viewerLogMock', 1, '2.3.0', '2.2.0'], + [false, 'viewerLogMock', 0, '2.2.2', '2.2.2'], + ]; + } } diff --git a/app/code/Magento/Advertisement/etc/module.xml b/app/code/Magento/Advertisement/etc/module.xml index 5db6c24c13cb6..fb3c9d0b05a79 100644 --- a/app/code/Magento/Advertisement/etc/module.xml +++ b/app/code/Magento/Advertisement/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php b/dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php new file mode 100644 index 0000000000000..32cebc13dc39b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Advertisement/Model/ResourceModel/Viewer/LoggerTest.php @@ -0,0 +1,62 @@ +logger = $objectManager->get(Logger::class); + } + + /** + * @magentoDataFixture Magento/User/_files/user_with_role.php + */ + public function testLogAndGet() + { + $userModel = Bootstrap::getObjectManager()->get(\Magento\User\Model\User::class); + $adminUserNameFromFixture = 'adminUser'; + $adminUserId = $userModel->loadByUsername($adminUserNameFromFixture)->getId(); + $this->assertNull($this->logger->get($adminUserId)); + $firstLogVersion = '2.2.2'; + $this->logger->log($adminUserId, $firstLogVersion); + $firstLog = $this->logger->get($adminUserId); + $this->assertInstanceOf(Log::class, $firstLog); + $this->assertEquals($firstLogVersion, $firstLog->getLastViewVersion()); + $this->assertEquals($adminUserId, $firstLog->getViewerId()); + + $secondLogVersion = '2.3.0'; + $this->logger->log($adminUserId, $secondLogVersion); + $secondLog = $this->logger->get($adminUserId); + $this->assertInstanceOf(Log::class, $secondLog); + $this->assertEquals($secondLogVersion, $secondLog->getLastViewVersion()); + $this->assertEquals($adminUserId, $secondLog->getViewerId()); + $this->assertEquals($firstLog->getId(), $secondLog->getId()); + } + + /** + * @expectedException \Zend_Db_Statement_Exception + */ + public function testLogNonExistUser() + { + $this->logger->log(200, '2.2.2'); + } +} From 001df498846877a042cfddf0b565ae3e335e8766 Mon Sep 17 00:00:00 2001 From: Martin Peverelli Date: Fri, 20 Oct 2017 14:48:08 -0300 Subject: [PATCH 199/528] Fix Issue #7225 - Remove hardcoding of apply_to when saving attributes --- .../Catalog/Controller/Adminhtml/Product/Attribute/Save.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index 8eb13af6f96f2..f2803c2399474 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -193,7 +193,7 @@ public function execute() ); } - $data += ['is_filterable' => 0, 'is_filterable_in_search' => 0, 'apply_to' => []]; + $data += ['is_filterable' => 0, 'is_filterable_in_search' => 0]; if (is_null($model->getIsUserDefined()) || $model->getIsUserDefined() != 0) { $data['backend_type'] = $model->getBackendTypeByInput($data['frontend_input']); From 158e47e1b4004513a6c88bb074771344fd668f78 Mon Sep 17 00:00:00 2001 From: Pieter Cappelle Date: Fri, 20 Oct 2017 20:24:01 +0200 Subject: [PATCH 200/528] Fix issue 10347 --- app/code/Magento/Tax/Model/Plugin/OrderSave.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Tax/Model/Plugin/OrderSave.php b/app/code/Magento/Tax/Model/Plugin/OrderSave.php index 7203285248688..c7bef8b69a41a 100644 --- a/app/code/Magento/Tax/Model/Plugin/OrderSave.php +++ b/app/code/Magento/Tax/Model/Plugin/OrderSave.php @@ -97,8 +97,12 @@ protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order) } else { $percentSum = 0; foreach ($taxRates as $rate) { - $realAmount = $rates['amount'] * $rate['percent'] / $rates['percent']; - $realBaseAmount = $rates['base_amount'] * $rate['percent'] / $rates['percent']; + $percentSum += $rate['percent']; + } + + foreach ($taxRates as $rate) { + $realAmount = $rates['amount'] * $rate['percent'] / $percentSum; + $realBaseAmount = $rates['base_amount'] * $rate['percent'] / $percentSum; $ratesIdQuoteItemId[$rates['id']][] = [ 'id' => $taxesArray['item_id'], 'percent' => $rate['percent'], @@ -110,7 +114,6 @@ protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order) 'real_amount' => $realAmount, 'real_base_amount' => $realBaseAmount, ]; - $percentSum += $rate['percent']; } } } From 4c26acf6b73655ee741b4fa38d7adf75e4ff3249 Mon Sep 17 00:00:00 2001 From: peterjaap Date: Fri, 20 Oct 2017 20:25:18 +0200 Subject: [PATCH 201/528] Added CLI command to enable and disable profiler --- app/bootstrap.php | 5 +- .../Command/ProfilerDisableCommand.php | 72 ++++++++++++ .../Console/Command/ProfilerEnableCommand.php | 108 ++++++++++++++++++ app/code/Magento/Developer/etc/di.xml | 2 + 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Developer/Console/Command/ProfilerDisableCommand.php create mode 100644 app/code/Magento/Developer/Console/Command/ProfilerEnableCommand.php diff --git a/app/bootstrap.php b/app/bootstrap.php index 6701a9f4dd51e..e9eb72380c161 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -49,12 +49,13 @@ unset($_SERVER['ORIG_PATH_INFO']); } -if (!empty($_SERVER['MAGE_PROFILER']) +if ( + (!empty($_SERVER['MAGE_PROFILER']) || file_exists(BP . '/var/profiler.flag')) && isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'text/html') !== false ) { \Magento\Framework\Profiler::applyConfig( - $_SERVER['MAGE_PROFILER'], + (isset($_SERVER['MAGE_PROFILER']) && strlen($_SERVER['MAGE_PROFILER'])) ? $_SERVER['MAGE_PROFILER'] : trim(file_get_contents(BP . '/var/profiler.flag')), BP, !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ); diff --git a/app/code/Magento/Developer/Console/Command/ProfilerDisableCommand.php b/app/code/Magento/Developer/Console/Command/ProfilerDisableCommand.php new file mode 100644 index 0000000000000..267ddcb75929f --- /dev/null +++ b/app/code/Magento/Developer/Console/Command/ProfilerDisableCommand.php @@ -0,0 +1,72 @@ +filesystem = $filesystem; + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName(self::COMMAND_NAME) + ->setDescription('Disable the profiler.'); + + parent::configure(); + } + + /** + * {@inheritdoc} + * @throws \InvalidArgumentException + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->filesystem->rm(BP . '/' . self::PROFILER_FLAG_FILE); + if (!$this->filesystem->fileExists(BP . '/' . self::PROFILER_FLAG_FILE)) { + $output->writeln(''. self::SUCCESS_MESSAGE . ''); + return; + } + $output->writeln('Something went wrong while disabling the profiler.'); + } +} diff --git a/app/code/Magento/Developer/Console/Command/ProfilerEnableCommand.php b/app/code/Magento/Developer/Console/Command/ProfilerEnableCommand.php new file mode 100644 index 0000000000000..3bfe804d9ac5e --- /dev/null +++ b/app/code/Magento/Developer/Console/Command/ProfilerEnableCommand.php @@ -0,0 +1,108 @@ +filesystem = $filesystem; + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName(self::COMMAND_NAME) + ->setDescription('Enable the profiler.') + ->addArgument('type', InputArgument::OPTIONAL, 'Profiler type'); + + parent::configure(); + } + + /** + * {@inheritdoc} + * @throws \InvalidArgumentException + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $type = $input->getArgument('type'); + if (!$type) { + $type = self::TYPE_DEFAULT; + } + + if (!in_array($type, self::BUILT_IN_TYPES)) { + $builtInTypes = implode(', ', self::BUILT_IN_TYPES); + $output->writeln( + '' . sprintf('Type %s is not one of the built-in output types (%s).', $type) . + sprintf('Make sure the necessary class exists.', $type, $builtInTypes) . '' + ); + } + + $this->filesystem->write(BP . '/' . self::PROFILER_FLAG_FILE, $type); + if ($this->filesystem->fileExists(BP . '/' . self::PROFILER_FLAG_FILE)) { + $output->write(''. sprintf(self::SUCCESS_MESSAGE, $type) . ''); + if ($type == 'csvfile') { + $output->write( + ' ' . sprintf( + 'Output will be saved in %s', + \Magento\Framework\Profiler\Driver\Standard\Output\Csvfile::DEFAULT_FILEPATH + ) + . '' + ); + } + $output->write(PHP_EOL); + return; + } + + $output->writeln('Something went wrong while enabling the profiler.'); + } +} diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml index ca35c38a31b68..85b28c90132af 100644 --- a/app/code/Magento/Developer/etc/di.xml +++ b/app/code/Magento/Developer/etc/di.xml @@ -102,6 +102,8 @@ Magento\Developer\Console\Command\QueryLogDisableCommand Magento\Developer\Console\Command\TemplateHintsDisableCommand Magento\Developer\Console\Command\TemplateHintsEnableCommand + Magento\Developer\Console\Command\ProfilerDisableCommand + Magento\Developer\Console\Command\ProfilerEnableCommand From 5ff6b675dcf6ba55fdab46a6afa402c40b04370c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Pihlstr=C3=B6m?= Date: Fri, 20 Oct 2017 21:31:07 +0200 Subject: [PATCH 202/528] fix indentation --- .../Plugin/Eav/Model/AttributeSetRepository.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php index 99370c9e48de8..4dc0c928c6993 100644 --- a/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php +++ b/app/code/Magento/CatalogUrlRewrite/Plugin/Eav/Model/AttributeSetRepository.php @@ -47,10 +47,10 @@ public function aroundDelete( callable $proceed, AttributeSetInterface $attributeSet ) { - if (!isset($subject) || !$attributeSet->getAttributeSetId()) - { - return false; - } + if (!isset($subject) || !$attributeSet->getAttributeSetId()) + { + return false; + } // Get the product ids $ids = $this->productCollection->addFieldToFilter('attribute_set_id', $attributeSet->getAttributeSetId()) From c630e4a7b7ba8cf2c638f50f2ec39304b6ee70f9 Mon Sep 17 00:00:00 2001 From: Pieter Cappelle Date: Fri, 20 Oct 2017 21:58:43 +0200 Subject: [PATCH 203/528] Fix issue 10032 --- .../Magento/Backup/Model/BackupFactory.php | 19 +++--- .../Test/Unit/Model/BackupFactoryTest.php | 59 ++++++++----------- 2 files changed, 31 insertions(+), 47 deletions(-) diff --git a/app/code/Magento/Backup/Model/BackupFactory.php b/app/code/Magento/Backup/Model/BackupFactory.php index c4e2be9758f72..28b0a7baf43cb 100644 --- a/app/code/Magento/Backup/Model/BackupFactory.php +++ b/app/code/Magento/Backup/Model/BackupFactory.php @@ -39,23 +39,20 @@ public function __construct(\Magento\Framework\ObjectManagerInterface $objectMan */ public function create($timestamp, $type) { - $backupId = $timestamp . '_' . $type; $fsCollection = $this->_objectManager->get(\Magento\Backup\Model\Fs\Collection::class); $backupInstance = $this->_objectManager->get(\Magento\Backup\Model\Backup::class); + foreach ($fsCollection as $backup) { - if ($backup->getId() == $backupId) { - $backupInstance->setType( - $backup->getType() - )->setTime( - $backup->getTime() - )->setName( - $backup->getName() - )->setPath( - $backup->getPath() - ); + if ($backup->getTime() === (int) $timestamp && $backup->getType() === $type) { + $backupInstance->setData(['id' => $backup->getId()]) + ->setType($backup->getType()) + ->setTime($backup->getTime()) + ->setName($backup->getName()) + ->setPath($backup->getPath()); break; } } + return $backupInstance; } } diff --git a/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php b/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php index dca65db48650f..629028bfd6f15 100644 --- a/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php +++ b/app/code/Magento/Backup/Test/Unit/Model/BackupFactoryTest.php @@ -77,42 +77,29 @@ protected function setUp() public function testCreate() { - $this->_backupModel->expects( - $this->once() - )->method( - 'setType' - )->with( - $this->_data['type'] - )->will( - $this->returnSelf() - ); - $this->_backupModel->expects( - $this->once() - )->method( - 'setTime' - )->with( - $this->_data['time'] - )->will( - $this->returnSelf() - ); - $this->_backupModel->expects( - $this->once() - )->method( - 'setName' - )->with( - $this->_data['name'] - )->will( - $this->returnSelf() - ); - $this->_backupModel->expects( - $this->once() - )->method( - 'setPath' - )->with( - $this->_data['path'] - )->will( - $this->returnSelf() - ); + $this->_backupModel->expects($this->once()) + ->method('setType') + ->with($this->_data['type']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setTime') + ->with($this->_data['time']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setName') + ->with($this->_data['name']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setPath') + ->with($this->_data['path']) + ->will($this->returnSelf()); + + $this->_backupModel->expects($this->once()) + ->method('setData') + ->will($this->returnSelf()); $this->_instance->create('1385661590', 'snapshot'); } From f686c4d4bd9804c0c11626b6b6cf8a157fb4a8f4 Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 20 Oct 2017 15:24:15 -0500 Subject: [PATCH 204/528] MAGETWO-82125: Display advertisement popup at the 1st time per admin login --- .../Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php index a38b888de4d64..3f757b865c9a7 100644 --- a/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php +++ b/app/code/Magento/Advertisement/Model/ResourceModel/Viewer/Logger.php @@ -54,7 +54,7 @@ public function log($viewerId, $lastViewVersion) $connection = $this->resource->getConnection(ResourceConnection::DEFAULT_CONNECTION); $connection->insertOnDuplicate( - $this->resource->getTableName(self::TABLE_NAME ), + $this->resource->getTableName(self::TABLE_NAME), [ 'viewer_id' => $viewerId, 'last_view_version' => $lastViewVersion From 215d04d90dd7acfbd388abe5afddb7ded9cbbd67 Mon Sep 17 00:00:00 2001 From: Oscar Recio Date: Sat, 21 Oct 2017 01:45:55 +0200 Subject: [PATCH 205/528] Add Unit tests for getSelectCountSql --- .../Review/Customer/Collection.php | 2 +- .../Report/Review/Customer/CollectionTest.php | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Reports/Test/Unit/Model/ResourceModel/Report/Review/Customer/CollectionTest.php diff --git a/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php b/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php index c25fe3c6508ed..9297a1dda18d8 100644 --- a/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php +++ b/app/code/Magento/Reports/Model/ResourceModel/Review/Customer/Collection.php @@ -110,7 +110,7 @@ protected function _joinCustomers() */ public function getSelectCountSql() { - $countSelect = clone $this->_select; + $countSelect = clone $this->getSelect(); $countSelect->reset(\Magento\Framework\DB\Select::ORDER); $countSelect->reset(\Magento\Framework\DB\Select::GROUP); $countSelect->reset(\Magento\Framework\DB\Select::HAVING); diff --git a/app/code/Magento/Reports/Test/Unit/Model/ResourceModel/Report/Review/Customer/CollectionTest.php b/app/code/Magento/Reports/Test/Unit/Model/ResourceModel/Report/Review/Customer/CollectionTest.php new file mode 100644 index 0000000000000..9534fe3b57f5a --- /dev/null +++ b/app/code/Magento/Reports/Test/Unit/Model/ResourceModel/Report/Review/Customer/CollectionTest.php @@ -0,0 +1,41 @@ +selectMock = $this->createMock(Select::class); + } + + public function testGetSelectCountSql() + { + /** @var $collection \PHPUnit_Framework_MockObject_MockObject */ + $collection = $this->getMockBuilder(Collection::class) + ->setMethods(['getSelect']) + ->disableOriginalConstructor() + ->getMock(); + + $collection->expects($this->atLeastOnce())->method('getSelect')->willReturn($this->selectMock); + + $this->selectMock->expects($this->atLeastOnce())->method('reset')->willReturnSelf(); + $this->selectMock->expects($this->exactly(1))->method('columns')->willReturnSelf(); + + $this->assertEquals($this->selectMock, $collection->getSelectCountSql()); + } +} From 70d7502aed7e6d9332399e7c38aa0e971d882b9a Mon Sep 17 00:00:00 2001 From: Marc Rodriguez Date: Sat, 21 Oct 2017 10:17:58 +0200 Subject: [PATCH 206/528] FR#6891_22 Add-to-cart checkbox still visible when = false --- .../Catalog/view/frontend/templates/product/list/items.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml index 1b9f014b7c27f..fc0967ca60d2d 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/list/items.phtml @@ -203,7 +203,7 @@ switch ($type = $block->getType()) { getReviewsSummaryHtml($_item, $templateType) ?> - isComposite() && $_item->isSaleable() && $type == 'related'): ?> + isComposite() && $_item->isSaleable() && $type == 'related'): ?> getRequiredOptions()): ?>
]]> @@ -247,7 +250,7 @@ release-notification-button-back - ns = ${ $.ns }, index = developer_experience_modal + ns = ${ $.ns }, index = instant_purchase_modal closeModal @@ -268,11 +271,11 @@ release-notification-button-next - ns = ${ $.ns }, index = developer_experience_modal + ns = ${ $.ns }, index = instant_purchase_modal closeModal - ns = ${ $.ns }, index = b2b_modal + ns = ${ $.ns }, index = email_marketing_modal openModal @@ -286,13 +289,12 @@ - + actionCancel - - + + @@ -309,17 +311,18 @@ release-notification-text Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform - their online purchasing experience to achieve greater operational efficiency, improved customer - service, and sales growth. New capabilities include: +

Unlock an unparalleled level of insight and control of your eCommerce marketing with + dotmailer Email Marketing Automation. Included with Magento 2.2.2 for easy set-up, dotmailer + ensures every customer’s journey is captured, segmented, and personalized, enabling you to + deliver customer-centric campaigns that beat your results over and over again. Benefits include:

    -
  • Company accounts with multiple tiers of buyers
  • -
  • Buyer roles and permissions
  • -
  • Custom catalogs and pricing
  • -
  • Quoting support
  • -
  • Rapid reorder experience
  • -
  • Payments on credit
  • +
  • No obligation 14-day trial.
  • +
  • Automation campaigns using your live Magento store data that drive revenue, + including abandoned cart, abandoned browse, product replenishment, and many more
  • +
  • Custom catalogs and pricing.
  • +
  • Built-in solution for transactional emails.
  • +
  • Telephone support and advice from marketing experts included.
]]>
@@ -337,11 +340,11 @@ release-notification-button-back - ns = ${ $.ns }, index = b2b_modal + ns = ${ $.ns }, index = email_marketing_modal closeModal - ns = ${ $.ns }, index = developer_experience_modal + ns = ${ $.ns }, index = instant_purchase_modal openModal @@ -358,7 +361,7 @@ release-notification-button-next - ns = ${ $.ns }, index = b2b_modal + ns = ${ $.ns }, index = email_marketing_modal closeReleaseNotes diff --git a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less index 81c9b70c71889..ce7a49481b6ea 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/css/source/_module.less @@ -7,7 +7,7 @@ // Magento_ReleaseNotification Modal on dashboard // --------------------------------------------- -.release-notification-modal, .analytics-subscription-modal, .developer-experience-modal, .b2b-modal { +.release-notification-modal, .analytics-subscription-modal, .instant-purchase-modal, .email-marketing-modal { -webkit-transition: visibility 0s .5s, opacity .5s ease; transition: visibility 0s .5s, opacity .5s ease; @@ -54,7 +54,9 @@ span { font-size: @font-size__base; - margin-left: 2rem; + vertical-align: middle; + position: relative; + left: 1rem; } } } @@ -77,17 +79,17 @@ background-size: 65px 58px; } -.b2b-highlight { - background: url("Magento_ReleaseNotification::images/b2b-icon.svg") no-repeat; +.email-marketing-highlight { + background: url("Magento_ReleaseNotification::images/email-marketing-icon.svg") no-repeat; background-size: 65px 53.37px; } -.developer-experience-highlight { - background: url("Magento_ReleaseNotification::images/developer-experience-icon.svg") no-repeat; +.instant-purchase-highlight { + background: url("Magento_ReleaseNotification::images/instant-purchase-icon.svg") no-repeat; background-size: 65px 59px; } -.analytics-highlight, .b2b-highlight, .developer-experience-highlight { +.analytics-highlight, .email-marketing-highlight, .instant-purchase-highlight { padding: 0 0 2rem 8.5rem; margin-left: 1rem; @@ -110,17 +112,17 @@ } } -.b2b-modal { +.email-marketing-modal { h1:first-of-type { - background: url("Magento_ReleaseNotification::images/b2b-icon.svg") no-repeat; + background: url("Magento_ReleaseNotification::images/email-marketing-icon.svg") no-repeat; background-size: 55px 49.92px; padding: 1.5rem 0 2rem 7rem; } } -.developer-experience-modal { +.instant-purchase-modal { h1:first-of-type { - background: url("Magento_ReleaseNotification::images/developer-experience-icon.svg") no-repeat; + background: url("Magento_ReleaseNotification::images/instant-purchase-icon.svg") no-repeat; background-size: 55px 46px; padding: 1.5rem 0 2rem 7rem; } diff --git a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/analytics-icon.svg b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/analytics-icon.svg index fde91d775d444..2846b29627df6 100644 --- a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/analytics-icon.svg +++ b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/analytics-icon.svg @@ -1,84 +1,27 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/b2b-icon.svg b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/b2b-icon.svg deleted file mode 100644 index 20552d6178c25..0000000000000 --- a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/b2b-icon.svg +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/developer-experience-icon.svg b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/developer-experience-icon.svg deleted file mode 100644 index 50d208118aedf..0000000000000 --- a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/developer-experience-icon.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - diff --git a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/email-marketing-icon.svg b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/email-marketing-icon.svg new file mode 100644 index 0000000000000..dc9ac2103d93f --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/email-marketing-icon.svg @@ -0,0 +1,27 @@ + + + + diff --git a/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/instant-purchase-icon.svg b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/instant-purchase-icon.svg new file mode 100644 index 0000000000000..c832fb75efe18 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/Magento_ReleaseNotification/web/images/instant-purchase-icon.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + From 24de9b0cad98f399b5f5ca6af7f8bb0a7af2c9d2 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Fri, 10 Nov 2017 16:08:16 -0600 Subject: [PATCH 452/528] MAGETWO-83184: Static Content Update for ReleaseNotification Module --- .../view/adminhtml/templates/admin/access_denied.phtml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml b/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml index 18d0b47d21498..b476e54d642c6 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml @@ -21,15 +21,9 @@
  • escapeHtml(__('Contact a system administrator or store owner to gain permissions.')) ?>
  • escapeHtml(__('Return to ')) ?> - + escapeHtml(__('previous page')) ?>escapeHtml(__('.')) ?>
  • - From 9ae097af660f77a27e36208d44ea3132a8027457 Mon Sep 17 00:00:00 2001 From: rossbrandon Date: Fri, 10 Nov 2017 17:00:06 -0600 Subject: [PATCH 453/528] MAGETWO-83184: Static Content Update for ReleaseNotification Module --- .../templates/admin/access_denied.phtml | 9 +- .../ReleaseNotification/i18n/en_US.csv | 123 +++++++++--------- .../ui_component/release_notification.xml | 2 +- 3 files changed, 73 insertions(+), 61 deletions(-) diff --git a/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml b/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml index b476e54d642c6..843328fbf17d7 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/admin/access_denied.phtml @@ -21,8 +21,13 @@
  • escapeHtml(__('Contact a system administrator or store owner to gain permissions.')) ?>
  • escapeHtml(__('Return to ')) ?> - - escapeHtml(__('previous page')) ?>escapeHtml(__('.')) ?> + + + escapeHtml(__('previous page')) ?>escapeHtml(__('.')) ?> + + + escapeHtml(__('previous page')) ?>escapeHtml(__('.')) ?> +
  • diff --git a/app/code/Magento/ReleaseNotification/i18n/en_US.csv b/app/code/Magento/ReleaseNotification/i18n/en_US.csv index 3fd0be63b4ab1..bf70afad8bf1a 100644 --- a/app/code/Magento/ReleaseNotification/i18n/en_US.csv +++ b/app/code/Magento/ReleaseNotification/i18n/en_US.csv @@ -1,42 +1,42 @@ "Next >","Next >" "< Back","< Back" "Done","Done" -"What's new for Magento 2.2.2","What's new for Magento 2.2.2" -"

    Magento 2.2.2 offers an exciting set of features and enhancements, including:

    +"What's new with Magento 2.2.2","What's new with Magento 2.2.2" +"

    Magento 2.2.2 offers advanced new features, including:


    Advanced Reporting

    Gain valuable insights through a dynamic suite of product, order, and customer reports, powered by Magento Business Intelligence.

    -
    -

    Developer Experience

    -

    We've improved the entire development lifecycle - installation, development, and maintenance - - while ensuring Magento's commitment to quality.

    +
    +

    Instant Purchase

    +

    Simplify ordering and boost conversion rates by allowing your customers to use stored + payment and shipping information to skip tedious checkout steps.

    -
    -

    Business-to-Business (B2B) Magento Commerce only

    -

    Features to manage your complex company accounts, rapid reordering, new buyers' roles and - permissions, and more.

    +
    +

    Email Marketing Automation

    +

    Send smarter, faster email campaigns with marketing automation from dotmailer, powered by + your Magento store's live data.

    Release notes and additional details can be found at Magento DevDocs. -

    ","

    Magento 2.2.2 offers an exciting set of features and enhancements, including:

    +

    ","

    Magento 2.2.2 offers advanced new features, including:


    Advanced Reporting

    Gain valuable insights through a dynamic suite of product, order, and customer reports, powered by Magento Business Intelligence.

    -
    -

    Developer Experience

    -

    We've improved the entire development lifecycle - installation, development, and maintenance - - while ensuring Magento's commitment to quality.

    +
    +

    Instant Purchase

    +

    Simplify ordering and boost conversion rates by allowing your customers to use stored + payment and shipping information to skip tedious checkout steps.

    -
    -

    Business-to-Business (B2B) Magento Commerce only

    -

    Features to manage your complex company accounts, rapid reordering, new buyers' roles and - permissions, and more.

    +
    +

    Email Marketing Automation

    +

    Send smarter, faster email campaigns with marketing automation from dotmailer, powered by + your Magento store's live data.

    Release notes and additional details can be found at Magento DevDocs. @@ -57,51 +57,58 @@ with new and improved analytics.


    By using Magento 2.2, you agree to the Advanced Reporting Privacy Policy and Terms - of Service. You may opt out at any time from the Stores Configuration page.

    - " -"Developer Experience","Developer Experience" -"

    Magento's 2.2.2 release offers a set of improvements that were developed using increased - quality standards. The release includes these features, among others: + of Service. You may opt out at any time from the Stores Configuration page.

    " +"Instant Purchase","Instant Purchase" +"

    Now you can deliver an Amazon-like experience with a new, streamlined checkout option. + Logged-in customers can use previously-stored payment credentials and shipping information + to skip steps, making the process faster and easier, especially for mobile shoppers. Key + features include:

      -
    • GitHub Community Moderator Team
    • -
    • GitHub Community Videos
    • -
    • DevDocs Enhancements
    • -
    -

    Find the 2.2.2 details and future plans in the - Magento DevBlog. -

    ","

    Magento's 2.2.2 release offers a set of improvements that were developed using increased - quality standards. The release includes these features, among others: +

  • Configurable “Instant Purchase” button to place orders
  • +
  • Support for all payment solutions using Braintree Vault, including Braintree Credit + Card, Braintree PayPal, and PayPal Payflow Pro.
  • +
  • Shipping to the customer’s default address using the lowest cost, available shipping + method
  • +
  • Ability for developers to customize the Instant Purchase business logic to meet + merchant needs
  • + ","

    Now you can deliver an Amazon-like experience with a new, streamlined checkout option. + Logged-in customers can use previously-stored payment credentials and shipping information + to skip steps, making the process faster and easier, especially for mobile shoppers. Key + features include:

      -
    • GitHub Community Moderator Team
    • -
    • GitHub Community Videos
    • -
    • DevDocs Enhancements
    • -
    -

    Find the 2.2.2 details and future plans in the - Magento DevBlog. -

    " -"Business-to-Business (B2B) Magento Commerce only","Business-to-Business (B2B) Magento Commerce only" -"

    Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform - their online purchasing experience to achieve greater operational efficiency, improved customer - service, and sales growth. New capabilities include: +

  • Configurable “Instant Purchase” button to place orders
  • +
  • Support for all payment solutions using Braintree Vault, including Braintree Credit + Card, Braintree PayPal, and PayPal Payflow Pro.
  • +
  • Shipping to the customer’s default address using the lowest cost, available shipping + method
  • +
  • Ability for developers to customize the Instant Purchase business logic to meet + merchant needs
  • + " +"Email Marketing Automation","Email Marketing Automation" +"

    Unlock an unparalleled level of insight and control of your eCommerce marketing with + dotmailer Email Marketing Automation. Included with Magento 2.2.2 for easy set-up, dotmailer + ensures every customer’s journey is captured, segmented, and personalized, enabling you to + deliver customer-centric campaigns that beat your results over and over again. Benefits include:

      -
    • Company accounts with multiple tiers of buyers
    • -
    • Buyer roles and permissions
    • -
    • Custom catalogs and pricing
    • -
    • Quoting support
    • -
    • Rapid reorder experience
    • -
    • Payments on credit
    • -
    ","

    Magento Commerce 2.2.2 offers rich new functionality that empowers B2B merchants to transform - their online purchasing experience to achieve greater operational efficiency, improved customer - service, and sales growth. New capabilities include: +

  • No obligation 14-day trial.
  • +
  • Automation campaigns using your live Magento store data that drive revenue, + including abandoned cart, abandoned browse, product replenishment, and many more
  • +
  • Custom catalogs and pricing.
  • +
  • Built-in solution for transactional emails.
  • +
  • Telephone support and advice from marketing experts included.
  • + ","

    Unlock an unparalleled level of insight and control of your eCommerce marketing with + dotmailer Email Marketing Automation. Included with Magento 2.2.2 for easy set-up, dotmailer + ensures every customer’s journey is captured, segmented, and personalized, enabling you to + deliver customer-centric campaigns that beat your results over and over again. Benefits include:

      -
    • Company accounts with multiple tiers of buyers
    • -
    • Buyer roles and permissions
    • -
    • Custom catalogs and pricing
    • -
    • Quoting support
    • -
    • Rapid reorder experience
    • -
    • Payments on credit
    • +
    • No obligation 14-day trial.
    • +
    • Automation campaigns using your live Magento store data that drive revenue, + including abandoned cart, abandoned browse, product replenishment, and many more
    • +
    • Custom catalogs and pricing.
    • +
    • Built-in solution for transactional emails.
    • +
    • Telephone support and advice from marketing experts included.
    " diff --git a/app/code/Magento/ReleaseNotification/view/adminhtml/ui_component/release_notification.xml b/app/code/Magento/ReleaseNotification/view/adminhtml/ui_component/release_notification.xml index 4364e8948adf5..7a6f0af74716d 100644 --- a/app/code/Magento/ReleaseNotification/view/adminhtml/ui_component/release_notification.xml +++ b/app/code/Magento/ReleaseNotification/view/adminhtml/ui_component/release_notification.xml @@ -43,7 +43,7 @@ true - + From 149268c5c30267a04d50f8cc63f2ea3df0b8708e Mon Sep 17 00:00:00 2001 From: Andrew Garside Date: Sun, 12 Nov 2017 14:24:12 +1000 Subject: [PATCH 454/528] Update the fixture and tests to reflect the functionality of getShippingMethod --- .../testsuite/Magento/Sales/Service/V1/OrderCreateTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php index b61bfdabe25cd..a907faac98b72 100755 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderCreateTest.php @@ -140,7 +140,7 @@ protected function prepareOrder() [ 'shipping' => [ 'address' => $address, - 'method' => 'Flat Rate - Fixed' + 'method' => 'flatrate_flatrate' ], 'items' => [$orderItem->getData()], 'stock_id' => null, @@ -232,6 +232,9 @@ public function testOrderCreate() $this->assertEquals($order['grand_total'], $model->getGrandTotal()); $this->assertNotNull($model->getShippingAddress()); $this->assertTrue((bool)$model->getShippingAddress()->getId()); - $this->assertEquals('Flat Rate - Fixed', $model->getShippingMethod()); + $this->assertEquals('Flat Rate - Fixed', $model->getShippingDescription()); + $shippingMethod = $model->getShippingMethod(true); + $this->assertEquals('flatrate', $shippingMethod['carrier_code']); + $this->assertEquals('flatrate', $shippingMethod['method']); } } From 061229bef7809fd0f55cee299a203ecc736b2fba Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Mon, 13 Nov 2017 12:03:20 +0200 Subject: [PATCH 455/528] MAGETWO-70726: [GITHUB] [2.1] Store View Language switch leads to 404 on some cases #5416 --- .../Model/Storage/DbStorage.php | 52 ++++++++----------- .../Test/Unit/Model/Storage/DbStorageTest.php | 16 +----- 2 files changed, 23 insertions(+), 45 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Storage/DbStorage.php b/app/code/Magento/CatalogUrlRewrite/Model/Storage/DbStorage.php index 9e9007e7f667c..f0351467e5f0e 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/Storage/DbStorage.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/Storage/DbStorage.php @@ -12,47 +12,37 @@ class DbStorage extends BaseDbStorage { /** - * @param array $data - * @return \Magento\Framework\DB\Select + * {@inheritDoc} */ protected function prepareSelect(array $data) { - if (!array_key_exists(UrlRewrite::ENTITY_ID, $data) - || !array_key_exists(UrlRewrite::ENTITY_TYPE, $data) - || !array_key_exists(UrlRewrite::STORE_ID, $data) - ) { - throw new \InvalidArgumentException( - UrlRewrite::ENTITY_ID . ', ' . UrlRewrite::ENTITY_TYPE - . ' and ' . UrlRewrite::STORE_ID . ' parameters are required.' - ); + $metadata = []; + if (array_key_exists(UrlRewrite::METADATA, $data)) { + $metadata = $data[UrlRewrite::METADATA]; + unset($data[UrlRewrite::METADATA]); } $select = $this->connection->select(); - $select->from(['url_rewrite' => $this->resource->getTableName('url_rewrite')]) - ->joinLeft( - ['relation' => $this->resource->getTableName(Product::TABLE_NAME)], - 'url_rewrite.url_rewrite_id = relation.url_rewrite_id' - ) - ->where( - 'url_rewrite.entity_id IN (?)', - $data[UrlRewrite::ENTITY_ID] - ) - ->where( - 'url_rewrite.entity_type = ?', - $data[UrlRewrite::ENTITY_TYPE] - ) - ->where('url_rewrite.store_id IN (?)', $data[UrlRewrite::STORE_ID]); - if (array_key_exists(UrlRewrite::REDIRECT_TYPE, $data)) { - $select->where( - 'url_rewrite.redirect_type = ?', - $data[UrlRewrite::REDIRECT_TYPE] - ); + $select->from([ + 'url_rewrite' => $this->resource->getTableName(self::TABLE_NAME) + ]); + $select->joinLeft( + ['relation' => $this->resource->getTableName(Product::TABLE_NAME)], + 'url_rewrite.url_rewrite_id = relation.url_rewrite_id' + ); + + foreach ($data as $column => $value) { + $select->where('url_rewrite.' . $column . ' IN (?)', $value); } - if (empty($data[UrlRewrite::METADATA]['category_id'])) { + if (empty($metadata['category_id'])) { $select->where('relation.category_id IS NULL'); } else { - $select->where('relation.category_id = ?', $data[UrlRewrite::METADATA]['category_id']); + $select->where( + 'relation.category_id = ?', + $metadata['category_id'] + ); } + return $select; } } diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php index 89e9616f107e0..d00b0c87fa5ad 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Storage/DbStorageTest.php @@ -89,18 +89,6 @@ protected function setUp() public function testPrepareSelect() { - //Not passing requried parameters. - try { - $this->storage->findOneByData(['SomeOtherParam'=>42]); - $this->fail('Didn\'t ask for required parameters'); - } catch (\InvalidArgumentException $exception) { - $this->assertEquals( - UrlRewrite::ENTITY_ID . ', ' . UrlRewrite::ENTITY_TYPE - . ' and ' . UrlRewrite::STORE_ID . ' parameters are required.', - $exception->getMessage() - ); - } - //Passing expected parameters, checking select built. $entityType = 'custom'; $entityId= 42; @@ -116,7 +104,7 @@ public function testPrepareSelect() $this->select ->expects($this->at(3)) ->method('where') - ->with('url_rewrite.entity_type = ?', $entityType) + ->with('url_rewrite.entity_type IN (?)', $entityType) ->willReturn($this->select); $this->select ->expects($this->at(4)) @@ -126,7 +114,7 @@ public function testPrepareSelect() $this->select ->expects($this->at(5)) ->method('where') - ->with('url_rewrite.redirect_type = ?', $redirectType) + ->with('url_rewrite.redirect_type IN (?)', $redirectType) ->willReturn($this->select); $this->select ->expects($this->at(6)) From b750e583b36d4409dfd2b2b3a82bea06a31b2511 Mon Sep 17 00:00:00 2001 From: RomanKis Date: Fri, 10 Nov 2017 12:29:03 +0200 Subject: [PATCH 456/528] 7691: address with saveInAddressBook 0 are still being added to the address book for new customers(backport to 2.2) --- .../Magento/Quote/Model/QuoteManagement.php | 2 + .../Test/Unit/Model/QuoteManagementTest.php | 67 +++++++++++----- .../Sales/Model/Order/CustomerManagement.php | 37 ++++++++- app/code/Magento/Sales/Setup/UpgradeData.php | 80 ++++++++++++++++++- .../Model/Order/CustomerManagementTest.php | 46 ++++++++++- app/code/Magento/Sales/etc/module.xml | 2 +- .../adminhtml/web/order/create/scripts.js | 4 +- .../Order/Create/Shipping/Method.php | 10 ++- 8 files changed, 213 insertions(+), 35 deletions(-) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 6f03bba5072a2..9bdcb083808ad 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -475,6 +475,7 @@ protected function submitQuote(QuoteEntity $quote, $orderData = []) 'email' => $quote->getCustomerEmail() ] ); + $shippingAddress->setData('quote_address_id', $quote->getShippingAddress()->getId()); $addresses[] = $shippingAddress; $order->setShippingAddress($shippingAddress); $order->setShippingMethod($quote->getShippingAddress()->getShippingMethod()); @@ -486,6 +487,7 @@ protected function submitQuote(QuoteEntity $quote, $orderData = []) 'email' => $quote->getCustomerEmail() ] ); + $billingAddress->setData('quote_address_id', $quote->getBillingAddress()->getId()); $addresses[] = $billingAddress; $order->setBillingAddress($billingAddress); $order->setAddresses($addresses); diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php index 8316885e9b45c..145a18fb34ca3 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php @@ -7,8 +7,8 @@ namespace Magento\Quote\Test\Unit\Model; use Magento\Framework\Exception\NoSuchEntityException; - use Magento\Quote\Model\CustomerManagement; +use Magento\Sales\Api\Data\OrderAddressInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -540,12 +540,12 @@ public function testSubmit() $shippingAddress = $this->createMock(\Magento\Quote\Model\Quote\Address::class); $payment = $this->createMock(\Magento\Quote\Model\Quote\Payment::class); $baseOrder = $this->createMock(\Magento\Sales\Api\Data\OrderInterface::class); - $convertedBillingAddress = $this->createMock(\Magento\Sales\Api\Data\OrderAddressInterface::class); - $convertedShippingAddress = $this->createMock(\Magento\Sales\Api\Data\OrderAddressInterface::class); + $convertedBilling = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['setData']); + $convertedShipping = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['setData']); $convertedPayment = $this->createMock(\Magento\Sales\Api\Data\OrderPaymentInterface::class); $convertedQuoteItem = $this->createMock(\Magento\Sales\Api\Data\OrderItemInterface::class); - $addresses = [$convertedShippingAddress, $convertedBillingAddress]; + $addresses = [$convertedShipping, $convertedBilling]; $quoteItems = [$quoteItem]; $convertedItems = [$convertedQuoteItem]; @@ -574,7 +574,7 @@ public function testSubmit() 'email' => 'customer@example.com' ] ) - ->willReturn($convertedShippingAddress); + ->willReturn($convertedShipping); $this->quoteAddressToOrderAddress->expects($this->at(1)) ->method('convert') ->with( @@ -584,22 +584,27 @@ public function testSubmit() 'email' => 'customer@example.com' ] ) - ->willReturn($convertedBillingAddress); + ->willReturn($convertedBilling); + + $billingAddress->expects($this->once())->method('getId')->willReturn(4); + $convertedBilling->expects($this->once())->method('setData')->with('quote_address_id', 4); $this->quoteItemToOrderItem->expects($this->once())->method('convert') ->with($quoteItem, ['parent_item' => null]) ->willReturn($convertedQuoteItem); $this->quotePaymentToOrderPayment->expects($this->once())->method('convert')->with($payment) ->willReturn($convertedPayment); $shippingAddress->expects($this->once())->method('getShippingMethod')->willReturn('free'); + $shippingAddress->expects($this->once())->method('getId')->willReturn(5); + $convertedShipping->expects($this->once())->method('setData')->with('quote_address_id', 5); $order = $this->prepareOrderFactory( $baseOrder, - $convertedBillingAddress, + $convertedBilling, $addresses, $convertedPayment, $convertedItems, $quoteId, - $convertedShippingAddress + $convertedShipping ); $this->orderManagement->expects($this->once()) @@ -973,9 +978,6 @@ protected function setPropertyValue(&$object, $property, $value) return $object; } - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ public function testSubmitForCustomer() { $orderData = []; @@ -988,16 +990,12 @@ public function testSubmitForCustomer() $shippingAddress = $this->createMock(\Magento\Quote\Model\Quote\Address::class); $payment = $this->createMock(\Magento\Quote\Model\Quote\Payment::class); $baseOrder = $this->createMock(\Magento\Sales\Api\Data\OrderInterface::class); - $convertedBillingAddress = $this->createMock( - \Magento\Sales\Api\Data\OrderAddressInterface::class - ); - $convertedShippingAddress = $this->createMock( - \Magento\Sales\Api\Data\OrderAddressInterface::class - ); + $convertedBilling = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['setData']); + $convertedShipping = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['setData']); $convertedPayment = $this->createMock(\Magento\Sales\Api\Data\OrderPaymentInterface::class); $convertedQuoteItem = $this->createMock(\Magento\Sales\Api\Data\OrderItemInterface::class); - $addresses = [$convertedShippingAddress, $convertedBillingAddress]; + $addresses = [$convertedShipping, $convertedBilling]; $quoteItems = [$quoteItem]; $convertedItems = [$convertedQuoteItem]; @@ -1026,7 +1024,7 @@ public function testSubmitForCustomer() 'email' => 'customer@example.com' ] ) - ->willReturn($convertedShippingAddress); + ->willReturn($convertedShipping); $this->quoteAddressToOrderAddress->expects($this->at(1)) ->method('convert') ->with( @@ -1036,22 +1034,24 @@ public function testSubmitForCustomer() 'email' => 'customer@example.com' ] ) - ->willReturn($convertedBillingAddress); + ->willReturn($convertedBilling); $this->quoteItemToOrderItem->expects($this->once())->method('convert') ->with($quoteItem, ['parent_item' => null]) ->willReturn($convertedQuoteItem); $this->quotePaymentToOrderPayment->expects($this->once())->method('convert')->with($payment) ->willReturn($convertedPayment); $shippingAddress->expects($this->once())->method('getShippingMethod')->willReturn('free'); + $shippingAddress->expects($this->once())->method('getId')->willReturn(5); + $convertedShipping->expects($this->once())->method('setData')->with('quote_address_id', 5); $order = $this->prepareOrderFactory( $baseOrder, - $convertedBillingAddress, + $convertedBilling, $addresses, $convertedPayment, $convertedItems, $quoteId, - $convertedShippingAddress + $convertedShipping ); $customerAddressMock = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) ->getMockForAbstractClass(); @@ -1060,6 +1060,8 @@ public function testSubmitForCustomer() $quote->expects($this->any())->method('addCustomerAddress')->with($customerAddressMock); $billingAddress->expects($this->once())->method('getCustomerId')->willReturn(2); $billingAddress->expects($this->once())->method('getSaveInAddressBook')->willReturn(false); + $billingAddress->expects($this->once())->method('getId')->willReturn(4); + $convertedBilling->expects($this->once())->method('setData')->with('quote_address_id', 4); $this->orderManagement->expects($this->once()) ->method('place') ->with($order) @@ -1073,4 +1075,25 @@ public function testSubmitForCustomer() $this->quoteRepositoryMock->expects($this->once())->method('save')->with($quote); $this->assertEquals($order, $this->model->submit($quote, $orderData)); } + + /** + * Get mock for abstract class with methods. + * + * @param string $className + * @param array $methods + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createPartialMockForAbstractClass($className, $methods = []) + { + return $this->getMockForAbstractClass( + $className, + [], + '', + true, + true, + true, + $methods + ); + } } diff --git a/app/code/Magento/Sales/Model/Order/CustomerManagement.php b/app/code/Magento/Sales/Model/Order/CustomerManagement.php index a84d90693e087..bf54e65d0ce10 100644 --- a/app/code/Magento/Sales/Model/Order/CustomerManagement.php +++ b/app/code/Magento/Sales/Model/Order/CustomerManagement.php @@ -3,8 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Sales\Model\Order; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\AlreadyExistsException; use Magento\Quote\Model\Quote\Address as QuoteAddress; @@ -43,6 +45,11 @@ class CustomerManagement implements \Magento\Sales\Api\OrderCustomerManagementIn */ protected $objectCopyService; + /** + * @var \Magento\Quote\Model\Quote\AddressFactory + */ + private $quoteAddressFactory; + /** * @param \Magento\Framework\DataObject\Copy $objectCopyService * @param \Magento\Customer\Api\AccountManagementInterface $accountManagement @@ -50,6 +57,7 @@ class CustomerManagement implements \Magento\Sales\Api\OrderCustomerManagementIn * @param \Magento\Customer\Api\Data\AddressInterfaceFactory $addressFactory * @param \Magento\Customer\Api\Data\RegionInterfaceFactory $regionFactory * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository + * @param \Magento\Quote\Model\Quote\AddressFactory|null $quoteAddressFactory */ public function __construct( \Magento\Framework\DataObject\Copy $objectCopyService, @@ -57,7 +65,8 @@ public function __construct( \Magento\Customer\Api\Data\CustomerInterfaceFactory $customerFactory, \Magento\Customer\Api\Data\AddressInterfaceFactory $addressFactory, \Magento\Customer\Api\Data\RegionInterfaceFactory $regionFactory, - \Magento\Sales\Api\OrderRepositoryInterface $orderRepository + \Magento\Sales\Api\OrderRepositoryInterface $orderRepository, + \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory = null ) { $this->objectCopyService = $objectCopyService; $this->accountManagement = $accountManagement; @@ -65,6 +74,9 @@ public function __construct( $this->customerFactory = $customerFactory; $this->addressFactory = $addressFactory; $this->regionFactory = $regionFactory; + $this->quoteAddressFactory = $quoteAddressFactory ?: ObjectManager::getInstance()->get( + \Magento\Quote\Model\Quote\AddressFactory::class + ); } /** @@ -84,6 +96,9 @@ public function create($orderId) ); $addresses = $order->getAddresses(); foreach ($addresses as $address) { + if (!$this->isNeededToSaveAddress($address->getData('quote_address_id'))) { + continue; + } $addressData = $this->objectCopyService->copyFieldsetToTarget( 'order_address', 'to_customer_address', @@ -117,6 +132,26 @@ public function create($orderId) $account = $this->accountManagement->createAccount($customer); $order->setCustomerId($account->getId()); $this->orderRepository->save($order); + return $account; } + + /** + * Check if we need to save address in address book. + * + * @param int $quoteAddressId + * + * @return bool + */ + private function isNeededToSaveAddress($quoteAddressId) + { + $saveInAddressBook = true; + + $quoteAddress = $this->quoteAddressFactory->create()->load($quoteAddressId); + if ($quoteAddress && $quoteAddress->getId()) { + $saveInAddressBook = (int)$quoteAddress->getData('save_in_address_book'); + } + + return $saveInAddressBook; + } } diff --git a/app/code/Magento/Sales/Setup/UpgradeData.php b/app/code/Magento/Sales/Setup/UpgradeData.php index 8b104b0b35590..1c36a9a538366 100644 --- a/app/code/Magento/Sales/Setup/UpgradeData.php +++ b/app/code/Magento/Sales/Setup/UpgradeData.php @@ -3,18 +3,25 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Sales\Setup; use Magento\Eav\Model\Config; +use Magento\Framework\App\State; use Magento\Framework\DB\AggregatedFieldDataConverter; use Magento\Framework\DB\DataConverter\SerializedToJson; use Magento\Framework\DB\FieldToConvert; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Framework\Setup\UpgradeDataInterface; +use Magento\Quote\Model\QuoteFactory; +use Magento\Sales\Model\OrderFactory; +use Magento\Sales\Model\ResourceModel\Order\Address\CollectionFactory as AddressCollectionFactory; /** * Data upgrade script + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class UpgradeData implements UpgradeDataInterface { @@ -36,20 +43,50 @@ class UpgradeData implements UpgradeDataInterface private $aggregatedFieldConverter; /** - * Constructor - * + * @var AddressCollectionFactory + */ + private $addressCollectionFactory; + + /** + * @var OrderFactory + */ + private $orderFactory; + + /** + * @var QuoteFactory + */ + private $quoteFactory; + + /** + * @var State + */ + private $state; + + /** * @param SalesSetupFactory $salesSetupFactory * @param Config $eavConfig * @param AggregatedFieldDataConverter $aggregatedFieldConverter + * @param AddressCollectionFactory $addressCollFactory + * @param OrderFactory $orderFactory + * @param QuoteFactory $quoteFactory + * @param State $state */ public function __construct( SalesSetupFactory $salesSetupFactory, Config $eavConfig, - AggregatedFieldDataConverter $aggregatedFieldConverter + AggregatedFieldDataConverter $aggregatedFieldConverter, + AddressCollectionFactory $addressCollFactory, + OrderFactory $orderFactory, + QuoteFactory $quoteFactory, + State $state ) { $this->salesSetupFactory = $salesSetupFactory; $this->eavConfig = $eavConfig; $this->aggregatedFieldConverter = $aggregatedFieldConverter; + $this->addressCollectionFactory = $addressCollFactory; + $this->orderFactory = $orderFactory; + $this->quoteFactory = $quoteFactory; + $this->state = $state; } /** @@ -64,6 +101,13 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface if (version_compare($context->getVersion(), '2.0.6', '<')) { $this->convertSerializedDataToJson($context->getVersion(), $salesSetup); } + if (version_compare($context->getVersion(), '2.0.8', '<')) { + $this->state->emulateAreaCode( + \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE, + [$this, 'fillQuoteAddressIdInSalesOrderAddress'], + [$setup] + ); + } $this->eavConfig->clear(); } @@ -118,4 +162,34 @@ private function convertSerializedDataToJson($setupVersion, SalesSetup $salesSet } $this->aggregatedFieldConverter->convert($fieldsToUpdate, $salesSetup->getConnection()); } + + /** + * Fill quote_address_id in table sales_order_address if it is empty. + */ + public function fillQuoteAddressIdInSalesOrderAddress() + { + $addressCollection = $this->addressCollectionFactory->create(); + /** @var \Magento\Sales\Model\Order\Address $orderAddress */ + foreach ($addressCollection as $orderAddress) { + if (!$orderAddress->getData('quote_address_id')) { + $orderId = $orderAddress->getParentId(); + $addressType = $orderAddress->getAddressType(); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->orderFactory->create()->load($orderId); + $quoteId = $order->getQuoteId(); + $quote = $this->quoteFactory->create()->load($quoteId); + + if ($addressType == \Magento\Sales\Model\Order\Address::TYPE_SHIPPING) { + $quoteAddressId = $quote->getShippingAddress()->getId(); + $orderAddress->setData('quote_address_id', $quoteAddressId); + } elseif ($addressType == \Magento\Sales\Model\Order\Address::TYPE_BILLING) { + $quoteAddressId = $quote->getBillingAddress()->getId(); + $orderAddress->setData('quote_address_id', $quoteAddressId); + } + + $orderAddress->save(); + } + } + } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CustomerManagementTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CustomerManagementTest.php index 8a2305543c490..2794860793ed6 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/CustomerManagementTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CustomerManagementTest.php @@ -6,6 +6,7 @@ namespace Magento\Sales\Test\Unit\Model\Order; use Magento\Quote\Model\Quote\Address; +use Magento\Sales\Api\Data\OrderAddressInterface; /** * Class BuilderTest @@ -49,6 +50,11 @@ class CustomerManagementTest extends \PHPUnit\Framework\TestCase */ protected $service; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $quoteAddressFactory; + protected function setUp() { $this->objectCopyService = $this->createMock(\Magento\Framework\DataObject\Copy::class); @@ -66,6 +72,7 @@ protected function setUp() ['create'] ); $this->orderRepository = $this->createMock(\Magento\Sales\Api\OrderRepositoryInterface::class); + $this->quoteAddressFactory = $this->createMock(\Magento\Quote\Model\Quote\AddressFactory::class); $this->service = new \Magento\Sales\Model\Order\CustomerManagement( $this->objectCopyService, @@ -73,7 +80,8 @@ protected function setUp() $this->customerFactory, $this->addressFactory, $this->regionFactory, - $this->orderRepository + $this->orderRepository, + $this->quoteAddressFactory ); } @@ -94,12 +102,12 @@ public function testCreateCreatesCustomerBasedonGuestOrder() $orderMock->expects($this->once())->method('getCustomerId')->will($this->returnValue(null)); $orderMock->expects($this->any())->method('getBillingAddress')->will($this->returnValue('billing_address')); - $orderBillingAddress = $this->createMock(\Magento\Sales\Api\Data\OrderAddressInterface::class); + $orderBillingAddress = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['getData']); $orderBillingAddress->expects($this->once()) ->method('getAddressType') ->willReturn(Address::ADDRESS_TYPE_BILLING); - $orderShippingAddress = $this->createMock(\Magento\Sales\Api\Data\OrderAddressInterface::class); + $orderShippingAddress = $this->createPartialMockForAbstractClass(OrderAddressInterface::class, ['getData']); $orderShippingAddress->expects($this->once()) ->method('getAddressType') ->willReturn(Address::ADDRESS_TYPE_SHIPPING); @@ -108,6 +116,17 @@ public function testCreateCreatesCustomerBasedonGuestOrder() ->method('getAddresses') ->will($this->returnValue([$orderBillingAddress, $orderShippingAddress])); + $billingQuoteAddress = $this->createMock(\Magento\Quote\Model\Quote\Address::class); + $billingQuoteAddress->expects($this->once())->method('load')->willReturn($billingQuoteAddress); + $billingQuoteAddress->expects($this->once())->method('getId')->willReturn(4); + $billingQuoteAddress->expects($this->once())->method('getData')->with('save_in_address_book')->willReturn(1); + + $shippingQuoteAddress = $this->createMock(\Magento\Quote\Model\Quote\Address::class); + $shippingQuoteAddress->expects($this->once())->method('load')->willReturn($shippingQuoteAddress); + $shippingQuoteAddress->expects($this->once())->method('getId')->willReturn(5); + $shippingQuoteAddress->expects($this->once())->method('getData')->with('save_in_address_book')->willReturn(1); + $this->quoteAddressFactory->expects($this->exactly(2))->method('create') + ->willReturnOnConsecutiveCalls($billingQuoteAddress, $shippingQuoteAddress); $this->orderRepository->expects($this->once())->method('get')->with(1)->will($this->returnValue($orderMock)); $this->objectCopyService->expects($this->any())->method('copyFieldsetToTarget')->will($this->returnValueMap( [ @@ -142,4 +161,25 @@ public function testCreateCreatesCustomerBasedonGuestOrder() $this->orderRepository->expects($this->once())->method('save')->with($orderMock); $this->assertEquals($customerMock, $this->service->create(1)); } + + /** + * Get mock for abstract class with methods. + * + * @param string $className + * @param array $methods + * + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createPartialMockForAbstractClass($className, $methods = []) + { + return $this->getMockForAbstractClass( + $className, + [], + '', + true, + true, + true, + $methods + ); + } } diff --git a/app/code/Magento/Sales/etc/module.xml b/app/code/Magento/Sales/etc/module.xml index 4c1a534faddf7..58c7a4f21202a 100644 --- a/app/code/Magento/Sales/etc/module.xml +++ b/app/code/Magento/Sales/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 02529cee5c0ff..8990ea8d3f75b 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -325,12 +325,12 @@ define([ data = this.serializeData(this.billingAddressContainer); } else { data = this.serializeData(this.shippingAddressContainer); - areasToLoad.push('shipping_method'); } + areasToLoad.push('shipping_method'); data = data.toObject(); data['shipping_as_billing'] = flag ? 1 : 0; data['reset_shipping'] = 1; - this.loadArea( areasToLoad, true, data); + this.loadArea(areasToLoad, true, data); }, resetShippingMethod : function(data){ diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php index e435211b69bc7..2ee6269c39d47 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php @@ -44,9 +44,13 @@ class Method extends Block public function selectShippingMethod(array $shippingMethod) { $this->waitFormLoading(); - if ($this->_rootElement->find($this->shippingMethodsLink)->isVisible()) { - $this->_rootElement->find($this->shippingMethodsLink)->click(); - } + $this->_rootElement->waitUntil( + function () { + return $this->_rootElement->find($this->shippingMethodsLink)->isVisible() ? true : null; + } + ); + + $this->_rootElement->find($this->shippingMethodsLink)->click(); $selector = sprintf( $this->shippingMethod, $shippingMethod['shipping_service'], From 97390b3d84dc463f99656a7bede6bb63fb8cf26e Mon Sep 17 00:00:00 2001 From: Kostyantyn Alexeyev Date: Mon, 13 Nov 2017 16:55:04 +0200 Subject: [PATCH 457/528] MAGETWO-52974: Configurable product options not saved when editing - for mainline --- .../web/js/fotorama-add-video-events.js | 4 +- .../Block/Product/Renderer/Configurable.php | 6 ++ ...ckout_cart_configure_type_configurable.xml | 12 +++- ...list_index_configure_type_configurable.xml | 6 +- .../templates/product/listing/renderer.phtml | 2 +- .../templates/product/view/renderer.phtml | 6 +- .../web/js/configurable-customer-data.js | 59 +++++++++++++------ .../view/frontend/web/js/swatch-renderer.js | 47 ++++++++++++--- 8 files changed, 108 insertions(+), 34 deletions(-) diff --git a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js index 03ce42bf25c4a..1dfcc95a552c6 100644 --- a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js +++ b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js @@ -134,7 +134,6 @@ define([ */ _create: function () { $(this.element).on('gallery:loaded', $.proxy(function () { - this.fotoramaItem = $(this.element).find('.fotorama-item'); this._initialize(); }, this)); }, @@ -154,6 +153,7 @@ define([ this.defaultVideoData = this.options.videoData = this.videoDataPlaceholder; } + this.fotoramaItem = $(this.element).find('.fotorama-item'); this.clearEvents(); if (this._checkForVideoExist()) { @@ -164,6 +164,8 @@ define([ this._initFotoramaVideo(); this._attachFotoramaEvents(); } + + this.element.trigger('AddFotoramaVideoEvents:loaded'); }, /** diff --git a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php index aef8a25da2834..dfd3d6ce15f71 100644 --- a/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php +++ b/app/code/Magento/Swatches/Block/Product/Renderer/Configurable.php @@ -119,6 +119,12 @@ public function __construct( $configurableAttributeData, $data ); + + $this->addData( + [ + 'cache_lifetime' => isset($data['cache_lifetime']) ? $data['cache_lifetime'] : 3600 + ] + ); } /** diff --git a/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml b/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml index 593ae32374417..62d6e57221f82 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/checkout_cart_configure_type_configurable.xml @@ -6,7 +6,13 @@ */ --> - - - + + + + + false + + + + diff --git a/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml b/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml index 28bf7baac0a36..9f47b4386c742 100644 --- a/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml +++ b/app/code/Magento/Swatches/view/frontend/layout/wishlist_index_configure_type_configurable.xml @@ -12,7 +12,11 @@ - + + + false + + diff --git a/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml b/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml index 7ecd6558ef6ea..75a39a0e4e270 100644 --- a/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml +++ b/app/code/Magento/Swatches/view/frontend/templates/product/listing/renderer.phtml @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ ?> - +