diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7237ebfacf5e1..0999bee6ea415 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -785,7 +785,7 @@ Tests:
* Refactored controller actions in the Product area
* Moved commands cache.php, indexer.php, log.php, test.php, compiler.php, singletenant\_compiler.php, generator.php, pack.php, deploy.php and file\_assembler.php to the new bin/magento CLI framework
* Data Migration Tool
- * The Data Migraiton Tool is published in the separate [repository](https://github.com/magento/data-migration-tool-ce "Data Migration Tool repository")
+ * The Data Migration Tool is published in the separate [repository](https://github.com/magento/data-migration-tool-ce "Data Migration Tool repository")
* Fixed bugs
* Fixed an issue where error appeared during placing order with virtual product
* Fixed an issue where billing and shipping sections didn't contain address information on order print
@@ -4136,7 +4136,7 @@ Tests:
* Moved Multishipping functionality to newly created module Multishipping
* Extracted Product duplication behavior from Product model to Product\Copier model
* Replaced event "catalog_model_product_duplicate" with composite Product\Copier model
- * Replaced event "catalog_product_prepare_save" with controller product initialization helper that can be customozed via plugins
+ * Replaced event "catalog_product_prepare_save" with controller product initialization helper that can be customized via plugins
* Consolidated Authorize.Net functionality in single module Authorizenet
* Eliminated dependency of Sales module on Shipping and Usa modules
* Eliminated dependency of Shipping module on Customer module
@@ -4335,7 +4335,7 @@ Tests:
* Fixed order placing with virtual product using Express Checkout
* Fixed the error during order placement with Recurring profile payment
* Fixed wrong redirect after customer registration during multishipping checkout
- * Fixed inability to crate shipping labels
+ * Fixed inability to create shipping labels
* Fixed inability to switch language, if the default language is English
* Fixed an issue with incorrect XML appearing in cache after some actions on the frontend
* Fixed product export
diff --git a/README.md b/README.md
index 9e3cf448f99fb..ecd457a4f1aef 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
Welcome to Magento 2 installation! We're glad you chose to install Magento 2, a cutting-edge, feature-rich eCommerce solution that gets results.
## Magento System Requirements
-[Magento System Requirements](https://devdocs.magento.com/guides/v2.3/install-gde/system-requirements2.html).
+[Magento System Requirements](https://devdocs.magento.com/guides/v2.3/install-gde/system-requirements.html).
## Install Magento
@@ -45,7 +45,7 @@ Please review the [Code Contributions guide](https://devdocs.magento.com/guides/
## Reporting Security Issues
-To report security vulnerabilities in Magento software or web sites, please create a Bugcrowd researcher account [there](https://bugcrowd.com/magento) to submit and follow-up your issue. Learn more about reporting security issues [here](https://magento.com/security/reporting-magento-security-issue).
+To report security vulnerabilities or learn more about reporting security issues in Magento software or web sites visit the [Magento Bug Bounty Program](https://hackerone.com/magento) on hackerone. Please create a hackerone account [there](https://hackerone.com/magento) to submit and follow-up your issue.
Stay up-to-date on the latest security news and patches for Magento by signing up for [Security Alert Notifications](https://magento.com/security/sign-up).
diff --git a/app/bootstrap.php b/app/bootstrap.php
index ddbcaffd42962..4974acdf0fc80 100644
--- a/app/bootstrap.php
+++ b/app/bootstrap.php
@@ -8,7 +8,9 @@
* Environment initialization
*/
error_reporting(E_ALL);
-stream_wrapper_unregister('phar');
+if (in_array('phar', \stream_get_wrappers())) {
+ stream_wrapper_unregister('phar');
+}
#ini_set('display_errors', 1);
/* PHP version validation */
diff --git a/app/code/Magento/AdminNotification/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/AdminNotification/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..3f0f251ce7ee4
--- /dev/null
+++ b/app/code/Magento/AdminNotification/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ System
+ Notifications
+ magento-backend-system
+
+
+ Notifications
+ Notifications
+ magento-adminnotification-system-adminnotification
+
+
diff --git a/app/code/Magento/AdminNotification/Test/Mftf/Test/AdminSystemNotificationNavigateMenuTest.xml b/app/code/Magento/AdminNotification/Test/Mftf/Test/AdminSystemNotificationNavigateMenuTest.xml
new file mode 100644
index 0000000000000..75dceb4028622
--- /dev/null
+++ b/app/code/Magento/AdminNotification/Test/Mftf/Test/AdminSystemNotificationNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Analytics/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Analytics/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..01b86101def28
--- /dev/null
+++ b/app/code/Magento/Analytics/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Reports
+ Reports
+ magento-reports-report
+
+
+ AdvancedReporting
+ AdvancedReporting
+ magento-analytics-advanced-reporting
+
+
diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingButtonTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingButtonTest.xml
index 505e178f49f43..e660a2eb8d428 100644
--- a/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingButtonTest.xml
+++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingButtonTest.xml
@@ -13,6 +13,9 @@
+
+
+
diff --git a/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingNavigateMenuTest.xml b/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingNavigateMenuTest.xml
new file mode 100644
index 0000000000000..67d6715285697
--- /dev/null
+++ b/app/code/Magento/Analytics/Test/Mftf/Test/AdminAdvancedReportingNavigateMenuTest.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Block/Dashboard/Graph.php b/app/code/Magento/Backend/Block/Dashboard/Graph.php
index 8e238ccab44cb..f57b03fdbfa0b 100644
--- a/app/code/Magento/Backend/Block/Dashboard/Graph.php
+++ b/app/code/Magento/Backend/Block/Dashboard/Graph.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Backend\Block\Dashboard;
/**
@@ -15,7 +17,7 @@ class Graph extends \Magento\Backend\Block\Dashboard\AbstractDashboard
/**
* Api URL
*/
- const API_URL = 'http://chart.apis.google.com/chart';
+ const API_URL = 'https://image-charts.com/chart';
/**
* All series
@@ -76,6 +78,7 @@ class Graph extends \Magento\Backend\Block\Dashboard\AbstractDashboard
/**
* Google chart api data encoding
*
+ * @deprecated since the Google Image Charts API not accessible from March 14, 2019
* @var string
*/
protected $_encoding = 'e';
@@ -187,11 +190,12 @@ public function getChartUrl($directUrl = true)
{
$params = [
'cht' => 'lc',
- 'chf' => 'bg,s,ffffff',
- 'chco' => 'ef672f',
'chls' => '7',
- 'chxs' => '0,676056,15,0,l,676056|1,676056,15,0,l,676056',
- 'chm' => 'h,f2ebde,0,0:1:.1,1,-1',
+ 'chf' => 'bg,s,f4f4f4|c,lg,90,ffffff,0.1,ededed,0',
+ 'chm' => 'B,f4d4b2,0,0,0',
+ 'chco' => 'db4814',
+ 'chxs' => '0,0,11|1,0,11',
+ 'chma' => '15,15,15,15'
];
$this->_allSeries = $this->getRowsData($this->_dataRows);
@@ -279,20 +283,11 @@ public function getChartUrl($directUrl = true)
$this->_axisLabels['x'] = $dates;
$this->_allSeries = $datas;
- //Google encoding values
- if ($this->_encoding == "s") {
- // simple encoding
- $params['chd'] = "s:";
- $dataDelimiter = "";
- $dataSetdelimiter = ",";
- $dataMissing = "_";
- } else {
- // extended encoding
- $params['chd'] = "e:";
- $dataDelimiter = "";
- $dataSetdelimiter = ",";
- $dataMissing = "__";
- }
+ // Image-Charts Awesome data format values
+ $params['chd'] = "a:";
+ $dataDelimiter = ",";
+ $dataSetdelimiter = "|";
+ $dataMissing = "_";
// process each string in the array, and find the max length
$localmaxvalue = [0];
@@ -306,7 +301,6 @@ public function getChartUrl($directUrl = true)
$minvalue = min($localminvalue);
// default values
- $yrange = 0;
$yLabels = [];
$miny = 0;
$maxy = 0;
@@ -321,7 +315,6 @@ public function getChartUrl($directUrl = true)
$maxy = ceil($maxvalue + 1);
$yLabels = range($miny, $maxy, 1);
}
- $yrange = $maxy;
$yorigin = 0;
}
@@ -329,44 +322,14 @@ public function getChartUrl($directUrl = true)
foreach ($this->getAllSeries() as $index => $serie) {
$thisdataarray = $serie;
- if ($this->_encoding == "s") {
- // SIMPLE ENCODING
- for ($j = 0; $j < sizeof($thisdataarray); $j++) {
- $currentvalue = $thisdataarray[$j];
- if (is_numeric($currentvalue)) {
- $ylocation = round(
- (strlen($this->_simpleEncoding) - 1) * ($yorigin + $currentvalue) / $yrange
- );
- $chartdata[] = substr($this->_simpleEncoding, $ylocation, 1) . $dataDelimiter;
- } else {
- $chartdata[] = $dataMissing . $dataDelimiter;
- }
- }
- } else {
- // EXTENDED ENCODING
- for ($j = 0; $j < sizeof($thisdataarray); $j++) {
- $currentvalue = $thisdataarray[$j];
- if (is_numeric($currentvalue)) {
- if ($yrange) {
- $ylocation = 4095 * ($yorigin + $currentvalue) / $yrange;
- } else {
- $ylocation = 0;
- }
- $firstchar = floor($ylocation / 64);
- $secondchar = $ylocation % 64;
- $mappedchar = substr(
- $this->_extendedEncoding,
- $firstchar,
- 1
- ) . substr(
- $this->_extendedEncoding,
- $secondchar,
- 1
- );
- $chartdata[] = $mappedchar . $dataDelimiter;
- } else {
- $chartdata[] = $dataMissing . $dataDelimiter;
- }
+ $count = count($thisdataarray);
+ for ($j = 0; $j < $count; $j++) {
+ $currentvalue = $thisdataarray[$j];
+ if (is_numeric($currentvalue)) {
+ $ylocation = $yorigin + $currentvalue;
+ $chartdata[] = $ylocation . $dataDelimiter;
+ } else {
+ $chartdata[] = $dataMissing . $dataDelimiter;
}
}
$chartdata[] = $dataSetdelimiter;
@@ -381,45 +344,13 @@ public function getChartUrl($directUrl = true)
$valueBuffer = [];
- if (sizeof($this->_axisLabels) > 0) {
+ if (count($this->_axisLabels) > 0) {
$params['chxt'] = implode(',', array_keys($this->_axisLabels));
$indexid = 0;
foreach ($this->_axisLabels as $idx => $labels) {
if ($idx == 'x') {
- /**
- * Format date
- */
- foreach ($this->_axisLabels[$idx] as $_index => $_label) {
- if ($_label != '') {
- $period = new \DateTime($_label, new \DateTimeZone($timezoneLocal));
- switch ($this->getDataHelper()->getParam('period')) {
- case '24h':
- $this->_axisLabels[$idx][$_index] = $this->_localeDate->formatDateTime(
- $period->setTime($period->format('H'), 0, 0),
- \IntlDateFormatter::NONE,
- \IntlDateFormatter::SHORT
- );
- break;
- case '7d':
- case '1m':
- $this->_axisLabels[$idx][$_index] = $this->_localeDate->formatDateTime(
- $period,
- \IntlDateFormatter::SHORT,
- \IntlDateFormatter::NONE
- );
- break;
- case '1y':
- case '2y':
- $this->_axisLabels[$idx][$_index] = date('m/Y', strtotime($_label));
- break;
- }
- } else {
- $this->_axisLabels[$idx][$_index] = '';
- }
- }
-
+ $this->formatAxisLabelDate($idx, $timezoneLocal);
$tmpstring = implode('|', $this->_axisLabels[$idx]);
-
$valueBuffer[] = $indexid . ":|" . $tmpstring;
} elseif ($idx == 'y') {
$valueBuffer[] = $indexid . ":|" . implode('|', $yLabels);
@@ -447,6 +378,46 @@ public function getChartUrl($directUrl = true)
}
}
+ /**
+ * Format dates for axis labels
+ *
+ * @param string $idx
+ * @param string $timezoneLocal
+ *
+ * @return void
+ */
+ private function formatAxisLabelDate($idx, $timezoneLocal)
+ {
+ foreach ($this->_axisLabels[$idx] as $_index => $_label) {
+ if ($_label != '') {
+ $period = new \DateTime($_label, new \DateTimeZone($timezoneLocal));
+ switch ($this->getDataHelper()->getParam('period')) {
+ case '24h':
+ $this->_axisLabels[$idx][$_index] = $this->_localeDate->formatDateTime(
+ $period->setTime($period->format('H'), 0, 0),
+ \IntlDateFormatter::NONE,
+ \IntlDateFormatter::SHORT
+ );
+ break;
+ case '7d':
+ case '1m':
+ $this->_axisLabels[$idx][$_index] = $this->_localeDate->formatDateTime(
+ $period,
+ \IntlDateFormatter::SHORT,
+ \IntlDateFormatter::NONE
+ );
+ break;
+ case '1y':
+ case '2y':
+ $this->_axisLabels[$idx][$_index] = date('m/Y', strtotime($_label));
+ break;
+ }
+ } else {
+ $this->_axisLabels[$idx][$_index] = '';
+ }
+ }
+ }
+
/**
* Get rows data
*
@@ -540,6 +511,8 @@ protected function getHeight()
}
/**
+ * Sets data helper
+ *
* @param \Magento\Backend\Helper\Dashboard\AbstractDashboard $dataHelper
* @return void
*/
diff --git a/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewed.php b/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewed.php
index 0de1111ffa722..a42a44814cb0c 100644
--- a/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewed.php
+++ b/app/code/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewed.php
@@ -6,12 +6,12 @@
*/
namespace Magento\Backend\Controller\Adminhtml\Dashboard;
-use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Framework\App\Action\HttpPostActionInterface;
/**
* Get most viewed products controller.
*/
-class ProductsViewed extends AjaxBlock implements HttpGetActionInterface
+class ProductsViewed extends AjaxBlock implements HttpPostActionInterface
{
/**
* Gets most viewed products list
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminAssertPageTitleActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminAssertPageTitleActionGroup.xml
new file mode 100644
index 0000000000000..42ffb4b7421ac
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminAssertPageTitleActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminNavigateMenuActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminNavigateMenuActionGroup.xml
new file mode 100644
index 0000000000000..8e0f5a067610d
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminNavigateMenuActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StoreFrontClickSignInButtonActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminDashboardPageIsVisibleActionGroup.xml
similarity index 56%
rename from app/code/Magento/Customer/Test/Mftf/ActionGroup/StoreFrontClickSignInButtonActionGroup.xml
rename to app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminDashboardPageIsVisibleActionGroup.xml
index b12858fc1037e..1c86a736ac2f1 100644
--- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/StoreFrontClickSignInButtonActionGroup.xml
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminDashboardPageIsVisibleActionGroup.xml
@@ -8,8 +8,8 @@
-
-
-
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminSuccessLoginActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminSuccessLoginActionGroup.xml
new file mode 100644
index 0000000000000..844f58c789a15
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertAdminSuccessLoginActionGroup.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertMessageOnAdminLoginActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertMessageOnAdminLoginActionGroup.xml
new file mode 100644
index 0000000000000..607fba3736c42
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertMessageOnAdminLoginActionGroup.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAdminWithCredentialsActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAdminWithCredentialsActionGroup.xml
new file mode 100644
index 0000000000000..6aaa612b249b6
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAdminWithCredentialsActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml
index 1070bc409962a..b2fbadcbe38e2 100644
--- a/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/LoginAsAdminActionGroup.xml
@@ -10,11 +10,11 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
-
+
-
-
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/SetWebsiteCountryOptionsToDefaultActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/SetWebsiteCountryOptionsToDefaultActionGroup.xml
new file mode 100644
index 0000000000000..4519648eb1d1b
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/SetWebsiteCountryOptionsToDefaultActionGroup.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Backend/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..4fe600d194e61
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+ Content
+ Content
+ magento-backend-content
+
+
+ Store Design Schedule
+ Schedule
+ magento-backend-system-design-schedule
+
+
+ Dashboard
+ Dashboard
+ magento-backend-dashboard
+
+
+ Stores
+ Stores
+ magento-backend-stores
+
+
+ Stores
+ All Stores
+ magento-backend-system-store
+
+
+ Configuration
+ Configuration
+ magento-config-system-config
+
+
+ Cache Management
+ Cache Management
+ magento-backend-system-cache
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminForgotPasswordPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminForgotPasswordPage.xml
new file mode 100644
index 0000000000000..84af56d102d84
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminForgotPasswordPage.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml b/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml
index b68b9914186f6..78226d79273d9 100644
--- a/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Page/AdminLoginPage.xml
@@ -9,6 +9,7 @@
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminForgotPasswordFormSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminForgotPasswordFormSection.xml
new file mode 100644
index 0000000000000..efaca22123354
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminForgotPasswordFormSection.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml
index 441ce886f117b..5b517c7be8a79 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminHeaderSection.xml
@@ -10,5 +10,6 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml
index 3b10fac7bb9dc..bd65dea89abc2 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginFormSection.xml
@@ -12,5 +12,6 @@
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginMessagesSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginMessagesSection.xml
new file mode 100644
index 0000000000000..f6ada50ada357
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminLoginMessagesSection.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml
index 278a738b60f0f..8498ad8c52e41 100644
--- a/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Section/AdminMenuSection.xml
@@ -21,5 +21,8 @@
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Section/CountryOptionsSection.xml b/app/code/Magento/Backend/Test/Mftf/Section/CountryOptionsSection.xml
new file mode 100644
index 0000000000000..2e2e5aec35ecd
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Section/CountryOptionsSection.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminContentScheduleNavigateMenuTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminContentScheduleNavigateMenuTest.xml
new file mode 100644
index 0000000000000..bead59653eee8
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminContentScheduleNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminDashboardNavigateMenuTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminDashboardNavigateMenuTest.xml
new file mode 100644
index 0000000000000..33561d7c3b03e
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminDashboardNavigateMenuTest.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminStoresAllStoresNavigateMenuTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminStoresAllStoresNavigateMenuTest.xml
new file mode 100644
index 0000000000000..7758b387e393b
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminStoresAllStoresNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminStoresConfigurationNavigateMenuTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminStoresConfigurationNavigateMenuTest.xml
new file mode 100644
index 0000000000000..a54269b186ba0
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminStoresConfigurationNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminSystemCacheManagementNavigateMenuTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminSystemCacheManagementNavigateMenuTest.xml
new file mode 100644
index 0000000000000..516631c1bd166
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminSystemCacheManagementNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminUserLoginWithStoreCodeInUrlTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminUserLoginWithStoreCodeInUrlTest.xml
new file mode 100644
index 0000000000000..5485dcaea33ee
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminUserLoginWithStoreCodeInUrlTest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php
index 99c48b727521a..ee5a56e814837 100644
--- a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php
+++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php
@@ -58,7 +58,9 @@ public function execute()
$this->_coreRegistry->register('backup_manager', $backupManager);
if ($this->getRequest()->getParam('maintenance_mode')) {
- if (!$this->maintenanceMode->set(true)) {
+ $this->maintenanceMode->set(true);
+
+ if (!$this->maintenanceMode->isOn()) {
$response->setError(
__(
'You need more permissions to activate maintenance mode right now.'
diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Rollback.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Rollback.php
index 0451f6ed09bd1..7f450e7e313cc 100644
--- a/app/code/Magento/Backup/Controller/Adminhtml/Index/Rollback.php
+++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Rollback.php
@@ -6,13 +6,16 @@
*/
namespace Magento\Backup\Controller\Adminhtml\Index;
+use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
/**
+ * Backup rollback controller.
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class Rollback extends \Magento\Backup\Controller\Adminhtml\Index
+class Rollback extends \Magento\Backup\Controller\Adminhtml\Index implements HttpPostActionInterface
{
/**
* Rollback Action
@@ -82,7 +85,9 @@ public function execute()
}
if ($this->getRequest()->getParam('maintenance_mode')) {
- if (!$this->maintenanceMode->set(true)) {
+ $this->maintenanceMode->set(true);
+
+ if (!$this->maintenanceMode->isOn()) {
$response->setError(
__(
'You need more permissions to activate maintenance mode right now.'
@@ -122,6 +127,7 @@ public function execute()
$adminSession->destroy();
$response->setRedirectUrl($this->getUrl('*'));
+ // phpcs:disable Magento2.Exceptions.ThrowCatch
} catch (\Magento\Framework\Backup\Exception\CantLoadSnapshot $e) {
$errorMsg = __('We can\'t find the backup file.');
} catch (\Magento\Framework\Backup\Exception\FtpConnectionFailed $e) {
diff --git a/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php b/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php
index 418cb93900610..ea8a44a1122b4 100644
--- a/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php
+++ b/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php
@@ -75,7 +75,7 @@ public function execute()
$this->logger->critical($e);
$this->messageManager->addExceptionMessage(
$e,
- 'The order #' . $quote->getReservedOrderId() . ' cannot be processed.'
+ __('The order #%1 cannot be processed.', $quote->getReservedOrderId())
);
}
diff --git a/app/code/Magento/Braintree/Controller/Paypal/Review.php b/app/code/Magento/Braintree/Controller/Paypal/Review.php
index eb2de7c7b6e39..2923db6fa88c3 100644
--- a/app/code/Magento/Braintree/Controller/Paypal/Review.php
+++ b/app/code/Magento/Braintree/Controller/Paypal/Review.php
@@ -14,6 +14,7 @@
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\Action\HttpGetActionInterface;
+use Magento\Payment\Model\Method\Logger;
/**
* Class Review
@@ -25,6 +26,11 @@ class Review extends AbstractAction implements HttpPostActionInterface, HttpGetA
*/
private $quoteUpdater;
+ /**
+ * @var Logger
+ */
+ private $logger;
+
/**
* @var string
*/
@@ -37,15 +43,18 @@ class Review extends AbstractAction implements HttpPostActionInterface, HttpGetA
* @param Config $config
* @param Session $checkoutSession
* @param QuoteUpdater $quoteUpdater
+ * @param Logger $logger
*/
public function __construct(
Context $context,
Config $config,
Session $checkoutSession,
- QuoteUpdater $quoteUpdater
+ QuoteUpdater $quoteUpdater,
+ Logger $logger
) {
parent::__construct($context, $config, $checkoutSession);
$this->quoteUpdater = $quoteUpdater;
+ $this->logger = $logger;
}
/**
@@ -57,6 +66,7 @@ public function execute()
$this->getRequest()->getPostValue('result', '{}'),
true
);
+ $this->logger->debug($requestData);
$quote = $this->checkoutSession->getQuote();
try {
diff --git a/app/code/Magento/Braintree/Model/Multishipping/PlaceOrder.php b/app/code/Magento/Braintree/Model/Multishipping/PlaceOrder.php
new file mode 100644
index 0000000000000..a6c1b088400a7
--- /dev/null
+++ b/app/code/Magento/Braintree/Model/Multishipping/PlaceOrder.php
@@ -0,0 +1,177 @@
+orderManagement = $orderManagement;
+ $this->paymentExtensionFactory = $paymentExtensionFactory;
+ $this->getPaymentNonceCommand = $getPaymentNonceCommand;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function place(array $orderList): array
+ {
+ if (empty($orderList)) {
+ return [];
+ }
+
+ $errorList = [];
+ $firstOrder = $this->orderManagement->place(array_shift($orderList));
+ // get payment token from first placed order
+ $paymentToken = $this->getPaymentToken($firstOrder);
+
+ foreach ($orderList as $order) {
+ try {
+ /** @var OrderInterface $order */
+ $orderPayment = $order->getPayment();
+ $this->setVaultPayment($orderPayment, $paymentToken);
+ $this->orderManagement->place($order);
+ } catch (\Exception $e) {
+ $incrementId = $order->getIncrementId();
+ $errorList[$incrementId] = $e;
+ }
+ }
+
+ return $errorList;
+ }
+
+ /**
+ * Sets vault payment method.
+ *
+ * @param OrderPaymentInterface $orderPayment
+ * @param PaymentTokenInterface $paymentToken
+ * @return void
+ */
+ private function setVaultPayment(OrderPaymentInterface $orderPayment, PaymentTokenInterface $paymentToken): void
+ {
+ $vaultMethod = $this->getVaultPaymentMethod(
+ $orderPayment->getMethod()
+ );
+ $orderPayment->setMethod($vaultMethod);
+
+ $publicHash = $paymentToken->getPublicHash();
+ $customerId = $paymentToken->getCustomerId();
+ $result = $this->getPaymentNonceCommand->execute(
+ ['public_hash' => $publicHash, 'customer_id' => $customerId]
+ )
+ ->get();
+
+ $orderPayment->setAdditionalInformation(
+ DataAssignObserver::PAYMENT_METHOD_NONCE,
+ $result['paymentMethodNonce']
+ );
+ $orderPayment->setAdditionalInformation(
+ PaymentTokenInterface::PUBLIC_HASH,
+ $publicHash
+ );
+ $orderPayment->setAdditionalInformation(
+ PaymentTokenInterface::CUSTOMER_ID,
+ $customerId
+ );
+ }
+
+ /**
+ * Returns vault payment method.
+ *
+ * For placing sequence of orders, we need to replace the original method on the vault method.
+ *
+ * @param string $method
+ * @return string
+ */
+ private function getVaultPaymentMethod(string $method): string
+ {
+ $vaultPaymentMap = [
+ ConfigProvider::CODE => ConfigProvider::CC_VAULT_CODE,
+ PaypalConfigProvider::PAYPAL_CODE => PaypalConfigProvider::PAYPAL_VAULT_CODE
+ ];
+
+ return $vaultPaymentMap[$method] ?? $method;
+ }
+
+ /**
+ * Returns payment token.
+ *
+ * @param OrderInterface $order
+ * @return PaymentTokenInterface
+ * @throws \BadMethodCallException
+ */
+ private function getPaymentToken(OrderInterface $order): PaymentTokenInterface
+ {
+ $orderPayment = $order->getPayment();
+ $extensionAttributes = $this->getExtensionAttributes($orderPayment);
+ $paymentToken = $extensionAttributes->getVaultPaymentToken();
+
+ if ($paymentToken === null) {
+ throw new \BadMethodCallException('Vault Payment Token should be defined for placed order payment.');
+ }
+
+ return $paymentToken;
+ }
+
+ /**
+ * Gets payment extension attributes.
+ *
+ * @param OrderPaymentInterface $payment
+ * @return OrderPaymentExtensionInterface
+ */
+ private function getExtensionAttributes(OrderPaymentInterface $payment): OrderPaymentExtensionInterface
+ {
+ $extensionAttributes = $payment->getExtensionAttributes();
+ if (null === $extensionAttributes) {
+ $extensionAttributes = $this->paymentExtensionFactory->create();
+ $payment->setExtensionAttributes($extensionAttributes);
+ }
+
+ return $extensionAttributes;
+ }
+}
diff --git a/app/code/Magento/Braintree/Model/Paypal/Helper/QuoteUpdater.php b/app/code/Magento/Braintree/Model/Paypal/Helper/QuoteUpdater.php
index aa23fa767d1ed..ae2b1b1423640 100644
--- a/app/code/Magento/Braintree/Model/Paypal/Helper/QuoteUpdater.php
+++ b/app/code/Magento/Braintree/Model/Paypal/Helper/QuoteUpdater.php
@@ -123,8 +123,8 @@ private function updateShippingAddress(Quote $quote, array $details)
{
$shippingAddress = $quote->getShippingAddress();
- $shippingAddress->setLastname($details['lastName']);
- $shippingAddress->setFirstname($details['firstName']);
+ $shippingAddress->setLastname($this->getShippingRecipientLastName($details));
+ $shippingAddress->setFirstname($this->getShippingRecipientFirstName($details));
$shippingAddress->setEmail($details['email']);
$shippingAddress->setCollectShippingRates(true);
@@ -188,4 +188,30 @@ private function updateAddressData(Address $address, array $addressData)
$address->setSameAsBilling(false);
$address->setCustomerAddressId(null);
}
+
+ /**
+ * Returns shipping recipient first name.
+ *
+ * @param array $details
+ * @return string
+ */
+ private function getShippingRecipientFirstName(array $details)
+ {
+ return isset($details['shippingAddress']['recipientName'])
+ ? explode(' ', $details['shippingAddress']['recipientName'], 2)[0]
+ : $details['firstName'];
+ }
+
+ /**
+ * Returns shipping recipient last name.
+ *
+ * @param array $details
+ * @return string
+ */
+ private function getShippingRecipientLastName(array $details)
+ {
+ return isset($details['shippingAddress']['recipientName'])
+ ? explode(' ', $details['shippingAddress']['recipientName'], 2)[1]
+ : $details['lastName'];
+ }
}
diff --git a/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml
index f27477ce8a672..a781841e0a77b 100644
--- a/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml
+++ b/app/code/Magento/Braintree/Test/Mftf/Test/BraintreeCreditCardOnCheckoutTest.xml
@@ -81,16 +81,12 @@
-
+
-
-
-
-
diff --git a/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/ReviewTest.php b/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/ReviewTest.php
index 609b7f21dbf87..d68838bafbf0e 100644
--- a/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/ReviewTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/ReviewTest.php
@@ -6,6 +6,7 @@
namespace Magento\Braintree\Test\Unit\Controller\Paypal;
+use Magento\Payment\Model\Method\Logger;
use Magento\Quote\Model\Quote;
use Magento\Framework\View\Layout;
use Magento\Checkout\Model\Session;
@@ -65,6 +66,11 @@ class ReviewTest extends \PHPUnit\Framework\TestCase
*/
private $review;
+ /**
+ * @var Logger|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $loggerMock;
+
protected function setUp()
{
/** @var Context|\PHPUnit_Framework_MockObject_MockObject $contextMock */
@@ -88,6 +94,9 @@ protected function setUp()
->getMock();
$this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class)
->getMockForAbstractClass();
+ $this->loggerMock = $this->getMockBuilder(Logger::class)
+ ->disableOriginalConstructor()
+ ->getMock();
$contextMock->expects(self::once())
->method('getRequest')
@@ -103,7 +112,8 @@ protected function setUp()
$contextMock,
$this->configMock,
$this->checkoutSessionMock,
- $this->quoteUpdaterMock
+ $this->quoteUpdaterMock,
+ $this->loggerMock
);
}
diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php
index a2b5380d2884b..c2678d1c78437 100644
--- a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php
+++ b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/QuoteUpdaterTest.php
@@ -165,7 +165,7 @@ private function getDetails(): array
'region' => 'IL',
'postalCode' => '60618',
'countryCodeAlpha2' => 'US',
- 'recipientName' => 'John Doe',
+ 'recipientName' => 'Jane Smith',
],
'billingAddress' => [
'streetAddress' => '123 Billing Street',
@@ -186,9 +186,9 @@ private function getDetails(): array
private function updateShippingAddressStep(array $details): void
{
$this->shippingAddress->method('setLastname')
- ->with($details['lastName']);
+ ->with('Smith');
$this->shippingAddress->method('setFirstname')
- ->with($details['firstName']);
+ ->with('Jane');
$this->shippingAddress->method('setEmail')
->with($details['email']);
$this->shippingAddress->method('setCollectShippingRates')
diff --git a/app/code/Magento/Braintree/composer.json b/app/code/Magento/Braintree/composer.json
index 5af56a2afd3fe..2f956076f3846 100644
--- a/app/code/Magento/Braintree/composer.json
+++ b/app/code/Magento/Braintree/composer.json
@@ -21,7 +21,8 @@
"magento/module-quote": "*",
"magento/module-sales": "*",
"magento/module-ui": "*",
- "magento/module-vault": "*"
+ "magento/module-vault": "*",
+ "magento/module-multishipping": "*"
},
"suggest": {
"magento/module-checkout-agreements": "*",
diff --git a/app/code/Magento/Braintree/etc/config.xml b/app/code/Magento/Braintree/etc/config.xml
index 9de4773af023a..fe4cfab9c0e30 100644
--- a/app/code/Magento/Braintree/etc/config.xml
+++ b/app/code/Magento/Braintree/etc/config.xml
@@ -42,7 +42,7 @@
cc_type,cc_number,avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,riskDataId,riskDataDecision
Magento\Braintree\Model\AvsEmsCodeMapper
Magento\Braintree\Model\CvvEmsCodeMapper
- braintree
+ braintree_group
BraintreePayPalFacade
@@ -68,7 +68,7 @@
processorResponseCode,processorResponseText,paymentId
processorResponseCode,processorResponseText,paymentId,payerEmail
en_US,en_GB,en_AU,da_DK,fr_FR,fr_CA,de_DE,zh_HK,it_IT,nl_NL,no_NO,pl_PL,es_ES,sv_SE,tr_TR,pt_BR,ja_JP,id_ID,ko_KR,pt_PT,ru_RU,th_TH,zh_CN,zh_TW
- braintree
+ braintree_group
BraintreeCreditCardVaultFacade
@@ -78,7 +78,7 @@
Magento\Braintree\Model\InstantPurchase\CreditCard\TokenFormatter
Magento\Braintree\Model\InstantPurchase\PaymentAdditionalInformationProvider
- braintree
+ braintree_group
BraintreePayPalVaultFacade
@@ -88,7 +88,7 @@
Magento\Braintree\Model\InstantPurchase\PayPal\TokenFormatter
Magento\Braintree\Model\InstantPurchase\PaymentAdditionalInformationProvider
- braintree
+ braintree_group
diff --git a/app/code/Magento/Braintree/etc/frontend/di.xml b/app/code/Magento/Braintree/etc/frontend/di.xml
index ea417c407dffd..d8d3a93b71dc3 100644
--- a/app/code/Magento/Braintree/etc/frontend/di.xml
+++ b/app/code/Magento/Braintree/etc/frontend/di.xml
@@ -61,4 +61,12 @@
Magento\Braintree\Model\LocaleResolver
+
+
+
+ - Magento\Braintree\Model\Multishipping\PlaceOrder
+ - Magento\Braintree\Model\Multishipping\PlaceOrder
+
+
+
diff --git a/app/code/Magento/Braintree/etc/payment.xml b/app/code/Magento/Braintree/etc/payment.xml
index dbabd91151022..4cae049aaf5a9 100644
--- a/app/code/Magento/Braintree/etc/payment.xml
+++ b/app/code/Magento/Braintree/etc/payment.xml
@@ -8,8 +8,16 @@
-
+
Braintree
+
+
+ 1
+
+
+ 1
+
+
diff --git a/app/code/Magento/Braintree/view/frontend/layout/multishipping_checkout_billing.xml b/app/code/Magento/Braintree/view/frontend/layout/multishipping_checkout_billing.xml
new file mode 100644
index 0000000000000..06390d403e63d
--- /dev/null
+++ b/app/code/Magento/Braintree/view/frontend/layout/multishipping_checkout_billing.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ - Magento_Braintree::multishipping/form.phtml
+ - Magento_Braintree::multishipping/form_paypal.phtml
+
+
+
+
+
diff --git a/app/code/Magento/Braintree/view/frontend/templates/multishipping/form.phtml b/app/code/Magento/Braintree/view/frontend/templates/multishipping/form.phtml
new file mode 100644
index 0000000000000..bf8aa8dd09c2c
--- /dev/null
+++ b/app/code/Magento/Braintree/view/frontend/templates/multishipping/form.phtml
@@ -0,0 +1,29 @@
+
+
+
diff --git a/app/code/Magento/Braintree/view/frontend/templates/multishipping/form_paypal.phtml b/app/code/Magento/Braintree/view/frontend/templates/multishipping/form_paypal.phtml
new file mode 100644
index 0000000000000..ea3eb2214c2d8
--- /dev/null
+++ b/app/code/Magento/Braintree/view/frontend/templates/multishipping/form_paypal.phtml
@@ -0,0 +1,29 @@
+
+
+
diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js
index 05c09abdb7b2e..9e496e43b27c5 100644
--- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js
+++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js
@@ -10,8 +10,9 @@ define([
'Magento_Braintree/js/view/payment/method-renderer/cc-form',
'Magento_Braintree/js/validator',
'Magento_Vault/js/view/payment/vault-enabler',
- 'mage/translate'
-], function ($, Component, validator, VaultEnabler, $t) {
+ 'mage/translate',
+ 'Magento_Checkout/js/model/payment/additional-validators'
+], function ($, Component, validator, VaultEnabler, $t, additionalValidators) {
'use strict';
return Component.extend({
@@ -154,7 +155,7 @@ define([
* Trigger order placing
*/
placeOrderClick: function () {
- if (this.validateCardType()) {
+ if (this.validateCardType() && additionalValidators.validate()) {
this.isPlaceOrderActionAllowed(false);
$(this.getSelector('submit')).trigger('click');
}
diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js
new file mode 100644
index 0000000000000..1ceebc8e66282
--- /dev/null
+++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/multishipping/hosted-fields.js
@@ -0,0 +1,102 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+/*browser:true*/
+/*global define*/
+
+define([
+ 'jquery',
+ 'Magento_Braintree/js/view/payment/method-renderer/hosted-fields',
+ 'Magento_Braintree/js/validator',
+ 'Magento_Ui/js/model/messageList',
+ 'mage/translate',
+ 'Magento_Checkout/js/model/full-screen-loader',
+ 'Magento_Checkout/js/action/set-payment-information',
+ 'Magento_Checkout/js/model/payment/additional-validators'
+], function (
+ $,
+ Component,
+ validator,
+ messageList,
+ $t,
+ fullScreenLoader,
+ setPaymentInformationAction,
+ additionalValidators
+) {
+ 'use strict';
+
+ return Component.extend({
+ defaults: {
+ template: 'Magento_Braintree/payment/multishipping/form'
+ },
+
+ /**
+ * Get list of available CC types
+ *
+ * @returns {Object}
+ */
+ getCcAvailableTypes: function () {
+ var availableTypes = validator.getAvailableCardTypes(),
+ billingCountryId;
+
+ billingCountryId = $('#multishipping_billing_country_id').val();
+
+ if (billingCountryId && validator.getCountrySpecificCardTypes(billingCountryId)) {
+ return validator.collectTypes(
+ availableTypes, validator.getCountrySpecificCardTypes(billingCountryId)
+ );
+ }
+
+ return availableTypes;
+ },
+
+ /**
+ * @override
+ */
+ placeOrder: function () {
+ var self = this;
+
+ this.validatorManager.validate(self, function () {
+ return self.setPaymentInformation();
+ });
+ },
+
+ /**
+ * @override
+ */
+ setPaymentInformation: function () {
+ if (additionalValidators.validate()) {
+
+ fullScreenLoader.startLoader();
+
+ $.when(
+ setPaymentInformationAction(
+ this.messageContainer,
+ this.getData()
+ )
+ ).done(this.done.bind(this))
+ .fail(this.fail.bind(this));
+ }
+ },
+
+ /**
+ * {Function}
+ */
+ fail: function () {
+ fullScreenLoader.stopLoader();
+
+ return this;
+ },
+
+ /**
+ * {Function}
+ */
+ done: function () {
+ fullScreenLoader.stopLoader();
+ $('#multishipping-billing-form').submit();
+
+ return this;
+ }
+ });
+});
diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/multishipping/paypal.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/multishipping/paypal.js
new file mode 100644
index 0000000000000..6702e58d1214b
--- /dev/null
+++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/multishipping/paypal.js
@@ -0,0 +1,143 @@
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+/*browser:true*/
+/*global define*/
+define([
+ 'jquery',
+ 'underscore',
+ 'Magento_Braintree/js/view/payment/method-renderer/paypal',
+ 'Magento_Checkout/js/action/set-payment-information',
+ 'Magento_Checkout/js/model/payment/additional-validators',
+ 'Magento_Checkout/js/model/full-screen-loader',
+ 'mage/translate'
+], function (
+ $,
+ _,
+ Component,
+ setPaymentInformationAction,
+ additionalValidators,
+ fullScreenLoader,
+ $t
+) {
+ 'use strict';
+
+ return Component.extend({
+ defaults: {
+ template: 'Magento_Braintree/payment/multishipping/paypal',
+ submitButtonSelector: '#payment-continue span'
+ },
+
+ /**
+ * @override
+ */
+ onActiveChange: function (isActive) {
+ this.updateSubmitButtonTitle(isActive);
+
+ this._super(isActive);
+ },
+
+ /**
+ * @override
+ */
+ beforePlaceOrder: function (data) {
+ this._super(data);
+
+ this.updateSubmitButtonTitle(true);
+ },
+
+ /**
+ * @override
+ */
+ getShippingAddress: function () {
+ return {};
+ },
+
+ /**
+ * @override
+ */
+ getData: function () {
+ var data = this._super();
+
+ data['additional_data']['is_active_payment_token_enabler'] = true;
+
+ return data;
+ },
+
+ /**
+ * @override
+ */
+ isActiveVault: function () {
+ return true;
+ },
+
+ /**
+ * Skipping order review step on checkout with multiple addresses is not allowed.
+ *
+ * @returns {Boolean}
+ */
+ isSkipOrderReview: function () {
+ return false;
+ },
+
+ /**
+ * Checks if payment method nonce is already received.
+ *
+ * @returns {Boolean}
+ */
+ isPaymentMethodNonceReceived: function () {
+ return this.paymentMethodNonce !== null;
+ },
+
+ /**
+ * Updates submit button title on multi-addresses checkout billing form.
+ *
+ * @param {Boolean} isActive
+ */
+ updateSubmitButtonTitle: function (isActive) {
+ var title = this.isPaymentMethodNonceReceived() || !isActive ?
+ $t('Go to Review Your Order') : $t('Continue to PayPal');
+
+ $(this.submitButtonSelector).html(title);
+ },
+
+ /**
+ * @override
+ */
+ placeOrder: function () {
+ if (!this.isPaymentMethodNonceReceived()) {
+ this.payWithPayPal();
+ } else {
+ fullScreenLoader.startLoader();
+
+ $.when(
+ setPaymentInformationAction(
+ this.messageContainer,
+ this.getData()
+ )
+ ).done(this.done.bind(this))
+ .fail(this.fail.bind(this));
+ }
+ },
+
+ /**
+ * {Function}
+ */
+ fail: function () {
+ fullScreenLoader.stopLoader();
+
+ return this;
+ },
+
+ /**
+ * {Function}
+ */
+ done: function () {
+ fullScreenLoader.stopLoader();
+ $('#multishipping-billing-form').submit();
+
+ return this;
+ }
+ });
+});
diff --git a/app/code/Magento/Braintree/view/frontend/web/template/payment/multishipping/form.html b/app/code/Magento/Braintree/view/frontend/web/template/payment/multishipping/form.html
new file mode 100644
index 0000000000000..964e15df166d3
--- /dev/null
+++ b/app/code/Magento/Braintree/view/frontend/web/template/payment/multishipping/form.html
@@ -0,0 +1,106 @@
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Braintree/view/frontend/web/template/payment/multishipping/paypal.html b/app/code/Magento/Braintree/view/frontend/web/template/payment/multishipping/paypal.html
new file mode 100644
index 0000000000000..722989e41f98f
--- /dev/null
+++ b/app/code/Magento/Braintree/view/frontend/web/template/payment/multishipping/paypal.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php
index 0e21e566d5e75..a768e2450bfe8 100644
--- a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php
+++ b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php
@@ -4,13 +4,13 @@
* See COPYING.txt for license details.
*/
+namespace Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes;
+
/**
- * Bundle Extended Attribures Block
+ * Bundle Extended Attribures Block.
*
- * @author Magento Core Team
+ * @author Magento Core Team
*/
-namespace Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes;
-
class Extend extends \Magento\Catalog\Block\Adminhtml\Form\Renderer\Fieldset\Element
{
/**
@@ -75,7 +75,7 @@ public function getElementHtml()
}
/**
- * Execute method getElementHtml from parrent class
+ * Execute method getElementHtml from parent class
*
* @return string
*/
@@ -85,6 +85,8 @@ public function getParentElementHtml()
}
/**
+ * Get options.
+ *
* @return array
*/
public function getOptions()
@@ -106,6 +108,8 @@ public function getOptions()
}
/**
+ * Is disabled field.
+ *
* @return bool
*/
public function isDisabledField()
@@ -118,6 +122,8 @@ public function isDisabledField()
}
/**
+ * Get product.
+ *
* @return mixed
*/
public function getProduct()
@@ -129,6 +135,8 @@ public function getProduct()
}
/**
+ * Get extended element.
+ *
* @param string $switchAttributeCode
* @return \Magento\Framework\Data\Form\Element\Select
* @throws \Magento\Framework\Exception\LocalizedException
diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php
index 7c63af0bd0e2e..7c5a64ca0232f 100644
--- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php
+++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle/Option.php
@@ -6,6 +6,8 @@
namespace Magento\Bundle\Block\Catalog\Product\View\Type\Bundle;
+use Magento\Catalog\Model\Product;
+
/**
* Bundle option renderer
* @api
@@ -169,7 +171,7 @@ protected function assignSelection(\Magento\Bundle\Model\Option $option, $select
{
if (is_array($selectionId)) {
$this->_selectedOptions = $selectionId;
- } else if ($selectionId && $option->getSelectionById($selectionId)) {
+ } elseif ($selectionId && $option->getSelectionById($selectionId)) {
$this->_selectedOptions = $selectionId;
} elseif (!$option->getRequired()) {
$this->_selectedOptions = 'None';
@@ -179,7 +181,7 @@ protected function assignSelection(\Magento\Bundle\Model\Option $option, $select
/**
* Define if selection is selected
*
- * @param \Magento\Catalog\Model\Product $selection
+ * @param Product $selection
* @return bool
*/
public function isSelected($selection)
@@ -219,7 +221,7 @@ protected function _getSelectedQty()
/**
* Get product model
*
- * @return \Magento\Catalog\Model\Product
+ * @return Product
*/
public function getProduct()
{
@@ -232,7 +234,7 @@ public function getProduct()
/**
* Get bundle option price title.
*
- * @param \Magento\Catalog\Model\Product $selection
+ * @param Product $selection
* @param bool $includeContainer
* @return string
*/
@@ -254,7 +256,7 @@ public function getSelectionQtyTitlePrice($selection, $includeContainer = true)
/**
* Get price for selection product
*
- * @param \Magento\Catalog\Model\Product $selection
+ * @param Product $selection
* @return int|float
*/
public function getSelectionPrice($selection)
@@ -277,7 +279,7 @@ public function getSelectionPrice($selection)
/**
* Get title price for selection product
*
- * @param \Magento\Catalog\Model\Product $selection
+ * @param Product $selection
* @param bool $includeContainer
* @return string
*/
@@ -299,7 +301,7 @@ public function getSelectionTitlePrice($selection, $includeContainer = true)
*/
public function setValidationContainer($elementId, $containerId)
{
- return;
+ return '';
}
/**
@@ -318,7 +320,7 @@ public function setOption(\Magento\Bundle\Model\Option $option)
/**
* Format price string
*
- * @param \Magento\Catalog\Model\Product $selection
+ * @param Product $selection
* @param bool $includeContainer
* @return string
*/
diff --git a/app/code/Magento/Bundle/Block/Checkout/Cart/Item/Renderer.php b/app/code/Magento/Bundle/Block/Checkout/Cart/Item/Renderer.php
index c75ebc700603b..863f273225693 100644
--- a/app/code/Magento/Bundle/Block/Checkout/Cart/Item/Renderer.php
+++ b/app/code/Magento/Bundle/Block/Checkout/Cart/Item/Renderer.php
@@ -69,6 +69,7 @@ public function __construct(
/**
* Overloaded method for getting list of bundle options
+ *
* Caches result in quote item, because it can be used in cart 'recent view' and on same page in cart checkout
*
* @return array
@@ -88,7 +89,7 @@ public function getMessages()
$messages = [];
$quoteItem = $this->getItem();
- // Add basic messages occuring during this page load
+ // Add basic messages occurring during this page load
$baseMessages = $quoteItem->getMessage(false);
if ($baseMessages) {
foreach ($baseMessages as $message) {
diff --git a/app/code/Magento/Bundle/Block/DataProviders/OptionPriceRenderer.php b/app/code/Magento/Bundle/Block/DataProviders/OptionPriceRenderer.php
new file mode 100644
index 0000000000000..058b3a981b52f
--- /dev/null
+++ b/app/code/Magento/Bundle/Block/DataProviders/OptionPriceRenderer.php
@@ -0,0 +1,63 @@
+layout = $layout;
+ }
+
+ /**
+ * Format tier price string
+ *
+ * @param Product $selection
+ * @param array $arguments
+ * @return string
+ */
+ public function renderTierPrice(Product $selection, array $arguments = []): string
+ {
+ if (!array_key_exists('zone', $arguments)) {
+ $arguments['zone'] = Render::ZONE_ITEM_OPTION;
+ }
+
+ $priceHtml = '';
+
+ /** @var Render $priceRender */
+ $priceRender = $this->layout->getBlock('product.price.render.default');
+ if ($priceRender !== false) {
+ $priceHtml = $priceRender->render(
+ TierPrice::PRICE_CODE,
+ $selection,
+ $arguments
+ );
+ }
+
+ return $priceHtml;
+ }
+}
diff --git a/app/code/Magento/Bundle/Model/Product/Price.php b/app/code/Magento/Bundle/Model/Product/Price.php
index 00b6b2d7a3f5a..0e75ad2dc828c 100644
--- a/app/code/Magento/Bundle/Model/Product/Price.php
+++ b/app/code/Magento/Bundle/Model/Product/Price.php
@@ -11,8 +11,11 @@
use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory;
/**
+ * Bundle product type price model
+ *
* @api
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
* @since 100.0.2
*/
class Price extends \Magento\Catalog\Model\Product\Type\Price
@@ -180,9 +183,9 @@ protected function getBundleSelectionIds(\Magento\Catalog\Model\Product $product
/**
* Get product final price
*
- * @param float $qty
- * @param \Magento\Catalog\Model\Product $product
- * @return float
+ * @param float $qty
+ * @param \Magento\Catalog\Model\Product $product
+ * @return float
*/
public function getFinalPrice($qty, $product)
{
@@ -207,9 +210,9 @@ public function getFinalPrice($qty, $product)
* Returns final price of a child product
*
* @param \Magento\Catalog\Model\Product $product
- * @param float $productQty
+ * @param float $productQty
* @param \Magento\Catalog\Model\Product $childProduct
- * @param float $childProductQty
+ * @param float $childProductQty
* @return float
*/
public function getChildFinalPrice($product, $productQty, $childProduct, $childProductQty)
@@ -220,10 +223,10 @@ public function getChildFinalPrice($product, $productQty, $childProduct, $childP
/**
* Retrieve Price considering tier price
*
- * @param \Magento\Catalog\Model\Product $product
- * @param string|null $which
- * @param bool|null $includeTax
- * @param bool $takeTierPrice
+ * @param \Magento\Catalog\Model\Product $product
+ * @param string|null $which
+ * @param bool|null $includeTax
+ * @param bool $takeTierPrice
* @return float|array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
@@ -255,67 +258,68 @@ public function getTotalPrices($product, $which = null, $includeTax = null, $tak
foreach ($options as $option) {
/* @var $option \Magento\Bundle\Model\Option */
$selections = $option->getSelections();
- if ($selections) {
- $selectionMinimalPrices = [];
- $selectionMaximalPrices = [];
-
- foreach ($option->getSelections() as $selection) {
- /* @var $selection \Magento\Bundle\Model\Selection */
- if (!$selection->isSalable()) {
- /**
- * @todo CatalogInventory Show out of stock Products
- */
- continue;
- }
-
- $qty = $selection->getSelectionQty();
-
- $item = $product->getPriceType() == self::PRICE_TYPE_FIXED ? $product : $selection;
-
- $selectionMinimalPrices[] = $this->_catalogData->getTaxPrice(
- $item,
- $this->getSelectionFinalTotalPrice(
- $product,
- $selection,
- 1,
- $qty,
- true,
- $takeTierPrice
- ),
- $includeTax
- );
- $selectionMaximalPrices[] = $this->_catalogData->getTaxPrice(
- $item,
- $this->getSelectionFinalTotalPrice(
- $product,
- $selection,
- 1,
- null,
- true,
- $takeTierPrice
- ),
- $includeTax
+ if (empty($selections)) {
+ continue;
+ }
+ $selectionMinimalPrices = [];
+ $selectionMaximalPrices = [];
+
+ foreach ($option->getSelections() as $selection) {
+ /* @var $selection \Magento\Bundle\Model\Selection */
+ if (!$selection->isSalable()) {
+ /**
+ * @todo CatalogInventory Show out of stock Products
+ */
+ continue;
+ }
+
+ $qty = $selection->getSelectionQty();
+
+ $item = $product->getPriceType() == self::PRICE_TYPE_FIXED ? $product : $selection;
+
+ $selectionMinimalPrices[] = $this->_catalogData->getTaxPrice(
+ $item,
+ $this->getSelectionFinalTotalPrice(
+ $product,
+ $selection,
+ 1,
+ $qty,
+ true,
+ $takeTierPrice
+ ),
+ $includeTax
+ );
+ $selectionMaximalPrices[] = $this->_catalogData->getTaxPrice(
+ $item,
+ $this->getSelectionFinalTotalPrice(
+ $product,
+ $selection,
+ 1,
+ null,
+ true,
+ $takeTierPrice
+ ),
+ $includeTax
+ );
+ }
+
+ if (count($selectionMinimalPrices)) {
+ $selMinPrice = min($selectionMinimalPrices);
+ if ($option->getRequired()) {
+ $minimalPrice += $selMinPrice;
+ $minPriceFounded = true;
+ } elseif (true !== $minPriceFounded) {
+ $selMinPrice += $minimalPrice;
+ $minPriceFounded = false === $minPriceFounded ? $selMinPrice : min(
+ $minPriceFounded,
+ $selMinPrice
);
}
- if (count($selectionMinimalPrices)) {
- $selMinPrice = min($selectionMinimalPrices);
- if ($option->getRequired()) {
- $minimalPrice += $selMinPrice;
- $minPriceFounded = true;
- } elseif (true !== $minPriceFounded) {
- $selMinPrice += $minimalPrice;
- $minPriceFounded = false === $minPriceFounded ? $selMinPrice : min(
- $minPriceFounded,
- $selMinPrice
- );
- }
-
- if ($option->isMultiSelection()) {
- $maximalPrice += array_sum($selectionMaximalPrices);
- } else {
- $maximalPrice += max($selectionMaximalPrices);
- }
+ if ($option->isMultiSelection()) {
+ $maximalPrice += array_sum($selectionMaximalPrices);
+ } else {
+ $maximalPrice += max($selectionMaximalPrices);
}
}
}
@@ -338,23 +342,25 @@ public function getTotalPrices($product, $which = null, $includeTax = null, $tak
$prices[] = $valuePrice;
}
- if (count($prices)) {
- if ($customOption->getIsRequire()) {
- $minimalPrice += $this->_catalogData->getTaxPrice($product, min($prices), $includeTax);
- }
-
- $multiTypes = [
- \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_CHECKBOX,
- \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE,
- ];
-
- if (in_array($customOption->getType(), $multiTypes)) {
- $maximalValue = array_sum($prices);
- } else {
- $maximalValue = max($prices);
- }
- $maximalPrice += $this->_catalogData->getTaxPrice($product, $maximalValue, $includeTax);
+ if (empty($prices)) {
+ continue;
+ }
+
+ if ($customOption->getIsRequire()) {
+ $minimalPrice += $this->_catalogData->getTaxPrice($product, min($prices), $includeTax);
+ }
+
+ $multiTypes = [
+ \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_CHECKBOX,
+ \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_MULTIPLE,
+ ];
+
+ if (in_array($customOption->getType(), $multiTypes)) {
+ $maximalValue = array_sum($prices);
+ } else {
+ $maximalValue = max($prices);
}
+ $maximalPrice += $this->_catalogData->getTaxPrice($product, $maximalValue, $includeTax);
} else {
$valuePrice = $customOption->getPrice(true);
@@ -402,8 +408,8 @@ public function getOptions($product)
*
* @param \Magento\Catalog\Model\Product $bundleProduct
* @param \Magento\Catalog\Model\Product $selectionProduct
- * @param float|null $selectionQty
- * @param null|bool $multiplyQty Whether to multiply selection's price by its quantity
+ * @param float|null $selectionQty
+ * @param null|bool $multiplyQty Whether to multiply selection's price by its quantity
* @return float
*
* @see \Magento\Bundle\Model\Product\Price::getSelectionFinalTotalPrice()
@@ -418,7 +424,7 @@ public function getSelectionPrice($bundleProduct, $selectionProduct, $selectionQ
*
* @param \Magento\Catalog\Model\Product $bundleProduct
* @param \Magento\Catalog\Model\Product $selectionProduct
- * @param float $qty
+ * @param float $qty
* @return float
*/
public function getSelectionPreFinalPrice($bundleProduct, $selectionProduct, $qty = null)
@@ -427,15 +433,14 @@ public function getSelectionPreFinalPrice($bundleProduct, $selectionProduct, $qt
}
/**
- * Calculate final price of selection
- * with take into account tier price
+ * Calculate final price of selection with take into account tier price
*
- * @param \Magento\Catalog\Model\Product $bundleProduct
- * @param \Magento\Catalog\Model\Product $selectionProduct
- * @param float $bundleQty
- * @param float $selectionQty
- * @param bool $multiplyQty
- * @param bool $takeTierPrice
+ * @param \Magento\Catalog\Model\Product $bundleProduct
+ * @param \Magento\Catalog\Model\Product $selectionProduct
+ * @param float $bundleQty
+ * @param float $selectionQty
+ * @param bool $multiplyQty
+ * @param bool $takeTierPrice
* @return float
*/
public function getSelectionFinalTotalPrice(
@@ -454,7 +459,11 @@ public function getSelectionFinalTotalPrice(
}
if ($bundleProduct->getPriceType() == self::PRICE_TYPE_DYNAMIC) {
- $price = $selectionProduct->getFinalPrice($takeTierPrice ? $selectionQty : 1);
+ $totalQty = $bundleQty * $selectionQty;
+ if (!$takeTierPrice || $totalQty === 0) {
+ $totalQty = 1;
+ }
+ $price = $selectionProduct->getFinalPrice($totalQty);
} else {
if ($selectionProduct->getSelectionPriceType()) {
// percent
@@ -485,10 +494,10 @@ public function getSelectionFinalTotalPrice(
/**
* Apply tier price for bundle
*
- * @param \Magento\Catalog\Model\Product $product
- * @param float $qty
- * @param float $finalPrice
- * @return float
+ * @param \Magento\Catalog\Model\Product $product
+ * @param float $qty
+ * @param float $finalPrice
+ * @return float
*/
protected function _applyTierPrice($product, $qty, $finalPrice)
{
@@ -509,9 +518,9 @@ protected function _applyTierPrice($product, $qty, $finalPrice)
/**
* Get product tier price by qty
*
- * @param float $qty
- * @param \Magento\Catalog\Model\Product $product
- * @return float|array
+ * @param float $qty
+ * @param \Magento\Catalog\Model\Product $product
+ * @return float|array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
*/
@@ -605,11 +614,11 @@ public function getTierPrice($qty, $product)
/**
* Calculate and apply special price
*
- * @param float $finalPrice
- * @param float $specialPrice
+ * @param float $finalPrice
+ * @param float $specialPrice
* @param string $specialPriceFrom
* @param string $specialPriceTo
- * @param mixed $store
+ * @param mixed $store
* @return float
*/
public function calculateSpecialPrice(
@@ -634,7 +643,7 @@ public function calculateSpecialPrice(
*
* @param /Magento/Catalog/Model/Product $bundleProduct
* @param float|string $price
- * @param int $bundleQty
+ * @param int $bundleQty
* @return float
*/
public function getLowestPrice($bundleProduct, $price, $bundleQty = 1)
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml
index ad9a8253e910c..4cd16320d3d78 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/AdminCreateApiBundleProductActionGroup.xml
@@ -106,4 +106,62 @@
+
+
+
+
+
+
+ 10
+
+
+ 20
+
+
+
+ {{productName}}
+
+
+
+ Drop-down Option
+
+
+
+ Radio Buttons Option
+
+
+
+ Checkbox Option
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml
index e36730a87b41a..1767db0a00974 100644
--- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml
@@ -38,4 +38,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml
index dbe48c46c820b..30a7e8b777f3b 100644
--- a/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml
+++ b/app/code/Magento/Bundle/Test/Mftf/Section/StorefrontBundledSection.xml
@@ -26,11 +26,14 @@
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductOptionTierPrices.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductOptionTierPrices.xml
new file mode 100644
index 0000000000000..4c39cbc4ab0a4
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCheckBundleProductOptionTierPrices.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Buy 5 for $5.00 each and save 50%
+ DropDownTierPriceTextProduct1
+
+
+
+
+
+
+ Buy 7 for $15.00 each and save 25%
+ dropDownTierPriceTextProduct2
+
+
+
+
+
+
+ Buy 5 for $5.00 each and save 50%
+ radioButtonsOptionTierPriceTextProduct1
+
+
+
+
+ Buy 7 for $15.00 each and save 25%
+ radioButtonsOptionTierPriceTextProduct2
+
+
+
+
+
+
+ Buy 5 for $5.00 each and save 50%
+ checkBoxOptionTierPriceTextProduct1
+
+
+
+
+ Buy 7 for $15.00 each and save 25%
+ checkBoxOptionTierPriceTextProduct2
+
+
+
diff --git a/app/code/Magento/Bundle/Test/Unit/Block/DataProviders/OptionPriceRendererTest.php b/app/code/Magento/Bundle/Test/Unit/Block/DataProviders/OptionPriceRendererTest.php
new file mode 100644
index 0000000000000..1af73bafc6256
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Unit/Block/DataProviders/OptionPriceRendererTest.php
@@ -0,0 +1,99 @@
+layoutMock = $this->createMock(
+ LayoutInterface::class
+ );
+
+ $this->renderer = $objectManager->getObject(
+ OptionPriceRenderer::class,
+ ['layout' => $this->layoutMock]
+ );
+ }
+
+ /**
+ * Test to render Tier price html
+ *
+ * @return void
+ */
+ public function testRenderTierPrice(): void
+ {
+ $expectedHtml = 'tier price html';
+ $expectedArguments = ['zone' => Render::ZONE_ITEM_OPTION];
+
+ $productMock = $this->createMock(Product::class);
+
+ $priceRenderer = $this->createPartialMock(BlockInterface::class, ['toHtml', 'render']);
+ $priceRenderer->expects($this->once())
+ ->method('render')
+ ->with('tier_price', $productMock, $expectedArguments)
+ ->willReturn($expectedHtml);
+
+ $this->layoutMock->method('getBlock')
+ ->with('product.price.render.default')
+ ->willReturn($priceRenderer);
+
+ $this->assertEquals(
+ $expectedHtml,
+ $this->renderer->renderTierPrice($productMock),
+ 'Render Tier price is wrong'
+ );
+ }
+
+ /**
+ * Test to render Tier price html when render block is not exists
+ *
+ * @return void
+ */
+ public function testRenderTierPriceNotExist(): void
+ {
+ $productMock = $this->createMock(Product::class);
+
+ $this->layoutMock->method('getBlock')
+ ->with('product.price.render.default')
+ ->willReturn(false);
+
+ $this->assertEquals(
+ '',
+ $this->renderer->renderTierPrice($productMock),
+ 'Render Tier price is wrong'
+ );
+ }
+}
diff --git a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js
index f8d2f8bc11116..49ee253ad1e88 100644
--- a/app/code/Magento/Bundle/view/base/web/js/price-bundle.js
+++ b/app/code/Magento/Bundle/view/base/web/js/price-bundle.js
@@ -27,7 +27,8 @@ define([
'<% } %>',
controlContainer: 'dd', // should be eliminated
priceFormat: {},
- isFixedPrice: false
+ isFixedPrice: false,
+ optionTierPricesBlocksSelector: '#option-tier-prices-{1} [data-role="selection-tier-prices"]'
};
$.widget('mage.priceBundle', {
@@ -91,6 +92,8 @@ define([
if (changes) {
priceBox.trigger('updatePrice', changes);
}
+
+ this._displayTierPriceBlock(bundleOption);
this.updateProductSummary();
},
@@ -207,6 +210,35 @@ define([
return this;
},
+ /**
+ * Show or hide option tier prices block
+ *
+ * @param {Object} optionElement
+ * @private
+ */
+ _displayTierPriceBlock: function (optionElement) {
+ var optionType = optionElement.prop('type'),
+ optionId,
+ optionValue,
+ optionTierPricesElements;
+
+ if (optionType === 'select-one') {
+ optionId = utils.findOptionId(optionElement[0]);
+ optionValue = optionElement.val() || null;
+ optionTierPricesElements = $(this.options.optionTierPricesBlocksSelector.replace('{1}', optionId));
+
+ _.each(optionTierPricesElements, function (tierPriceElement) {
+ var selectionId = $(tierPriceElement).data('selection-id') + '';
+
+ if (selectionId === optionValue) {
+ $(tierPriceElement).show();
+ } else {
+ $(tierPriceElement).hide();
+ }
+ });
+ }
+ },
+
/**
* Handler to update productSummary box
*/
diff --git a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml
index 5b8c050e5af54..d12f2e8f6a952 100644
--- a/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml
+++ b/app/code/Magento/Bundle/view/frontend/layout/catalog_product_view_type_bundle.xml
@@ -29,10 +29,22 @@
-
+
+
+ \Magento\Bundle\Block\DataProviders\OptionPriceRenderer
+
+
-
-
+
+
+ \Magento\Bundle\Block\DataProviders\OptionPriceRenderer
+
+
+
+
+ \Magento\Bundle\Block\DataProviders\OptionPriceRenderer
+
+
diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/checkbox.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/checkbox.phtml
index bda649eb603e6..830d03c826f32 100644
--- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/checkbox.phtml
+++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/checkbox.phtml
@@ -19,6 +19,7 @@
showSingle()): ?>
= /* @escapeNotVerified */ $block->getSelectionQtyTitlePrice($_selections[0]) ?>
+ = /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selections[0]) ?>
= /* @escapeNotVerified */ $block->getSelectionQtyTitlePrice($_selection) ?>
+
+ = /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selection) ?>
diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml
index 7ea89e8609818..1f33d97227ea3 100644
--- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml
+++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml
@@ -21,6 +21,7 @@
showSingle()): ?>
= /* @escapeNotVerified */ $block->getSelectionTitlePrice($_selections[0]) ?>
+ = /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selections[0]) ?>
= /* @escapeNotVerified */ $block->getSelectionTitlePrice($_selection) ?>
+
+ = /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selection) ?>
diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/select.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/select.phtml
index 977daa2b2a446..4ea00f62b2043 100644
--- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/select.phtml
+++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/select.phtml
@@ -20,6 +20,7 @@
showSingle()): ?>
= /* @escapeNotVerified */ $block->getSelectionTitlePrice($_selections[0]) ?>
+ = /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selections[0]) ?>
+
+
+
+ = /* @noEscape */ $block->getTierPriceRenderer()->renderTierPrice($_selection) ?>
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AdminLoginWithCaptchaActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AdminLoginWithCaptchaActionGroup.xml
new file mode 100644
index 0000000000000..07329e2659876
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AdminLoginWithCaptchaActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaNotVisibleOnCustomerLoginFormActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaNotVisibleOnCustomerLoginFormActionGroup.xml
new file mode 100644
index 0000000000000..a371f177e3552
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaNotVisibleOnCustomerLoginFormActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnAdminLoginFormActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnAdminLoginFormActionGroup.xml
new file mode 100644
index 0000000000000..aa02588000d2b
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnAdminLoginFormActionGroup.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnContactUsFormActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnContactUsFormActionGroup.xml
new file mode 100644
index 0000000000000..d800c65cabb60
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnContactUsFormActionGroup.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerAccountCreatePageActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerAccountCreatePageActionGroup.xml
new file mode 100644
index 0000000000000..6c09d1d49381f
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerAccountCreatePageActionGroup.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerAccountInfoActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerAccountInfoActionGroup.xml
new file mode 100644
index 0000000000000..c68ffbfb5be4b
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerAccountInfoActionGroup.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerLoginFormActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerLoginFormActionGroup.xml
new file mode 100644
index 0000000000000..5616b099c026d
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/AssertCaptchaVisibleOnCustomerLoginFormActionGroup.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml
index beb2c2bffa135..f3b6eb1d9af84 100644
--- a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/CaptchaFormsDisplayingActionGroup.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontCustomerChangeEmailWithCaptchaActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontCustomerChangeEmailWithCaptchaActionGroup.xml
new file mode 100644
index 0000000000000..8aff3d5482f2c
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontCustomerChangeEmailWithCaptchaActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillContactUsFormWithCaptchaActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillContactUsFormWithCaptchaActionGroup.xml
new file mode 100644
index 0000000000000..3546fa2e57a33
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillContactUsFormWithCaptchaActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillCustomerAccountCreationFormWithCaptchaActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillCustomerAccountCreationFormWithCaptchaActionGroup.xml
new file mode 100644
index 0000000000000..d67ebc1a00768
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillCustomerAccountCreationFormWithCaptchaActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillCustomerLoginFormWithCaptchaActionGroup.xml b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillCustomerLoginFormWithCaptchaActionGroup.xml
new file mode 100644
index 0000000000000..5ad727a8fe99d
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/ActionGroup/StorefrontFillCustomerLoginFormWithCaptchaActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaConfigData.xml b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaConfigData.xml
new file mode 100644
index 0000000000000..90f48c320f2ac
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaConfigData.xml
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+ customer/captcha/enable
+ 0
+ Yes
+ 1
+
+
+ customer/captcha/enable
+ 0
+ No
+ 0
+
+
+ customer/captcha/forms
+ 0
+ Create user
+ user_create
+
+
+ customer/captcha/forms
+ 0
+ Contact Us
+ contact_us
+
+
+
+ customer/captcha/forms
+ 0
+ Login
+ user_login
+
+
+ customer/captcha/forms
+ 0
+ Change password
+ user_edit
+
+
+
+ customer/captcha/forms
+ 0
+ Forgot password
+ user_forgotpassword
+
+
+ customer/captcha/mode
+ 0
+ Always
+ always
+
+
+
+ customer/captcha/mode
+ 0
+ After number of attempts to login
+ after_fail
+
+
+ customer/captcha/length
+ admin
+ 1
+ 3
+ 3
+
+
+ customer/captcha/symbols
+ admin
+ 1
+ 1
+ 1
+
+
+
+ customer/captcha/length
+ admin
+ 1
+ 4-5
+ 4-5
+
+
+
+ customer/captcha/symbols
+ admin
+ 1
+ ABCDEFGHJKMnpqrstuvwxyz23456789
+ ABCDEFGHJKMnpqrstuvwxyz23456789
+
+
+
+ admin/captcha/enable
+ 0
+ Yes
+ 1
+
+
+ admin/captcha/enable
+ 0
+ No
+ 0
+
+
+ admin/captcha/length
+ admin
+ 1
+ 3
+ 3
+
+
+ admin/captcha/symbols
+ admin
+ 1
+ 1
+ 1
+
+
+
+ admin/captcha/length
+ admin
+ 1
+ 4-5
+ 4-5
+
+
+
+ admin/captcha/symbols
+ admin
+ 1
+ ABCDEFGHJKMnpqrstuvwxyz23456789
+ ABCDEFGHJKMnpqrstuvwxyz23456789
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaData.xml b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaData.xml
new file mode 100644
index 0000000000000..d8fb206b8111c
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaData.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ WrongCAPTCHA
+
+
+
+
+ 111
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaFormsDisplayingData.xml b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaFormsDisplayingData.xml
index 9db8110c0f64b..57a09219fe4db 100644
--- a/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaFormsDisplayingData.xml
+++ b/app/code/Magento/Captcha/Test/Mftf/Data/CaptchaFormsDisplayingData.xml
@@ -7,7 +7,7 @@
-->
+ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd">
Create user
Login
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/AdminLoginFormSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/AdminLoginFormSection.xml
new file mode 100644
index 0000000000000..2bcc6fc542d82
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/AdminLoginFormSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontContactUsCaptchaSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontContactUsCaptchaSection.xml
new file mode 100644
index 0000000000000..f587812576ff1
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontContactUsCaptchaSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontContactUsFormSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontContactUsFormSection.xml
new file mode 100644
index 0000000000000..60cf961ba7e8c
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontContactUsFormSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerAccountInformationSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerAccountInformationSection.xml
new file mode 100644
index 0000000000000..a273c8d4abd28
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerAccountInformationSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerCreateFormSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerCreateFormSection.xml
new file mode 100644
index 0000000000000..f48e6124cb214
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerCreateFormSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerSignInFormSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerSignInFormSection.xml
index 7a0557c4a2744..54aa36d1ca267 100644
--- a/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerSignInFormSection.xml
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerSignInFormSection.xml
@@ -8,7 +8,7 @@
-
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerSignInPopupFormSection.xml b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerSignInPopupFormSection.xml
new file mode 100644
index 0000000000000..7a0557c4a2744
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Section/StorefrontCustomerSignInPopupFormSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/AdminLoginWithCaptchaTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/AdminLoginWithCaptchaTest.xml
new file mode 100644
index 0000000000000..e5ee55910df65
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/AdminLoginWithCaptchaTest.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml
new file mode 100644
index 0000000000000..8f9c5828e2f5e
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaEditCustomerEmailTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaEditCustomerEmailTest.xml
new file mode 100644
index 0000000000000..54237087227d8
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaEditCustomerEmailTest.xml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnContactUsTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnContactUsTest.xml
new file mode 100644
index 0000000000000..0c6a3f31c1df2
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnContactUsTest.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnCustomerLoginTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnCustomerLoginTest.xml
new file mode 100644
index 0000000000000..5a1be68d3f251
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnCustomerLoginTest.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaRegisterNewCustomerTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaRegisterNewCustomerTest.xml
new file mode 100644
index 0000000000000..2c331f958e467
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaRegisterNewCustomerTest.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontResetCustomerPasswordFailedTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontResetCustomerPasswordFailedTest.xml
new file mode 100644
index 0000000000000..36d7989b9acc1
--- /dev/null
+++ b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontResetCustomerPasswordFailedTest.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
index b9a23e9d08ec3..1940a0ac80c0b 100644
--- a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
+++ b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php
@@ -1,7 +1,5 @@
getLevel() < 2) {
+ if ($isParent || $node->getLevel() < 1) {
$item['expanded'] = true;
}
@@ -390,6 +414,8 @@ public function buildNodeName($node)
}
/**
+ * Is category movable
+ *
* @param Node|array $node
* @return bool
*/
@@ -403,6 +429,8 @@ protected function _isCategoryMoveable($node)
}
/**
+ * Is parent selected category
+ *
* @param Node|array $node
* @return bool
*/
diff --git a/app/code/Magento/Catalog/Block/Product/View/Gallery.php b/app/code/Magento/Catalog/Block/Product/View/Gallery.php
index 706d9b83b9711..8b98fbdc8f7ef 100644
--- a/app/code/Magento/Catalog/Block/Product/View/Gallery.php
+++ b/app/code/Magento/Catalog/Block/Product/View/Gallery.php
@@ -207,8 +207,8 @@ public function isMainImage($image)
*/
public function getImageAttribute($imageId, $attributeName, $default = null)
{
- $attributes =
- $this->getConfigView()->getMediaAttributes('Magento_Catalog', Image::MEDIA_TYPE_CONFIG_NODE, $imageId);
+ $attributes = $this->getConfigView()
+ ->getMediaAttributes('Magento_Catalog', Image::MEDIA_TYPE_CONFIG_NODE, $imageId);
return $attributes[$attributeName] ?? $default;
}
diff --git a/app/code/Magento/Catalog/Block/Product/View/GalleryOptions.php b/app/code/Magento/Catalog/Block/Product/View/GalleryOptions.php
new file mode 100644
index 0000000000000..0384c9cd9acce
--- /dev/null
+++ b/app/code/Magento/Catalog/Block/Product/View/GalleryOptions.php
@@ -0,0 +1,156 @@
+gallery = $gallery;
+ $this->jsonSerializer = $jsonSerializer;
+ parent::__construct($context, $arrayUtils, $data);
+ }
+
+ /**
+ * Retrieve gallery options in JSON format
+ *
+ * @return string
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ * @SuppressWarnings(PHPMD.ElseExpression)
+ */
+ public function getOptionsJson()
+ {
+ $optionItems = null;
+
+ //Special case for gallery/nav which can be the string "thumbs/false/dots"
+ if (is_bool($this->getVar("gallery/nav"))) {
+ $optionItems['nav'] = $this->getVar("gallery/nav") ? 'true' : 'false';
+ } else {
+ $optionItems['nav'] = $this->escapeHtml($this->getVar("gallery/nav"));
+ }
+
+ $optionItems['loop'] = $this->getVar("gallery/loop");
+ $optionItems['keyboard'] = $this->getVar("gallery/keyboard");
+ $optionItems['arrows'] = $this->getVar("gallery/arrows");
+ $optionItems['allowfullscreen'] = $this->getVar("gallery/allowfullscreen");
+ $optionItems['showCaption'] = $this->getVar("gallery/caption");
+ $optionItems['width'] = (int)$this->escapeHtml(
+ $this->gallery->getImageAttribute('product_page_image_medium', 'width')
+ );
+ $optionItems['thumbwidth'] = (int)$this->escapeHtml(
+ $this->gallery->getImageAttribute('product_page_image_small', 'width')
+ );
+
+ if ($this->gallery->getImageAttribute('product_page_image_small', 'height') ||
+ $this->gallery->getImageAttribute('product_page_image_small', 'width')) {
+ $optionItems['thumbheight'] = (int)$this->escapeHtml(
+ $this->gallery->getImageAttribute('product_page_image_small', 'height') ?:
+ $this->gallery->getImageAttribute('product_page_image_small', 'width')
+ );
+ }
+
+ if ($this->gallery->getImageAttribute('product_page_image_medium', 'height') ||
+ $this->gallery->getImageAttribute('product_page_image_medium', 'width')) {
+ $optionItems['height'] = (int)$this->escapeHtml(
+ $this->gallery->getImageAttribute('product_page_image_medium', 'height') ?:
+ $this->gallery->getImageAttribute('product_page_image_medium', 'width')
+ );
+ }
+
+ if ($this->getVar("gallery/transition/duration")) {
+ $optionItems['transitionduration'] =
+ (int)$this->escapeHtml($this->getVar("gallery/transition/duration"));
+ }
+
+ $optionItems['transition'] = $this->escapeHtml($this->getVar("gallery/transition/effect"));
+ $optionItems['navarrows'] = $this->getVar("gallery/navarrows");
+ $optionItems['navtype'] = $this->escapeHtml($this->getVar("gallery/navtype"));
+ $optionItems['navdir'] = $this->escapeHtml($this->getVar("gallery/navdir"));
+
+ if ($this->getVar("gallery/thumbmargin")) {
+ $optionItems['thumbmargin'] = (int)$this->escapeHtml($this->getVar("gallery/thumbmargin"));
+ }
+
+ return $this->jsonSerializer->serialize($optionItems);
+ }
+
+ /**
+ * Retrieve gallery fullscreen options in JSON format
+ *
+ * @return string
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ * @SuppressWarnings(PHPMD.NPathComplexity)
+ * @SuppressWarnings(PHPMD.ElseExpression)
+ */
+ public function getFSOptionsJson()
+ {
+ $fsOptionItems = null;
+
+ //Special case for gallery/nav which can be the string "thumbs/false/dots"
+ if (is_bool($this->getVar("gallery/fullscreen/nav"))) {
+ $fsOptionItems['nav'] = $this->getVar("gallery/fullscreen/nav") ? 'true' : 'false';
+ } else {
+ $fsOptionItems['nav'] = $this->escapeHtml($this->getVar("gallery/fullscreen/nav"));
+ }
+
+ $fsOptionItems['loop'] = $this->getVar("gallery/fullscreen/loop");
+ $fsOptionItems['navdir'] = $this->escapeHtml($this->getVar("gallery/fullscreen/navdir"));
+ $fsOptionItems['navarrows'] = $this->getVar("gallery/fullscreen/navarrows");
+ $fsOptionItems['navtype'] = $this->escapeHtml($this->getVar("gallery/fullscreen/navtype"));
+ $fsOptionItems['arrows'] = $this->getVar("gallery/fullscreen/arrows");
+ $fsOptionItems['showCaption'] = $this->getVar("gallery/fullscreen/caption");
+
+ if ($this->getVar("gallery/fullscreen/transition/duration")) {
+ $fsOptionItems['transitionduration'] = (int)$this->escapeHtml(
+ $this->getVar("gallery/fullscreen/transition/duration")
+ );
+ }
+
+ $fsOptionItems['transition'] = $this->escapeHtml($this->getVar("gallery/fullscreen/transition/effect"));
+
+ if ($this->getVar("gallery/fullscreen/keyboard")) {
+ $fsOptionItems['keyboard'] = $this->getVar("gallery/fullscreen/keyboard");
+ }
+
+ if ($this->getVar("gallery/fullscreen/thumbmargin")) {
+ $fsOptionItems['thumbmargin'] =
+ (int)$this->escapeHtml($this->getVar("gallery/fullscreen/thumbmargin"));
+ }
+
+ return $this->jsonSerializer->serialize($fsOptionItems);
+ }
+}
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Search.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Search.php
index c7c71b2f56026..316983298a1b9 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Search.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Search.php
@@ -9,11 +9,12 @@
namespace Magento\Catalog\Controller\Adminhtml\Product;
use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Framework\App\Action\HttpGetActionInterface;
/**
* Controller to search product for ui-select component
*/
-class Search extends \Magento\Backend\App\Action
+class Search extends \Magento\Backend\App\Action implements HttpGetActionInterface
{
/**
* Authorization level of a basic admin session
@@ -48,6 +49,8 @@ public function __construct(
}
/**
+ * Execute product search.
+ *
* @return \Magento\Framework\Controller\ResultInterface
*/
public function execute() : \Magento\Framework\Controller\ResultInterface
diff --git a/app/code/Magento/Catalog/Helper/Image.php b/app/code/Magento/Catalog/Helper/Image.php
index 170f1209ad9e6..9b8d0ad75a8c9 100644
--- a/app/code/Magento/Catalog/Helper/Image.php
+++ b/app/code/Magento/Catalog/Helper/Image.php
@@ -6,6 +6,7 @@
namespace Magento\Catalog\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
+use Magento\Framework\View\Element\Block\ArgumentInterface;
/**
* Catalog image helper
@@ -14,7 +15,7 @@
* @SuppressWarnings(PHPMD.TooManyFields)
* @since 100.0.2
*/
-class Image extends AbstractHelper
+class Image extends AbstractHelper implements ArgumentInterface
{
/**
* Media config node
@@ -764,7 +765,7 @@ protected function getImageFile()
protected function parseSize($string)
{
$size = explode('x', strtolower($string));
- if (sizeof($size) == 2) {
+ if (count($size) == 2) {
return ['width' => $size[0] > 0 ? $size[0] : null, 'height' => $size[1] > 0 ? $size[1] : null];
}
return false;
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
index a3d958ea537e1..e6c098ab0254e 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/TableBuilder.php
@@ -115,7 +115,7 @@ public function build($storeId, $changedIds, $valueFieldSuffix)
/**
* Create empty temporary table with given columns list
*
- * @param string $tableName Table name
+ * @param string $tableName Table name
* @param array $columns array('columnName' => \Magento\Catalog\Model\ResourceModel\Eav\Attribute, ...)
* @param string $valueFieldSuffix
*
@@ -304,12 +304,16 @@ protected function _fillTemporaryTable(
/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
foreach ($columnsList as $columnName => $attribute) {
- $countTableName = 't' . $iterationNum++;
+ $countTableName = 't' . ($iterationNum++);
$joinCondition = sprintf(
- 'e.%3$s = %1$s.%3$s AND %1$s.attribute_id = %2$d AND %1$s.store_id = 0',
+ 'e.%3$s = %1$s.%3$s' .
+ ' AND %1$s.attribute_id = %2$d' .
+ ' AND (%1$s.store_id = %4$d' .
+ ' OR %1$s.store_id = 0)',
$countTableName,
$attribute->getId(),
- $metadata->getLinkField()
+ $metadata->getLinkField(),
+ $storeId
);
$select->joinLeft(
@@ -323,9 +327,10 @@ protected function _fillTemporaryTable(
$columnValueName = $attributeCode . $valueFieldSuffix;
if (isset($flatColumns[$columnValueName])) {
$valueJoinCondition = sprintf(
- 'e.%1$s = %2$s.option_id AND %2$s.store_id = 0',
+ 'e.%1$s = %2$s.option_id AND (%2$s.store_id = %3$d OR %2$s.store_id = 0)',
$attributeCode,
- $countTableName
+ $countTableName,
+ $storeId
);
$selectValue->joinLeft(
[
diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
index 42b9639d2717b..e06e85e90a2d8 100644
--- a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
+++ b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php
@@ -206,7 +206,7 @@ public function execute($product, $arguments = [])
}
/**
- * Returns media gallery atribute instance
+ * Returns media gallery attribute instance
*
* @return \Magento\Catalog\Api\Data\ProductAttributeInterface
* @since 101.0.0
@@ -230,6 +230,7 @@ public function getAttribute()
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @since 101.0.0
+ * phpcs:disable Magento2.CodeAnalysis.EmptyBlock
*/
protected function processDeletedImages($product, array &$images)
{
@@ -400,6 +401,7 @@ protected function getUniqueFileName($file, $forTmp = false)
$destinationFile = $forTmp
? $this->mediaDirectory->getAbsolutePath($this->mediaConfig->getTmpMediaPath($file))
: $this->mediaDirectory->getAbsolutePath($this->mediaConfig->getMediaPath($file));
+ // phpcs:disable Magento2.Functions.DiscouragedFunction
$destFile = dirname($file) . '/' . FileUploader::getNewFileName($destinationFile);
}
@@ -420,6 +422,7 @@ protected function copyImage($file)
$destinationFile = $this->getUniqueFileName($file);
if (!$this->mediaDirectory->isFile($this->mediaConfig->getMediaPath($file))) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
throw new \Exception();
}
@@ -437,6 +440,7 @@ protected function copyImage($file)
}
return str_replace('\\', '/', $destinationFile);
+ // phpcs:ignore Magento2.Exceptions.ThrowCatch
} catch (\Exception $e) {
$file = $this->mediaConfig->getMediaPath($file);
throw new \Magento\Framework\Exception\LocalizedException(
diff --git a/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php b/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php
index 0941aa2478935..9cb6cda4d0a09 100644
--- a/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php
+++ b/app/code/Magento/Catalog/Model/Product/Option/SaveHandler.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Model\Product\Option;
use Magento\Catalog\Api\ProductCustomOptionRepositoryInterface as OptionRepository;
@@ -58,11 +60,26 @@ public function execute($entity, $arguments = [])
}
}
if ($options) {
- foreach ($options as $option) {
- $this->optionRepository->save($option);
- }
+ $this->processOptionsSaving($options, (bool)$entity->dataHasChangedFor('sku'), (string)$entity->getSku());
}
return $entity;
}
+
+ /**
+ * Save custom options
+ *
+ * @param array $options
+ * @param bool $hasChangedSku
+ * @param string $newSku
+ */
+ private function processOptionsSaving(array $options, bool $hasChangedSku, string $newSku)
+ {
+ foreach ($options as $option) {
+ if ($hasChangedSku && $option->hasData('product_sku')) {
+ $option->setProductSku($newSku);
+ }
+ $this->optionRepository->save($option);
+ }
+ }
}
diff --git a/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php b/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php
index f6893a41113e6..dabfdb74f0118 100644
--- a/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php
+++ b/app/code/Magento/Catalog/Model/Product/Type/FrontSpecialPrice.php
@@ -17,6 +17,9 @@
*
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ *
+ * @deprecated
+ * @see \Magento\Catalog\Model\Product\Type\Price
*/
class FrontSpecialPrice extends Price
{
@@ -66,6 +69,8 @@ public function __construct(
/**
* @inheritdoc
+ *
+ * @deprecated
*/
protected function _applySpecialPrice($product, $finalPrice)
{
diff --git a/app/code/Magento/Catalog/Observer/SetSpecialPriceStartDate.php b/app/code/Magento/Catalog/Observer/SetSpecialPriceStartDate.php
index a597b8fddda9f..ed9f89efc6891 100644
--- a/app/code/Magento/Catalog/Observer/SetSpecialPriceStartDate.php
+++ b/app/code/Magento/Catalog/Observer/SetSpecialPriceStartDate.php
@@ -3,9 +3,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Observer;
use Magento\Framework\Event\ObserverInterface;
+use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
/**
* Set value for Special Price start date
@@ -13,21 +16,20 @@
class SetSpecialPriceStartDate implements ObserverInterface
{
/**
- * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
+ * @var TimezoneInterface
*/
private $localeDate;
/**
- * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
- * @codeCoverageIgnore
+ * @param TimezoneInterface $localeDate
*/
- public function __construct(\Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate)
+ public function __construct(TimezoneInterface $localeDate)
{
$this->localeDate = $localeDate;
}
/**
- * Set the current date to Special Price From attribute if it empty
+ * Set the current date to Special Price From attribute if it's empty.
*
* @param \Magento\Framework\Event\Observer $observer
* @return $this
@@ -36,8 +38,8 @@ public function execute(\Magento\Framework\Event\Observer $observer)
{
/** @var $product \Magento\Catalog\Model\Product */
$product = $observer->getEvent()->getProduct();
- if ($product->getSpecialPrice() && !$product->getSpecialFromDate()) {
- $product->setData('special_from_date', $this->localeDate->date());
+ if ($product->getSpecialPrice() && ! $product->getSpecialFromDate()) {
+ $product->setData('special_from_date', $this->localeDate->date()->setTime(0, 0));
}
return $this;
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml
new file mode 100644
index 0000000000000..dd66919640a73
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminOpenNewProductFormPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminOpenNewProductFormPageActionGroup.xml
new file mode 100644
index 0000000000000..fe859fab52667
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminOpenNewProductFormPageActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
index da570f9ed99b0..3c44a8f1898ad 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml
@@ -19,6 +19,14 @@
+
+
+
+
+
+
+
+
@@ -96,6 +104,9 @@
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
index 46329dde278bc..86158aba68f82 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml
@@ -65,6 +65,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
index 2914ecc470220..019d103a31cf2 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml
@@ -45,6 +45,9 @@
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
index cbdabe6a2d218..ad32b8edbd243 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml
@@ -289,4 +289,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml
index 2d966dde64c4a..b914d5e20712d 100644
--- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/CustomOptionsActionGroup.xml
@@ -52,4 +52,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductInWidgetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductInWidgetActionGroup.xml
new file mode 100644
index 0000000000000..c25b73bab21ae
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductInWidgetActionGroup.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontClickAddToCartOnProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontClickAddToCartOnProductPageActionGroup.xml
new file mode 100644
index 0000000000000..fb2065d228d5a
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontClickAddToCartOnProductPageActionGroup.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..24e1fe9cf5ecd
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+ Catalog
+ Catalog
+ magento-catalog-catalog
+
+
+ Default Category (ID: 2)
+ Categories
+ magento-catalog-catalog-categories
+
+
+ Products
+ Products
+ magento-catalog-catalog-products
+
+
+ Attribute Sets
+ Attribute Set
+ magento-catalog-catalog-attributes-sets
+
+
+ Product Attributes
+ Product
+ magento-catalog-catalog-attributes-attributes
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/AttributeSetData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/AttributeSetData.xml
new file mode 100644
index 0000000000000..6e1b25fb9cdc4
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/AttributeSetData.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ 4
+ Default
+ 0
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CatalogRecentlyProductsConfigData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogRecentlyProductsConfigData.xml
new file mode 100644
index 0000000000000..d1e469deaebba
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/CatalogRecentlyProductsConfigData.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+ EnableCatalogRecentlyProductsSynchronize
+
+
+
+ 1
+
+
+
+ DefaultCatalogRecentlyProductsSynchronize
+
+
+
+ 0
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml
index 8a26b6babdbbc..d09880f14afbf 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ConstData.xml
@@ -13,4 +13,8 @@
1
2
+
+ "Pursuit Lumaflex™ Tone Band"
+ "x™"
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
index 134abcaa50354..817dd637f81dd 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
@@ -73,6 +73,20 @@
false
ProductAttributeFrontendLabel
+
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+
attribute
select
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
index 713c453bb7ad4..6d4314a6d865f 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeSetData.xml
@@ -20,4 +20,10 @@
7
1
+
+
+ 0
+ 0
+ 0
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
index 383797933074e..3492dffd7cc7d 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
@@ -35,6 +35,10 @@
EavStockItem
CustomAttributeCategoryIds
+
+ Pursuit Lumaflex™ Tone Band
+ x™
+
100
@@ -936,6 +940,19 @@
13
0
+
+ AAA Product
+
+
+ BBB Product
+
+
+ Product "!@#$%^&*()+:;\|}{][?=~`
+ |}{][?=~`
+
+
+ ProductWith128Chars 1234567891123456789112345678911234567891123456789112345678911234567891123456789112345678 endnums
+
sku_simple_product_
simple
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
index ea0bcafe56c48..71c8af318e9b4 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductGridData.xml
@@ -12,4 +12,7 @@
10
100
+
+ 1
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml
index 83f0a56c21545..18564ff101fd9 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/WidgetsData.xml
@@ -12,4 +12,24 @@
Catalog Product Link
Product Link Block Template
+
+ Recently Compared Products
+ Magento Luma
+ Recently Compared Products
+
+ - All Store Views
+
+ All Pages
+ Sidebar Additional
+
+
+ Recently Viewed Products
+ Magento Luma
+ Recently Viewed Products
+
+ - All Store Views
+
+ All Pages
+ Sidebar Additional
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_recently_products-meta.xml b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_recently_products-meta.xml
new file mode 100644
index 0000000000000..0fe4f154d5ef5
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Metadata/catalog_recently_products-meta.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ integer
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml
index e23a503266e33..dd5d5aef08a7c 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminNewWidgetPage.xml
@@ -10,5 +10,6 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCatalogProductWidgetSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCatalogProductWidgetSection.xml
new file mode 100644
index 0000000000000..3261db1f63f24
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCatalogProductWidgetSection.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml
index 14e714cb2b6b7..fba28b3feaff1 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategorySidebarTreeSection.xml
@@ -16,5 +16,6 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml
index fc78c25ec49fa..352d219351fb8 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml
@@ -45,5 +45,15 @@
+
-
\ No newline at end of file
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml
index 697648cedb7ba..3ef78a3fe8f41 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml
@@ -14,6 +14,7 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml
index e159a4ce5c0b6..a2a349ed67611 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAttributeSection.xml
@@ -17,8 +17,23 @@
-
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml
index da282d06145aa..f515171e835db 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml
@@ -203,7 +203,9 @@
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml
index 02bdbac313076..07dd26381fe08 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml
@@ -17,6 +17,7 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontNavigationSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontNavigationSection.xml
index c6bad0efb3ca7..292b2d7008bc1 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontNavigationSection.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontNavigationSection.xml
@@ -12,5 +12,6 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontWidgetsSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontWidgetsSection.xml
new file mode 100644
index 0000000000000..87aab45bd8cb7
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontWidgetsSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml
new file mode 100644
index 0000000000000..4f66395bd0fbf
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogCategoriesNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogCategoriesNavigateMenuTest.xml
new file mode 100644
index 0000000000000..a51df86d0327a
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogCategoriesNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogProductsNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogProductsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..1d9400bf81e4d
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCatalogProductsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSet.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSet.xml
index 3027416ee520b..bcfab6ccfdf1f 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSet.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSet.xml
@@ -34,7 +34,7 @@
-
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilterByNameByStoreViewOnProductGridTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilterByNameByStoreViewOnProductGridTest.xml
new file mode 100644
index 0000000000000..f3ec225540c75
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilterByNameByStoreViewOnProductGridTest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberAfterSaveAndCloseActionTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberAfterSaveAndCloseActionTest.xml
new file mode 100644
index 0000000000000..b24ed7f9c9a81
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberAfterSaveAndCloseActionTest.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminImportCustomizableOptionToProductWithSKUTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminImportCustomizableOptionToProductWithSKUTest.xml
new file mode 100644
index 0000000000000..79ff7bcade77b
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminImportCustomizableOptionToProductWithSKUTest.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml
index 060720ab007eb..8316f54c15a52 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml
@@ -65,6 +65,8 @@
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresAttributeSetNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresAttributeSetNavigateMenuTest.xml
new file mode 100644
index 0000000000000..ed29c281b804c
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresAttributeSetNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresProductNavigateMenuTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresProductNavigateMenuTest.xml
new file mode 100644
index 0000000000000..28a33c4f20c01
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminStoresProductNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminTierPriceNotAvailableForProductOptionsWithoutTierPriceTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminTierPriceNotAvailableForProductOptionsWithoutTierPriceTest.xml
index 3086f4398e08d..51af9d78dfd46 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminTierPriceNotAvailableForProductOptionsWithoutTierPriceTest.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminTierPriceNotAvailableForProductOptionsWithoutTierPriceTest.xml
@@ -11,8 +11,8 @@
-
-
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest.xml
index 52022f32fd8ec..d895993217e32 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest.xml
@@ -262,10 +262,10 @@
-
-
-
-
+
+
+
+
@@ -333,8 +333,8 @@
-
-
+
+
@@ -417,9 +417,9 @@
-
-
-
-
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml
index df4803bcd7906..fb95fc3f57bca 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml
@@ -52,10 +52,6 @@
-
-
-
-
@@ -67,6 +63,14 @@
+
+
+
+
+
+
+
+
@@ -78,8 +82,9 @@
-
-
+
+
+
@@ -101,15 +106,12 @@
-
-
-
-
-
+
+
+
-
@@ -129,11 +131,9 @@
-
-
-
-
-
+
+
+
@@ -176,24 +176,29 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
@@ -205,14 +210,12 @@
-
-
-
-
-
-
-
+
+
+
+
+
@@ -250,13 +253,22 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -296,8 +308,7 @@
-
-
+
diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/View/GalleryOptionsTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/View/GalleryOptionsTest.php
new file mode 100644
index 0000000000000..7ed8b13fce750
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/View/GalleryOptionsTest.php
@@ -0,0 +1,223 @@
+escaper = $objectManager->getObject(Escaper::class);
+ $this->configView = $this->createMock(View::class);
+
+ $this->viewConfig = $this->createConfiguredMock(
+ Config::class,
+ [
+ 'getViewConfig' => $this->configView
+ ]
+ );
+
+ $this->context = $this->createConfiguredMock(
+ Context::class,
+ [
+ 'getEscaper' => $this->escaper,
+ 'getViewConfig' => $this->viewConfig
+ ]
+ );
+
+ $this->gallery = $this->createMock(Gallery::class);
+
+ $this->jsonSerializer = $objectManager->getObject(
+ Json::class
+ );
+
+ $this->model = $objectManager->getObject(GalleryOptions::class, [
+ 'context' => $this->context,
+ 'jsonSerializer' => $this->jsonSerializer,
+ 'gallery' => $this->gallery
+ ]);
+ }
+
+ public function testGetOptionsJson()
+ {
+ $configMap = [
+ ['Magento_Catalog', 'gallery/nav', 'thumbs'],
+ ['Magento_Catalog', 'gallery/loop', false],
+ ['Magento_Catalog', 'gallery/keyboard', true],
+ ['Magento_Catalog', 'gallery/arrows', true],
+ ['Magento_Catalog', 'gallery/caption', false],
+ ['Magento_Catalog', 'gallery/allowfullscreen', true],
+ ['Magento_Catalog', 'gallery/navdir', 'horizontal'],
+ ['Magento_Catalog', 'gallery/navarrows', true],
+ ['Magento_Catalog', 'gallery/navtype', 'slides'],
+ ['Magento_Catalog', 'gallery/thumbmargin', '5'],
+ ['Magento_Catalog', 'gallery/transition/effect', 'slide'],
+ ['Magento_Catalog', 'gallery/transition/duration', '500'],
+ ];
+
+ $imageAttributesMap = [
+ ['product_page_image_medium','height',null, 100],
+ ['product_page_image_medium','width',null, 200],
+ ['product_page_image_small','height',null, 300],
+ ['product_page_image_small','width',null, 400]
+ ];
+
+ $this->configView->expects($this->any())
+ ->method('getVarValue')
+ ->will($this->returnValueMap($configMap));
+ $this->gallery->expects($this->any())
+ ->method('getImageAttribute')
+ ->will($this->returnValueMap($imageAttributesMap));
+
+ $json = $this->model->getOptionsJson();
+
+ $decodedJson = $this->jsonSerializer->unserialize($json);
+
+ $this->assertSame('thumbs', $decodedJson['nav']);
+ $this->assertSame(false, $decodedJson['loop']);
+ $this->assertSame(true, $decodedJson['keyboard']);
+ $this->assertSame(true, $decodedJson['arrows']);
+ $this->assertSame(false, $decodedJson['showCaption']);
+ $this->assertSame(true, $decodedJson['allowfullscreen']);
+ $this->assertSame('horizontal', $decodedJson['navdir']);
+ $this->assertSame(true, $decodedJson['navarrows']);
+ $this->assertSame('slides', $decodedJson['navtype']);
+ $this->assertSame(5, $decodedJson['thumbmargin']);
+ $this->assertSame('slide', $decodedJson['transition']);
+ $this->assertSame(500, $decodedJson['transitionduration']);
+ $this->assertSame(100, $decodedJson['height']);
+ $this->assertSame(200, $decodedJson['width']);
+ $this->assertSame(300, $decodedJson['thumbheight']);
+ $this->assertSame(400, $decodedJson['thumbwidth']);
+ }
+
+ public function testGetFSOptionsJson()
+ {
+ $configMap = [
+ ['Magento_Catalog', 'gallery/fullscreen/nav', false],
+ ['Magento_Catalog', 'gallery/fullscreen/loop', true],
+ ['Magento_Catalog', 'gallery/fullscreen/keyboard', true],
+ ['Magento_Catalog', 'gallery/fullscreen/arrows', false],
+ ['Magento_Catalog', 'gallery/fullscreen/caption', true],
+ ['Magento_Catalog', 'gallery/fullscreen/navdir', 'vertical'],
+ ['Magento_Catalog', 'gallery/fullscreen/navarrows', false],
+ ['Magento_Catalog', 'gallery/fullscreen/navtype', 'thumbs'],
+ ['Magento_Catalog', 'gallery/fullscreen/thumbmargin', '10'],
+ ['Magento_Catalog', 'gallery/fullscreen/transition/effect', 'dissolve'],
+ ['Magento_Catalog', 'gallery/fullscreen/transition/duration', '300']
+ ];
+
+ $this->configView->expects($this->any())
+ ->method('getVarValue')
+ ->will($this->returnValueMap($configMap));
+
+ $json = $this->model->getFSOptionsJson();
+
+ $decodedJson = $this->jsonSerializer->unserialize($json);
+
+ //Note, this tests the special case for nav variable set to false. It
+ //Should not be converted to boolean.
+ $this->assertSame('false', $decodedJson['nav']);
+ $this->assertSame(true, $decodedJson['loop']);
+ $this->assertSame(false, $decodedJson['arrows']);
+ $this->assertSame(true, $decodedJson['keyboard']);
+ $this->assertSame(true, $decodedJson['showCaption']);
+ $this->assertSame('vertical', $decodedJson['navdir']);
+ $this->assertSame(false, $decodedJson['navarrows']);
+ $this->assertSame(10, $decodedJson['thumbmargin']);
+ $this->assertSame('thumbs', $decodedJson['navtype']);
+ $this->assertSame('dissolve', $decodedJson['transition']);
+ $this->assertSame(300, $decodedJson['transitionduration']);
+ }
+
+ public function testGetOptionsJsonOptionals()
+ {
+ $configMap = [
+ ['Magento_Catalog', 'gallery/fullscreen/thumbmargin', false],
+ ['Magento_Catalog', 'gallery/fullscreen/transition/duration', false]
+ ];
+
+ $this->configView->expects($this->any())
+ ->method('getVarValue')
+ ->will($this->returnValueMap($configMap));
+
+ $json = $this->model->getOptionsJson();
+
+ $decodedJson = $this->jsonSerializer->unserialize($json);
+
+ $this->assertArrayNotHasKey('thumbmargin', $decodedJson);
+ $this->assertArrayNotHasKey('transitionduration', $decodedJson);
+ }
+
+ public function testGetFSOptionsJsonOptionals()
+ {
+ $configMap = [
+ ['Magento_Catalog', 'gallery/fullscreen/keyboard', false],
+ ['Magento_Catalog', 'gallery/fullscreen/thumbmargin', false],
+ ['Magento_Catalog', 'gallery/fullscreen/transition/duration', false]
+ ];
+
+ $this->configView->expects($this->any())
+ ->method('getVarValue')
+ ->will($this->returnValueMap($configMap));
+
+ $json = $this->model->getFSOptionsJson();
+
+ $decodedJson = $this->jsonSerializer->unserialize($json);
+
+ $this->assertArrayNotHasKey('thumbmargin', $decodedJson);
+ $this->assertArrayNotHasKey('keyboard', $decodedJson);
+ $this->assertArrayNotHasKey('transitionduration', $decodedJson);
+ }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
index cd6565f32ed18..a2d81854607a0 100644
--- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php
@@ -154,38 +154,4 @@ public function modifyMetaLockedDataProvider()
{
return [[true], [false]];
}
-
- public function testModifyMetaWithCaching()
- {
- $this->arrayManagerMock->expects($this->exactly(2))
- ->method('findPath')
- ->willReturn(true);
- $cacheManager = $this->getMockBuilder(CacheInterface::class)
- ->getMockForAbstractClass();
- $cacheManager->expects($this->once())
- ->method('load')
- ->with(Categories::CATEGORY_TREE_ID . '_');
- $cacheManager->expects($this->once())
- ->method('save');
-
- $modifier = $this->createModel();
- $cacheContextProperty = new \ReflectionProperty(
- Categories::class,
- 'cacheManager'
- );
- $cacheContextProperty->setAccessible(true);
- $cacheContextProperty->setValue($modifier, $cacheManager);
-
- $groupCode = 'test_group_code';
- $meta = [
- $groupCode => [
- 'children' => [
- 'category_ids' => [
- 'sortOrder' => 10,
- ],
- ],
- ],
- ];
- $modifier->modifyMeta($meta);
- }
}
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
index 681435851fbde..800ead0e4030c 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Categories.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Catalog\Ui\DataProvider\Product\Form\Modifier;
use Magento\Catalog\Model\Locator\LocatorInterface;
@@ -11,6 +13,7 @@
use Magento\Framework\App\CacheInterface;
use Magento\Framework\DB\Helper as DbHelper;
use Magento\Catalog\Model\Category as CategoryModel;
+use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\UrlInterface;
use Magento\Framework\Stdlib\ArrayManager;
@@ -202,6 +205,7 @@ protected function createNewCategoryModal(array $meta)
*
* @param array $meta
* @return array
+ * @throws LocalizedException
* @since 101.0.0
*/
protected function customizeCategoriesField(array $meta)
@@ -306,20 +310,64 @@ protected function customizeCategoriesField(array $meta)
*
* @param string|null $filter
* @return array
+ * @throws LocalizedException
* @since 101.0.0
*/
protected function getCategoriesTree($filter = null)
{
- $categoryTree = $this->getCacheManager()->load(self::CATEGORY_TREE_ID . '_' . $filter);
- if ($categoryTree) {
- return $this->serializer->unserialize($categoryTree);
+ $storeId = (int) $this->locator->getStore()->getId();
+
+ $cachedCategoriesTree = $this->getCacheManager()
+ ->load($this->getCategoriesTreeCacheId($storeId, (string) $filter));
+ if (!empty($cachedCategoriesTree)) {
+ return $this->serializer->unserialize($cachedCategoriesTree);
}
- $storeId = $this->locator->getStore()->getId();
+ $categoriesTree = $this->retrieveCategoriesTree(
+ $storeId,
+ $this->retrieveShownCategoriesIds($storeId, (string) $filter)
+ );
+
+ $this->getCacheManager()->save(
+ $this->serializer->serialize($categoriesTree),
+ $this->getCategoriesTreeCacheId($storeId, (string) $filter),
+ [
+ \Magento\Catalog\Model\Category::CACHE_TAG,
+ \Magento\Framework\App\Cache\Type\Block::CACHE_TAG
+ ]
+ );
+
+ return $categoriesTree;
+ }
+
+ /**
+ * Get cache id for categories tree.
+ *
+ * @param int $storeId
+ * @param string $filter
+ * @return string
+ */
+ private function getCategoriesTreeCacheId(int $storeId, string $filter = '') : string
+ {
+ return self::CATEGORY_TREE_ID
+ . '_' . (string) $storeId
+ . '_' . $filter;
+ }
+
+ /**
+ * Retrieve filtered list of categories id.
+ *
+ * @param int $storeId
+ * @param string $filter
+ * @return array
+ * @throws LocalizedException
+ */
+ private function retrieveShownCategoriesIds(int $storeId, string $filter = '') : array
+ {
/* @var $matchingNamesCollection \Magento\Catalog\Model\ResourceModel\Category\Collection */
$matchingNamesCollection = $this->categoryCollectionFactory->create();
- if ($filter !== null) {
+ if (!empty($filter)) {
$matchingNamesCollection->addAttributeToFilter(
'name',
['like' => $this->dbHelper->addLikeEscape($filter, ['position' => 'any'])]
@@ -339,6 +387,19 @@ protected function getCategoriesTree($filter = null)
}
}
+ return $shownCategoriesIds;
+ }
+
+ /**
+ * Retrieve tree of categories with attributes.
+ *
+ * @param int $storeId
+ * @param array $shownCategoriesIds
+ * @return array|null
+ * @throws LocalizedException
+ */
+ private function retrieveCategoriesTree(int $storeId, array $shownCategoriesIds) : ?array
+ {
/* @var $collection \Magento\Catalog\Model\ResourceModel\Category\Collection */
$collection = $this->categoryCollectionFactory->create();
@@ -365,15 +426,6 @@ protected function getCategoriesTree($filter = null)
$categoryById[$category->getParentId()]['optgroup'][] = &$categoryById[$category->getId()];
}
- $this->getCacheManager()->save(
- $this->serializer->serialize($categoryById[CategoryModel::TREE_ROOT_ID]['optgroup']),
- self::CATEGORY_TREE_ID . '_' . $filter,
- [
- \Magento\Catalog\Model\Category::CACHE_TAG,
- \Magento\Framework\App\Cache\Type\Block::CACHE_TAG
- ]
- );
-
return $categoryById[CategoryModel::TREE_ROOT_ID]['optgroup'];
}
}
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
old mode 100755
new mode 100644
index 99f7122efa0a8..8326c3b531892
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php
@@ -676,7 +676,7 @@ public function setupAttributeMeta(ProductAttributeInterface $attribute, $groupC
// TODO: Refactor to $attribute->getOptions() when MAGETWO-48289 is done
$attributeModel = $this->getAttributeModel($attribute);
if ($attributeModel->usesSource()) {
- $options = $attributeModel->getSource()->getAllOptions();
+ $options = $attributeModel->getSource()->getAllOptions(true, true);
$meta = $this->arrayManager->merge($configPath, $meta, [
'options' => $this->convertOptionsValueToString($options),
]);
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php
index f4334bc25efd8..e5451c8e49847 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php
@@ -5,10 +5,16 @@
*/
namespace Magento\Catalog\Ui\DataProvider\Product;
+use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Eav\Model\Entity\Attribute\AttributeInterface;
+
/**
* Collection which is used for rendering product list in the backend.
*
* Used for product grid and customizes behavior of the default Product collection for grid needs.
+ *
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class ProductCollection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
{
@@ -25,4 +31,63 @@ protected function _productLimitationJoinPrice()
$this->_productLimitationFilters->setUsePriceIndex(false);
return $this->_productLimitationPrice(true);
}
+
+ /**
+ * Add attribute filter to collection
+ *
+ * @param AttributeInterface|integer|string|array $attribute
+ * @param null|string|array $condition
+ * @param string $joinType
+ * @return $this
+ * @throws LocalizedException
+ */
+ public function addAttributeToFilter($attribute, $condition = null, $joinType = 'inner')
+ {
+ $storeId = (int)$this->getStoreId();
+ if ($attribute === 'is_saleable'
+ || is_array($attribute)
+ || $storeId !== $this->getDefaultStoreId()
+ ) {
+ return parent::addAttributeToFilter($attribute, $condition, $joinType);
+ }
+
+ if ($attribute instanceof AttributeInterface) {
+ $attributeModel = $attribute;
+ } else {
+ $attributeModel = $this->getEntity()->getAttribute($attribute);
+ if ($attributeModel === false) {
+ throw new LocalizedException(
+ __('Invalid attribute identifier for filter (%1)', get_class($attribute))
+ );
+ }
+ }
+
+ if ($attributeModel->isScopeGlobal() || $attributeModel->getBackend()->isStatic()) {
+ return parent::addAttributeToFilter($attribute, $condition, $joinType);
+ }
+
+ $this->addAttributeToFilterAllStores($attributeModel, $condition);
+
+ return $this;
+ }
+
+ /**
+ * Add attribute to filter by all stores
+ *
+ * @param Attribute $attributeModel
+ * @param array $condition
+ * @return void
+ */
+ private function addAttributeToFilterAllStores(Attribute $attributeModel, array $condition): void
+ {
+ $tableName = $this->getTable($attributeModel->getBackendTable());
+ $entity = $this->getEntity();
+ $fKey = 'e.' . $this->getEntityPkName($entity);
+ $pKey = $tableName . '.' . $this->getEntityPkName($entity);
+ $condition = "({$pKey} = {$fKey}) AND ("
+ . $this->_getConditionSql("{$tableName}.value", $condition)
+ . ')';
+ $selectExistsInAllStores = $this->getConnection()->select()->from($tableName);
+ $this->getSelect()->exists($selectExistsInAllStores, $condition);
+ }
}
diff --git a/app/code/Magento/Catalog/ViewModel/Product/Checker/AddToCompareAvailability.php b/app/code/Magento/Catalog/ViewModel/Product/Checker/AddToCompareAvailability.php
new file mode 100644
index 0000000000000..27829155af292
--- /dev/null
+++ b/app/code/Magento/Catalog/ViewModel/Product/Checker/AddToCompareAvailability.php
@@ -0,0 +1,58 @@
+stockConfiguration = $stockConfiguration;
+ }
+
+ /**
+ * Is product available for comparison.
+ *
+ * @param ProductInterface $product
+ * @return bool
+ */
+ public function isAvailableForCompare(ProductInterface $product): bool
+ {
+ return $this->isInStock($product) || $this->stockConfiguration->isShowOutOfStock();
+ }
+
+ /**
+ * Get is in stock status.
+ *
+ * @param ProductInterface $product
+ * @return bool
+ */
+ private function isInStock(ProductInterface $product): bool
+ {
+ $quantityAndStockStatus = $product->getQuantityAndStockStatus();
+ if (!$quantityAndStockStatus) {
+ return $product->isSalable();
+ }
+
+ return isset($quantityAndStockStatus['is_in_stock']) && $quantityAndStockStatus['is_in_stock'];
+ }
+}
diff --git a/app/code/Magento/Catalog/etc/frontend/di.xml b/app/code/Magento/Catalog/etc/frontend/di.xml
index 793a2291f599c..ee9c5b29da894 100644
--- a/app/code/Magento/Catalog/etc/frontend/di.xml
+++ b/app/code/Magento/Catalog/etc/frontend/di.xml
@@ -120,5 +120,4 @@
-
diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml
index 578281f44c4cf..d689daef4bcab 100644
--- a/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml
+++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml
@@ -132,6 +132,7 @@
true
text
+ ui/grid/cells/html
Name
@@ -154,6 +155,7 @@
text
+ ui/grid/cells/html
SKU
diff --git a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
index 8d3248896b434..13e2d998f6cdd 100644
--- a/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
+++ b/app/code/Magento/Catalog/view/frontend/layout/catalog_product_view.xml
@@ -91,7 +91,11 @@
+ template="Magento_Catalog::product/view/addto/compare.phtml" >
+
+ Magento\Catalog\ViewModel\Product\Checker\AddToCompareAvailability
+
+
@@ -121,7 +125,12 @@
-
+
+
+ Magento\Catalog\Block\Product\View\GalleryOptions
+ Magento\Catalog\Helper\Image
+
+
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 f434402346087..ecc9700802d27 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
@@ -169,7 +169,7 @@ switch ($type = $block->getType()) {
= /* @escapeNotVerified */ __('Check items to add to the cart or') ?>
- = /* @escapeNotVerified */ __('select all') ?>
+ = /* @escapeNotVerified */ __('select all') ?>
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml
index adf0f44d0c831..194a472d81d58 100644
--- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml
+++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addto/compare.phtml
@@ -9,6 +9,10 @@
/** @var $block \Magento\Catalog\Block\Product\View\Addto\Compare */
?>
+getData('addToCompareViewModel'); ?>
+isAvailableForCompare($block->getProduct())): ?>
= /* @escapeNotVerified */ __('Add to Compare') ?>
+
+
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml
index 1bfa30478df8a..1f06b90758d0b 100644
--- a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml
+++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml
@@ -12,32 +12,32 @@
* @var $block \Magento\Catalog\Block\Product\View\Gallery
*/
?>
-
-
-
-
-
-
-
-
-
+ $helper = $block->getData('imageHelper');
+ $mainImageData = $mainImage ?
+ $mainImage->getData('medium_image_url') :
+ $helper->getDefaultPlaceholderUrl('image');
+
+?>
+
+
+
+
+
diff --git a/app/code/Magento/PageCache/etc/varnish4.vcl b/app/code/Magento/PageCache/etc/varnish4.vcl
index 8068447e5ca99..801e6cb475d8a 100644
--- a/app/code/Magento/PageCache/etc/varnish4.vcl
+++ b/app/code/Magento/PageCache/etc/varnish4.vcl
@@ -91,10 +91,11 @@ sub vcl_recv {
}
}
- # Remove Google gclid parameters to minimize the cache objects
- set req.url = regsuball(req.url,"\?gclid=[^&]+$",""); # strips when QS = "?gclid=AAA"
- set req.url = regsuball(req.url,"\?gclid=[^&]+&","?"); # strips when QS = "?gclid=AAA&foo=bar"
- set req.url = regsuball(req.url,"&gclid=[^&]+",""); # strips when QS = "?foo=bar&gclid=AAA" or QS = "?foo=bar&gclid=AAA&bar=baz"
+ # Remove all marketing get parameters to minimize the cache objects
+ if (req.url ~ "(\?|&)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=") {
+ set req.url = regsuball(req.url, "(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
+ set req.url = regsub(req.url, "[?|&]+$", "");
+ }
# Static files caching
if (req.url ~ "^/(pub/)?(media|static)/") {
diff --git a/app/code/Magento/PageCache/etc/varnish5.vcl b/app/code/Magento/PageCache/etc/varnish5.vcl
index 6c8414a5cb641..76c5ffee5f14f 100644
--- a/app/code/Magento/PageCache/etc/varnish5.vcl
+++ b/app/code/Magento/PageCache/etc/varnish5.vcl
@@ -92,10 +92,11 @@ sub vcl_recv {
}
}
- # Remove Google gclid parameters to minimize the cache objects
- set req.url = regsuball(req.url,"\?gclid=[^&]+$",""); # strips when QS = "?gclid=AAA"
- set req.url = regsuball(req.url,"\?gclid=[^&]+&","?"); # strips when QS = "?gclid=AAA&foo=bar"
- set req.url = regsuball(req.url,"&gclid=[^&]+",""); # strips when QS = "?foo=bar&gclid=AAA" or QS = "?foo=bar&gclid=AAA&bar=baz"
+ # Remove all marketing get parameters to minimize the cache objects
+ if (req.url ~ "(\?|&)(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=") {
+ set req.url = regsuball(req.url, "(gclid|cx|ie|cof|siteurl|zanpid|origin|fbclid|mc_[a-z]+|utm_[a-z]+|_bta_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
+ set req.url = regsub(req.url, "[?|&]+$", "");
+ }
# Static files caching
if (req.url ~ "^/(pub/)?(media|static)/") {
diff --git a/app/code/Magento/Paypal/Model/Payflow/Service/Response/Transaction.php b/app/code/Magento/Paypal/Model/Payflow/Service/Response/Transaction.php
index 06a8a5b680bf4..7143576b71a07 100644
--- a/app/code/Magento/Paypal/Model/Payflow/Service/Response/Transaction.php
+++ b/app/code/Magento/Paypal/Model/Payflow/Service/Response/Transaction.php
@@ -3,9 +3,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Paypal\Model\Payflow\Service\Response;
use Magento\Framework\DataObject;
+use Magento\Framework\Intl\DateTimeFactory;
use Magento\Payment\Model\Method\Logger;
use Magento\Paypal\Model\Payflow\Service\Response\Handler\HandlerInterface;
use Magento\Framework\Session\Generic;
@@ -18,6 +21,7 @@
/**
* Class Transaction
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Transaction
{
@@ -51,6 +55,11 @@ class Transaction
*/
private $logger;
+ /**
+ * @var DateTimeFactory
+ */
+ private $dateTimeFactory;
+
/**
* @param Generic $sessionTransparent
* @param CartRepositoryInterface $quoteRepository
@@ -58,6 +67,7 @@ class Transaction
* @param PaymentMethodManagementInterface $paymentManagement
* @param HandlerInterface $errorHandler
* @param Logger $logger
+ * @param DateTimeFactory $dateTimeFactory
*/
public function __construct(
Generic $sessionTransparent,
@@ -65,7 +75,8 @@ public function __construct(
Transparent $transparent,
PaymentMethodManagementInterface $paymentManagement,
HandlerInterface $errorHandler,
- Logger $logger
+ Logger $logger,
+ DateTimeFactory $dateTimeFactory
) {
$this->sessionTransparent = $sessionTransparent;
$this->quoteRepository = $quoteRepository;
@@ -73,6 +84,7 @@ public function __construct(
$this->paymentManagement = $paymentManagement;
$this->errorHandler = $errorHandler;
$this->logger = $logger;
+ $this->dateTimeFactory = $dateTimeFactory;
}
/**
@@ -114,8 +126,45 @@ public function savePaymentInQuote($response)
$payment->setData(OrderPaymentInterface::CC_TYPE, $response->getData(OrderPaymentInterface::CC_TYPE));
$payment->setAdditionalInformation(Payflowpro::PNREF, $response->getData(Payflowpro::PNREF));
+ $expDate = $response->getData('expdate');
+ $expMonth = $this->getCcExpMonth($expDate);
+ $payment->setCcExpMonth($expMonth);
+ $expYear = $this->getCcExpYear($expDate);
+ $payment->setCcExpYear($expYear);
+
$this->errorHandler->handle($payment, $response);
$this->paymentManagement->set($quote->getId(), $payment);
}
+
+ /**
+ * Extracts expiration month from PayPal response expiration date.
+ *
+ * @param string $expDate format {MMYY}
+ * @return int
+ */
+ private function getCcExpMonth(string $expDate): int
+ {
+ return (int)substr($expDate, 0, 2);
+ }
+
+ /**
+ * Extracts expiration year from PayPal response expiration date.
+ *
+ * @param string $expDate format {MMYY}
+ * @return int
+ */
+ private function getCcExpYear(string $expDate): int
+ {
+ $last2YearDigits = (int)substr($expDate, 2, 2);
+ $currentDate = $this->dateTimeFactory->create('now', new \DateTimeZone('UTC'));
+ $first2YearDigits = (int)substr($currentDate->format('Y'), 0, 2);
+
+ // case when credit card expires at next century
+ if ((int)$currentDate->format('y') > $last2YearDigits) {
+ $first2YearDigits++;
+ }
+
+ return 100 * $first2YearDigits + $last2YearDigits;
+ }
}
diff --git a/app/code/Magento/Paypal/README.md b/app/code/Magento/Paypal/README.md
index 8f4453ae0a058..0ed4f2e90291b 100644
--- a/app/code/Magento/Paypal/README.md
+++ b/app/code/Magento/Paypal/README.md
@@ -1,6 +1,6 @@
Module Magento\PayPal implements integration with the PayPal payment system. Namely, it enables the following payment methods:
-*PayPal Express Checkout
-*PayPal Payments Standard
-*PayPal Payments Pro
-*PayPal Credit
-*PayFlow Payment Gateway
+* PayPal Express Checkout
+* PayPal Payments Standard
+* PayPal Payments Pro
+* PayPal Credit
+* PayFlow Payment Gateway
diff --git a/app/code/Magento/Paypal/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Paypal/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..207bf62abf3ce
--- /dev/null
+++ b/app/code/Magento/Paypal/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+ PayPal Settlement Reports
+ PayPal Settlement
+ magento-paypal-report-salesroot-paypal-settlement-reports
+
+
+ Sales
+ Sales
+ magento-sales-sales
+
+
+ Billing Agreements
+ Billing Agreements
+ magento-paypal-paypal-billing-agreement
+
+
diff --git a/app/code/Magento/Paypal/Test/Mftf/Test/AdminReportsPayPalSettlementNavigateMenuTest.xml b/app/code/Magento/Paypal/Test/Mftf/Test/AdminReportsPayPalSettlementNavigateMenuTest.xml
new file mode 100644
index 0000000000000..03f0167230e9f
--- /dev/null
+++ b/app/code/Magento/Paypal/Test/Mftf/Test/AdminReportsPayPalSettlementNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Paypal/Test/Mftf/Test/AdminSalesBillingAgreementsNavigateMenuTest.xml b/app/code/Magento/Paypal/Test/Mftf/Test/AdminSalesBillingAgreementsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..8c3735fcbd253
--- /dev/null
+++ b/app/code/Magento/Paypal/Test/Mftf/Test/AdminSalesBillingAgreementsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml b/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml
index 425e4cffb666c..694e517816b22 100644
--- a/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml
+++ b/app/code/Magento/Paypal/etc/adminhtml/system/paypal_payflowpro_with_express_checkout.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
Payflow Pro
0
@@ -30,7 +30,7 @@
-
+
Enable PayPal Credit
See Details.
"
+"PayPal Express Checkout Payflow Edition lets you give customers access to financing through PayPal Credit® - at no additional cost to you.
+ You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®.
+ Learn More ","PayPal Express Checkout Payflow Edition lets you give customers access to financing through PayPal Credit® - at no additional cost to you.
+ You get paid up front, even though customers have more time to pay. A pre-integrated payment button lets customers pay quickly with PayPal Credit®.
+ Learn More "
"Customize Smart Buttons","Customize Smart Buttons"
"Checkout Page","Checkout Page"
"Label","Label"
@@ -731,4 +736,4 @@ User,User
"PayPal will automatically display each enabled funding option to eligible buyers. For example, PayPal Credit is only shown to buyers in countries where PayPal Credit is offered and the currency offered by the merchant is USD.","PayPal will automatically display each enabled funding option to eligible buyers. For example, PayPal Credit is only shown to buyers in countries where PayPal Credit is offered and the currency offered by the merchant is USD."
"PayPal Credit","PayPal Credit"
"PayPal Guest Checkout Credit Card Icons","PayPal Guest Checkout Credit Card Icons"
-"Elektronisches Lastschriftverfahren - German ELV","Elektronisches Lastschriftverfahren - German ELV"
\ No newline at end of file
+"Elektronisches Lastschriftverfahren - German ELV","Elektronisches Lastschriftverfahren - German ELV"
diff --git a/app/code/Magento/Persistent/Model/QuoteManager.php b/app/code/Magento/Persistent/Model/QuoteManager.php
index 35c2c70be30dc..8ae22e4c26c6f 100644
--- a/app/code/Magento/Persistent/Model/QuoteManager.php
+++ b/app/code/Magento/Persistent/Model/QuoteManager.php
@@ -7,6 +7,8 @@
/**
* Class QuoteManager
+ *
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class QuoteManager
{
@@ -87,6 +89,7 @@ public function setGuest($checkQuote = false)
->setCustomerLastname(null)
->setCustomerGroupId(\Magento\Customer\Api\Data\GroupInterface::NOT_LOGGED_IN_ID)
->setIsPersistent(false)
+ ->setCustomerIsGuest(true)
->removeAllAddresses();
//Create guest addresses
$quote->getShippingAddress();
diff --git a/app/code/Magento/Persistent/Observer/CheckExpirePersistentQuoteObserver.php b/app/code/Magento/Persistent/Observer/CheckExpirePersistentQuoteObserver.php
index f3720960ca6e5..79fdf44c3c551 100644
--- a/app/code/Magento/Persistent/Observer/CheckExpirePersistentQuoteObserver.php
+++ b/app/code/Magento/Persistent/Observer/CheckExpirePersistentQuoteObserver.php
@@ -1,6 +1,5 @@
_persistentSession->isPersistent() &&
!$this->_customerSession->isLoggedIn() &&
$this->_checkoutSession->getQuoteId() &&
- !$this->isRequestFromCheckoutPage($this->request)
+ !$this->isRequestFromCheckoutPage($this->request) &&
// persistent session does not expire on onepage checkout page
+ (
+ $this->_checkoutSession->getQuote()->getIsPersistent() ||
+ $this->_checkoutSession->getQuote()->getCustomerIsGuest()
+ )
) {
$this->_eventManager->dispatch('persistent_session_expired');
$this->quoteManager->expire();
diff --git a/app/code/Magento/Persistent/Observer/SetQuotePersistentDataObserver.php b/app/code/Magento/Persistent/Observer/SetQuotePersistentDataObserver.php
index db6b6d1ee370d..2803bc998dcbe 100644
--- a/app/code/Magento/Persistent/Observer/SetQuotePersistentDataObserver.php
+++ b/app/code/Magento/Persistent/Observer/SetQuotePersistentDataObserver.php
@@ -1,6 +1,5 @@
_persistentSession->isPersistent() && !$this->_customerSession->isLoggedIn())
- && !$this->_persistentData->isShoppingCartPersist()
+ ($this->_persistentSession->isPersistent())
+ && $this->_persistentData->isShoppingCartPersist()
)
&& $this->quoteManager->isPersistent()
) {
diff --git a/app/code/Magento/Persistent/Test/Mftf/Test/ShippingQuotePersistedForGuestTest.xml b/app/code/Magento/Persistent/Test/Mftf/Test/ShippingQuotePersistedForGuestTest.xml
new file mode 100644
index 0000000000000..e5c77ee414362
--- /dev/null
+++ b/app/code/Magento/Persistent/Test/Mftf/Test/ShippingQuotePersistedForGuestTest.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 150
+
+
+
+ John1
+ Doe1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{US_Address_CA.postcode}}
+ grabTextPostCode
+
+
+
diff --git a/app/code/Magento/Persistent/Test/Mftf/Test/StorefrontVerifyThatInformationAboutViewingComparisonWishlistIsPersistedUnderLongTermCookieTest.xml b/app/code/Magento/Persistent/Test/Mftf/Test/StorefrontVerifyThatInformationAboutViewingComparisonWishlistIsPersistedUnderLongTermCookieTest.xml
new file mode 100644
index 0000000000000..dc6f87bef0ba8
--- /dev/null
+++ b/app/code/Magento/Persistent/Test/Mftf/Test/StorefrontVerifyThatInformationAboutViewingComparisonWishlistIsPersistedUnderLongTermCookieTest.xml
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/CheckExpirePersistentQuoteObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/CheckExpirePersistentQuoteObserverTest.php
index 46dda1be365d4..b096dd2317a33 100644
--- a/app/code/Magento/Persistent/Test/Unit/Observer/CheckExpirePersistentQuoteObserverTest.php
+++ b/app/code/Magento/Persistent/Test/Unit/Observer/CheckExpirePersistentQuoteObserverTest.php
@@ -1,12 +1,16 @@
checkoutSessionMock,
$this->requestMock
);
+ $this->quoteMock = $this->getMockBuilder(Quote::class)
+ ->setMethods(['getCustomerIsGuest', 'getIsPersistent'])
+ ->disableOriginalConstructor()
+ ->getMock();
}
public function testExecuteWhenCanNotApplyPersistentData()
@@ -133,6 +146,11 @@ public function testExecuteWhenPersistentIsEnabled(
->willReturn(true);
$this->persistentHelperMock->expects($this->once())->method('isEnabled')->willReturn(true);
$this->sessionMock->expects($this->once())->method('isPersistent')->willReturn(false);
+ $this->checkoutSessionMock
+ ->method('getQuote')
+ ->willReturn($this->quoteMock);
+ $this->quoteMock->method('getCustomerIsGuest')->willReturn(true);
+ $this->quoteMock->method('getIsPersistent')->willReturn(true);
$this->customerSessionMock
->expects($this->atLeastOnce())
->method('isLoggedIn')
diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/SetQuotePersistentDataObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/SetQuotePersistentDataObserverTest.php
index 6724743789cea..ffa829e8456cc 100644
--- a/app/code/Magento/Persistent/Test/Unit/Observer/SetQuotePersistentDataObserverTest.php
+++ b/app/code/Magento/Persistent/Test/Unit/Observer/SetQuotePersistentDataObserverTest.php
@@ -7,6 +7,9 @@
namespace Magento\Persistent\Test\Unit\Observer;
+/**
+ * Observer test for setting "is_persistent" value to quote
+ */
class SetQuotePersistentDataObserverTest extends \PHPUnit\Framework\TestCase
{
/**
@@ -83,7 +86,6 @@ public function testExecuteWhenQuoteNotExist()
->method('getEvent')
->will($this->returnValue($this->eventManagerMock));
$this->eventManagerMock->expects($this->once())->method('getQuote');
- $this->customerSessionMock->expects($this->never())->method('isLoggedIn');
$this->model->execute($this->observerMock);
}
@@ -98,8 +100,7 @@ public function testExecuteWhenSessionIsPersistent()
->expects($this->once())
->method('getQuote')
->will($this->returnValue($this->quoteMock));
- $this->customerSessionMock->expects($this->once())->method('isLoggedIn')->will($this->returnValue(false));
- $this->helperMock->expects($this->once())->method('isShoppingCartPersist')->will($this->returnValue(false));
+ $this->helperMock->expects($this->once())->method('isShoppingCartPersist')->will($this->returnValue(true));
$this->quoteManagerMock->expects($this->once())->method('isPersistent')->will($this->returnValue(true));
$this->quoteMock->expects($this->once())->method('setIsPersistent')->with(true);
$this->model->execute($this->observerMock);
diff --git a/app/code/Magento/ProductVideo/i18n/de_DE.csv b/app/code/Magento/ProductVideo/i18n/de_DE.csv
deleted file mode 100644
index ca24668bb8d16..0000000000000
--- a/app/code/Magento/ProductVideo/i18n/de_DE.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-"Add video","Add video"
-"New Video","New Video"
-"Product Video","Product Video"
-"YouTube API key","YouTube API key"
-"You have not entered youtube API key. No information about youtube video will be retrieved.","You have not entered youtube API key. No information about youtube video will be retrieved."
-"Url","Url"
-"Preview Image","Preview Image"
-"Get Video Information","Get Video Information"
-"Youtube or Vimeo supported","Youtube or Vimeo supported"
-"Delete image in all store views","Delete image in all store views"
diff --git a/app/code/Magento/ProductVideo/i18n/es_ES.csv b/app/code/Magento/ProductVideo/i18n/es_ES.csv
deleted file mode 100644
index ca24668bb8d16..0000000000000
--- a/app/code/Magento/ProductVideo/i18n/es_ES.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-"Add video","Add video"
-"New Video","New Video"
-"Product Video","Product Video"
-"YouTube API key","YouTube API key"
-"You have not entered youtube API key. No information about youtube video will be retrieved.","You have not entered youtube API key. No information about youtube video will be retrieved."
-"Url","Url"
-"Preview Image","Preview Image"
-"Get Video Information","Get Video Information"
-"Youtube or Vimeo supported","Youtube or Vimeo supported"
-"Delete image in all store views","Delete image in all store views"
diff --git a/app/code/Magento/ProductVideo/i18n/fr_FR.csv b/app/code/Magento/ProductVideo/i18n/fr_FR.csv
deleted file mode 100644
index ca24668bb8d16..0000000000000
--- a/app/code/Magento/ProductVideo/i18n/fr_FR.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-"Add video","Add video"
-"New Video","New Video"
-"Product Video","Product Video"
-"YouTube API key","YouTube API key"
-"You have not entered youtube API key. No information about youtube video will be retrieved.","You have not entered youtube API key. No information about youtube video will be retrieved."
-"Url","Url"
-"Preview Image","Preview Image"
-"Get Video Information","Get Video Information"
-"Youtube or Vimeo supported","Youtube or Vimeo supported"
-"Delete image in all store views","Delete image in all store views"
diff --git a/app/code/Magento/ProductVideo/i18n/nl_NL.csv b/app/code/Magento/ProductVideo/i18n/nl_NL.csv
deleted file mode 100644
index 5ad8386573040..0000000000000
--- a/app/code/Magento/ProductVideo/i18n/nl_NL.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-"Add video","Add video"
-"New Video","New Video"
-"Product Video","Product Video"
-"YouTube API key","YouTube API key"
-"You have not entered youtube API key. No information about youtube video will be retrieved.","You have not entered youtube API key. No information about youtube video will be retrieved."
-"Url","Url"
-"Preview Image","Preview Image"
-"Get Video Information","Get Video Information"
-"Youtube or Vimeo supported","Youtube or Vimeo supported"
-"Delete image in all store views","Delete image in all store views"
\ No newline at end of file
diff --git a/app/code/Magento/ProductVideo/i18n/pt_BR.csv b/app/code/Magento/ProductVideo/i18n/pt_BR.csv
deleted file mode 100644
index 5ad8386573040..0000000000000
--- a/app/code/Magento/ProductVideo/i18n/pt_BR.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-"Add video","Add video"
-"New Video","New Video"
-"Product Video","Product Video"
-"YouTube API key","YouTube API key"
-"You have not entered youtube API key. No information about youtube video will be retrieved.","You have not entered youtube API key. No information about youtube video will be retrieved."
-"Url","Url"
-"Preview Image","Preview Image"
-"Get Video Information","Get Video Information"
-"Youtube or Vimeo supported","Youtube or Vimeo supported"
-"Delete image in all store views","Delete image in all store views"
\ No newline at end of file
diff --git a/app/code/Magento/ProductVideo/i18n/zh_Hans_CN.csv b/app/code/Magento/ProductVideo/i18n/zh_Hans_CN.csv
deleted file mode 100644
index 5ad8386573040..0000000000000
--- a/app/code/Magento/ProductVideo/i18n/zh_Hans_CN.csv
+++ /dev/null
@@ -1,10 +0,0 @@
-"Add video","Add video"
-"New Video","New Video"
-"Product Video","Product Video"
-"YouTube API key","YouTube API key"
-"You have not entered youtube API key. No information about youtube video will be retrieved.","You have not entered youtube API key. No information about youtube video will be retrieved."
-"Url","Url"
-"Preview Image","Preview Image"
-"Get Video Information","Get Video Information"
-"Youtube or Vimeo supported","Youtube or Vimeo supported"
-"Delete image in all store views","Delete image in all store views"
\ No newline at end of file
diff --git a/app/code/Magento/Quote/Model/Quote/Item/Compare.php b/app/code/Magento/Quote/Model/Quote/Item/Compare.php
index ddaa636ef32b3..76ba324518dc1 100644
--- a/app/code/Magento/Quote/Model/Quote/Item/Compare.php
+++ b/app/code/Magento/Quote/Model/Quote/Item/Compare.php
@@ -50,7 +50,7 @@ protected function getOptionValues($value)
if (is_string($value) && $this->jsonValidator->isValid($value)) {
$value = $this->serializer->unserialize($value);
if (is_array($value)) {
- unset($value['qty'], $value['uenc']);
+ unset($value['qty'], $value['uenc'], $value['related_product'], $value['item']);
$value = array_filter($value, function ($optionValue) {
return !empty($optionValue);
});
diff --git a/app/code/Magento/Quote/Model/QuoteIdMask.php b/app/code/Magento/Quote/Model/QuoteIdMask.php
index 7950ab47c3665..47b02db7650df 100644
--- a/app/code/Magento/Quote/Model/QuoteIdMask.php
+++ b/app/code/Magento/Quote/Model/QuoteIdMask.php
@@ -53,11 +53,14 @@ protected function _construct()
* Initialize quote identifier before save
*
* @return $this
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
public function beforeSave()
{
parent::beforeSave();
- $this->setMaskedId($this->randomDataGenerator->getUniqueHash());
+ if (empty($this->getMaskedId())) {
+ $this->setMaskedId($this->randomDataGenerator->getUniqueHash());
+ }
return $this;
}
}
diff --git a/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php b/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
index 76c9a49b290c5..77dfec9603a5c 100644
--- a/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
+++ b/app/code/Magento/Quote/Observer/Frontend/Quote/Address/CollectTotalsObserver.php
@@ -7,6 +7,11 @@
use Magento\Framework\Event\ObserverInterface;
+/**
+ * Handle customer VAT number on collect_totals_before event of quote address.
+ *
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
+ */
class CollectTotalsObserver implements ObserverInterface
{
/**
@@ -124,7 +129,7 @@ public function execute(\Magento\Framework\Event\Observer $observer)
);
}
- if ($groupId) {
+ if ($groupId !== null) {
$address->setPrevQuoteCustomerGroupId($quote->getCustomerGroupId());
$quote->setCustomerGroupId($groupId);
$this->customerSession->setCustomerGroupId($groupId);
diff --git a/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php b/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php
index f3357f8aacd31..4ea067c9be8f6 100644
--- a/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Observer/Frontend/Quote/Address/CollectTotalsObserverTest.php
@@ -199,7 +199,7 @@ public function testDispatchWithCustomerCountryNotInEUAndNotLoggedCustomerInGrou
->method('getNotLoggedInGroup')
->will($this->returnValue($this->groupInterfaceMock));
$this->groupInterfaceMock->expects($this->once())
- ->method('getId')->will($this->returnValue(0));
+ ->method('getId')->will($this->returnValue(null));
$this->vatValidatorMock->expects($this->once())
->method('isEnabled')
->with($this->quoteAddressMock, $this->storeId)
@@ -220,9 +220,6 @@ public function testDispatchWithCustomerCountryNotInEUAndNotLoggedCustomerInGrou
$this->returnValue(false)
);
- $groupMock = $this->getMockBuilder(\Magento\Customer\Api\Data\GroupInterface::class)
- ->disableOriginalConstructor()
- ->getMock();
$this->customerMock->expects($this->once())->method('getId')->will($this->returnValue(null));
/** Assertions */
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/CreateEmptyCartForCustomer.php b/app/code/Magento/QuoteGraphQl/Model/Cart/CreateEmptyCartForCustomer.php
new file mode 100644
index 0000000000000..481bad090dac1
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/CreateEmptyCartForCustomer.php
@@ -0,0 +1,70 @@
+cartManagement = $cartManagement;
+ $this->quoteIdMaskFactory = $quoteIdMaskFactory;
+ $this->quoteIdMaskResourceModel = $quoteIdMaskResourceModel;
+ }
+
+ /**
+ * Create empty cart for customer
+ *
+ * @param int $customerId
+ * @param string|null $predefinedMaskedQuoteId
+ * @return string
+ */
+ public function execute(int $customerId, string $predefinedMaskedQuoteId = null): string
+ {
+ $quoteId = $this->cartManagement->createEmptyCartForCustomer($customerId);
+
+ $quoteIdMask = $this->quoteIdMaskFactory->create();
+ $quoteIdMask->setQuoteId($quoteId);
+
+ if (isset($predefinedMaskedQuoteId)) {
+ $quoteIdMask->setMaskedId($predefinedMaskedQuoteId);
+ }
+
+ $this->quoteIdMaskResourceModel->save($quoteIdMask);
+ return $quoteIdMask->getMaskedId();
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/CreateEmptyCartForGuest.php b/app/code/Magento/QuoteGraphQl/Model/Cart/CreateEmptyCartForGuest.php
new file mode 100644
index 0000000000000..a6396ed6352ab
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/CreateEmptyCartForGuest.php
@@ -0,0 +1,68 @@
+guestCartManagement = $guestCartManagement;
+ $this->quoteIdMaskFactory = $quoteIdMaskFactory;
+ $this->quoteIdMaskResourceModel = $quoteIdMaskResourceModel;
+ }
+
+ /**
+ * Create empty cart for guest
+ *
+ * @param string|null $predefinedMaskedQuoteId
+ * @return string
+ */
+ public function execute(string $predefinedMaskedQuoteId = null): string
+ {
+ $maskedQuoteId = $this->guestCartManagement->createEmptyCart();
+
+ if (isset($predefinedMaskedQuoteId)) {
+ $quoteIdMask = $this->quoteIdMaskFactory->create();
+ $this->quoteIdMaskResourceModel->load($quoteIdMask, $maskedQuoteId, 'masked_id');
+
+ $quoteIdMask->setMaskedId($predefinedMaskedQuoteId);
+ $this->quoteIdMaskResourceModel->save($quoteIdMask);
+ }
+ return $predefinedMaskedQuoteId ?? $maskedQuoteId;
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php
index 145e9c01980a5..3506ffc8c8792 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php
@@ -13,6 +13,7 @@
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
use Magento\Quote\Model\Quote;
+use Magento\Store\Model\StoreManagerInterface;
/**
* Get cart
@@ -29,16 +30,24 @@ class GetCartForUser
*/
private $cartRepository;
+ /**
+ * @var StoreManagerInterface
+ */
+ private $storeManager;
+
/**
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
* @param CartRepositoryInterface $cartRepository
+ * @param StoreManagerInterface $storeManager
*/
public function __construct(
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
- CartRepositoryInterface $cartRepository
+ CartRepositoryInterface $cartRepository,
+ StoreManagerInterface $storeManager
) {
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
$this->cartRepository = $cartRepository;
+ $this->storeManager = $storeManager;
}
/**
@@ -75,6 +84,15 @@ public function execute(string $cartHash, ?int $customerId): Quote
);
}
+ if ((int)$cart->getStoreId() !== (int)$this->storeManager->getStore()->getId()) {
+ throw new GraphQlNoSuchEntityException(
+ __(
+ 'Wrong store code specified for cart "%masked_cart_id"',
+ ['masked_cart_id' => $cartHash]
+ )
+ );
+ }
+
$cartCustomerId = (int)$cart->getCustomerId();
/* Guest cart, allow operations */
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php b/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php
index 76bdc74611131..13d6a1d3dce70 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/QuoteAddressFactory.php
@@ -7,9 +7,12 @@
namespace Magento\QuoteGraphQl\Model\Cart;
-use Magento\Customer\Api\Data\AddressInterface as CustomerAddress;
+use Magento\Customer\Helper\Address as AddressHelper;
+use Magento\CustomerGraphQl\Model\Customer\Address\GetCustomerAddress;
use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Quote\Model\Quote\Address as QuoteAddress;
use Magento\Quote\Model\Quote\AddressFactory as BaseQuoteAddressFactory;
@@ -23,13 +26,29 @@ class QuoteAddressFactory
*/
private $quoteAddressFactory;
+ /**
+ * @var GetCustomerAddress
+ */
+ private $getCustomerAddress;
+
+ /**
+ * @var AddressHelper
+ */
+ private $addressHelper;
+
/**
* @param BaseQuoteAddressFactory $quoteAddressFactory
+ * @param GetCustomerAddress $getCustomerAddress
+ * @param AddressHelper $addressHelper
*/
public function __construct(
- BaseQuoteAddressFactory $quoteAddressFactory
+ BaseQuoteAddressFactory $quoteAddressFactory,
+ GetCustomerAddress $getCustomerAddress,
+ AddressHelper $addressHelper
) {
$this->quoteAddressFactory = $quoteAddressFactory;
+ $this->getCustomerAddress = $getCustomerAddress;
+ $this->addressHelper = $addressHelper;
}
/**
@@ -37,25 +56,38 @@ public function __construct(
*
* @param array $addressInput
* @return QuoteAddress
+ * @throws GraphQlInputException
*/
public function createBasedOnInputData(array $addressInput): QuoteAddress
{
$addressInput['country_id'] = $addressInput['country_code'] ?? '';
+ $maxAllowedLineCount = $this->addressHelper->getStreetLines();
+ if (is_array($addressInput['street']) && count($addressInput['street']) > $maxAllowedLineCount) {
+ throw new GraphQlInputException(
+ __('"Street Address" cannot contain more than %1 lines.', $maxAllowedLineCount)
+ );
+ }
+
$quoteAddress = $this->quoteAddressFactory->create();
$quoteAddress->addData($addressInput);
return $quoteAddress;
}
/**
- * Create QuoteAddress based on CustomerAddress
+ * Create Quote Address based on Customer Address
*
- * @param CustomerAddress $customerAddress
+ * @param int $customerAddressId
+ * @param int $customerId
* @return QuoteAddress
* @throws GraphQlInputException
+ * @throws GraphQlAuthorizationException
+ * @throws GraphQlNoSuchEntityException
*/
- public function createBasedOnCustomerAddress(CustomerAddress $customerAddress): QuoteAddress
+ public function createBasedOnCustomerAddress(int $customerAddressId, int $customerId): QuoteAddress
{
+ $customerAddress = $this->getCustomerAddress->execute((int)$customerAddressId, $customerId);
+
$quoteAddress = $this->quoteAddressFactory->create();
try {
$quoteAddress->importCustomerAddressData($customerAddress);
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetBillingAddressOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetBillingAddressOnCart.php
index 31524ea023222..c2bac13c07067 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetBillingAddressOnCart.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetBillingAddressOnCart.php
@@ -7,8 +7,9 @@
namespace Magento\QuoteGraphQl\Model\Cart;
-use Magento\CustomerGraphQl\Model\Customer\Address\GetCustomerAddress;
use Magento\CustomerGraphQl\Model\Customer\GetCustomer;
+use Magento\Framework\GraphQl\Exception\GraphQlAuthenticationException;
+use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
@@ -29,11 +30,6 @@ class SetBillingAddressOnCart
*/
private $getCustomer;
- /**
- * @var GetCustomerAddress
- */
- private $getCustomerAddress;
-
/**
* @var AssignBillingAddressToCart
*/
@@ -42,18 +38,15 @@ class SetBillingAddressOnCart
/**
* @param QuoteAddressFactory $quoteAddressFactory
* @param GetCustomer $getCustomer
- * @param GetCustomerAddress $getCustomerAddress
* @param AssignBillingAddressToCart $assignBillingAddressToCart
*/
public function __construct(
QuoteAddressFactory $quoteAddressFactory,
GetCustomer $getCustomer,
- GetCustomerAddress $getCustomerAddress,
AssignBillingAddressToCart $assignBillingAddressToCart
) {
$this->quoteAddressFactory = $quoteAddressFactory;
$this->getCustomer = $getCustomer;
- $this->getCustomerAddress = $getCustomerAddress;
$this->assignBillingAddressToCart = $assignBillingAddressToCart;
}
@@ -65,6 +58,8 @@ public function __construct(
* @param array $billingAddressInput
* @return void
* @throws GraphQlInputException
+ * @throws GraphQlAuthenticationException
+ * @throws GraphQlAuthorizationException
* @throws GraphQlNoSuchEntityException
*/
public function execute(ContextInterface $context, CartInterface $cart, array $billingAddressInput): void
@@ -97,8 +92,10 @@ public function execute(ContextInterface $context, CartInterface $cart, array $b
$billingAddress = $this->quoteAddressFactory->createBasedOnInputData($addressInput);
} else {
$customer = $this->getCustomer->execute($context);
- $customerAddress = $this->getCustomerAddress->execute((int)$customerAddressId, (int)$customer->getId());
- $billingAddress = $this->quoteAddressFactory->createBasedOnCustomerAddress($customerAddress);
+ $billingAddress = $this->quoteAddressFactory->createBasedOnCustomerAddress(
+ (int)$customerAddressId,
+ (int)$customer->getId()
+ );
}
$this->assignBillingAddressToCart->execute($cart, $billingAddress, $useForShipping);
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php
index bbca7721754cb..6b0e2a311bf44 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/SetShippingAddressesOnCart.php
@@ -7,7 +7,6 @@
namespace Magento\QuoteGraphQl\Model\Cart;
-use Magento\CustomerGraphQl\Model\Customer\Address\GetCustomerAddress;
use Magento\CustomerGraphQl\Model\Customer\GetCustomer;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
@@ -28,11 +27,6 @@ class SetShippingAddressesOnCart implements SetShippingAddressesOnCartInterface
*/
private $getCustomer;
- /**
- * @var GetCustomerAddress
- */
- private $getCustomerAddress;
-
/**
* @var AssignShippingAddressToCart
*/
@@ -41,18 +35,15 @@ class SetShippingAddressesOnCart implements SetShippingAddressesOnCartInterface
/**
* @param QuoteAddressFactory $quoteAddressFactory
* @param GetCustomer $getCustomer
- * @param GetCustomerAddress $getCustomerAddress
* @param AssignShippingAddressToCart $assignShippingAddressToCart
*/
public function __construct(
QuoteAddressFactory $quoteAddressFactory,
GetCustomer $getCustomer,
- GetCustomerAddress $getCustomerAddress,
AssignShippingAddressToCart $assignShippingAddressToCart
) {
$this->quoteAddressFactory = $quoteAddressFactory;
$this->getCustomer = $getCustomer;
- $this->getCustomerAddress = $getCustomerAddress;
$this->assignShippingAddressToCart = $assignShippingAddressToCart;
}
@@ -86,8 +77,10 @@ public function execute(ContextInterface $context, CartInterface $cart, array $s
$shippingAddress = $this->quoteAddressFactory->createBasedOnInputData($addressInput);
} else {
$customer = $this->getCustomer->execute($context);
- $customerAddress = $this->getCustomerAddress->execute((int)$customerAddressId, (int)$customer->getId());
- $shippingAddress = $this->quoteAddressFactory->createBasedOnCustomerAddress($customerAddress);
+ $shippingAddress = $this->quoteAddressFactory->createBasedOnCustomerAddress(
+ (int)$customerAddressId,
+ (int)$customer->getId()
+ );
}
$this->assignShippingAddressToCart->execute($cart, $shippingAddress);
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/AppliedCoupon.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/AppliedCoupon.php
index ca69b763929be..8251089abcd60 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Resolver/AppliedCoupon.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/AppliedCoupon.php
@@ -11,12 +11,27 @@
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\Quote\Api\CouponManagementInterface;
/**
* @inheritdoc
*/
class AppliedCoupon implements ResolverInterface
{
+ /**
+ * @var CouponManagementInterface
+ */
+ private $couponManagement;
+
+ /**
+ * @param CouponManagementInterface $couponManagement
+ */
+ public function __construct(
+ CouponManagementInterface $couponManagement
+ ) {
+ $this->couponManagement = $couponManagement;
+ }
+
/**
* @inheritdoc
*/
@@ -26,9 +41,9 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
throw new LocalizedException(__('"model" value should be specified'));
}
$cart = $value['model'];
+ $cartId = $cart->getId();
- $appliedCoupon = $cart->getCouponCode();
-
+ $appliedCoupon = $this->couponManagement->get($cartId);
return $appliedCoupon ? ['code' => $appliedCoupon] : null;
}
}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartEmail.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartEmail.php
new file mode 100644
index 0000000000000..8d0cb114d8315
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartEmail.php
@@ -0,0 +1,49 @@
+getCartForUser = $getCartForUser;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
+ {
+ if (!isset($value['model'])) {
+ throw new LocalizedException(__('"model" value should be specified'));
+ }
+ /** @var Quote $cart */
+ $cart = $value['model'];
+
+ return $cart->getCustomerEmail();
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartPrices.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartPrices.php
new file mode 100644
index 0000000000000..7a9bdd926764c
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartPrices.php
@@ -0,0 +1,87 @@
+totalsCollector = $totalsCollector;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
+ {
+ if (!isset($value['model'])) {
+ throw new LocalizedException(__('"model" value should be specified'));
+ }
+
+ /** @var Quote $quote */
+ $quote = $value['model'];
+ $cartTotals = $this->totalsCollector->collectQuoteTotals($quote);
+ $currency = $quote->getQuoteCurrencyCode();
+
+ return [
+ 'grand_total' => ['value' => $cartTotals->getGrandTotal(), 'currency' => $currency],
+ 'subtotal_including_tax' => ['value' => $cartTotals->getSubtotalInclTax(), 'currency' => $currency],
+ 'subtotal_excluding_tax' => ['value' => $cartTotals->getSubtotal(), 'currency' => $currency],
+ 'subtotal_with_discount_excluding_tax' => [
+ 'value' => $cartTotals->getSubtotalWithDiscount(), 'currency' => $currency
+ ],
+ 'applied_taxes' => $this->getAppliedTaxes($cartTotals, $currency),
+ 'model' => $quote
+ ];
+ }
+
+ /**
+ * Returns taxes applied to the current quote
+ *
+ * @param Total $total
+ * @param string $currency
+ * @return array
+ */
+ private function getAppliedTaxes(Total $total, string $currency): array
+ {
+ $appliedTaxesData = [];
+ $appliedTaxes = $total->getAppliedTaxes();
+
+ if (count($appliedTaxes) === 0) {
+ return $appliedTaxesData;
+ }
+
+ foreach ($appliedTaxes as $appliedTax) {
+ $appliedTaxesData[] = [
+ 'label' => $appliedTax['id'],
+ 'amount' => ['value' => $appliedTax['amount'], 'currency' => $currency]
+ ];
+ }
+ return $appliedTaxesData;
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php
index 06123abe615e6..f020527d958e4 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CreateEmptyCart.php
@@ -7,13 +7,15 @@
namespace Magento\QuoteGraphQl\Model\Resolver;
+use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlAlreadyExistsException;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
-use Magento\Quote\Api\CartManagementInterface;
-use Magento\Quote\Api\GuestCartManagementInterface;
-use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
-use Magento\Quote\Model\QuoteIdMaskFactory;
+use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
+use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForCustomer;
+use Magento\QuoteGraphQl\Model\Cart\CreateEmptyCartForGuest;
/**
* @inheritdoc
@@ -21,41 +23,33 @@
class CreateEmptyCart implements ResolverInterface
{
/**
- * @var CartManagementInterface
+ * @var CreateEmptyCartForCustomer
*/
- private $cartManagement;
+ private $createEmptyCartForCustomer;
/**
- * @var GuestCartManagementInterface
+ * @var CreateEmptyCartForGuest
*/
- private $guestCartManagement;
+ private $createEmptyCartForGuest;
/**
- * @var QuoteIdToMaskedQuoteIdInterface
+ * @var MaskedQuoteIdToQuoteIdInterface
*/
- private $quoteIdToMaskedId;
+ private $maskedQuoteIdToQuoteId;
/**
- * @var QuoteIdMaskFactory
- */
- private $quoteIdMaskFactory;
-
- /**
- * @param CartManagementInterface $cartManagement
- * @param GuestCartManagementInterface $guestCartManagement
- * @param QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedId
- * @param QuoteIdMaskFactory $quoteIdMaskFactory
+ * @param CreateEmptyCartForCustomer $createEmptyCartForCustomer
+ * @param CreateEmptyCartForGuest $createEmptyCartForGuest
+ * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
*/
public function __construct(
- CartManagementInterface $cartManagement,
- GuestCartManagementInterface $guestCartManagement,
- QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedId,
- QuoteIdMaskFactory $quoteIdMaskFactory
+ CreateEmptyCartForCustomer $createEmptyCartForCustomer,
+ CreateEmptyCartForGuest $createEmptyCartForGuest,
+ MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
) {
- $this->cartManagement = $cartManagement;
- $this->guestCartManagement = $guestCartManagement;
- $this->quoteIdToMaskedId = $quoteIdToMaskedId;
- $this->quoteIdMaskFactory = $quoteIdMaskFactory;
+ $this->createEmptyCartForCustomer = $createEmptyCartForCustomer;
+ $this->createEmptyCartForGuest = $createEmptyCartForGuest;
+ $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
}
/**
@@ -65,19 +59,49 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
{
$customerId = $context->getUserId();
- if (0 !== $customerId && null !== $customerId) {
- $quoteId = $this->cartManagement->createEmptyCartForCustomer($customerId);
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quoteId);
-
- if (empty($maskedQuoteId)) {
- $quoteIdMask = $this->quoteIdMaskFactory->create();
- $quoteIdMask->setQuoteId($quoteId)->save();
- $maskedQuoteId = $quoteIdMask->getMaskedId();
- }
- } else {
- $maskedQuoteId = $this->guestCartManagement->createEmptyCart();
+ $predefinedMaskedQuoteId = null;
+ if (isset($args['input']['cart_id'])) {
+ $predefinedMaskedQuoteId = $args['input']['cart_id'];
+ $this->validateMaskedId($predefinedMaskedQuoteId);
}
+ $maskedQuoteId = (0 === $customerId || null === $customerId)
+ ? $this->createEmptyCartForGuest->execute($predefinedMaskedQuoteId)
+ : $this->createEmptyCartForCustomer->execute($customerId, $predefinedMaskedQuoteId);
return $maskedQuoteId;
}
+
+ /**
+ * Validate masked id
+ *
+ * @param string $maskedId
+ * @throws GraphQlAlreadyExistsException
+ * @throws GraphQlInputException
+ */
+ private function validateMaskedId(string $maskedId): void
+ {
+ if (mb_strlen($maskedId) != 32) {
+ throw new GraphQlInputException(__('Cart ID length should to be 32 symbols.'));
+ }
+
+ if ($this->isQuoteWithSuchMaskedIdAlreadyExists($maskedId)) {
+ throw new GraphQlAlreadyExistsException(__('Cart with ID "%1" already exists.', $maskedId));
+ }
+ }
+
+ /**
+ * Check is quote with such maskedId already exists
+ *
+ * @param string $maskedId
+ * @return bool
+ */
+ private function isQuoteWithSuchMaskedIdAlreadyExists(string $maskedId): bool
+ {
+ try {
+ $this->maskedQuoteIdToQuoteId->execute($maskedId);
+ return true;
+ } catch (NoSuchEntityException $e) {
+ return false;
+ }
+ }
}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php
new file mode 100644
index 0000000000000..1672474bb3ddd
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php
@@ -0,0 +1,90 @@
+getCartForUser = $getCartForUser;
+ $this->cartManagement = $cartManagement;
+ $this->orderRepository = $orderRepository;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
+ {
+ if (!isset($args['input']['cart_id']) || empty($args['input']['cart_id'])) {
+ throw new GraphQlInputException(__('Required parameter "cart_id" is missing'));
+ }
+ $maskedCartId = $args['input']['cart_id'];
+
+ $cart = $this->getCartForUser->execute($maskedCartId, $context->getUserId());
+
+ if ($context->getUserId() === 0) {
+ if (!$cart->getCustomerEmail()) {
+ throw new GraphQlInputException(__("Guest email for cart is missing. Please enter"));
+ }
+ $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST);
+ }
+
+ try {
+ $orderId = $this->cartManagement->placeOrder($cart->getId());
+ $order = $this->orderRepository->get($orderId);
+
+ return [
+ 'order' => [
+ 'order_id' => $order->getIncrementId(),
+ ],
+ ];
+ } catch (NoSuchEntityException $e) {
+ throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
+ } catch (LocalizedException $e) {
+ throw new GraphQlInputException(__('Unable to place order: %message', ['message' => $e->getMessage()]), $e);
+ }
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php
index 5a708ceaedc28..f81ea3020d3d0 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/RemoveCouponFromCart.php
@@ -62,7 +62,11 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
try {
$this->couponManagement->remove($cartId);
} catch (NoSuchEntityException $e) {
- throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
+ $message = $e->getMessage();
+ if (preg_match('/The "\d+" Cart doesn\'t contain products/', $message)) {
+ $message = 'Cart does not contain products';
+ }
+ throw new GraphQlNoSuchEntityException(__($message), $e);
} catch (CouldNotDeleteException $e) {
throw new LocalizedException(__($e->getMessage()), $e);
}
diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetGuestEmailOnCart.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetGuestEmailOnCart.php
new file mode 100644
index 0000000000000..d621057348b54
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetGuestEmailOnCart.php
@@ -0,0 +1,95 @@
+getCartForUser = $getCartForUser;
+ $this->cartRepository = $cartRepository;
+ $this->emailValidator = $emailValidator;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
+ {
+ if (!isset($args['input']['cart_id']) || empty($args['input']['cart_id'])) {
+ throw new GraphQlInputException(__('Required parameter "cart_id" is missing'));
+ }
+ $maskedCartId = $args['input']['cart_id'];
+
+ if (!isset($args['input']['email']) || empty($args['input']['email'])) {
+ throw new GraphQlInputException(__('Required parameter "email" is missing'));
+ }
+
+ if (false === $this->emailValidator->isValid($args['input']['email'])) {
+ throw new GraphQlInputException(__('Invalid email format'));
+ }
+ $email = $args['input']['email'];
+
+ $currentUserId = $context->getUserId();
+
+ if ($currentUserId !== 0) {
+ throw new GraphQlInputException(__('The request is not allowed for logged in customers'));
+ }
+
+ $cart = $this->getCartForUser->execute($maskedCartId, $currentUserId);
+ $cart->setCustomerEmail($email);
+
+ try {
+ $this->cartRepository->save($cart);
+ } catch (CouldNotSaveException $e) {
+ throw new LocalizedException(__($e->getMessage()), $e);
+ }
+
+ return [
+ 'cart' => [
+ 'model' => $cart,
+ ],
+ ];
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json
index 1bf4d581a5fe3..22ca9cfdfae9a 100644
--- a/app/code/Magento/QuoteGraphQl/composer.json
+++ b/app/code/Magento/QuoteGraphQl/composer.json
@@ -10,7 +10,8 @@
"magento/module-catalog": "*",
"magento/module-store": "*",
"magento/module-customer": "*",
- "magento/module-customer-graph-ql": "*"
+ "magento/module-customer-graph-ql": "*",
+ "magento/module-sales": "*"
},
"suggest": {
"magento/module-graph-ql": "*"
diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls
index 79cea3855f6f3..a9784e97c8952 100644
--- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls
+++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls
@@ -6,7 +6,7 @@ type Query {
}
type Mutation {
- createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Creates an empty shopping cart for a guest or logged in user")
+ createEmptyCart(input: createEmptyCartInput): String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CreateEmptyCart") @doc(description:"Creates an empty shopping cart for a guest or logged in user")
addSimpleProductsToCart(input: AddSimpleProductsToCartInput): AddSimpleProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart")
addVirtualProductsToCart(input: AddVirtualProductsToCartInput): AddVirtualProductsToCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddSimpleProductsToCart")
applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ApplyCouponToCart")
@@ -17,6 +17,12 @@ type Mutation {
setBillingAddressOnCart(input: SetBillingAddressOnCartInput): SetBillingAddressOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetBillingAddressOnCart")
setShippingMethodsOnCart(input: SetShippingMethodsOnCartInput): SetShippingMethodsOnCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetShippingMethodsOnCart")
setPaymentMethodOnCart(input: SetPaymentMethodOnCartInput): SetPaymentMethodOnCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\SetPaymentMethodOnCart")
+ setGuestEmailOnCart(input: SetGuestEmailOnCartInput): SetGuestEmailOnCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\SetGuestEmailOnCart")
+ placeOrder(input: PlaceOrderInput): PlaceOrderOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\PlaceOrder")
+}
+
+input createEmptyCartInput {
+ cart_id: String
}
input AddSimpleProductsToCartInput {
@@ -114,6 +120,10 @@ input ShippingMethodInput {
method_code: String!
}
+input PlaceOrderInput {
+ cart_id: String!
+}
+
input SetPaymentMethodOnCartInput {
cart_id: String!
payment_method: PaymentMethodInput!
@@ -124,6 +134,24 @@ input PaymentMethodInput {
purchase_order_number: String @doc(description:"Purchase order number")
}
+input SetGuestEmailOnCartInput {
+ cart_id: String!
+ email: String!
+}
+
+type CartPrices {
+ grand_total: Money
+ subtotal_including_tax: Money
+ subtotal_excluding_tax: Money
+ subtotal_with_discount_excluding_tax: Money
+ applied_taxes: [CartTaxItem]
+}
+
+type CartTaxItem {
+ amount: Money!
+ label: String!
+}
+
type SetPaymentMethodOnCartOutput {
cart: Cart!
}
@@ -144,13 +172,19 @@ type ApplyCouponToCartOutput {
cart: Cart!
}
+type PlaceOrderOutput {
+ order: Order!
+}
+
type Cart {
items: [CartItemInterface] @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartItems")
applied_coupon: AppliedCoupon @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\AppliedCoupon")
+ email: String @resolver (class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartEmail")
shipping_addresses: [CartAddress]! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\ShippingAddresses")
billing_address: CartAddress! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\BillingAddress")
available_payment_methods: [AvailablePaymentMethod] @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AvailablePaymentMethods") @doc(description: "Available payment methods")
selected_payment_method: SelectedPaymentMethod @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SelectedPaymentMethod")
+ prices: CartPrices @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartPrices")
}
type CartAddress {
@@ -249,6 +283,10 @@ type RemoveItemFromCartOutput {
cart: Cart!
}
+type SetGuestEmailOnCartOutput {
+ cart: Cart!
+}
+
type SimpleCartItem implements CartItemInterface @doc(description: "Simple Cart Item") {
customizable_options: [SelectedCustomizableOption] @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\CustomizableOptions")
}
@@ -285,3 +323,7 @@ type CartItemSelectedOptionValuePrice {
units: String!
type: PriceTypeEnum!
}
+
+type Order {
+ order_id: String
+}
diff --git a/app/code/Magento/ReleaseNotification/etc/di.xml b/app/code/Magento/ReleaseNotification/etc/di.xml
index 1404a6adb0a10..a4c434ff7f623 100644
--- a/app/code/Magento/ReleaseNotification/etc/di.xml
+++ b/app/code/Magento/ReleaseNotification/etc/di.xml
@@ -6,7 +6,6 @@
*/
-->
-
diff --git a/app/code/Magento/Reports/Model/ResourceModel/Product/Downloads/Collection.php b/app/code/Magento/Reports/Model/ResourceModel/Product/Downloads/Collection.php
index 1985db0b90e2a..2009cd3ff9d92 100644
--- a/app/code/Magento/Reports/Model/ResourceModel/Product/Downloads/Collection.php
+++ b/app/code/Magento/Reports/Model/ResourceModel/Product/Downloads/Collection.php
@@ -4,16 +4,16 @@
* See COPYING.txt for license details.
*/
+namespace Magento\Reports\Model\ResourceModel\Product\Downloads;
+
/**
* Product Downloads Report collection
*
* @author Magento Core Team
- */
-namespace Magento\Reports\Model\ResourceModel\Product\Downloads;
-
-/**
+ *
* @api
* @since 100.0.2
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class Collection extends \Magento\Catalog\Model\ResourceModel\Product\Collection
{
@@ -97,4 +97,14 @@ public function addFieldToFilter($field, $condition = null)
}
return $this;
}
+
+ /**
+ * @inheritDoc
+ */
+ public function getSelectCountSql()
+ {
+ $countSelect = parent::getSelectCountSql();
+ $countSelect->reset(\Zend\Db\Sql\Select::GROUP);
+ return $countSelect;
+ }
}
diff --git a/app/code/Magento/Reports/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Reports/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..e77e3ee8abd87
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+ Abandoned Carts
+ Abandoned Carts
+ magento-reports-report-shopcart-abandoned
+
+
+ Bestsellers Report
+ Bestsellers
+ magento-reports-report-products-bestsellers
+
+
+ Coupons Report
+ Coupons
+ magento-reports-report-salesroot-coupons
+
+
+ Downloads Report
+ Downloads
+ magento-downloadable-report-products-downloads
+
+
+ Invoice Report
+ Invoiced
+ magento-reports-report-salesroot-invoiced
+
+
+ Low Stock Report
+ Low Stock
+ magento-reports-report-products-lowstock
+
+
+ New Accounts Report
+ New
+ magento-reports-report-customers-accounts
+
+
+ Order Count Report
+ Order Count
+ magento-reports-report-customers-orders
+
+
+ Ordered Products Report
+ Ordered
+ magento-reports-report-products-sold
+
+
+ Orders Report
+ Orders
+ magento-reports-report-salesroot-sales
+
+
+ Order Total Report
+ Order Total
+ magento-reports-report-customers-totals
+
+
+ Products in Carts
+ Products in Cart
+ magento-reports-report-shopcart-product
+
+
+ Refresh Statistics
+ Refresh Statistics
+ magento-reports-report-statistics-refresh
+
+
+ Tax Report
+ Tax
+ magento-reports-report-salesroot-tax
+
+
+ Product Views Report
+ Views
+ magento-reports-report-products-viewed
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsAbandonedCartsNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsAbandonedCartsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..342955e0684b3
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsAbandonedCartsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsBestsellersNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsBestsellersNavigateMenuTest.xml
new file mode 100644
index 0000000000000..259f2cde2786a
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsBestsellersNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsCouponsNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsCouponsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..321f3078bc63f
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsCouponsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsDownloadsNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsDownloadsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..584c1af6683aa
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsDownloadsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsInvoicedNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsInvoicedNavigateMenuTest.xml
new file mode 100644
index 0000000000000..34aec0620cad9
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsInvoicedNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsLowStockNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsLowStockNavigateMenuTest.xml
new file mode 100644
index 0000000000000..5d91d65a3a457
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsLowStockNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsNewNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsNewNavigateMenuTest.xml
new file mode 100644
index 0000000000000..aeb35ba65a380
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsNewNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderCountNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderCountNavigateMenuTest.xml
new file mode 100644
index 0000000000000..1bfbc654746e6
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderCountNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderTotalNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderTotalNavigateMenuTest.xml
new file mode 100644
index 0000000000000..88c94b53f5233
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderTotalNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderedNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderedNavigateMenuTest.xml
new file mode 100644
index 0000000000000..e81239539a5b5
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrderedNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrdersNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrdersNavigateMenuTest.xml
new file mode 100644
index 0000000000000..13fc8e7353139
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsOrdersNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsProductsInCartNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsProductsInCartNavigateMenuTest.xml
new file mode 100644
index 0000000000000..03877f8e58ecc
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsProductsInCartNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsRefreshStatisticsNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsRefreshStatisticsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..d05fc091357df
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsRefreshStatisticsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsTaxNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsTaxNavigateMenuTest.xml
new file mode 100644
index 0000000000000..11a065c933a3b
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsTaxNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsViewsNavigateMenuTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsViewsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..9154b96c71e38
--- /dev/null
+++ b/app/code/Magento/Reports/Test/Mftf/Test/AdminReportsViewsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Review/Block/Adminhtml/Edit/Form.php b/app/code/Magento/Review/Block/Adminhtml/Edit/Form.php
index 8a8395de72b62..4f7237a0b44be 100644
--- a/app/code/Magento/Review/Block/Adminhtml/Edit/Form.php
+++ b/app/code/Magento/Review/Block/Adminhtml/Edit/Form.php
@@ -4,11 +4,11 @@
* See COPYING.txt for license details.
*/
+namespace Magento\Review\Block\Adminhtml\Edit;
+
/**
* Adminhtml Review Edit Form
*/
-namespace Magento\Review\Block\Adminhtml\Edit;
-
class Form extends \Magento\Backend\Block\Widget\Form\Generic
{
/**
@@ -84,7 +84,8 @@ protected function _prepareForm()
'review/*/save',
[
'id' => $this->getRequest()->getParam('id'),
- 'ret' => $this->_coreRegistry->registry('ret')
+ 'ret' => $this->_coreRegistry->registry('ret'),
+ 'productId' => $this->getRequest()->getParam('productId')
]
),
'method' => 'post',
diff --git a/app/code/Magento/Review/Controller/Adminhtml/Product/Save.php b/app/code/Magento/Review/Controller/Adminhtml/Product/Save.php
index 6217729f53e50..57b1e538ddb6b 100644
--- a/app/code/Magento/Review/Controller/Adminhtml/Product/Save.php
+++ b/app/code/Magento/Review/Controller/Adminhtml/Product/Save.php
@@ -73,6 +73,10 @@ public function execute()
} else {
$resultRedirect->setPath('*/*/');
}
+ $productId = (int)$this->getRequest()->getParam('productId');
+ if ($productId) {
+ $resultRedirect->setPath("catalog/product/edit/id/$productId");
+ }
return $resultRedirect;
}
$resultRedirect->setPath('review/*/');
diff --git a/app/code/Magento/Review/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Review/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..89882707f5ebd
--- /dev/null
+++ b/app/code/Magento/Review/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ Reviews
+ Reviews
+ magento-review-catalog-reviews-ratings-reviews-all
+
+
+ Customer Reviews Report
+ By Customers
+ magento-review-report-review-customer
+
+
+ Product Reviews Report
+ By Products
+ magento-review-report-review-product
+
+
+ Ratings
+ Rating
+ magento-review-catalog-reviews-ratings-ratings
+
+
diff --git a/app/code/Magento/Review/Test/Mftf/Test/AdminMarketingReviewsNavigateMenuTest.xml b/app/code/Magento/Review/Test/Mftf/Test/AdminMarketingReviewsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..fade220d22100
--- /dev/null
+++ b/app/code/Magento/Review/Test/Mftf/Test/AdminMarketingReviewsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Review/Test/Mftf/Test/AdminReportsByCustomersNavigateMenuTest.xml b/app/code/Magento/Review/Test/Mftf/Test/AdminReportsByCustomersNavigateMenuTest.xml
new file mode 100644
index 0000000000000..58492424e76f7
--- /dev/null
+++ b/app/code/Magento/Review/Test/Mftf/Test/AdminReportsByCustomersNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Review/Test/Mftf/Test/AdminReportsByProductsNavigateMenuTest.xml b/app/code/Magento/Review/Test/Mftf/Test/AdminReportsByProductsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..e848aa4f22023
--- /dev/null
+++ b/app/code/Magento/Review/Test/Mftf/Test/AdminReportsByProductsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Review/Test/Mftf/Test/AdminStoresRatingNavigateMenuTest.xml b/app/code/Magento/Review/Test/Mftf/Test/AdminStoresRatingNavigateMenuTest.xml
new file mode 100644
index 0000000000000..511ed5439dc3d
--- /dev/null
+++ b/app/code/Magento/Review/Test/Mftf/Test/AdminStoresRatingNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Rule/view/adminhtml/web/rules.js b/app/code/Magento/Rule/view/adminhtml/web/rules.js
index 202337c39da35..95175d272f9af 100644
--- a/app/code/Magento/Rule/view/adminhtml/web/rules.js
+++ b/app/code/Magento/Rule/view/adminhtml/web/rules.js
@@ -13,6 +13,7 @@ define([
'mage/translate',
'prototype'
], function (jQuery) {
+ 'use strict';
var VarienRulesForm = new Class.create();
@@ -125,7 +126,7 @@ define([
var values = this.updateElement.value.split(','),
s = '';
- for (i = 0; i < values.length; i++) {
+ for (var i = 0; i < values.length; i++) {
s = values[i].strip();
if (s != '') {
@@ -254,7 +255,7 @@ define([
if (elem && elem.options) {
var selectedOptions = [];
- for (i = 0; i < elem.options.length; i++) {
+ for (var i = 0; i < elem.options.length; i++) {
if (elem.options[i].selected) {
selectedOptions.push(elem.options[i].text);
}
@@ -299,14 +300,14 @@ define([
},
changeVisibilityForValueRuleParam: function(elem) {
- let parsedElementId = elem.id.split('__');
- if (parsedElementId[2] != 'operator') {
+ var parsedElementId = elem.id.split('__');
+ if (parsedElementId[2] !== 'operator') {
return false;
}
- let valueElement = jQuery('#' + parsedElementId[0] + '__' + parsedElementId[1] + '__value');
+ var valueElement = jQuery('#' + parsedElementId[0] + '__' + parsedElementId[1] + '__value');
- if(elem.value == '<=>') {
+ if(elem.value === '<=>') {
valueElement.closest('.rule-param').hide();
} else {
valueElement.closest('.rule-param').show();
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php
index 4bd2227d4bb1e..9a271f741edda 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php
@@ -5,12 +5,17 @@
*/
namespace Magento\Sales\Block\Adminhtml\Order\Create\Search;
+use Magento\Sales\Block\Adminhtml\Order\Create\Search\Grid\DataProvider\ProductCollection
+ as ProductCollectionDataProvider;
+use Magento\Framework\App\ObjectManager;
+
/**
* Adminhtml sales order create search products block
*
* @api
* @author Magento Core Team
* @since 100.0.2
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Grid extends \Magento\Backend\Block\Widget\Grid\Extended
{
@@ -42,6 +47,11 @@ class Grid extends \Magento\Backend\Block\Widget\Grid\Extended
*/
protected $_productFactory;
+ /**
+ * @var ProductCollectionDataProvider $productCollectionProvider
+ */
+ private $productCollectionProvider;
+
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Backend\Helper\Data $backendHelper
@@ -50,6 +60,7 @@ class Grid extends \Magento\Backend\Block\Widget\Grid\Extended
* @param \Magento\Backend\Model\Session\Quote $sessionQuote
* @param \Magento\Sales\Model\Config $salesConfig
* @param array $data
+ * @param ProductCollectionDataProvider|null $productCollectionProvider
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
@@ -58,12 +69,15 @@ public function __construct(
\Magento\Catalog\Model\Config $catalogConfig,
\Magento\Backend\Model\Session\Quote $sessionQuote,
\Magento\Sales\Model\Config $salesConfig,
- array $data = []
+ array $data = [],
+ ProductCollectionDataProvider $productCollectionProvider = null
) {
$this->_productFactory = $productFactory;
$this->_catalogConfig = $catalogConfig;
$this->_sessionQuote = $sessionQuote;
$this->_salesConfig = $salesConfig;
+ $this->productCollectionProvider = $productCollectionProvider
+ ?: ObjectManager::getInstance()->get(ProductCollectionDataProvider::class);
parent::__construct($context, $backendHelper, $data);
}
@@ -140,20 +154,18 @@ protected function _addColumnFilterToCollection($column)
*/
protected function _prepareCollection()
{
+
$attributes = $this->_catalogConfig->getProductAttributes();
+ $store = $this->getStore();
+
/* @var $collection \Magento\Catalog\Model\ResourceModel\Product\Collection */
- $collection = $this->_productFactory->create()->getCollection();
- $collection->setStore(
- $this->getStore()
- )->addAttributeToSelect(
+ $collection = $this->productCollectionProvider->getCollectionForStore($store);
+ $collection->addAttributeToSelect(
$attributes
- )->addAttributeToSelect(
- 'sku'
- )->addStoreFilter()->addAttributeToFilter(
+ );
+ $collection->addAttributeToFilter(
'type_id',
$this->_salesConfig->getAvailableProductTypes()
- )->addAttributeToSelect(
- 'gift_message_available'
);
$this->setCollection($collection);
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid/DataProvider/ProductCollection.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid/DataProvider/ProductCollection.php
new file mode 100644
index 0000000000000..733791a2f9549
--- /dev/null
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid/DataProvider/ProductCollection.php
@@ -0,0 +1,55 @@
+collectionFactory = $collectionFactory;
+ }
+
+ /**
+ * Provide products collection filtered with store
+ *
+ * @param Store $store
+ * @return Collection
+ */
+ public function getCollectionForStore(Store $store):Collection
+ {
+ /** @var Collection $collection */
+ $collection = $this->collectionFactory->create();
+
+ $collection->setStore($store);
+ $collection->addAttributeToSelect(
+ 'gift_message_available'
+ );
+ $collection->addAttributeToSelect(
+ 'sku'
+ );
+ $collection->addStoreFilter();
+
+ return $collection;
+ }
+}
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View.php
index fd6e5f403f2de..074aa99a5e791 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Invoice/View.php
@@ -113,8 +113,8 @@ protected function _construct()
$orderPayment->canRefund() && !$this->getInvoice()->getIsUsedForRefund()
) {
$this->buttonList->add(
- 'capture',
- [ // capture?
+ 'credit-memo',
+ [
'label' => __('Credit Memo'),
'class' => 'credit-memo',
'onclick' => 'setLocation(\'' . $this->getCreditMemoUrl() . '\')'
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Totals.php b/app/code/Magento/Sales/Block/Adminhtml/Totals.php
index 83b155293c2b9..8172a3c0db4ad 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Totals.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Totals.php
@@ -5,6 +5,11 @@
*/
namespace Magento\Sales\Block\Adminhtml;
+use Magento\Sales\Model\Order;
+
+/**
+ * Adminhtml sales totals block
+ */
class Totals extends \Magento\Sales\Block\Order\Totals
{
/**
@@ -67,12 +72,16 @@ protected function _initTotals()
if (!$this->getSource()->getIsVirtual() && ((double)$this->getSource()->getShippingAmount() ||
$this->getSource()->getShippingDescription())
) {
+ $shippingLabel = __('Shipping & Handling');
+ if ($this->isFreeShipping($this->getOrder()) && $this->getSource()->getDiscountDescription()) {
+ $shippingLabel .= sprintf(' (%s)', $this->getSource()->getDiscountDescription());
+ }
$this->_totals['shipping'] = new \Magento\Framework\DataObject(
[
'code' => 'shipping',
'value' => $this->getSource()->getShippingAmount(),
'base_value' => $this->getSource()->getBaseShippingAmount(),
- 'label' => __('Shipping & Handling'),
+ 'label' => $shippingLabel,
]
);
}
@@ -109,4 +118,23 @@ protected function _initTotals()
return $this;
}
+
+ /**
+ * Availability of free shipping in at least one order item
+ *
+ * @param Order $order
+ * @return bool
+ */
+ private function isFreeShipping(Order $order): bool
+ {
+ $isFreeShipping = false;
+ foreach ($order->getItems() as $orderItem) {
+ if ($orderItem->getFreeShipping() == '1') {
+ $isFreeShipping = true;
+ break;
+ }
+ }
+
+ return $isFreeShipping;
+ }
}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
index ecd5670a319e7..3d2c13cbaaaa9 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
@@ -89,6 +89,7 @@ public function __construct(
* @param bool $forceSyncMode
*
* @return bool
+ * @throws \Exception
*/
public function send(
\Magento\Sales\Api\Data\OrderInterface $order,
@@ -96,7 +97,7 @@ public function send(
\Magento\Sales\Api\Data\CreditmemoCommentCreationInterface $comment = null,
$forceSyncMode = false
) {
- $creditmemo->setSendEmail(true);
+ $creditmemo->setSendEmail($this->identityContainer->isEnabled());
if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
$transport = [
@@ -145,6 +146,7 @@ public function send(
* @param \Magento\Sales\Api\Data\OrderInterface $order
*
* @return string
+ * @throws \Exception
*/
private function getPaymentHtml(\Magento\Sales\Api\Data\OrderInterface $order)
{
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php
index 8004483583114..126fe4f93f1e0 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php
@@ -57,10 +57,10 @@ class CreditmemoSender extends Sender
* @param CreditmemoIdentity $identityContainer
* @param Order\Email\SenderBuilderFactory $senderBuilderFactory
* @param \Psr\Log\LoggerInterface $logger
+ * @param Renderer $addressRenderer
* @param PaymentHelper $paymentHelper
* @param CreditmemoResource $creditmemoResource
* @param \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig
- * @param Renderer $addressRenderer
* @param ManagerInterface $eventManager
*/
public function __construct(
@@ -96,10 +96,11 @@ public function __construct(
* @param Creditmemo $creditmemo
* @param bool $forceSyncMode
* @return bool
+ * @throws \Exception
*/
public function send(Creditmemo $creditmemo, $forceSyncMode = false)
{
- $creditmemo->setSendEmail(true);
+ $creditmemo->setSendEmail($this->identityContainer->isEnabled());
if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
$order = $creditmemo->getOrder();
@@ -146,6 +147,7 @@ public function send(Creditmemo $creditmemo, $forceSyncMode = false)
*
* @param Order $order
* @return string
+ * @throws \Exception
*/
protected function getPaymentHtml(Order $order)
{
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php
index 994fd79945cfd..ba3895cfa1524 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php
@@ -57,10 +57,10 @@ class InvoiceSender extends Sender
* @param InvoiceIdentity $identityContainer
* @param Order\Email\SenderBuilderFactory $senderBuilderFactory
* @param \Psr\Log\LoggerInterface $logger
+ * @param Renderer $addressRenderer
* @param PaymentHelper $paymentHelper
* @param InvoiceResource $invoiceResource
* @param \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig
- * @param Renderer $addressRenderer
* @param ManagerInterface $eventManager
*/
public function __construct(
@@ -96,10 +96,11 @@ public function __construct(
* @param Invoice $invoice
* @param bool $forceSyncMode
* @return bool
+ * @throws \Exception
*/
public function send(Invoice $invoice, $forceSyncMode = false)
{
- $invoice->setSendEmail(true);
+ $invoice->setSendEmail($this->identityContainer->isEnabled());
if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
$order = $invoice->getOrder();
@@ -146,6 +147,7 @@ public function send(Invoice $invoice, $forceSyncMode = false)
*
* @param Order $order
* @return string
+ * @throws \Exception
*/
protected function getPaymentHtml(Order $order)
{
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php
index 6729c746f5565..10e5e37a49394 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php
@@ -57,10 +57,10 @@ class ShipmentSender extends Sender
* @param ShipmentIdentity $identityContainer
* @param Order\Email\SenderBuilderFactory $senderBuilderFactory
* @param \Psr\Log\LoggerInterface $logger
+ * @param Renderer $addressRenderer
* @param PaymentHelper $paymentHelper
* @param ShipmentResource $shipmentResource
* @param \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig
- * @param Renderer $addressRenderer
* @param ManagerInterface $eventManager
*/
public function __construct(
@@ -96,10 +96,11 @@ public function __construct(
* @param Shipment $shipment
* @param bool $forceSyncMode
* @return bool
+ * @throws \Exception
*/
public function send(Shipment $shipment, $forceSyncMode = false)
{
- $shipment->setSendEmail(true);
+ $shipment->setSendEmail($this->identityContainer->isEnabled());
if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
$order = $shipment->getOrder();
@@ -146,6 +147,7 @@ public function send(Shipment $shipment, $forceSyncMode = false)
*
* @param Order $order
* @return string
+ * @throws \Exception
*/
protected function getPaymentHtml(Order $order)
{
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php
index aa0687bee504f..5ae3306ddf75b 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php
@@ -89,6 +89,7 @@ public function __construct(
* @param bool $forceSyncMode
*
* @return bool
+ * @throws \Exception
*/
public function send(
\Magento\Sales\Api\Data\OrderInterface $order,
@@ -96,7 +97,7 @@ public function send(
\Magento\Sales\Api\Data\InvoiceCommentCreationInterface $comment = null,
$forceSyncMode = false
) {
- $invoice->setSendEmail(true);
+ $invoice->setSendEmail($this->identityContainer->isEnabled());
if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
$transport = [
@@ -145,6 +146,7 @@ public function send(
* @param \Magento\Sales\Api\Data\OrderInterface $order
*
* @return string
+ * @throws \Exception
*/
private function getPaymentHtml(\Magento\Sales\Api\Data\OrderInterface $order)
{
diff --git a/app/code/Magento/Sales/Model/Order/Payment.php b/app/code/Magento/Sales/Model/Order/Payment.php
index fc39755c94ee0..5d1d3f0d040a7 100644
--- a/app/code/Magento/Sales/Model/Order/Payment.php
+++ b/app/code/Magento/Sales/Model/Order/Payment.php
@@ -300,7 +300,7 @@ public function canCapture()
}
/**
- * Check refund availability
+ * Check refund availability.
*
* @return bool
*/
@@ -310,7 +310,7 @@ public function canRefund()
}
/**
- * Check partial refund availability for invoice
+ * Check partial refund availability for invoice.
*
* @return bool
*/
@@ -320,7 +320,7 @@ public function canRefundPartialPerInvoice()
}
/**
- * Check partial capture availability
+ * Check partial capture availability.
*
* @return bool
*/
@@ -546,9 +546,7 @@ public function cancelInvoice($invoice)
}
/**
- * Create new invoice with maximum qty for invoice for each item
- *
- * Register this invoice and capture
+ * Create new invoice with maximum qty for invoice for each item register this invoice and capture
*
* @return Invoice
*/
@@ -686,6 +684,7 @@ public function refund($creditmemo)
$gateway->refund($this, $baseAmountToRefund);
$creditmemo->setTransactionId($this->getLastTransId());
+ // phpcs:ignore Magento2.Exceptions.ThrowCatch
} catch (\Magento\Framework\Exception\LocalizedException $e) {
if (!$captureTxn) {
throw new \Magento\Framework\Exception\LocalizedException(
@@ -732,10 +731,14 @@ public function refund($creditmemo)
$message = $message = $this->prependMessage($message);
$message = $this->_appendTransactionToMessage($transaction, $message);
$orderState = $this->getOrderStateResolver()->getStateForOrder($this->getOrder());
+ $statuses = $this->getOrder()->getConfig()->getStateStatuses($orderState, false);
+ $status = in_array($this->getOrder()->getStatus(), $statuses, true)
+ ? $this->getOrder()->getStatus()
+ : $this->getOrder()->getConfig()->getStateDefaultStatus($orderState);
$this->getOrder()
->addStatusHistoryComment(
$message,
- $this->getOrder()->getConfig()->getStateDefaultStatus($orderState)
+ $status
)->setIsCustomerNotified($creditmemo->getOrder()->getCustomerNoteNotify());
$this->_eventManager->dispatch(
'sales_order_payment_refund',
@@ -1203,7 +1206,7 @@ public function addTransaction($type, $salesDocument = null, $failSafe = false)
}
/**
- * Add message to the specified transaction.
+ * Add transaction comments to order.
*
* @param Transaction|null $transaction
* @param string $message
diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Items/Creditmemo/DefaultCreditmemo.php b/app/code/Magento/Sales/Model/Order/Pdf/Items/Creditmemo/DefaultCreditmemo.php
index 11908864236f6..48934e24a3795 100644
--- a/app/code/Magento/Sales/Model/Order/Pdf/Items/Creditmemo/DefaultCreditmemo.php
+++ b/app/code/Magento/Sales/Model/Order/Pdf/Items/Creditmemo/DefaultCreditmemo.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Sales\Model\Order\Pdf\Items\Creditmemo;
/**
@@ -66,11 +68,18 @@ public function draw()
$lines = [];
// draw Product name
- $lines[0] = [['text' => $this->string->split($item->getName(), 35, true, true), 'feed' => 35]];
+ $lines[0] = [
+ [
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'text' => $this->string->split(html_entity_decode($item->getName()), 35, true, true),
+ 'feed' => 35
+ ]
+ ];
// draw SKU
$lines[0][] = [
- 'text' => $this->string->split($this->getSku($item), 17),
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'text' => $this->string->split(html_entity_decode($this->getSku($item)), 17),
'feed' => 255,
'align' => 'right',
];
diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php b/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php
index 8562328025540..23c2c00daadc3 100644
--- a/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php
+++ b/app/code/Magento/Sales/Model/Order/Pdf/Items/Invoice/DefaultInvoice.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Sales\Model\Order\Pdf\Items\Invoice;
/**
@@ -66,11 +68,18 @@ public function draw()
$lines = [];
// draw Product name
- $lines[0] = [['text' => $this->string->split($item->getName(), 35, true, true), 'feed' => 35]];
+ $lines[0] = [
+ [
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'text' => $this->string->split(html_entity_decode($item->getName()), 35, true, true),
+ 'feed' => 35
+ ]
+ ];
// draw SKU
$lines[0][] = [
- 'text' => $this->string->split($this->getSku($item), 17),
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'text' => $this->string->split(html_entity_decode($this->getSku($item)), 17),
'feed' => 290,
'align' => 'right',
];
diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php b/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php
index 6007e1dcf2b47..a88b508ba0789 100644
--- a/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php
+++ b/app/code/Magento/Sales/Model/Order/Pdf/Items/Shipment/DefaultShipment.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Sales\Model\Order\Pdf\Items\Shipment;
/**
@@ -65,14 +67,21 @@ public function draw()
$lines = [];
// draw Product name
- $lines[0] = [['text' => $this->string->split($item->getName(), 60, true, true), 'feed' => 100]];
+ $lines[0] = [
+ [
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'text' => $this->string->split(html_entity_decode($item->getName()), 60, true, true),
+ 'feed' => 100
+ ]
+ ];
// draw QTY
$lines[0][] = ['text' => $item->getQty() * 1, 'feed' => 35];
// draw SKU
$lines[0][] = [
- 'text' => $this->string->split($this->getSku($item), 25),
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'text' => $this->string->split(html_entity_decode($this->getSku($item)), 25),
'feed' => 565,
'align' => 'right',
];
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
index 0a393548069f5..3657f84d4445d 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
@@ -89,6 +89,7 @@ public function __construct(
* @param bool $forceSyncMode
*
* @return bool
+ * @throws \Exception
*/
public function send(
\Magento\Sales\Api\Data\OrderInterface $order,
@@ -96,7 +97,7 @@ public function send(
\Magento\Sales\Api\Data\ShipmentCommentCreationInterface $comment = null,
$forceSyncMode = false
) {
- $shipment->setSendEmail(true);
+ $shipment->setSendEmail($this->identityContainer->isEnabled());
if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
$transport = [
@@ -145,6 +146,7 @@ public function send(
* @param \Magento\Sales\Api\Data\OrderInterface $order
*
* @return string
+ * @throws \Exception
*/
private function getPaymentHtml(\Magento\Sales\Api\Data\OrderInterface $order)
{
diff --git a/app/code/Magento/Sales/Model/OrderRepository.php b/app/code/Magento/Sales/Model/OrderRepository.php
index 9a1392fbe9065..79548cb190754 100644
--- a/app/code/Magento/Sales/Model/OrderRepository.php
+++ b/app/code/Magento/Sales/Model/OrderRepository.php
@@ -6,7 +6,9 @@
namespace Magento\Sales\Model;
+use Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface;
use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Sales\Api\Data\OrderExtensionFactory;
@@ -16,7 +18,6 @@
use Magento\Sales\Api\Data\ShippingAssignmentInterface;
use Magento\Sales\Model\Order\ShippingAssignmentBuilder;
use Magento\Sales\Model\ResourceModel\Metadata;
-use Magento\Framework\App\ObjectManager;
use Magento\Tax\Api\OrderTaxManagementInterface;
use Magento\Payment\Api\Data\PaymentAdditionalInfoInterface;
use Magento\Payment\Api\Data\PaymentAdditionalInfoInterfaceFactory;
@@ -74,6 +75,11 @@ class OrderRepository implements \Magento\Sales\Api\OrderRepositoryInterface
*/
private $serializer;
+ /**
+ * @var JoinProcessorInterface
+ */
+ private $extensionAttributesJoinProcessor;
+
/**
* Constructor
*
@@ -84,6 +90,7 @@ class OrderRepository implements \Magento\Sales\Api\OrderRepositoryInterface
* @param OrderTaxManagementInterface|null $orderTaxManagement
* @param PaymentAdditionalInfoInterfaceFactory|null $paymentAdditionalInfoFactory
* @param JsonSerializer|null $serializer
+ * @param JoinProcessorInterface $extensionAttributesJoinProcessor
*/
public function __construct(
Metadata $metadata,
@@ -92,7 +99,8 @@ public function __construct(
\Magento\Sales\Api\Data\OrderExtensionFactory $orderExtensionFactory = null,
OrderTaxManagementInterface $orderTaxManagement = null,
PaymentAdditionalInfoInterfaceFactory $paymentAdditionalInfoFactory = null,
- JsonSerializer $serializer = null
+ JsonSerializer $serializer = null,
+ JoinProcessorInterface $extensionAttributesJoinProcessor = null
) {
$this->metadata = $metadata;
$this->searchResultFactory = $searchResultFactory;
@@ -106,6 +114,8 @@ public function __construct(
->get(PaymentAdditionalInfoInterfaceFactory::class);
$this->serializer = $serializer ?: ObjectManager::getInstance()
->get(JsonSerializer::class);
+ $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor
+ ?: ObjectManager::getInstance()->get(JoinProcessorInterface::class);
}
/**
@@ -198,6 +208,7 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr
{
/** @var \Magento\Sales\Api\Data\OrderSearchResultInterface $searchResult */
$searchResult = $this->searchResultFactory->create();
+ $this->extensionAttributesJoinProcessor->process($searchResult);
$this->collectionProcessor->process($searchCriteria, $searchResult);
$searchResult->setSearchCriteria($searchCriteria);
foreach ($searchResult->getItems() as $order) {
diff --git a/app/code/Magento/Sales/Model/RefundOrder.php b/app/code/Magento/Sales/Model/RefundOrder.php
index d79f5ecf857cb..07555cba1b7f7 100644
--- a/app/code/Magento/Sales/Model/RefundOrder.php
+++ b/app/code/Magento/Sales/Model/RefundOrder.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Sales\Model;
use Magento\Framework\App\ResourceConnection;
@@ -151,10 +152,13 @@ public function execute(
$creditmemo->setState(\Magento\Sales\Model\Order\Creditmemo::STATE_REFUNDED);
$order->setCustomerNoteNotify($notify);
$order = $this->refundAdapter->refund($creditmemo, $order);
- $order->setState(
- $this->orderStateResolver->getStateForOrder($order, [])
- );
- $order->setStatus($this->config->getStateDefaultStatus($order->getState()));
+ $orderState = $this->orderStateResolver->getStateForOrder($order, []);
+ $order->setState($orderState);
+ $statuses = $this->config->getStateStatuses($orderState, false);
+ $status = in_array($order->getStatus(), $statuses, true)
+ ? $order->getStatus()
+ : $this->config->getStateDefaultStatus($orderState);
+ $order->setStatus($status);
$order = $this->orderRepository->save($order);
$creditmemo = $this->creditmemoRepository->save($creditmemo);
diff --git a/app/code/Magento/Sales/Model/Service/InvoiceService.php b/app/code/Magento/Sales/Model/Service/InvoiceService.php
index 02242e92c8bf5..18efeba726c1b 100644
--- a/app/code/Magento/Sales/Model/Service/InvoiceService.php
+++ b/app/code/Magento/Sales/Model/Service/InvoiceService.php
@@ -149,6 +149,7 @@ public function setVoid($id)
*/
public function prepareInvoice(Order $order, array $qtys = [])
{
+ $isQtysEmpty = empty($qtys);
$invoice = $this->orderConverter->toInvoice($order);
$totalQty = 0;
$qtys = $this->prepareItemsQty($order, $qtys);
@@ -161,7 +162,7 @@ public function prepareInvoice(Order $order, array $qtys = [])
$qty = (double) $qtys[$orderItem->getId()];
} elseif ($orderItem->isDummy()) {
$qty = $orderItem->getQtyOrdered() ? $orderItem->getQtyOrdered() : 1;
- } elseif (empty($qtys)) {
+ } elseif ($isQtysEmpty) {
$qty = $orderItem->getQtyToInvoice();
} else {
$qty = 0;
diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml
index 0061411d576e2..b90bac7e0881b 100644
--- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml
+++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml
@@ -19,18 +19,15 @@
-
-
-
@@ -38,7 +35,6 @@
-
@@ -50,19 +46,22 @@
-
+
+
+
+
+
+
-
-
@@ -70,4 +69,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Sales/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..4f6faccbb26d4
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+ Credit Memos
+ Credit Memos
+ magento-sales-sales-creditmemo
+
+
+ Invoices
+ Invoices
+ magento-sales-sales-invoice
+
+
+ Orders
+ Orders
+ magento-sales-sales-order
+
+
+ Shipments
+ Shipments
+ magento-sales-sales-shipment
+
+
+ Transactions
+ Transactions
+ magento-sales-sales-transactions
+
+
+ Order Status
+ Order Status
+ magento-sales-system-order-statuses
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesCreditMemosNavigateMenuTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesCreditMemosNavigateMenuTest.xml
new file mode 100644
index 0000000000000..af7cc1822d215
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesCreditMemosNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesInvoicesNavigateMenuTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesInvoicesNavigateMenuTest.xml
new file mode 100644
index 0000000000000..5a38a66d1f4b2
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesInvoicesNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesOrdersNavigateMenuTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesOrdersNavigateMenuTest.xml
new file mode 100644
index 0000000000000..8099254923a2c
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesOrdersNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesShipmentsNavigateMenuTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesShipmentsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..5717c6c90fc17
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesShipmentsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesTransactionsNavigateMenuTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesTransactionsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..68933be92efe6
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSalesTransactionsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminStoresOrderStatusNavigateMenuTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminStoresOrderStatusNavigateMenuTest.xml
new file mode 100644
index 0000000000000..d55cde1449033
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminStoresOrderStatusNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
index 9fd2a8b0d929f..467476c9bb406 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
@@ -1,5 +1,4 @@
creditmemoMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with($emailSendingResult);
if (!$configValue || $forceSyncMode) {
$transport = [
@@ -279,7 +278,7 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
->method('setTemplateVars')
->with($transport->getData());
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn($emailSendingResult);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php
index 31bf846689230..1f074d7262f4d 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php
@@ -7,6 +7,9 @@
use Magento\Sales\Model\Order\Email\Sender\CreditmemoSender;
+/**
+ * Test for Magento\Sales\Model\Order\Email\Sender\CreditmemoSender class.
+ */
class CreditmemoSenderTest extends AbstractSenderTest
{
/**
@@ -90,7 +93,7 @@ public function testSend($configValue, $forceSyncMode, $customerNoteNotify, $ema
$this->creditmemoMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with($emailSendingResult);
$this->globalConfig->expects($this->once())
->method('getValue')
@@ -130,7 +133,7 @@ public function testSend($configValue, $forceSyncMode, $customerNoteNotify, $ema
]
);
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn($emailSendingResult);
@@ -197,6 +200,8 @@ public function sendDataProvider()
* @param bool $isVirtualOrder
* @param int $formatCallCount
* @param string|null $expectedShippingAddress
+ *
+ * @return void
* @dataProvider sendVirtualOrderDataProvider
*/
public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expectedShippingAddress)
@@ -207,7 +212,7 @@ public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expecte
$this->creditmemoMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with(false);
$this->globalConfig->expects($this->once())
->method('getValue')
@@ -242,7 +247,7 @@ public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expecte
]
);
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn(false);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php
index 9c54c716e4207..d1aa5af53da4d 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php
@@ -7,6 +7,9 @@
use Magento\Sales\Model\Order\Email\Sender\InvoiceSender;
+/**
+ * Test for Magento\Sales\Model\Order\Email\Sender\InvoiceSender class.
+ */
class InvoiceSenderTest extends AbstractSenderTest
{
/**
@@ -90,7 +93,7 @@ public function testSend($configValue, $forceSyncMode, $customerNoteNotify, $ema
$this->invoiceMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with($emailSendingResult);
$this->globalConfig->expects($this->once())
->method('getValue')
@@ -136,7 +139,7 @@ public function testSend($configValue, $forceSyncMode, $customerNoteNotify, $ema
]
);
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn($emailSendingResult);
@@ -212,7 +215,7 @@ public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expecte
$this->invoiceMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with(false);
$this->globalConfig->expects($this->once())
->method('getValue')
@@ -247,7 +250,7 @@ public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expecte
]
);
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn(false);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php
index b1b18af63b590..2d7b42bccae5a 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php
@@ -7,6 +7,9 @@
use Magento\Sales\Model\Order\Email\Sender\ShipmentSender;
+/**
+ * Test for Magento\Sales\Model\Order\Email\Sender\ShipmentSender class.
+ */
class ShipmentSenderTest extends AbstractSenderTest
{
/**
@@ -90,7 +93,7 @@ public function testSend($configValue, $forceSyncMode, $customerNoteNotify, $ema
$this->shipmentMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with($emailSendingResult);
$this->globalConfig->expects($this->once())
->method('getValue')
@@ -136,7 +139,7 @@ public function testSend($configValue, $forceSyncMode, $customerNoteNotify, $ema
]
);
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn($emailSendingResult);
@@ -212,7 +215,7 @@ public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expecte
$this->shipmentMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with(false);
$this->globalConfig->expects($this->once())
->method('getValue')
@@ -247,7 +250,7 @@ public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expecte
]
);
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn(false);
$this->shipmentResourceMock->expects($this->once())
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php
index 8a4e2920ba207..dcf689cf7d53b 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php
@@ -247,7 +247,7 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
$this->invoiceMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with($emailSendingResult);
if (!$configValue || $forceSyncMode) {
$transport = [
@@ -277,7 +277,7 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
->method('setTemplateVars')
->with($transport->getData());
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn($emailSendingResult);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php
index 30b584b8c4ebf..9d0f10a30e6ef 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/PaymentTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Sales\Test\Unit\Model\Order;
use Magento\Framework\Model\Context;
@@ -1526,7 +1527,7 @@ public function testRefund()
$this->orderStateResolver->expects($this->once())->method('getStateForOrder')
->with($this->order)
->willReturn(Order::STATE_CLOSED);
- $this->mockGetDefaultStatus(Order::STATE_CLOSED, $status);
+ $this->mockGetDefaultStatus(Order::STATE_CLOSED, $status, ['first, second']);
$this->assertOrderUpdated(Order::STATE_PROCESSING, $status, $message);
static::assertSame($this->payment, $this->payment->refund($this->creditMemoMock));
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
index 94347e8b32d54..391e99ba6f835 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
@@ -249,7 +249,7 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
$this->shipmentMock->expects($this->once())
->method('setSendEmail')
- ->with(true);
+ ->with($emailSendingResult);
if (!$configValue || $forceSyncMode) {
$transport = [
@@ -279,7 +279,7 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
->method('setTemplateVars')
->with($transport->getData());
- $this->identityContainerMock->expects($this->once())
+ $this->identityContainerMock->expects($this->exactly(2))
->method('isEnabled')
->willReturn($emailSendingResult);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php
index c95b56d81d6f4..1ffeaa053cc2e 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/RefundOrderTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Sales\Test\Unit\Model;
use Magento\Framework\App\ResourceConnection;
@@ -245,9 +246,9 @@ public function testOrderCreditmemo($orderId, $notify, $appendComment)
->method('setState')
->with(Order::STATE_CLOSED)
->willReturnSelf();
- $this->orderMock->expects($this->once())
- ->method('getState')
- ->willReturn(Order::STATE_CLOSED);
+ $this->configMock->expects($this->once())
+ ->method('getStateStatuses')
+ ->willReturn(['first, second']);
$this->configMock->expects($this->once())
->method('getStateDefaultStatus')
->with(Order::STATE_CLOSED)
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml
index b0a88b8fa37dc..d1a90783c68c7 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml
@@ -89,11 +89,8 @@ endif; ?>
= $block->getForm()->toHtml() ?>
- getDontSaveInAddressBook() && $block->getAddress()->getSaveInAddressBook()): ?> checked="checked"
- class="admin__control-checkbox"/>
+ getDontSaveInAddressBook()): ?> checked="checked" class="admin__control-checkbox"/>
= /* @escapeNotVerified */ __('Save in address book') ?>
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/totals/tax.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/totals/tax.phtml
index 92139896273da..643146f7bb5cb 100755
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/totals/tax.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/totals/tax.phtml
@@ -33,7 +33,6 @@ $taxAmount = $block->getTotal()->getValue();
-
@@ -44,13 +43,10 @@ $taxAmount = $block->getTotal()->getValue();
-
-
- = /* @escapeNotVerified */ $block->formatPrice($amount) ?>
-
-
+
+ = /* @escapeNotVerified */ $block->formatPrice(($amount*(float)$rate['percent'])/$percent) ?>
+
-
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml
index fcf4ccad7060b..ba4af32ff69b2 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml
@@ -136,67 +136,76 @@
#is';
+ $content = preg_replace_callback(
+ $pattern,
+ function ($matchPart) use (&$script) {
+ $script[] = $matchPart[0];
+ return '';
+ },
+ $content
+ );
+ $subject->setContent(
+ str_replace(' Testwhere($condition);
diff --git a/app/code/Magento/Theme/Model/Wysiwyg/Storage.php b/app/code/Magento/Theme/Model/Wysiwyg/Storage.php
index 2c3350e695a85..0519460c02423 100644
--- a/app/code/Magento/Theme/Model/Wysiwyg/Storage.php
+++ b/app/code/Magento/Theme/Model/Wysiwyg/Storage.php
@@ -4,17 +4,12 @@
* See COPYING.txt for license details.
*/
-/**
- * Theme wysiwyg storage model
- */
namespace Magento\Theme\Model\Wysiwyg;
use Magento\Framework\App\Filesystem\DirectoryList;
/**
- * Class Storage
- *
- * @package Magento\Theme\Model\Wysiwyg
+ * Theme wysiwyg storage model
*/
class Storage
{
@@ -110,7 +105,7 @@ public function __construct(
* Upload file
*
* @param string $targetPath
- * @return bool
+ * @return array
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function uploadFile($targetPath)
@@ -271,7 +266,7 @@ public function getFilesCollection()
if (self::TYPE_IMAGE == $storageType) {
$requestParams['file'] = $fileName;
$file['thumbnailParams'] = $requestParams;
-
+ //phpcs:ignore Generic.PHP.NoSilencedErrors
$size = @getimagesize($path);
if (is_array($size)) {
$file['width'] = $size[0];
diff --git a/app/code/Magento/Theme/Test/Mftf/ActionGroup/StorefrontClickOnHeaderLogoActionGroup.xml b/app/code/Magento/Theme/Test/Mftf/ActionGroup/StorefrontClickOnHeaderLogoActionGroup.xml
new file mode 100644
index 0000000000000..cd4117a4cfa6e
--- /dev/null
+++ b/app/code/Magento/Theme/Test/Mftf/ActionGroup/StorefrontClickOnHeaderLogoActionGroup.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Theme/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Theme/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..e826651062562
--- /dev/null
+++ b/app/code/Magento/Theme/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ Themes
+ Themes
+ magento-theme-system-design-theme
+
+
diff --git a/app/code/Magento/Theme/Test/Mftf/Section/StorefrontHeaderSection.xml b/app/code/Magento/Theme/Test/Mftf/Section/StorefrontHeaderSection.xml
index a4088c7a4a0b7..e2f0a01fc733b 100644
--- a/app/code/Magento/Theme/Test/Mftf/Section/StorefrontHeaderSection.xml
+++ b/app/code/Magento/Theme/Test/Mftf/Section/StorefrontHeaderSection.xml
@@ -9,5 +9,6 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/Theme/Test/Mftf/Test/AdminContentThemesNavigateMenuTest.xml b/app/code/Magento/Theme/Test/Mftf/Test/AdminContentThemesNavigateMenuTest.xml
new file mode 100644
index 0000000000000..8e7bfd71b07d3
--- /dev/null
+++ b/app/code/Magento/Theme/Test/Mftf/Test/AdminContentThemesNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Theme/etc/frontend/di.xml b/app/code/Magento/Theme/etc/frontend/di.xml
index 7db2783cd8dfa..3837c6f717b54 100644
--- a/app/code/Magento/Theme/etc/frontend/di.xml
+++ b/app/code/Magento/Theme/etc/frontend/di.xml
@@ -26,4 +26,7 @@
+
+
+
diff --git a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml
index f719f5dd78307..9c34dfea3218b 100644
--- a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml
+++ b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml
@@ -12,7 +12,11 @@
?>
getThemeName() ? $block->getThemeName() : $block->getLogoAlt();?>
= /* @escapeNotVerified */ __('Toggle Nav') ?>
-
+
compiler->compile($templateRootElement, $this->component, $this->component);
$this->appendLayoutConfiguration();
$result = $this->compiler->postprocessing($this->template->__toString());
- } catch (\Exception $e) {
+ } catch (\Throwable $e) {
$this->logger->critical($e->getMessage());
$result = $e->getMessage();
}
diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminDataGridPaginationActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminDataGridPaginationActionGroup.xml
index 9148c22976c19..fbb543a6cab92 100644
--- a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminDataGridPaginationActionGroup.xml
+++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminDataGridPaginationActionGroup.xml
@@ -23,8 +23,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml
index 0f54f51549e7a..133836761174d 100644
--- a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml
+++ b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml
@@ -11,11 +11,15 @@
diff --git a/app/code/Magento/Ui/etc/db_schema.xml b/app/code/Magento/Ui/etc/db_schema.xml
index e2a04b0cdc72d..13a384024f18a 100644
--- a/app/code/Magento/Ui/etc/db_schema.xml
+++ b/app/code/Magento/Ui/etc/db_schema.xml
@@ -18,8 +18,8 @@
comment="Mark current bookmark per user and identifier"/>
-
-
+
+
diff --git a/app/code/Magento/Ui/i18n/de_DE.csv b/app/code/Magento/Ui/i18n/de_DE.csv
deleted file mode 100644
index 2efac126b857c..0000000000000
--- a/app/code/Magento/Ui/i18n/de_DE.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-"Log JS Errors to Session Storage","Log JS Errors to Session Storage"
-"If enabled, can be used by functional tests for extended reporting","If enabled, can be used by functional tests for extended reporting"
-"Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key"
-"Use this key to retrieve collected js errors","Use this key to retrieve collected js errors"
diff --git a/app/code/Magento/Ui/i18n/es_ES.csv b/app/code/Magento/Ui/i18n/es_ES.csv
deleted file mode 100644
index 2efac126b857c..0000000000000
--- a/app/code/Magento/Ui/i18n/es_ES.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-"Log JS Errors to Session Storage","Log JS Errors to Session Storage"
-"If enabled, can be used by functional tests for extended reporting","If enabled, can be used by functional tests for extended reporting"
-"Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key"
-"Use this key to retrieve collected js errors","Use this key to retrieve collected js errors"
diff --git a/app/code/Magento/Ui/i18n/fr_FR.csv b/app/code/Magento/Ui/i18n/fr_FR.csv
deleted file mode 100644
index 2efac126b857c..0000000000000
--- a/app/code/Magento/Ui/i18n/fr_FR.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-"Log JS Errors to Session Storage","Log JS Errors to Session Storage"
-"If enabled, can be used by functional tests for extended reporting","If enabled, can be used by functional tests for extended reporting"
-"Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key"
-"Use this key to retrieve collected js errors","Use this key to retrieve collected js errors"
diff --git a/app/code/Magento/Ui/i18n/nl_NL.csv b/app/code/Magento/Ui/i18n/nl_NL.csv
deleted file mode 100644
index 2efac126b857c..0000000000000
--- a/app/code/Magento/Ui/i18n/nl_NL.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-"Log JS Errors to Session Storage","Log JS Errors to Session Storage"
-"If enabled, can be used by functional tests for extended reporting","If enabled, can be used by functional tests for extended reporting"
-"Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key"
-"Use this key to retrieve collected js errors","Use this key to retrieve collected js errors"
diff --git a/app/code/Magento/Ui/i18n/pt_BR.csv b/app/code/Magento/Ui/i18n/pt_BR.csv
deleted file mode 100644
index 2efac126b857c..0000000000000
--- a/app/code/Magento/Ui/i18n/pt_BR.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-"Log JS Errors to Session Storage","Log JS Errors to Session Storage"
-"If enabled, can be used by functional tests for extended reporting","If enabled, can be used by functional tests for extended reporting"
-"Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key"
-"Use this key to retrieve collected js errors","Use this key to retrieve collected js errors"
diff --git a/app/code/Magento/Ui/i18n/zh_Hans_CN.csv b/app/code/Magento/Ui/i18n/zh_Hans_CN.csv
deleted file mode 100644
index 2efac126b857c..0000000000000
--- a/app/code/Magento/Ui/i18n/zh_Hans_CN.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-"Log JS Errors to Session Storage","Log JS Errors to Session Storage"
-"If enabled, can be used by functional tests for extended reporting","If enabled, can be used by functional tests for extended reporting"
-"Log JS Errors to Session Storage Key","Log JS Errors to Session Storage Key"
-"Use this key to retrieve collected js errors","Use this key to retrieve collected js errors"
diff --git a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js
index dc6f8d930a144..17b2d1db4eb1b 100644
--- a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js
+++ b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows-grid.js
@@ -33,6 +33,15 @@ define([
}
},
+ /**
+ * @inheritdoc
+ */
+ initialize: function () {
+ this.setToInsertData = _.debounce(this.setToInsertData, 200);
+
+ return this._super();
+ },
+
/**
* Calls 'initObservable' of parent
*
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js
index 0ae09f14fa946..b490ac557e71b 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js
@@ -11,8 +11,7 @@ define([
'Magento_Ui/js/modal/alert',
'Magento_Ui/js/lib/validation/validator',
'Magento_Ui/js/form/element/file-uploader',
- 'mage/adminhtml/browser',
- 'mage/adminhtml/tools'
+ 'mage/adminhtml/browser'
], function ($, _, utils, uiAlert, validator, Element, browser) {
'use strict';
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js b/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js
index dba0992c5ba52..4479cff5135dc 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/ui-select.js
@@ -131,6 +131,7 @@ define([
return Abstract.extend({
defaults: {
options: [],
+ total: 0,
listVisible: false,
value: [],
filterOptions: false,
@@ -153,6 +154,7 @@ define([
labelsDecoration: false,
disableLabel: false,
filterRateLimit: 500,
+ filterRateLimitMethod: 'notifyAtFixedRate',
closeBtnLabel: $t('Done'),
optgroupTmpl: 'ui/grid/filters/elements/ui-select-optgroup',
quantityPlaceholder: $t('options'),
@@ -180,6 +182,7 @@ define([
debounce: 300,
missingValuePlaceholder: $t('Entity with ID: %s doesn\'t exist'),
isDisplayMissingValuePlaceholder: false,
+ currentSearchKey: '',
listens: {
listVisible: 'cleanHoveredElement',
filterInputValue: 'filterOptionsList',
@@ -330,7 +333,10 @@ define([
]);
this.filterInputValue.extend({
- rateLimit: this.filterRateLimit
+ rateLimit: {
+ timeout: this.filterRateLimit,
+ method: this.filterRateLimitMethod
+ }
});
return this;
@@ -460,7 +466,7 @@ define([
}
if (this.searchOptions) {
- return _.debounce(this.loadOptions.bind(this, value), this.debounce)();
+ return this.loadOptions(value);
}
this.cleanHoveredElement();
@@ -547,11 +553,21 @@ define([
_setItemsQuantity: function (data) {
if (this.showFilteredQuantity) {
data || parseInt(data, 10) === 0 ?
- this.itemsQuantity(data + ' ' + this.quantityPlaceholder) :
+ this.itemsQuantity(this.getItemsPlaceholder(data)) :
this.itemsQuantity('');
}
},
+ /**
+ * Return formatted items placeholder.
+ *
+ * @param {Object} data - option data
+ * @returns {String}
+ */
+ getItemsPlaceholder: function (data) {
+ return data + ' ' + this.quantityPlaceholder;
+ },
+
/**
* Remove element from selected array
*/
@@ -1234,13 +1250,11 @@ define([
* @param {Number} page
*/
processRequest: function (searchKey, page) {
- var total = 0,
- existingOptions = this.options();
-
this.loading(true);
+ this.currentSearchKey = searchKey;
$.ajax({
url: this.searchUrl,
- type: 'post',
+ type: 'get',
dataType: 'json',
context: this,
data: {
@@ -1248,27 +1262,39 @@ define([
page: page,
limit: this.pageLimit
},
+ success: $.proxy(this.success, this),
+ error: $.proxy(this.error, this),
+ beforeSend: $.proxy(this.beforeSend, this),
+ complete: $.proxy(this.complete, this, searchKey, page)
+ });
+ },
- /** @param {Object} response */
- success: function (response) {
- _.each(response.options, function (opt) {
- existingOptions.push(opt);
- });
- total = response.total;
- this.options(existingOptions);
- },
-
- /** set empty array if error occurs */
- error: function () {
- this.options([]);
- },
+ /** @param {Object} response */
+ success: function (response) {
+ var existingOptions = this.options();
- /** cache options and stop loading*/
- complete: function () {
- this.setCachedSearchResults(searchKey, this.options(), page, total);
- this.afterLoadOptions(searchKey, page, total);
- }
+ _.each(response.options, function (opt) {
+ existingOptions.push(opt);
});
+
+ this.total = response.total;
+ this.options(existingOptions);
+ },
+
+ /** add actions before ajax request */
+ beforeSend: function () {
+
+ },
+
+ /** set empty array if error occurs */
+ error: function () {
+ this.options([]);
+ },
+
+ /** cache options and stop loading*/
+ complete: function (searchKey, page) {
+ this.setCachedSearchResults(searchKey, this.options(), page, this.total);
+ this.afterLoadOptions(searchKey, page, this.total);
},
/**
@@ -1279,9 +1305,9 @@ define([
* @param {Number} total
*/
afterLoadOptions: function (searchKey, page, total) {
- this._setItemsQuantity(total);
- this.lastSearchPage = page;
this.lastSearchKey = searchKey;
+ this.lastSearchPage = page;
+ this._setItemsQuantity(total);
this.loading(false);
}
});
diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js
index abd79e797e413..8e6f1496495c7 100644
--- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js
+++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js
@@ -19,7 +19,9 @@ define([
defaults: {
template: 'ui/grid/paging/paging',
totalTmpl: 'ui/grid/paging-total',
+ totalRecords: 0,
pageSize: 20,
+ pages: 1,
current: 1,
selectProvider: 'ns = ${ $.ns }, index = ids',
@@ -35,7 +37,8 @@ define([
imports: {
pageSize: '${ $.sizesConfig.name }:value',
totalSelected: '${ $.selectProvider }:totalSelected',
- totalRecords: '${ $.provider }:data.totalRecords'
+ totalRecords: '${ $.provider }:data.totalRecords',
+ filters: '${ $.provider }:params.filters'
},
exports: {
@@ -43,6 +46,11 @@ define([
current: '${ $.provider }:params.paging.current'
},
+ statefull: {
+ pageSize: true,
+ current: true
+ },
+
listens: {
'pages': 'onPagesChange',
'pageSize': 'onPageSizeChange',
@@ -173,7 +181,9 @@ define([
* @returns {Paging} Chainable.
*/
goFirst: function () {
- this.current = 1;
+ if (!_.isUndefined(this.filters)) {
+ this.current = 1;
+ }
return this;
},
@@ -219,13 +229,11 @@ define([
/**
* Calculates new page cursor based on the
* previous and current page size values.
- *
- * @returns {Number} Updated cursor value.
*/
updateCursor: function () {
var cursor = this.current - 1,
size = this.pageSize,
- oldSize = this.previousSize,
+ oldSize = _.isUndefined(this.previousSize) ? this.pageSize : this.previousSize,
delta = cursor * (oldSize - size) / size;
delta = size > oldSize ?
diff --git a/app/code/Magento/Ui/view/base/web/js/grid/search/search.js b/app/code/Magento/Ui/view/base/web/js/grid/search/search.js
index 999e3262dbbdd..ce53b23b79e11 100644
--- a/app/code/Magento/Ui/view/base/web/js/grid/search/search.js
+++ b/app/code/Magento/Ui/view/base/web/js/grid/search/search.js
@@ -11,8 +11,9 @@ define([
'uiLayout',
'mage/translate',
'mageUtils',
- 'uiElement'
-], function (_, layout, $t, utils, Element) {
+ 'uiElement',
+ 'jquery'
+], function (_, layout, $t, utils, Element, $) {
'use strict';
return Element.extend({
@@ -29,11 +30,13 @@ define([
tracks: {
value: true,
previews: true,
- inputValue: true
+ inputValue: true,
+ focused: true
},
imports: {
inputValue: 'value',
- updatePreview: 'value'
+ updatePreview: 'value',
+ focused: false
},
exports: {
value: '${ $.provider }:params.search'
@@ -88,6 +91,18 @@ define([
return this;
},
+ /**
+ * Click To ScrollTop.
+ */
+ scrollTo: function ($data) {
+ $('html, body').animate({
+ scrollTop: 0
+ }, 'slow', function () {
+ $data.focused = false;
+ $data.focused = true;
+ });
+ },
+
/**
* Resets input value to the last applied state.
*
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/core/storage/local.js b/app/code/Magento/Ui/view/base/web/js/lib/core/storage/local.js
index 038907c21224d..adeb510ab3e40 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/core/storage/local.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/core/storage/local.js
@@ -114,8 +114,8 @@ define([
*
* @param {String} path - Path to the property.
*
- * @example Retrieveing data.
- * localStoarge =>
+ * @example Retrieving data.
+ * localStorage =>
* 'appData' => '
* "one": {"two": "three"}
* '
@@ -139,7 +139,7 @@ define([
*
* @example Setting data.
* storage.set('one.two', 'four');
- * => localStoarge =>
+ * => localStorage =>
* 'appData' => '
* "one": {"two": "four"}
* '
@@ -159,7 +159,7 @@ define([
*
* @example Removing data.
* storage.remove('one.two', 'four');
- * => localStoarge =>
+ * => localStorage =>
* 'appData' => '
* "one": {}
* '
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js b/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js
index 2e0c53373f807..2cfd961619249 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/knockout/template/renderer.js
@@ -519,7 +519,7 @@ define([
},
/**
- * Custom 'render' attrobute handler function. Wraps child elements
+ * Custom 'render' attribute handler function. Wraps child elements
* of a node with knockout's 'ko template:' comment tag.
*
* @param {HTMLElement} node - Element to be processed.
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/logger/logger-utils.js b/app/code/Magento/Ui/view/base/web/js/lib/logger/logger-utils.js
index fe83f600132ed..bf7ae0cdc3e98 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/logger/logger-utils.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/logger/logger-utils.js
@@ -42,14 +42,14 @@ define([], function () {
* Method that creates object of messages
* @param {String} requested - log message that showing that request for class is started
* @param {String} loaded - log message that show when requested class is loaded
- * @param {String} failded - log message that show when requested class is failed
+ * @param {String} failed - log message that show when requested class is failed
* @returns {Object}
*/
- LogUtils.prototype.createMessages = function (requested, loaded, failded) {
+ LogUtils.prototype.createMessages = function (requested, loaded, failed) {
return {
requested: requested || '',
loaded: loaded || '',
- failed: failded || ''
+ failed: failed || ''
};
};
@@ -57,14 +57,14 @@ define([], function () {
* Method that creates object of log levels
* @param {String} requested - log message that showing that request for class is started
* @param {String} loaded - log message that show when requested class is loaded
- * @param {String} failded - log message that show when requested class is failed
+ * @param {String} failed - log message that show when requested class is failed
* @returns {Object}
*/
- LogUtils.prototype.createLevels = function (requested, loaded, failded) {
+ LogUtils.prototype.createLevels = function (requested, loaded, failed) {
return {
requested: requested || 'info',
loaded: loaded || 'info',
- failed: failded || 'warn'
+ failed: failed || 'warn'
};
};
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/validator.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/validator.js
index 8ebbf88775b86..407984c7881a2 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/validation/validator.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/validator.js
@@ -64,7 +64,7 @@ define([
}
/**
- * Validates provied value by a specified set of rules.
+ * Validates provided value by a specified set of rules.
*
* @param {(String|Object)} rules - One or many validation rules.
* @param {*} value - Value to be checked.
diff --git a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js
index 03012918f4a0d..f8e752fb77af2 100644
--- a/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js
+++ b/app/code/Magento/Ui/view/base/web/js/lib/view/utils/dom-observer.js
@@ -141,7 +141,7 @@ define([
}
/**
- * Calls handlers assocoiated with an added node.
+ * Calls handlers associated with an added node.
* Adds listeners for the node removal.
*
* @param {HTMLElement} node - Added node.
@@ -163,7 +163,7 @@ define([
}
/**
- * Calls handlers assocoiated with a removed node.
+ * Calls handlers associated with a removed node.
*
* @param {HTMLElement} node - Removed node.
*/
diff --git a/app/code/Magento/Ui/view/base/web/templates/grid/search/search.html b/app/code/Magento/Ui/view/base/web/templates/grid/search/search.html
index 13b82a93eca25..fcad729a95fbb 100644
--- a/app/code/Magento/Ui/view/base/web/templates/grid/search/search.html
+++ b/app/code/Magento/Ui/view/base/web/templates/grid/search/search.html
@@ -5,7 +5,7 @@
*/
-->
diff --git a/app/code/Magento/Ui/view/frontend/web/templates/form/element/uploader/uploader.html b/app/code/Magento/Ui/view/frontend/web/templates/form/element/uploader/uploader.html
new file mode 100644
index 0000000000000..226ad2915bb61
--- /dev/null
+++ b/app/code/Magento/Ui/view/frontend/web/templates/form/element/uploader/uploader.html
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php
index 9cb1fe615aa42..0e2ce05f2d079 100644
--- a/app/code/Magento/Ups/Model/Carrier.php
+++ b/app/code/Magento/Ups/Model/Carrier.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
namespace Magento\Ups\Model;
@@ -454,7 +455,7 @@ protected function _getCgiQuotes()
{
$rowRequest = $this->_rawRequest;
if (self::USA_COUNTRY_ID == $rowRequest->getDestCountry()) {
- $destPostal = substr($rowRequest->getDestPostal(), 0, 5);
+ $destPostal = substr((string)$rowRequest->getDestPostal(), 0, 5);
} else {
$destPostal = $rowRequest->getDestPostal();
}
@@ -472,7 +473,7 @@ protected function _getCgiQuotes()
'47_rate_chart' => $rowRequest->getPickup(),
'48_container' => $rowRequest->getContainer(),
'49_residential' => $rowRequest->getDestType(),
- 'weight_std' => strtolower($rowRequest->getUnitMeasure()),
+ 'weight_std' => strtolower((string)$rowRequest->getUnitMeasure()),
];
$params['47_rate_chart'] = $params['47_rate_chart']['label'];
@@ -536,7 +537,7 @@ protected function _parseCgiResponse($response)
$priceArr = [];
if (strlen(trim($response)) > 0) {
$rRows = explode("\n", $response);
- $allowedMethods = explode(",", $this->getConfigData('allowed_methods'));
+ $allowedMethods = explode(",", (string)$this->getConfigData('allowed_methods'));
foreach ($rRows as $rRow) {
$row = explode('%', $rRow);
switch (substr($row[0], -1)) {
@@ -612,7 +613,7 @@ protected function _getXmlQuotes()
$rowRequest = $this->_rawRequest;
if (self::USA_COUNTRY_ID == $rowRequest->getDestCountry()) {
- $destPostal = substr($rowRequest->getDestPostal(), 0, 5);
+ $destPostal = substr((string)$rowRequest->getDestPostal(), 0, 5);
} else {
$destPostal = $rowRequest->getDestPostal();
}
@@ -832,76 +833,15 @@ protected function _parseXmlResponse($xmlResponse)
$allowedCurrencies = $this->_currencyFactory->create()->getConfigAllowCurrencies();
foreach ($arr as $shipElement) {
- $code = (string)$shipElement->Service->Code;
- if (in_array($code, $allowedMethods)) {
- //The location of tax information is in a different place
- // depending on whether we are using negotiated rates or not
- if ($negotiatedActive) {
- $includeTaxesArr = $xml->getXpath(
- "//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates"
- . "/NetSummaryCharges/TotalChargesWithTaxes"
- );
- $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr);
- if ($includeTaxesActive) {
- $cost = $shipElement->NegotiatedRates
- ->NetSummaryCharges
- ->TotalChargesWithTaxes
- ->MonetaryValue;
-
- $responseCurrencyCode = $this->mapCurrencyCode(
- (string)$shipElement->NegotiatedRates
- ->NetSummaryCharges
- ->TotalChargesWithTaxes
- ->CurrencyCode
- );
- } else {
- $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue;
- $responseCurrencyCode = $this->mapCurrencyCode(
- (string)$shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->CurrencyCode
- );
- }
- } else {
- $includeTaxesArr = $xml->getXpath(
- "//RatingServiceSelectionResponse/RatedShipment/TotalChargesWithTaxes"
- );
- $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr);
- if ($includeTaxesActive) {
- $cost = $shipElement->TotalChargesWithTaxes->MonetaryValue;
- $responseCurrencyCode = $this->mapCurrencyCode(
- (string)$shipElement->TotalChargesWithTaxes->CurrencyCode
- );
- } else {
- $cost = $shipElement->TotalCharges->MonetaryValue;
- $responseCurrencyCode = $this->mapCurrencyCode(
- (string)$shipElement->TotalCharges->CurrencyCode
- );
- }
- }
-
- //convert price with Origin country currency code to base currency code
- $successConversion = true;
- if ($responseCurrencyCode) {
- if (in_array($responseCurrencyCode, $allowedCurrencies)) {
- $cost = (double)$cost * $this->_getBaseCurrencyRate($responseCurrencyCode);
- } else {
- $errorTitle = __(
- 'We can\'t convert a rate from "%1-%2".',
- $responseCurrencyCode,
- $this->_request->getPackageCurrency()->getCode()
- );
- $error = $this->_rateErrorFactory->create();
- $error->setCarrier('ups');
- $error->setCarrierTitle($this->getConfigData('title'));
- $error->setErrorMessage($errorTitle);
- $successConversion = false;
- }
- }
-
- if ($successConversion) {
- $costArr[$code] = $cost;
- $priceArr[$code] = $this->getMethodPrice((float)$cost, $code);
- }
- }
+ $this->processShippingRateForItem(
+ $shipElement,
+ $allowedMethods,
+ $allowedCurrencies,
+ $costArr,
+ $priceArr,
+ $negotiatedActive,
+ $xml
+ );
}
} else {
$arr = $xml->getXpath("//RatingServiceSelectionResponse/Response/Error/ErrorDescription/text()");
@@ -944,6 +884,99 @@ protected function _parseXmlResponse($xmlResponse)
return $result;
}
+ /**
+ * Processing rate for ship element
+ *
+ * @param \Magento\Framework\Simplexml\Element $shipElement
+ * @param array $allowedMethods
+ * @param array $allowedCurrencies
+ * @param array $costArr
+ * @param array $priceArr
+ * @param bool $negotiatedActive
+ * @param \Magento\Framework\Simplexml\Config $xml
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+ */
+ private function processShippingRateForItem(
+ \Magento\Framework\Simplexml\Element $shipElement,
+ array $allowedMethods,
+ array $allowedCurrencies,
+ array &$costArr,
+ array &$priceArr,
+ bool $negotiatedActive,
+ \Magento\Framework\Simplexml\Config $xml
+ ): void {
+ $code = (string)$shipElement->Service->Code;
+ if (in_array($code, $allowedMethods)) {
+ //The location of tax information is in a different place
+ // depending on whether we are using negotiated rates or not
+ if ($negotiatedActive) {
+ $includeTaxesArr = $xml->getXpath(
+ "//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates"
+ . "/NetSummaryCharges/TotalChargesWithTaxes"
+ );
+ $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr);
+ if ($includeTaxesActive) {
+ $cost = $shipElement->NegotiatedRates
+ ->NetSummaryCharges
+ ->TotalChargesWithTaxes
+ ->MonetaryValue;
+
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->NegotiatedRates
+ ->NetSummaryCharges
+ ->TotalChargesWithTaxes
+ ->CurrencyCode
+ );
+ } else {
+ $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue;
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->CurrencyCode
+ );
+ }
+ } else {
+ $includeTaxesArr = $xml->getXpath(
+ "//RatingServiceSelectionResponse/RatedShipment/TotalChargesWithTaxes"
+ );
+ $includeTaxesActive = $this->getConfigFlag('include_taxes') && !empty($includeTaxesArr);
+ if ($includeTaxesActive) {
+ $cost = $shipElement->TotalChargesWithTaxes->MonetaryValue;
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->TotalChargesWithTaxes->CurrencyCode
+ );
+ } else {
+ $cost = $shipElement->TotalCharges->MonetaryValue;
+ $responseCurrencyCode = $this->mapCurrencyCode(
+ (string)$shipElement->TotalCharges->CurrencyCode
+ );
+ }
+ }
+
+ //convert price with Origin country currency code to base currency code
+ $successConversion = true;
+ if ($responseCurrencyCode) {
+ if (in_array($responseCurrencyCode, $allowedCurrencies)) {
+ $cost = (double)$cost * $this->_getBaseCurrencyRate($responseCurrencyCode);
+ } else {
+ $errorTitle = __(
+ 'We can\'t convert a rate from "%1-%2".',
+ $responseCurrencyCode,
+ $this->_request->getPackageCurrency()->getCode()
+ );
+ $error = $this->_rateErrorFactory->create();
+ $error->setCarrier('ups');
+ $error->setCarrierTitle($this->getConfigData('title'));
+ $error->setErrorMessage($errorTitle);
+ $successConversion = false;
+ }
+ }
+
+ if ($successConversion) {
+ $costArr[$code] = $cost;
+ $priceArr[$code] = $this->getMethodPrice((float)$cost, $code);
+ }
+ }
+ }
+
/**
* Get tracking
*
@@ -1100,54 +1133,7 @@ protected function _parseXmlTrackingResponse($trackingValue, $xmlResponse)
if ($activityTags) {
$index = 1;
foreach ($activityTags as $activityTag) {
- $addressArr = [];
- if (isset($activityTag->ActivityLocation->Address->City)) {
- $addressArr[] = (string)$activityTag->ActivityLocation->Address->City;
- }
- if (isset($activityTag->ActivityLocation->Address->StateProvinceCode)) {
- $addressArr[] = (string)$activityTag->ActivityLocation->Address->StateProvinceCode;
- }
- if (isset($activityTag->ActivityLocation->Address->CountryCode)) {
- $addressArr[] = (string)$activityTag->ActivityLocation->Address->CountryCode;
- }
- $dateArr = [];
- $date = (string)$activityTag->Date;
- //YYYYMMDD
- $dateArr[] = substr($date, 0, 4);
- $dateArr[] = substr($date, 4, 2);
- $dateArr[] = substr($date, -2, 2);
-
- $timeArr = [];
- $time = (string)$activityTag->Time;
- //HHMMSS
- $timeArr[] = substr($time, 0, 2);
- $timeArr[] = substr($time, 2, 2);
- $timeArr[] = substr($time, -2, 2);
-
- if ($index === 1) {
- $resultArr['status'] = (string)$activityTag->Status->StatusType->Description;
- $resultArr['deliverydate'] = implode('-', $dateArr);
- //YYYY-MM-DD
- $resultArr['deliverytime'] = implode(':', $timeArr);
- //HH:MM:SS
- $resultArr['deliverylocation'] = (string)$activityTag->ActivityLocation->Description;
- $resultArr['signedby'] = (string)$activityTag->ActivityLocation->SignedForByName;
- if ($addressArr) {
- $resultArr['deliveryto'] = implode(', ', $addressArr);
- }
- } else {
- $tempArr = [];
- $tempArr['activity'] = (string)$activityTag->Status->StatusType->Description;
- $tempArr['deliverydate'] = implode('-', $dateArr);
- //YYYY-MM-DD
- $tempArr['deliverytime'] = implode(':', $timeArr);
- //HH:MM:SS
- if ($addressArr) {
- $tempArr['deliverylocation'] = implode(', ', $addressArr);
- }
- $packageProgress[] = $tempArr;
- }
- $index++;
+ $this->processActivityTagInfo($activityTag, $index, $resultArr, $packageProgress);
}
$resultArr['progressdetail'] = $packageProgress;
}
@@ -1180,6 +1166,70 @@ protected function _parseXmlTrackingResponse($trackingValue, $xmlResponse)
return $this->_result;
}
+ /**
+ * Process tracking info from activity tag
+ *
+ * @param \Magento\Framework\Simplexml\Element $activityTag
+ * @param int $index
+ * @param array $resultArr
+ * @param array $packageProgress
+ */
+ private function processActivityTagInfo(
+ \Magento\Framework\Simplexml\Element $activityTag,
+ int &$index,
+ array &$resultArr,
+ array &$packageProgress
+ ) {
+ $addressArr = [];
+ if (isset($activityTag->ActivityLocation->Address->City)) {
+ $addressArr[] = (string)$activityTag->ActivityLocation->Address->City;
+ }
+ if (isset($activityTag->ActivityLocation->Address->StateProvinceCode)) {
+ $addressArr[] = (string)$activityTag->ActivityLocation->Address->StateProvinceCode;
+ }
+ if (isset($activityTag->ActivityLocation->Address->CountryCode)) {
+ $addressArr[] = (string)$activityTag->ActivityLocation->Address->CountryCode;
+ }
+ $dateArr = [];
+ $date = (string)$activityTag->Date;
+ //YYYYMMDD
+ $dateArr[] = substr($date, 0, 4);
+ $dateArr[] = substr($date, 4, 2);
+ $dateArr[] = substr($date, -2, 2);
+
+ $timeArr = [];
+ $time = (string)$activityTag->Time;
+ //HHMMSS
+ $timeArr[] = substr($time, 0, 2);
+ $timeArr[] = substr($time, 2, 2);
+ $timeArr[] = substr($time, -2, 2);
+
+ if ($index === 1) {
+ $resultArr['status'] = (string)$activityTag->Status->StatusType->Description;
+ $resultArr['deliverydate'] = implode('-', $dateArr);
+ //YYYY-MM-DD
+ $resultArr['deliverytime'] = implode(':', $timeArr);
+ //HH:MM:SS
+ $resultArr['deliverylocation'] = (string)$activityTag->ActivityLocation->Description;
+ $resultArr['signedby'] = (string)$activityTag->ActivityLocation->SignedForByName;
+ if ($addressArr) {
+ $resultArr['deliveryto'] = implode(', ', $addressArr);
+ }
+ } else {
+ $tempArr = [];
+ $tempArr['activity'] = (string)$activityTag->Status->StatusType->Description;
+ $tempArr['deliverydate'] = implode('-', $dateArr);
+ //YYYY-MM-DD
+ $tempArr['deliverytime'] = implode(':', $timeArr);
+ //HH:MM:SS
+ if ($addressArr) {
+ $tempArr['deliverylocation'] = implode(', ', $addressArr);
+ }
+ $packageProgress[] = $tempArr;
+ }
+ $index++;
+ }
+
/**
* Get tracking response
*
@@ -1478,6 +1528,7 @@ protected function _sendShipmentAcceptRequest(Element $shipmentConfirmResponse)
$shippingLabelContent = (string)$response->ShipmentResults->PackageResults->LabelImage->GraphicImage;
$trackingNumber = (string)$response->ShipmentResults->PackageResults->TrackingNumber;
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
$result->setShippingLabelContent(base64_decode($shippingLabelContent));
$result->setTrackingNumber($trackingNumber);
}
diff --git a/app/code/Magento/Ups/Test/Mftf/Data/ShippingMethodsData.xml b/app/code/Magento/Ups/Test/Mftf/Data/ShippingMethodsData.xml
new file mode 100644
index 0000000000000..d4156d4f3358b
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Mftf/Data/ShippingMethodsData.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ ShippingMethodsUpsTypeDefault
+
+
+ true
+
+
diff --git a/app/code/Magento/Ups/Test/Mftf/Metadata/shipping_methods_ups_type_config-meta.xml b/app/code/Magento/Ups/Test/Mftf/Metadata/shipping_methods_ups_type_config-meta.xml
new file mode 100644
index 0000000000000..d642b7923282e
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Mftf/Metadata/shipping_methods_ups_type_config-meta.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+ boolean
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Mftf/Page/AdminShippingMethodsConfigPage.xml b/app/code/Magento/Ups/Test/Mftf/Page/AdminShippingMethodsConfigPage.xml
new file mode 100644
index 0000000000000..ebc44aace6dfb
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Mftf/Page/AdminShippingMethodsConfigPage.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Mftf/Section/AdminShippingMethodsUpsSection.xml b/app/code/Magento/Ups/Test/Mftf/Section/AdminShippingMethodsUpsSection.xml
new file mode 100644
index 0000000000000..4107f17dbc18c
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Mftf/Section/AdminShippingMethodsUpsSection.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/Test/Mftf/Test/DefaultConfigForUPSTypeTest.xml b/app/code/Magento/Ups/Test/Mftf/Test/DefaultConfigForUPSTypeTest.xml
new file mode 100644
index 0000000000000..51db704a7abc7
--- /dev/null
+++ b/app/code/Magento/Ups/Test/Mftf/Test/DefaultConfigForUPSTypeTest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Ups/etc/config.xml b/app/code/Magento/Ups/etc/config.xml
index 791b325c65e3f..73b10dd5ff41b 100644
--- a/app/code/Magento/Ups/etc/config.xml
+++ b/app/code/Magento/Ups/etc/config.xml
@@ -37,7 +37,7 @@
0
0
1
- UPS
+ UPS_XML
0
0
1
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..66eb3c9ba9f46
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ URL Rewrites
+ URL Rewrites
+ magento-urlrewrite-urlrewrite
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/MetaData/url_rewrite-meta.xml b/app/code/Magento/UrlRewrite/Test/Mftf/MetaData/url_rewrite-meta.xml
deleted file mode 100644
index 0738b17d6e0f0..0000000000000
--- a/app/code/Magento/UrlRewrite/Test/Mftf/MetaData/url_rewrite-meta.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
- integer
- integer
- string
- string
- string
-
-
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminMarketingUrlRewritesNavigateMenuTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminMarketingUrlRewritesNavigateMenuTest.xml
new file mode 100644
index 0000000000000..443307b427b42
--- /dev/null
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminMarketingUrlRewritesNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest.xml
index 7453b7b5a43f3..7e1b9acbc47ab 100644
--- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest.xml
+++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminUpdateCategoryUrlRewriteAndAddTemporaryRedirectTest.xml
@@ -10,7 +10,7 @@
-
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminClickSaveButtonOnUserFormActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminClickSaveButtonOnUserFormActionGroup.xml
new file mode 100644
index 0000000000000..e1edb16aba6ea
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminClickSaveButtonOnUserFormActionGroup.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml
index 303713132d2b0..5d51dcc610f78 100644
--- a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminCreateUserActionGroup.xml
@@ -39,7 +39,7 @@
-
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminFillForgotPasswordFormActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminFillForgotPasswordFormActionGroup.xml
new file mode 100644
index 0000000000000..01be51e72ec6d
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminFillForgotPasswordFormActionGroup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminFillNewUserFormRequiredFieldsActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminFillNewUserFormRequiredFieldsActionGroup.xml
new file mode 100644
index 0000000000000..87bf1e003931a
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminFillNewUserFormRequiredFieldsActionGroup.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminOpenForgotPasswordPageActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminOpenForgotPasswordPageActionGroup.xml
new file mode 100644
index 0000000000000..fa17c5a7f8b76
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminOpenForgotPasswordPageActionGroup.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminOpenNewUserPageActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminOpenNewUserPageActionGroup.xml
new file mode 100644
index 0000000000000..67aef9379faa8
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminOpenNewUserPageActionGroup.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AdminSubmitForgotPasswordFormActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminSubmitForgotPasswordFormActionGroup.xml
new file mode 100644
index 0000000000000..198bc713093ea
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AdminSubmitForgotPasswordFormActionGroup.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/ActionGroup/AssertAdminUserSaveMessageActionGroup.xml b/app/code/Magento/User/Test/Mftf/ActionGroup/AssertAdminUserSaveMessageActionGroup.xml
new file mode 100644
index 0000000000000..db4f0a89348a9
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/ActionGroup/AssertAdminUserSaveMessageActionGroup.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/User/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..e8b7d2aa8e047
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+ Users
+ All Users
+ magento-user-system-acl-users
+
+
+ Locked Users
+ Locked Users
+ magento-user-system-acl-locks
+
+
+ Encryption Key
+ Manage Encryption Key
+ magento-encryptionkey-system-crypt-key
+
+
+ Roles
+ User Roles
+ magento-user-system-acl-roles
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Data/UserData.xml b/app/code/Magento/User/Test/Mftf/Data/UserData.xml
index 80c1cc3022964..e665736ae28f1 100644
--- a/app/code/Magento/User/Test/Mftf/Data/UserData.xml
+++ b/app/code/Magento/User/Test/Mftf/Data/UserData.xml
@@ -8,6 +8,48 @@
+
+ {{_ENV.MAGENTO_ADMIN_USERNAME}}
+ {{_ENV.MAGENTO_ADMIN_PASSWORD}}
+
+
+ username_
+ password_
+
+
+ admin
+ John
+ Doe
+ admin@example.com
+ 123123q
+ 123123q
+ en_US
+ English (United States)
+ true
+ Active
+ {{_ENV.MAGENTO_ADMIN_PASSWORD}}
+ Administrators
+
+ - 1
+
+
+
+ admin
+ John
+ Doe
+ admin@example.com
+ 123123q
+ 123123q
+ en_US
+ English (United States)
+ true
+ Active
+ password_
+ Administrators
+
+ - 1
+
+
admin@magento.com
admin123
diff --git a/app/code/Magento/User/Test/Mftf/Page/AdminNewUserPage.xml b/app/code/Magento/User/Test/Mftf/Page/AdminNewUserPage.xml
new file mode 100644
index 0000000000000..6de0945793447
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Page/AdminNewUserPage.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Section/AdminNewUserFormSection.xml b/app/code/Magento/User/Test/Mftf/Section/AdminNewUserFormSection.xml
new file mode 100644
index 0000000000000..9b030b216ce2c
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Section/AdminNewUserFormSection.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Section/AdminUserFormMessagesSection.xml b/app/code/Magento/User/Test/Mftf/Section/AdminUserFormMessagesSection.xml
new file mode 100644
index 0000000000000..ec4f4d8bf3ad7
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Section/AdminUserFormMessagesSection.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml b/app/code/Magento/User/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml
new file mode 100644
index 0000000000000..4b48c65a18994
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Test/AdminResetUserPasswordFailedTest.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Test/AdminSystemAllUsersNavigateMenuTest.xml b/app/code/Magento/User/Test/Mftf/Test/AdminSystemAllUsersNavigateMenuTest.xml
new file mode 100644
index 0000000000000..b899320403d71
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Test/AdminSystemAllUsersNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Test/AdminSystemLockedUsersNavigateMenuTest.xml b/app/code/Magento/User/Test/Mftf/Test/AdminSystemLockedUsersNavigateMenuTest.xml
new file mode 100644
index 0000000000000..aea46f3273157
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Test/AdminSystemLockedUsersNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Test/AdminSystemManageEncryptionKeyNavigateMenuTest.xml b/app/code/Magento/User/Test/Mftf/Test/AdminSystemManageEncryptionKeyNavigateMenuTest.xml
new file mode 100644
index 0000000000000..f8013a54058c3
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Test/AdminSystemManageEncryptionKeyNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Test/AdminSystemUserRolesNavigateMenuTest.xml b/app/code/Magento/User/Test/Mftf/Test/AdminSystemUserRolesNavigateMenuTest.xml
new file mode 100644
index 0000000000000..c4052a7f4219c
--- /dev/null
+++ b/app/code/Magento/User/Test/Mftf/Test/AdminSystemUserRolesNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 a4bc9aa5ed48b..8289b3e730d5d 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
@@ -16,6 +16,7 @@
username
asc
+ true
diff --git a/app/code/Magento/Variable/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Variable/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..e094239767486
--- /dev/null
+++ b/app/code/Magento/Variable/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ Custom Variables
+ Custom Variables
+ magento-variable-system-variable
+
+
diff --git a/app/code/Magento/Variable/Test/Mftf/Test/AdminSystemCustomVariablesNavigateMenuTest.xml b/app/code/Magento/Variable/Test/Mftf/Test/AdminSystemCustomVariablesNavigateMenuTest.xml
new file mode 100644
index 0000000000000..74446cf601348
--- /dev/null
+++ b/app/code/Magento/Variable/Test/Mftf/Test/AdminSystemCustomVariablesNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php b/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php
index cc2af4996d562..32bae10c801c8 100644
--- a/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php
+++ b/app/code/Magento/Widget/Block/Adminhtml/Widget/Options.php
@@ -91,7 +91,7 @@ public function getMainFieldset()
if ($this->_getData('main_fieldset') instanceof \Magento\Framework\Data\Form\Element\Fieldset) {
return $this->_getData('main_fieldset');
}
- $mainFieldsetHtmlId = 'options_fieldset' . md5($this->getWidgetType());
+ $mainFieldsetHtmlId = 'options_fieldset' . hash('sha256', $this->getWidgetType());
$this->setMainFieldsetHtmlId($mainFieldsetHtmlId);
$fieldset = $this->getForm()->addFieldset(
$mainFieldsetHtmlId,
@@ -141,7 +141,6 @@ protected function _addField($parameter)
{
$form = $this->getForm();
$fieldset = $this->getMainFieldset();
- //$form->getElement('options_fieldset');
// prepare element data with values (either from request of from default values)
$fieldName = $parameter->getKey();
@@ -166,9 +165,13 @@ protected function _addField($parameter)
if (is_array($data['value'])) {
foreach ($data['value'] as &$value) {
- $value = html_entity_decode($value);
+ if (is_string($value)) {
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ $value = html_entity_decode($value);
+ }
}
} else {
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
$data['value'] = html_entity_decode($data['value']);
}
diff --git a/app/code/Magento/Widget/Model/Widget.php b/app/code/Magento/Widget/Model/Widget.php
index 52dc8e7837a3c..d07e84186b2c9 100644
--- a/app/code/Magento/Widget/Model/Widget.php
+++ b/app/code/Magento/Widget/Model/Widget.php
@@ -248,17 +248,13 @@ public function getWidgets($filters = [])
$result = $widgets;
// filter widgets by params
- if (is_array($filters) && count($filters) > 0) {
+ if (is_array($filters) && !empty($filters)) {
foreach ($widgets as $code => $widget) {
- try {
- foreach ($filters as $field => $value) {
- if (!isset($widget[$field]) || (string)$widget[$field] != $value) {
- throw new \Exception();
- }
+ foreach ($filters as $field => $value) {
+ if (!isset($widget[$field]) || (string)$widget[$field] != $value) {
+ unset($result[$code]);
+ break;
}
- } catch (\Exception $e) {
- unset($result[$code]);
- continue;
}
}
}
@@ -323,8 +319,6 @@ public function getWidgetDeclaration($type, $params = [], $asIs = true)
$directive .= $this->getWidgetPageVarName($params);
- $directive .= sprintf(' type_name="%s"', $widget['name']);
-
$directive .= '}}';
if ($asIs) {
diff --git a/app/code/Magento/Widget/Model/Widget/Config.php b/app/code/Magento/Widget/Model/Widget/Config.php
index 4f81ef33f47f7..00b055b35a69d 100644
--- a/app/code/Magento/Widget/Model/Widget/Config.php
+++ b/app/code/Magento/Widget/Model/Widget/Config.php
@@ -120,6 +120,7 @@ public function getWidgetPlaceholderImageUrls()
/**
* Return url to error image
+ *
* @return string
*/
public function getErrorImageUrl()
@@ -129,6 +130,7 @@ public function getErrorImageUrl()
/**
* Return url to wysiwyg plugin
+ *
* @return string
*/
public function getWysiwygJsPluginSrc()
@@ -157,7 +159,7 @@ public function getWidgetWindowUrl($config)
}
}
- if (count($skipped) > 0) {
+ if (!empty($skipped)) {
$params['skip_widgets'] = $this->encodeWidgetsToQuery($skipped);
}
return $this->_backendUrl->getUrl('adminhtml/widget/index', $params);
@@ -189,6 +191,8 @@ public function decodeWidgetsFromQuery($queryParam)
}
/**
+ * Get available widgets.
+ *
* @param \Magento\Framework\DataObject $config Editor element config
* @return array
*/
@@ -202,7 +206,7 @@ public function getAvailableWidgets($config)
if (is_array($skipped) && in_array($widget['type'], $skipped)) {
continue;
}
- $result[] = $widget['name']->getText();
+ $result[$widget['type']] = $widget['name']->getText();
}
}
diff --git a/app/code/Magento/Widget/Test/Mftf/Data/AdminMenuData.xml b/app/code/Magento/Widget/Test/Mftf/Data/AdminMenuData.xml
new file mode 100644
index 0000000000000..8fa652b8f73eb
--- /dev/null
+++ b/app/code/Magento/Widget/Test/Mftf/Data/AdminMenuData.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ Widgets
+ Widgets
+ magento-widget-cms-widget-instance
+
+
diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminContentWidgetsNavigateMenuTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminContentWidgetsNavigateMenuTest.xml
new file mode 100644
index 0000000000000..f5af024ec1d51
--- /dev/null
+++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminContentWidgetsNavigateMenuTest.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php
index 5c546d7e2435c..850a3fbe83211 100644
--- a/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php
+++ b/app/code/Magento/Widget/Test/Unit/Model/WidgetTest.php
@@ -224,7 +224,6 @@ public function testGetWidgetDeclaration()
$this->assertContains('title="my "widget""', $result);
$this->assertContains('conditions_encoded="encoded-conditions-string"', $result);
$this->assertContains('page_var_name="pasdf"', $result);
- $this->assertContains('type_name=""}}', $result);
}
/**
@@ -275,7 +274,6 @@ public function testGetWidgetDeclarationWithZeroValueParam()
);
$this->assertContains('{{widget type="Magento\CatalogWidget\Block\Product\ProductsList"', $result);
$this->assertContains('page_var_name="pasdf"', $result);
- $this->assertContains('type_name=""}}', $result);
$this->assertContains('products_count=""', $result);
}
}
diff --git a/app/code/Magento/Wishlist/Helper/Data.php b/app/code/Magento/Wishlist/Helper/Data.php
index 3b9f431566da0..3d25e16294fcd 100644
--- a/app/code/Magento/Wishlist/Helper/Data.php
+++ b/app/code/Magento/Wishlist/Helper/Data.php
@@ -13,6 +13,7 @@
*
* @author Magento Core Team
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*
* @api
* @since 100.0.2
@@ -171,7 +172,7 @@ public function setCustomer(\Magento\Customer\Api\Data\CustomerInterface $custom
public function getCustomer()
{
if (!$this->_currentCustomer && $this->_customerSession->isLoggedIn()) {
- $this->_currentCustomer = $this->_customerSession->getCustomerDataObject();
+ $this->_currentCustomer = $this->_customerSession->getCustomerData();
}
return $this->_currentCustomer;
}
@@ -355,7 +356,7 @@ public function getMoveFromCartParams($itemId)
*
* @param \Magento\Catalog\Model\Product|\Magento\Wishlist\Model\Item $item
*
- * @return string|false
+ * @return string|false
*/
public function getUpdateParams($item)
{
@@ -382,7 +383,7 @@ public function getUpdateParams($item)
* Retrieve params for adding item to shopping cart
*
* @param string|\Magento\Catalog\Model\Product|\Magento\Wishlist\Model\Item $item
- * @return string
+ * @return string
*/
public function getAddToCartUrl($item)
{
@@ -428,7 +429,7 @@ public function addRefererToParams(array $params)
* Retrieve URL for adding item to shopping cart from shared wishlist
*
* @param string|\Magento\Catalog\Model\Product|\Magento\Wishlist\Model\Item $item
- * @return string
+ * @return string
*/
public function getSharedAddToCartUrl($item)
{
diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml
index 6cb32d70ee1d8..f296b950f3abb 100644
--- a/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml
+++ b/app/code/Magento/Wishlist/view/frontend/templates/item/column/cart.phtml
@@ -25,7 +25,7 @@ $allowedQty = $viewModel->setItem($item)->getMinMaxQty();
= $block->escapeHtml(__('Qty')) ?>
+ name="qty[= $block->escapeHtmlAttr($item->getId()) ?>]" value="= /* @noEscape */ (int)($block->getAddToCartQty($item) * 1) ?>" = $product->isSaleable() ? '' : 'disabled="disabled"' ?>>
diff --git a/app/code/Magento/Wishlist/view/frontend/templates/item/column/comment.phtml b/app/code/Magento/Wishlist/view/frontend/templates/item/column/comment.phtml
index 17e2404ee23cf..5ab5bc5422e7e 100644
--- a/app/code/Magento/Wishlist/view/frontend/templates/item/column/comment.phtml
+++ b/app/code/Magento/Wishlist/view/frontend/templates/item/column/comment.phtml
@@ -17,6 +17,6 @@ $item = $block->getItem();
= $block->escapeHtml(__('Comment')) ?>
-
+
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
index 5698afdaac7ae..66c9086c15aa7 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less
@@ -81,7 +81,7 @@
min-width: 0;
padding: 0;
- // Filedset section
+ // Fieldset section
.fieldset-wrapper {
&.admin__fieldset-section {
> .fieldset-wrapper-title {
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less
index 5d9bf80ce2255..71f57b765ff0e 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/_temp.less
@@ -470,8 +470,6 @@ label.mage-error {
}
.admin__data-grid-header-row {
- &:extend(.abs-cleafix);
-
.action-select-multiselect {
-webkit-appearance: menulist-button;
appearance: menulist-button;
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less
old mode 100644
new mode 100755
index 8184a5c4bb248..befd27fa57df6
--- a/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/forms/fields/_field-tooltips.less
@@ -22,7 +22,7 @@
@field-tooltip-content__width: 32rem;
@field-tooltip-content__z-index: 1;
-@field-tooltip-action__margin-left: 2rem;
+@field-tooltip-action__margin-left: 0;
//
// Form Fields
diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less
index d3b314836ae8e..299c138832064 100644
--- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less
+++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/_module.less
@@ -507,17 +507,6 @@
min-height: inherit;
}
}
-
- //
- // Category page 1 column layout
- // ---------------------------------------------
-
- .catalog-category-view.page-layout-1column {
- .column.main {
- min-height: inherit;
- }
- }
-
}
//
diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less
index 664726ddfd798..423923d5e6457 100644
--- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less
+++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_tooltip.less
@@ -55,6 +55,10 @@
}
}
+ .label {
+ .lib-visually-hidden();
+ }
+
.field-tooltip-action {
.lib-icon-font(
@checkout-tooltip-icon__content,
@@ -173,10 +177,10 @@
width: 0;
}
.field-tooltip .field-tooltip-content::before {
- border-bottom-color: @color-gray40;
+ .lib-css(border-bottom-color, @checkout-tooltip-content__border-color);
}
.field-tooltip .field-tooltip-content::after {
- border-bottom-color: @color-gray-light01;
+ .lib-css(border-bottom-color, @checkout-tooltip-content__background-color);
top: 1px;
}
}
diff --git a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less
index 215d7d8b322b4..b189d4e08ba17 100644
--- a/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less
+++ b/app/design/frontend/Magento/blank/Magento_Sales/web/css/source/_email.less
@@ -68,8 +68,10 @@
}
// Remove address and phone number link color on iOS
-.address-details a {
- &:extend(.no-link a);
+.email-non-inline() {
+ .address-details a {
+ &:extend(.no-link a);
+ }
}
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__xs) {
diff --git a/app/design/frontend/Magento/blank/web/css/source/_forms.less b/app/design/frontend/Magento/blank/web/css/source/_forms.less
index c9f3c3d72ef4c..26f5ff89e99e3 100644
--- a/app/design/frontend/Magento/blank/web/css/source/_forms.less
+++ b/app/design/frontend/Magento/blank/web/css/source/_forms.less
@@ -101,6 +101,18 @@
.lib-form-validation-note();
}
+ .product-options-wrapper {
+ .date {
+ &.required {
+ div[for*='options'] {
+ &.mage-error {
+ display: none !important;
+ }
+ }
+ }
+ }
+ }
+
.field .tooltip {
.lib-tooltip(right);
.tooltip-content {
diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less
index e5915969c91b9..77fb53a2ab02a 100644
--- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less
+++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less
@@ -34,12 +34,12 @@
.product {
&-items {
- font-size: 0;
+ .lib-inline-block-space-container();
&:extend(.abs-reset-list all);
}
&-item {
- font-size: 1.4rem;
+ .lib-inline-block-space-item();
vertical-align: top;
.products-grid & {
diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less
index 3ea1f5b7f6842..ac5ab0d87bf62 100644
--- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less
+++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_checkout.less
@@ -7,6 +7,8 @@
// Variables
// _____________________________________________
+@import 'fields/_file-uploader.less';
+
@checkout-wrapper__margin: @indent__base;
@checkout-wrapper__columns: 16;
diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/fields/_file-uploader.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/fields/_file-uploader.less
new file mode 100644
index 0000000000000..7b06186ef9ad3
--- /dev/null
+++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/fields/_file-uploader.less
@@ -0,0 +1,450 @@
+// /**
+// * Copyright © Magento, Inc. All rights reserved.
+// * See COPYING.txt for license details.
+// */
+
+//
+// Components -> Single File Uploader
+// _____________________________________________
+
+//
+// Variables
+// ---------------------------------------------
+
+@icon-delete__content: '\e604';
+@icon-file__content: '\e626';
+
+
+@file-uploader-preview__border-color: @color-lighter-grayish;
+@file-uploader-preview__background-color: @color-white;
+@file-uploader-preview-focus__color: @color-blue2;
+
+@file-uploader-document-icon__color: @color-gray80;
+@file-uploader-document-icon__size: 7rem;
+@file-uploader-document-icon__z-index: @data-grid-file-uploader-image__z-index + 1;
+
+@file-uploader-video-icon__color: @color-gray80;
+@file-uploader-video-icon__size: 4rem;
+@file-uploader-video-icon__z-index: @data-grid-file-uploader-image__z-index + 1;
+
+@file-uploader-placeholder-icon__color: @color-gray80;
+@file-uploader-placeholder-icon__z-index: @data-grid-file-uploader-image__z-index + 1;
+
+@file-uploader-delete-icon__color: @color-brownie;
+@file-uploader-delete-icon__hover__color: @color-brownie-vanilla;
+@file-uploader-delete-icon__font-size: 1.6rem;
+
+@file-uploader-muted-text__color: @color-gray62;
+
+@file-uploader-preview__width: 150px;
+@file-uploader-preview__height: @file-uploader-preview__width;
+@file-uploader-preview__opacity: .7;
+
+@file-uploader-spinner-dimensions: 15px;
+
+@file-uploader-dragover__background: @color-gray83;
+@file-uploader-dragover-focus__color: @color-blue2;
+
+// Grid uploader
+
+@data-grid-file-uploader-image__size: 5rem;
+@data-grid-file-uploader-image__z-index: 1;
+
+@data-grid-file-uploader-menu-button__width: 2rem;
+
+@data-grid-file-uploader-upload-icon__color: @color-darkie-gray;
+@data-grid-file-uploader-upload-icon__hover__color: @color-very-dark-gray;
+@data-grid-file-uploader-upload-icon__line-height: 48px;
+
+@data-grid-file-uploader-wrapper__size: @data-grid-file-uploader-image__size + 2rem;
+
+//
+// Single file uploader
+// ---------------------------------------------
+
+.file-uploader-area {
+ position: relative;
+
+ input[type='file'] {
+ cursor: pointer;
+ opacity: 0;
+ overflow: hidden;
+ position: absolute;
+ visibility: hidden;
+ width: 0;
+
+ &:focus {
+ + .file-uploader-button {
+ box-shadow: 0 0 0 1px @file-uploader-preview-focus__color;
+ }
+ }
+
+ &:disabled {
+ + .file-uploader-button {
+ cursor: default;
+ opacity: .5;
+ pointer-events: none;
+ }
+ }
+ }
+}
+
+.file-uploader-summary {
+ display: inline-block;
+ vertical-align: top;
+}
+
+.file-uploader-button {
+ background: @color-gray-darken0;
+ border: 1px solid @color-gray_light;
+ box-sizing: border-box;
+ color: @color-black_dark;
+ cursor: pointer;
+ display: inline-block;
+ font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-size: 1.4rem;
+ font-weight: 600;
+ line-height: 1.6rem;
+ margin: 0;
+ padding: 7px 15px;
+ vertical-align: middle;
+
+ &._is-dragover {
+ background: @file-uploader-dragover__background;
+ border: 1px solid @file-uploader-preview-focus__color;
+ }
+}
+
+.file-uploader-spinner {
+ background-image: url('@{baseDir}images/loader-1.gif');
+ background-position: 50%;
+ background-repeat: no-repeat;
+ background-size: @file-uploader-spinner-dimensions;
+ display: none;
+ height: 30px;
+ margin-left: @indent__s;
+ vertical-align: top;
+ width: @file-uploader-spinner-dimensions;
+}
+
+.file-uploader-preview {
+ .action-remove {
+ &:extend(.abs-action-reset all);
+ .lib-icon-font (
+ @icon-delete__content,
+ @_icon-font: @icons__font-name,
+ @_icon-font-size: @file-uploader-delete-icon__font-size,
+ @_icon-font-color: @file-uploader-delete-icon__color,
+ @_icon-font-color-hover: @file-uploader-delete-icon__hover__color,
+ @_icon-font-text-hide: true,
+ @_icon-font-display: block
+ );
+ bottom: 4px;
+ cursor: pointer;
+ display: block;
+ height: 27px;
+ left: 6px;
+ padding: 2px;
+ position: absolute;
+ text-decoration: none;
+ width: 25px;
+ z-index: 2;
+ }
+
+ &:hover {
+ .preview-image img,
+ .preview-link:before {
+ opacity: @file-uploader-preview__opacity;
+ }
+ }
+
+ .preview-link {
+ display: block;
+ height: 100%;
+ }
+
+ .preview-image img {
+ bottom: 0;
+ left: 0;
+ margin: auto;
+ max-height: 100%;
+ max-width: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: 1;
+ }
+
+ .preview-video {
+ .lib-icon-font(
+ @icon-file__content,
+ @_icon-font: @icons__font-name,
+ @_icon-font-size: @file-uploader-video-icon__size,
+ @_icon-font-color: @file-uploader-video-icon__color,
+ @_icon-font-color-hover: @file-uploader-video-icon__color
+ );
+
+ &:before {
+ left: 0;
+ margin-top: -@file-uploader-video-icon__size / 2;
+ position: absolute;
+ right: 0;
+ top: 50%;
+ z-index: @file-uploader-video-icon__z-index;
+ }
+ }
+
+ .preview-document {
+ .lib-icon-font(
+ @icon-file__content,
+ @_icon-font: @icons__font-name,
+ @_icon-font-size: @file-uploader-document-icon__size,
+ @_icon-font-color: @file-uploader-document-icon__color,
+ @_icon-font-color-hover: @file-uploader-document-icon__color
+ );
+
+ &:before {
+ left: 0;
+ margin-top: -@file-uploader-document-icon__size / 2;
+ position: absolute;
+ right: 0;
+ top: 50%;
+ z-index: @file-uploader-document-icon__z-index;
+ }
+ }
+}
+
+.file-uploader-preview,
+.file-uploader-placeholder {
+ background: @file-uploader-preview__background-color;
+ border: 1px solid @file-uploader-preview__border-color;
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ height: @file-uploader-preview__height;
+ line-height: 1;
+ margin: @indent__s @indent__m @indent__s 0;
+ overflow: hidden;
+ position: relative;
+ width: @file-uploader-preview__width;
+}
+
+.file-uploader {
+ &._loading {
+ .file-uploader-spinner {
+ display: inline-block;
+ }
+ }
+
+ .admin__field-note,
+ .admin__field-error {
+ margin-bottom: @indent__s;
+ }
+
+ .file-uploader-filename {
+ .lib-text-overflow();
+ max-width: @file-uploader-preview__width;
+ word-break: break-all;
+
+ &:first-child {
+ margin-bottom: @indent__s;
+ }
+ }
+
+ .file-uploader-meta {
+ color: @file-uploader-muted-text__color;
+ }
+
+ .admin__field-fallback-reset {
+ margin-left: @indent__s;
+ }
+
+ ._keyfocus & .action-remove {
+ &:focus {
+ box-shadow: 0 0 0 1px @file-uploader-preview-focus__color;
+ }
+ }
+}
+
+// Placeholder for multiple uploader
+.file-uploader-placeholder {
+ &.placeholder-document {
+ .lib-icon-font(
+ @icon-file__content,
+ @_icon-font: @icons__font-name,
+ @_icon-font-size: 5rem,
+ @_icon-font-color: @file-uploader-placeholder-icon__color,
+ @_icon-font-color-hover: @file-uploader-placeholder-icon__color
+ );
+
+ &:before {
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 20px;
+ z-index: @file-uploader-placeholder-icon__z-index;
+ }
+ }
+
+ &.placeholder-image {
+ .lib-icon-font(
+ @icon-file__content,
+ @_icon-font: @icons__font-name,
+ @_icon-font-size: 5rem,
+ @_icon-font-color: @file-uploader-placeholder-icon__color,
+ @_icon-font-color-hover: @file-uploader-placeholder-icon__color
+ );
+
+ &:before {
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 20px;
+ z-index: @file-uploader-placeholder-icon__z-index;
+ }
+ }
+
+ &.placeholder-video {
+ .lib-icon-font(
+ @icon-file__content,
+ @_icon-font: @icons__font-name,
+ @_icon-font-size: 3rem,
+ @_icon-font-color: @file-uploader-placeholder-icon__color,
+ @_icon-font-color-hover: @file-uploader-placeholder-icon__color
+ );
+
+ &:before {
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 30px;
+ z-index: @file-uploader-placeholder-icon__z-index;
+ }
+ }
+}
+
+.file-uploader-placeholder-text {
+ bottom: 0;
+ color: @color-blue-dodger;
+ font-size: 1.1rem;
+ left: 0;
+ line-height: @line-height__base;
+ margin-bottom: 15%;
+ padding: 0 @indent__base;
+ position: absolute;
+ right: 0;
+ text-align: center;
+}
+
+//
+// Grid image uploader
+// ---------------------------------------------
+
+.data-grid-file-uploader {
+ min-width: @data-grid-file-uploader-wrapper__size;
+
+ &._loading {
+ .file-uploader-spinner {
+ display: block;
+ }
+
+ .file-uploader-button {
+ &:before {
+ display: none;
+ }
+ }
+ }
+
+ .file-uploader-image {
+ background: transparent;
+ bottom: 0;
+ left: 0;
+ margin: auto;
+ max-height: 100%;
+ max-width: 100%;
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: @data-grid-file-uploader-image__z-index;
+
+ + .file-uploader-area {
+ .file-uploader-button {
+ &:before {
+ display: none;
+ }
+ }
+ }
+ }
+
+ .file-uploader-area {
+ z-index: @data-grid-file-uploader-image__z-index + 1;
+ }
+
+ .file-uploader-spinner {
+ height: 100%;
+ margin: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ }
+
+ .file-uploader-button {
+ display: block;
+ height: @data-grid-file-uploader-upload-icon__line-height;
+ text-align: center;
+
+ .lib-icon-font (
+ @icon-file__content,
+ @_icon-font: @icons__font-name,
+ @_icon-font-size: 1.3rem,
+ @_icon-font-line-height: @data-grid-file-uploader-upload-icon__line-height,
+ @_icon-font-color: @data-grid-file-uploader-upload-icon__color,
+ @_icon-font-color-hover: @data-grid-file-uploader-upload-icon__hover__color,
+ @_icon-font-text-hide: true,
+ @_icon-font-display: block
+ );
+ }
+
+ .action-select-wrap {
+ float: left;
+
+ .action-select {
+ border: 1px solid @file-uploader-preview__border-color;
+ display: block;
+ height: @data-grid-file-uploader-image__size;
+ margin-left: -1px;
+ padding: 0;
+ width: @data-grid-file-uploader-menu-button__width;
+
+ &:after {
+ border-color: @data-grid-file-uploader-upload-icon__color transparent transparent transparent;
+ left: 50%;
+ margin: 0 0 0 -5px;
+ }
+
+ &:hover {
+ &:after {
+ border-color: @data-grid-file-uploader-upload-icon__hover__color transparent transparent transparent;
+ }
+ }
+
+ > span {
+ display: none;
+ }
+ }
+
+ .action-menu {
+ left: 4rem;
+ right: auto;
+ z-index: @data-grid-file-uploader-image__z-index + 1;
+ }
+ }
+}
+
+.data-grid-file-uploader-inner {
+ border: 1px solid @file-uploader-preview__border-color;
+ float: left;
+ height: @data-grid-file-uploader-image__size;
+ position: relative;
+ width: @data-grid-file-uploader-image__size;
+}
diff --git a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less
index 3f19d1020bab9..31c128e07e3a6 100644
--- a/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less
+++ b/app/design/frontend/Magento/luma/Magento_Sales/web/css/source/_email.less
@@ -76,8 +76,10 @@
}
// Remove address and phone number link color on iOS
-.address-details a {
- &:extend(.no-link a);
+.email-non-inline() {
+ .address-details a {
+ &:extend(.no-link a);
+ }
}
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__xs) {
diff --git a/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml b/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml
index 2dfb1d3ee6bf0..7e64e5f3f01cd 100644
--- a/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml
+++ b/app/design/frontend/Magento/luma/Magento_Theme/layout/default_head_blocks.xml
@@ -7,6 +7,6 @@
-->
-
+
diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less
index 1f1ea93d0b54a..dfcc51e0a0a26 100644
--- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less
+++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less
@@ -112,6 +112,10 @@
font-size: @font-size__base;
margin: 0 0 0 15px;
+ &.customer-welcome {
+ margin: 0 0 0 5px;
+ }
+
> a {
.lib-link(
@_link-color: @header-panel__text-color,
diff --git a/app/design/frontend/Magento/luma/web/css/source/_forms.less b/app/design/frontend/Magento/luma/web/css/source/_forms.less
index 98dd57dead74c..8533318a12d1b 100644
--- a/app/design/frontend/Magento/luma/web/css/source/_forms.less
+++ b/app/design/frontend/Magento/luma/web/css/source/_forms.less
@@ -104,6 +104,10 @@
.select-styling();
}
+ select.admin__control-multiselect {
+ height: auto;
+ }
+
.field-error,
div.mage-error[generated] {
margin-top: 7px;
@@ -113,6 +117,18 @@
.lib-form-validation-note();
}
+ .product-options-wrapper {
+ .date {
+ &.required {
+ div[for*='options'] {
+ &.mage-error {
+ display: none !important;
+ }
+ }
+ }
+ }
+ }
+
// TEMP
.field .tooltip {
diff --git a/app/etc/di.xml b/app/etc/di.xml
index d0b45ea16c855..476285878650b 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -210,6 +210,7 @@
+
@@ -1739,7 +1740,7 @@
- \Magento\Framework\App\Action\HttpOptionsActionInterface
- \Magento\Framework\App\Action\HttpGetActionInterface
- - \Magento\Framework\App\Action\HttpHeadActionInterface
+ - \Magento\Framework\App\Action\HttpGetActionInterface
- \Magento\Framework\App\Action\HttpPostActionInterface
- \Magento\Framework\App\Action\HttpPutActionInterface
- \Magento\Framework\App\Action\HttpPatchActionInterface
diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml
index 3bd64a7aff728..8254a9d8e92cf 100644
--- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml
+++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/extension_attributes.xml
@@ -31,4 +31,16 @@
+
+
+
+ firstname
+ lastname
+ email
+
+
+
diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php
index add0510c6b40c..e18a8c8e97c79 100644
--- a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php
+++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQl/Client.php
@@ -51,7 +51,7 @@ public function __construct(
* @return array|string|int|float|bool
* @throws \Exception
*/
- public function postQuery(string $query, array $variables = [], string $operationName = '', array $headers = [])
+ public function post(string $query, array $variables = [], string $operationName = '', array $headers = [])
{
$url = $this->getEndpointUrl();
$headers = array_merge($headers, ['Accept: application/json', 'Content-Type: application/json']);
@@ -63,19 +63,57 @@ public function postQuery(string $query, array $variables = [], string $operatio
$postData = $this->json->jsonEncode($requestArray);
$responseBody = $this->curlClient->post($url, $postData, $headers);
- $responseBodyArray = $this->json->jsonDecode($responseBody);
+ return $this->processResponse($responseBody);
+ }
+
+ /**
+ * Perform HTTP GET request for query
+ *
+ * @param string $query
+ * @param array $variables
+ * @param string $operationName
+ * @param array $headers
+ * @return mixed
+ * @throws \Exception
+ */
+ public function get(string $query, array $variables = [], string $operationName = '', array $headers = [])
+ {
+ $url = $this->getEndpointUrl();
+ $requestArray = [
+ 'query' => $query,
+ 'variables' => $variables ? $this->json->jsonEncode($variables) : null,
+ 'operationName' => $operationName ?? null
+ ];
+ array_filter($requestArray);
+
+ $responseBody = $this->curlClient->get($url, $requestArray, $headers);
+ return $this->processResponse($responseBody);
+ }
+
+ /**
+ * Process response from GraphQl server
+ *
+ * @param string $response
+ * @return mixed
+ * @throws \Exception
+ */
+ private function processResponse(string $response)
+ {
+ $responseArray = $this->json->jsonDecode($response);
- if (!is_array($responseBodyArray)) {
- throw new \Exception('Unknown GraphQL response body: ' . json_encode($responseBodyArray));
+ if (!is_array($responseArray)) {
+ //phpcs:ignore Magento2.Exceptions.DirectThrow
+ throw new \Exception('Unknown GraphQL response body: ' . $response);
}
- $this->processErrors($responseBodyArray);
+ $this->processErrors($responseArray);
- if (!isset($responseBodyArray['data'])) {
- throw new \Exception('Unknown GraphQL response body: ' . json_encode($responseBodyArray));
- } else {
- return $responseBodyArray['data'];
+ if (!isset($responseArray['data'])) {
+ //phpcs:ignore Magento2.Exceptions.DirectThrow
+ throw new \Exception('Unknown GraphQL response body: ' . $response);
}
+
+ return $responseArray['data'];
}
/**
@@ -107,6 +145,7 @@ private function processErrors($responseBodyArray)
$responseBodyArray
);
}
+ //phpcs:ignore Magento2.Exceptions.DirectThrow
throw new \Exception('GraphQL responded with an unknown error: ' . json_encode($responseBodyArray));
}
}
diff --git a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php
index 790581c476da1..8abd97b4b744d 100644
--- a/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php
+++ b/dev/tests/api-functional/framework/Magento/TestFramework/TestCase/GraphQlAbstract.php
@@ -6,6 +6,7 @@
namespace Magento\TestFramework\TestCase;
use Magento\TestFramework\Helper\Bootstrap;
+use Magento\Framework\App\Request\Http;
/**
* Test case for Web API functional tests for Graphql.
@@ -27,7 +28,7 @@ abstract class GraphQlAbstract extends WebapiAbstract
private $appCache;
/**
- * Perform GraphQL call to the system under test.
+ * Perform GraphQL query call via GET to the system under test.
*
* @see \Magento\TestFramework\TestCase\GraphQl\Client::call()
* @param string $query
@@ -43,7 +44,32 @@ public function graphQlQuery(
string $operationName = '',
array $headers = []
) {
- return $this->getGraphQlClient()->postQuery(
+ return $this->getGraphQlClient()->get(
+ $query,
+ $variables,
+ $operationName,
+ $this->composeHeaders($headers)
+ );
+ }
+
+ /**
+ * Perform GraphQL mutations call via POST to the system under test.
+ *
+ * @see \Magento\TestFramework\TestCase\GraphQl\Client::call()
+ * @param string $query
+ * @param array $variables
+ * @param string $operationName
+ * @param array $headers
+ * @return array|int|string|float|bool GraphQL call results
+ * @throws \Exception
+ */
+ public function graphQlMutation(
+ string $query,
+ array $variables = [],
+ string $operationName = '',
+ array $headers = []
+ ) {
+ return $this->getGraphQlClient()->post(
$query,
$variables,
$operationName,
diff --git a/dev/tests/api-functional/testsuite/Magento/Analytics/Api/LinkProviderTest.php b/dev/tests/api-functional/testsuite/Magento/Analytics/Api/LinkProviderTest.php
index 6fd7551676660..4bf1335f20667 100644
--- a/dev/tests/api-functional/testsuite/Magento/Analytics/Api/LinkProviderTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Analytics/Api/LinkProviderTest.php
@@ -95,6 +95,6 @@ public function testGetAll()
*/
private function isTestBaseUrlSecure()
{
- return strpos('https://', TESTS_BASE_URL) !== false;
+ return strpos(TESTS_BASE_URL, 'https://') !== false;
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/ProductRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/ProductRepositoryTest.php
index 4608b255459b6..769abadf20585 100644
--- a/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/ProductRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/ProductRepositoryTest.php
@@ -51,11 +51,13 @@ protected function getLinkData()
'link_type' => 'file',
'link_file_content' => [
'name' => 'link1_content.jpg',
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
'sample_type' => 'file',
'sample_file_content' => [
'name' => 'link1_sample.jpg',
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
],
@@ -114,6 +116,7 @@ protected function getSampleData()
'sample_type' => 'file',
'sample_file_content' => [
'name' => 'sample2.jpg',
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
],
@@ -146,7 +149,9 @@ protected function createDownloadableProduct()
"price" => 10,
'attribute_set_id' => 4,
"extension_attributes" => [
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
"downloadable_product_links" => array_values($this->getLinkData()),
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
"downloadable_product_samples" => array_values($this->getSampleData()),
],
];
@@ -301,11 +306,13 @@ public function testUpdateDownloadableProductLinksWithNewFile()
'link_type' => 'file',
'link_file_content' => [
'name' => $linkFile . $extension,
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
'sample_type' => 'file',
'sample_file_content' => [
'name' => $sampleFile . $extension,
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
];
@@ -319,11 +326,13 @@ public function testUpdateDownloadableProductLinksWithNewFile()
'link_type' => 'file',
'link_file_content' => [
'name' => 'link2_content.jpg',
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
'sample_type' => 'file',
'sample_file_content' => [
'name' => 'link2_sample.jpg',
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
];
@@ -463,6 +472,7 @@ public function testUpdateDownloadableProductSamplesWithNewFile()
'sample_type' => 'file',
'sample_file_content' => [
'name' => 'sample1.jpg',
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
'file_data' => base64_encode(file_get_contents($this->testImagePath)),
],
];
@@ -472,6 +482,11 @@ public function testUpdateDownloadableProductSamplesWithNewFile()
'title' => 'sample2_updated',
'sort_order' => 2,
'sample_type' => 'file',
+ 'sample_file_content' => [
+ 'name' => 'sample2.jpg',
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+ ],
];
$response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"] =
@@ -606,7 +621,7 @@ protected function deleteProductBySku($productSku)
protected function saveProduct($product)
{
if (isset($product['custom_attributes'])) {
- for ($i=0; $iquoteResource = $objectManager->get(QuoteResource::class);
- $this->quoteFactory = $objectManager->get(QuoteFactory::class);
- $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
}
/**
@@ -51,11 +40,10 @@ public function testAddProductIfQuantityIsNotAvailable()
{
$sku = 'simple';
$qty = 200;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
- $maskedQuoteId = $this->getMaskedQuoteId();
- $query = $this->getAddSimpleProductQuery($maskedQuoteId, $sku, $qty);
- $this->graphQlQuery($query);
- self::fail('Should be "The requested qty is not available" error message.');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query);
}
/**
@@ -71,22 +59,26 @@ public function testAddMoreProductsThatAllowed()
$sku = 'custom-design-simple-product';
$qty = 7;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
- $maskedQuoteId = $this->getMaskedQuoteId();
- $query = $this->getAddSimpleProductQuery($maskedQuoteId, $sku, $qty);
- $this->graphQlQuery($query);
- self::fail('Should be "The most you may purchase is 5." error message.');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query);
}
/**
- * @return string
+ * @magentoApiDataFixture Magento/Catalog/_files/products.php
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage Please enter a number greater than 0 in this field.
*/
- public function getMaskedQuoteId() : string
+ public function testAddSimpleProductToCartWithNegativeQty()
{
- $quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id');
+ $sku = 'simple';
+ $qty = -2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
- return $this->quoteIdToMaskedId->execute((int)$quote->getId());
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query);
}
/**
@@ -95,7 +87,7 @@ public function getMaskedQuoteId() : string
* @param int $qty
* @return string
*/
- public function getAddSimpleProductQuery(string $maskedQuoteId, string $sku, int $qty) : string
+ private function getQuery(string $maskedQuoteId, string $sku, int $qty) : string
{
return <<quoteResource = $objectManager->get(QuoteResource::class);
- $this->quote = $objectManager->create(Quote::class);
- $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
}
/**
@@ -49,12 +38,11 @@ public function testAddConfigurableProductToCart()
{
$variantSku = 'simple_41';
$qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
- $maskedQuoteId = $this->getMaskedQuoteId();
-
- $query = $this->getAddConfigurableProductMutationQuery($maskedQuoteId, $variantSku, $qty);
+ $query = $this->getQuery($maskedQuoteId, $variantSku, $qty);
+ $response = $this->graphQlMutation($query);
- $response = $this->graphQlQuery($query);
$cartItems = $response['addConfigurableProductsToCart']['cart']['items'];
self::assertEquals($qty, $cartItems[0]['qty']);
self::assertEquals($variantSku, $cartItems[0]['product']['sku']);
@@ -70,11 +58,10 @@ public function testAddProductIfQuantityIsNotAvailable()
{
$variantSku = 'simple_41';
$qty = 200;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
- $maskedQuoteId = $this->getMaskedQuoteId();
- $query = $this->getAddConfigurableProductMutationQuery($maskedQuoteId, $variantSku, $qty);
-
- $this->graphQlQuery($query);
+ $query = $this->getQuery($maskedQuoteId, $variantSku, $qty);
+ $this->graphQlMutation($query);
}
/**
@@ -87,35 +74,19 @@ public function testAddOutOfStockProduct()
{
$variantSku = 'simple_1010';
$qty = 1;
- $maskedQuoteId = $this->getMaskedQuoteId();
- $query = $this->getAddConfigurableProductMutationQuery($maskedQuoteId, $variantSku, $qty);
-
- $this->graphQlQuery($query);
- }
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
- * @return string
- * @throws \Magento\Framework\Exception\NoSuchEntityException
- */
- private function getMaskedQuoteId()
- {
- $this->quoteResource->load(
- $this->quote,
- 'test_order_1',
- 'reserved_order_id'
- );
- return $this->quoteIdToMaskedId->execute((int)$this->quote->getId());
+ $query = $this->getQuery($maskedQuoteId, $variantSku, $qty);
+ $this->graphQlMutation($query);
}
/**
* @param string $maskedQuoteId
- * @param string $sku
+ * @param string $variantSku
* @param int $qty
- *
* @return string
*/
- private function getAddConfigurableProductMutationQuery(string $maskedQuoteId, string $variantSku, int $qty): string
+ private function getQuery(string $maskedQuoteId, string $variantSku, int $qty): string
{
return <<getChangePassQuery($oldCustomerPassword, $newCustomerPassword);
$headerMap = $this->getCustomerAuthHeaders($customerEmail, $oldCustomerPassword);
- $response = $this->graphQlQuery($query, [], '', $headerMap);
+ $response = $this->graphQlMutation($query, [], '', $headerMap);
$this->assertEquals($customerEmail, $response['changeCustomerPassword']['email']);
try {
@@ -69,7 +72,7 @@ public function testChangePassword()
public function testChangePasswordIfUserIsNotAuthorizedTest()
{
$query = $this->getChangePassQuery('currentpassword', 'newpassword');
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -87,7 +90,7 @@ public function testChangeWeakPassword()
$this->expectException(\Exception::class);
$this->expectExceptionMessageRegExp('/Minimum of different classes of characters in password is.*/');
- $this->graphQlQuery($query, [], '', $headerMap);
+ $this->graphQlMutation($query, [], '', $headerMap);
}
/**
@@ -105,7 +108,7 @@ public function testChangePasswordIfPasswordIsInvalid()
$query = $this->getChangePassQuery($incorrectPassword, $newCustomerPassword);
$headerMap = $this->getCustomerAuthHeaders($customerEmail, $oldCustomerPassword);
- $this->graphQlQuery($query, [], '', $headerMap);
+ $this->graphQlMutation($query, [], '', $headerMap);
}
private function getChangePassQuery($currentPassword, $newPassword)
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php
index 602d969924fbd..891c74ca3c1e2 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerAddressTest.php
@@ -13,6 +13,9 @@
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\Integration\Api\CustomerTokenServiceInterface;
+/**
+ * Create customer address tests
+ */
class CreateCustomerAddressTest extends GraphQlAbstract
{
/**
@@ -117,7 +120,7 @@ public function testCreateCustomerAddress()
$userName = 'customer@example.com';
$password = 'password';
- $response = $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $response = $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
$this->assertArrayHasKey('createCustomerAddress', $response);
$this->assertArrayHasKey('customer_id', $response['createCustomerAddress']);
$this->assertEquals($customerId, $response['createCustomerAddress']['customer_id']);
@@ -158,7 +161,7 @@ public function testCreateCustomerAddressIfUserIsNotAuthorized()
}
}
MUTATION;
- $this->graphQlQuery($mutation);
+ $this->graphQlMutation($mutation);
}
/**
@@ -195,7 +198,73 @@ public function testCreateCustomerAddressWithMissingAttribute()
$userName = 'customer@example.com';
$password = 'password';
- $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer_without_addresses.php
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
+ public function testCreateCustomerAddressWithRedundantStreetLine()
+ {
+ $newAddress = [
+ 'region' => [
+ 'region' => 'Arizona',
+ 'region_id' => 4,
+ 'region_code' => 'AZ'
+ ],
+ 'country_id' => 'US',
+ 'street' => ['Line 1 Street', 'Line 2', 'Line 3'],
+ 'company' => 'Company name',
+ 'telephone' => '123456789',
+ 'fax' => '123123123',
+ 'postcode' => '7777',
+ 'city' => 'City Name',
+ 'firstname' => 'Adam',
+ 'lastname' => 'Phillis',
+ 'middlename' => 'A',
+ 'prefix' => 'Mr.',
+ 'suffix' => 'Jr.',
+ 'vat_id' => '1',
+ 'default_shipping' => true,
+ 'default_billing' => false
+ ];
+
+ $mutation
+ = <<graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerTest.php
index 388028c4ca750..fc51f57a83a76 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CreateCustomerTest.php
@@ -66,7 +66,7 @@ public function testCreateCustomerAccountWithPassword()
}
}
QUERY;
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
$this->assertEquals($newFirstname, $response['createCustomer']['customer']['firstname']);
$this->assertEquals($newLastname, $response['createCustomer']['customer']['lastname']);
@@ -103,7 +103,7 @@ public function testCreateCustomerAccountWithoutPassword()
}
}
QUERY;
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
$this->assertEquals($newFirstname, $response['createCustomer']['customer']['firstname']);
$this->assertEquals($newLastname, $response['createCustomer']['customer']['lastname']);
@@ -134,7 +134,7 @@ public function testCreateCustomerIfInputDataIsEmpty()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -167,7 +167,7 @@ public function testCreateCustomerIfEmailMissed()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -202,7 +202,7 @@ public function testCreateCustomerIfEmailIsNotValid()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -238,7 +238,7 @@ public function testCreateCustomerIfPassedAttributeDosNotExistsInCustomerInput()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
public function tearDown()
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/DeleteCustomerAddressTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/DeleteCustomerAddressTest.php
index 1153b9662b41a..bdfd428a78c20 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/DeleteCustomerAddressTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/DeleteCustomerAddressTest.php
@@ -13,6 +13,9 @@
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\Integration\Api\CustomerTokenServiceInterface;
+/**
+ * Delete customer address tests
+ */
class DeleteCustomerAddressTest extends GraphQlAbstract
{
/**
@@ -55,7 +58,7 @@ public function testDeleteCustomerAddress()
deleteCustomerAddress(id: {$addressId})
}
MUTATION;
- $response = $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $response = $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
$this->assertArrayHasKey('deleteCustomerAddress', $response);
$this->assertEquals(true, $response['deleteCustomerAddress']);
}
@@ -73,7 +76,7 @@ public function testDeleteCustomerAddressIfUserIsNotAuthorized()
deleteCustomerAddress(id: {$addressId})
}
MUTATION;
- $this->graphQlQuery($mutation);
+ $this->graphQlMutation($mutation);
}
/**
@@ -99,7 +102,7 @@ public function testDeleteDefaultShippingCustomerAddress()
deleteCustomerAddress(id: {$addressId})
}
MUTATION;
- $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
}
/**
@@ -125,7 +128,7 @@ public function testDeleteDefaultBillingCustomerAddress()
deleteCustomerAddress(id: {$addressId})
}
MUTATION;
- $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
}
/**
@@ -144,7 +147,7 @@ public function testDeleteNonExistCustomerAddress()
deleteCustomerAddress(id: 9999)
}
MUTATION;
- $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/GenerateCustomerTokenTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/GenerateCustomerTokenTest.php
index ae28e23a28bf1..88eaeaa8f9dd5 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/GenerateCustomerTokenTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/GenerateCustomerTokenTest.php
@@ -38,7 +38,7 @@ public function testGenerateCustomerValidToken()
}
MUTATION;
- $response = $this->graphQlQuery($mutation);
+ $response = $this->graphQlMutation($mutation);
$this->assertArrayHasKey('generateCustomerToken', $response);
$this->assertInternalType('array', $response['generateCustomerToken']);
}
@@ -66,6 +66,6 @@ public function testGenerateCustomerTokenWithInvalidCredentials()
$this->expectException(\Exception::class);
$this->expectExceptionMessage('GraphQL response contains errors: The account sign-in' . ' ' .
'was incorrect or your account is disabled temporarily. Please wait and try again later.');
- $this->graphQlQuery($mutation);
+ $this->graphQlMutation($mutation);
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php
index 9bdbf3059eeaf..fc0c02bae5508 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/RevokeCustomerTokenTest.php
@@ -36,7 +36,7 @@ public function testRevokeCustomerTokenValidCredentials()
$customerToken = $customerTokenService->createCustomerAccessToken($userName, $password);
$headerMap = ['Authorization' => 'Bearer ' . $customerToken];
- $response = $this->graphQlQuery($query, [], '', $headerMap);
+ $response = $this->graphQlMutation($query, [], '', $headerMap);
$this->assertTrue($response['revokeCustomerToken']['result']);
}
@@ -53,6 +53,6 @@ public function testRevokeCustomerTokenForGuestCustomer()
}
}
QUERY;
- $this->graphQlQuery($query, [], '');
+ $this->graphQlMutation($query, [], '');
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/SubscriptionStatusTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/SubscriptionStatusTest.php
index 191ea1ae6b877..2b54c97cd1e97 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/SubscriptionStatusTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/SubscriptionStatusTest.php
@@ -12,6 +12,9 @@
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
+/**
+ * Tests for subscription status
+ */
class SubscriptionStatusTest extends GraphQlAbstract
{
/**
@@ -88,7 +91,12 @@ public function testChangeSubscriptionStatusTest()
}
}
QUERY;
- $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $response = $this->graphQlMutation(
+ $query,
+ [],
+ '',
+ $this->getCustomerAuthHeaders($currentEmail, $currentPassword)
+ );
$this->assertTrue($response['updateCustomer']['customer']['is_subscribed']);
}
@@ -111,7 +119,7 @@ public function testChangeSubscriptionStatuIfUserIsNotAuthorizedTest()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php
index 6a9708b4f86a2..e7a7eda2897b2 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerAddressTest.php
@@ -14,6 +14,9 @@
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\Integration\Api\CustomerTokenServiceInterface;
+/**
+ * Update customer address tests
+ */
class UpdateCustomerAddressTest extends GraphQlAbstract
{
/**
@@ -128,7 +131,7 @@ public function testUpdateCustomerAddress()
}
MUTATION;
- $response = $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $response = $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
$this->assertArrayHasKey('updateCustomerAddress', $response);
$this->assertArrayHasKey('customer_id', $response['updateCustomerAddress']);
$this->assertEquals($customerId, $response['updateCustomerAddress']['customer_id']);
@@ -158,7 +161,7 @@ public function testUpdateCustomerAddressIfUserIsNotAuthorized()
}
}
MUTATION;
- $this->graphQlQuery($mutation);
+ $this->graphQlMutation($mutation);
}
/**
@@ -187,7 +190,7 @@ public function testUpdateCustomerAddressWithMissingAttribute()
}
}
MUTATION;
- $this->graphQlQuery($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
+ $this->graphQlMutation($mutation, [], '', $this->getCustomerAuthHeaders($userName, $password));
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php
index df45e1de771d9..08933f47191b9 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/UpdateCustomerTest.php
@@ -13,6 +13,9 @@
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
+/**
+ * Tests for update customer
+ */
class UpdateCustomerTest extends GraphQlAbstract
{
/**
@@ -87,7 +90,12 @@ public function testUpdateCustomer()
}
}
QUERY;
- $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $response = $this->graphQlMutation(
+ $query,
+ [],
+ '',
+ $this->getCustomerAuthHeaders($currentEmail, $currentPassword)
+ );
$this->assertEquals($newPrefix, $response['updateCustomer']['customer']['prefix']);
$this->assertEquals($newFirstname, $response['updateCustomer']['customer']['firstname']);
@@ -123,7 +131,7 @@ public function testUpdateCustomerIfInputDataIsEmpty()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
/**
@@ -147,7 +155,7 @@ public function testUpdateCustomerIfUserIsNotAuthorized()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -176,7 +184,7 @@ public function testUpdateCustomerIfAccountIsLocked()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
/**
@@ -203,7 +211,7 @@ public function testUpdateEmailIfPasswordIsMissed()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
/**
@@ -232,7 +240,7 @@ public function testUpdateEmailIfPasswordIsInvalid()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
/**
@@ -260,7 +268,7 @@ public function testUpdateEmailIfEmailAlreadyExists()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php
index 352947714360a..e784061d5562f 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php
@@ -393,7 +393,8 @@ public function testQueryComplexityIsLimited()
QUERY;
self::expectExceptionMessageRegExp('/Max query complexity should be 300 but got 302/');
- $this->graphQlQuery($query);
+ //Use POST request because request uri is too large for some servers
+ $this->graphQlMutation($query);
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductToCartTest.php
deleted file mode 100644
index d9ab8db62a195..0000000000000
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductToCartTest.php
+++ /dev/null
@@ -1,163 +0,0 @@
-quoteResource = $objectManager->get(QuoteResource::class);
- $this->quoteFactory = $objectManager->get(QuoteFactory::class);
- $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
- }
-
- /**
- * @magentoApiDataFixture Magento/Catalog/_files/products.php
- * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
- */
- public function testAddSimpleProductToCart()
- {
- $sku = 'simple';
- $qty = 2;
- $maskedQuoteId = $this->getMaskedQuoteId();
-
- $query = $this->getAddSimpleProductQuery($maskedQuoteId, $sku, $qty);
- $response = $this->graphQlQuery($query);
- self::assertArrayHasKey('cart', $response['addSimpleProductsToCart']);
-
- self::assertEquals($qty, $response['addSimpleProductsToCart']['cart']['items'][0]['qty']);
- self::assertEquals($sku, $response['addSimpleProductsToCart']['cart']['items'][0]['product']['sku']);
- }
-
- /**
- * @magentoApiDataFixture Magento/Catalog/_files/products.php
- * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
- * @expectedException \Exception
- * @expectedExceptionMessage Please enter a number greater than 0 in this field.
- */
- public function testAddSimpleProductToCartWithNegativeQty()
- {
- $sku = 'simple';
- $qty = -2;
- $maskedQuoteId = $this->getMaskedQuoteId();
-
- $query = $this->getAddSimpleProductQuery($maskedQuoteId, $sku, $qty);
- $this->graphQlQuery($query);
- }
-
- /**
- * @return string
- */
- public function getMaskedQuoteId() : string
- {
- $quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id');
-
- return $this->quoteIdToMaskedId->execute((int)$quote->getId());
- }
-
- /**
- * @param string $maskedQuoteId
- * @param string $sku
- * @param int $qty
- * @return string
- */
- public function getAddSimpleProductQuery(string $maskedQuoteId, string $sku, int $qty): string
- {
- return <<graphQlQuery($query);
- }
-}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductWithCustomOptionsToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductWithCustomOptionsToCartTest.php
new file mode 100644
index 0000000000000..f33ccce82fcb7
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductWithCustomOptionsToCartTest.php
@@ -0,0 +1,184 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->productCustomOptionsRepository = $objectManager->get(ProductCustomOptionRepositoryInterface::class);
+ }
+
+ /**
+ * Test adding a simple product to the shopping cart with all supported
+ * customizable options assigned
+ *
+ * @magentoApiDataFixture Magento/Catalog/_files/product_simple_with_options.php
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
+ */
+ public function testAddSimpleProductWithOptions()
+ {
+ $sku = 'simple';
+ $qty = 1;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
+
+ $customOptionsValues = $this->getCustomOptionsValuesForQuery($sku);
+
+ /* Generate customizable options fragment for GraphQl request */
+ $queryCustomizableOptions = preg_replace('/"([^"]+)"\s*:\s*/', '$1:', json_encode($customOptionsValues));
+
+ $query = <<graphQlMutation($query);
+
+ self::assertArrayHasKey('items', $response['addSimpleProductsToCart']['cart']);
+ self::assertCount(1, $response['addSimpleProductsToCart']['cart']);
+
+ $customizableOptionsOutput = $response['addSimpleProductsToCart']['cart']['items'][0]['customizable_options'];
+ $assignedOptionsCount = count($customOptionsValues);
+ for ($counter = 0; $counter < $assignedOptionsCount; $counter++) {
+ self::assertEquals(
+ $customOptionsValues[$counter]['value'],
+ $customizableOptionsOutput[$counter]['values'][0]['value']
+ );
+ }
+ }
+
+ /**
+ * Test adding a simple product with empty values for required options
+ *
+ * @magentoApiDataFixture Magento/Catalog/_files/product_simple_with_options.php
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
+ */
+ public function testAddSimpleProductWithNoRequiredOptionsSet()
+ {
+ $sku = 'simple';
+ $qty = 1;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
+
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * Generate an array with test values for customizable options
+ * based on the option type
+ *
+ * @param string $sku
+ * @return array
+ */
+ private function getCustomOptionsValuesForQuery(string $sku): array
+ {
+ $customOptions = $this->productCustomOptionsRepository->getList($sku);
+ $customOptionsValues = [];
+
+ foreach ($customOptions as $customOption) {
+ $optionType = $customOption->getType();
+ if ($optionType == 'field' || $optionType == 'area') {
+ $customOptionsValues[] = [
+ 'id' => (int) $customOption->getOptionId(),
+ 'value' => 'test'
+ ];
+ } elseif ($optionType == 'drop_down') {
+ $optionSelectValues = $customOption->getValues();
+ $customOptionsValues[] = [
+ 'id' => (int) $customOption->getOptionId(),
+ 'value' => reset($optionSelectValues)->getOptionTypeId()
+ ];
+ }
+ }
+
+ return $customOptionsValues;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddVirtualProductWithCustomOptionsToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddVirtualProductWithCustomOptionsToCartTest.php
new file mode 100644
index 0000000000000..ffd52bcf7fb15
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddVirtualProductWithCustomOptionsToCartTest.php
@@ -0,0 +1,184 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->productCustomOptionsRepository = $objectManager->get(ProductCustomOptionRepositoryInterface::class);
+ }
+
+ /**
+ * Test adding a virtual product to the shopping cart with all supported
+ * customizable options assigned
+ *
+ * @magentoApiDataFixture Magento/Catalog/_files/product_virtual_with_options.php
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
+ */
+ public function testAddVirtualProductWithOptions()
+ {
+ $sku = 'virtual';
+ $qty = 1;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
+
+ $customOptionsValues = $this->getCustomOptionsValuesForQuery($sku);
+
+ /* Generate customizable options fragment for GraphQl request */
+ $queryCustomizableOptions = preg_replace('/"([^"]+)"\s*:\s*/', '$1:', json_encode($customOptionsValues));
+
+ $query = <<graphQlMutation($query);
+
+ self::assertArrayHasKey('items', $response['addVirtualProductsToCart']['cart']);
+ self::assertCount(1, $response['addVirtualProductsToCart']['cart']);
+
+ $customizableOptionsOutput = $response['addVirtualProductsToCart']['cart']['items'][0]['customizable_options'];
+ $assignedOptionsCount = count($customOptionsValues);
+ for ($counter = 0; $counter < $assignedOptionsCount; $counter++) {
+ self::assertEquals(
+ $customOptionsValues[$counter]['value'],
+ $customizableOptionsOutput[$counter]['values'][0]['value']
+ );
+ }
+ }
+
+ /**
+ * Test adding a virtual product with empty values for required options
+ *
+ * @magentoApiDataFixture Magento/Catalog/_files/product_virtual_with_options.php
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
+ */
+ public function testAddVirtualProductWithNoRequiredOptionsSet()
+ {
+ $sku = 'virtual';
+ $qty = 1;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
+
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * Generate an array with test values for customizable options
+ * based on the option type
+ *
+ * @param string $sku
+ * @return array
+ */
+ private function getCustomOptionsValuesForQuery(string $sku): array
+ {
+ $customOptions = $this->productCustomOptionsRepository->getList($sku);
+ $customOptionsValues = [];
+
+ foreach ($customOptions as $customOption) {
+ $optionType = $customOption->getType();
+ if ($optionType == 'field' || $optionType == 'area') {
+ $customOptionsValues[] = [
+ 'id' => (int) $customOption->getOptionId(),
+ 'value' => 'test'
+ ];
+ } elseif ($optionType == 'drop_down') {
+ $optionSelectValues = $customOption->getValues();
+ $customOptionsValues[] = [
+ 'id' => (int) $customOption->getOptionId(),
+ 'value' => reset($optionSelectValues)->getOptionTypeId()
+ ];
+ }
+ }
+
+ return $customOptionsValues;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CouponTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CouponTest.php
deleted file mode 100644
index 828784ca27885..0000000000000
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CouponTest.php
+++ /dev/null
@@ -1,225 +0,0 @@
-quoteResource = $objectManager->create(QuoteResource::class);
- $this->quote = $objectManager->create(Quote::class);
- $this->quoteIdToMaskedId = $objectManager->create(QuoteIdToMaskedQuoteIdInterface::class);
- }
-
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
- * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
- */
- public function testApplyCouponToGuestCartWithItems()
- {
- $couponCode = '2?ds5!2d';
-
- $this->quoteResource->load(
- $this->quote,
- 'test_order_with_simple_product_without_address',
- 'reserved_order_id'
- );
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId());
- $query = $this->prepareAddCouponRequestQuery($maskedQuoteId, $couponCode);
- $response = $this->graphQlQuery($query);
-
- self::assertArrayHasKey('applyCouponToCart', $response);
- self::assertEquals($couponCode, $response['applyCouponToCart']['cart']['applied_coupon']['code']);
- }
-
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
- * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
- */
- public function testApplyCouponTwice()
- {
- $couponCode = '2?ds5!2d';
-
- $this->quoteResource->load(
- $this->quote,
- 'test_order_with_simple_product_without_address',
- 'reserved_order_id'
- );
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId());
- $query = $this->prepareAddCouponRequestQuery($maskedQuoteId, $couponCode);
- $response = $this->graphQlQuery($query);
-
- self::assertArrayHasKey("applyCouponToCart", $response);
- self::assertEquals($couponCode, $response['applyCouponToCart']['cart']['applied_coupon']['code']);
-
- self::expectExceptionMessage('A coupon is already applied to the cart. Please remove it to apply another');
- $this->graphQlQuery($query);
- }
-
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
- * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
- * @expectedException \Exception
- * @expectedExceptionMessage Cart does not contain products.
- */
- public function testApplyCouponToCartWithNoItems()
- {
- $couponCode = '2?ds5!2d';
-
- $this->quoteResource->load($this->quote, 'test_order_1', 'reserved_order_id');
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId());
- $query = $this->prepareAddCouponRequestQuery($maskedQuoteId, $couponCode);
-
- $this->graphQlQuery($query);
- }
-
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
- * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
- * @magentoApiDataFixture Magento/Customer/_files/customer.php
- */
- public function testGuestCustomerAttemptToChangeCustomerCart()
- {
- $couponCode = '2?ds5!2d';
-
- $this->quoteResource->load(
- $this->quote,
- 'test_order_with_simple_product_without_address',
- 'reserved_order_id'
- );
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId());
- $this->quote->setCustomerId(1);
- $this->quoteResource->save($this->quote);
- $query = $this->prepareAddCouponRequestQuery($maskedQuoteId, $couponCode);
-
- self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
- $this->graphQlQuery($query);
- }
-
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
- * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
- */
- public function testRemoveCoupon()
- {
- $couponCode = '2?ds5!2d';
-
- /* Apply coupon to the quote */
- $this->quoteResource->load(
- $this->quote,
- 'test_order_with_simple_product_without_address',
- 'reserved_order_id'
- );
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId());
- $this->quoteResource->load(
- $this->quote,
- 'test_order_with_simple_product_without_address',
- 'reserved_order_id'
- );
- $query = $this->prepareAddCouponRequestQuery($maskedQuoteId, $couponCode);
- $this->graphQlQuery($query);
-
- /* Remove coupon from quote */
- $query = $this->prepareRemoveCouponRequestQuery($maskedQuoteId);
- $response = $this->graphQlQuery($query);
-
- self::assertArrayHasKey('removeCouponFromCart', $response);
- self::assertNull($response['removeCouponFromCart']['cart']['applied_coupon']['code']);
- }
-
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
- * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
- * @magentoApiDataFixture Magento/Customer/_files/customer.php
- */
- public function testRemoveCouponFromCustomerCartByGuest()
- {
- $this->quoteResource->load(
- $this->quote,
- 'test_order_with_simple_product_without_address',
- 'reserved_order_id'
- );
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$this->quote->getId());
- $this->quoteResource->load(
- $this->quote,
- 'test_order_with_simple_product_without_address',
- 'reserved_order_id'
- );
- $this->quote->setCustomerId(1);
- $this->quoteResource->save($this->quote);
- $query = $this->prepareRemoveCouponRequestQuery($maskedQuoteId);
-
- self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
- $this->graphQlQuery($query);
- }
-
- /**
- * @param string $maskedQuoteId
- * @param string $couponCode
- * @return string
- */
- private function prepareAddCouponRequestQuery(string $maskedQuoteId, string $couponCode): string
- {
- return <<customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testAddSimpleProductToCart()
+ {
+ $sku = 'simple_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('cart', $response['addSimpleProductsToCart']);
+ self::assertEquals($qty, $response['addSimpleProductsToCart']['cart']['items'][0]['qty']);
+ self::assertEquals($sku, $response['addSimpleProductsToCart']['cart']['items'][0]['product']['sku']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testAddProductToNonExistentCart()
+ {
+ $sku = 'simple_product';
+ $qty = 2;
+ $maskedQuoteId = 'non_existent_masked_id';
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a product with SKU "simple_product"
+ */
+ public function testNonExistentProductToCart()
+ {
+ $sku = 'simple_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ */
+ public function testAddSimpleProductToGuestCart()
+ {
+ $sku = 'simple_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testAddSimpleProductToAnotherCustomerCart()
+ {
+ $sku = 'simple_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @param string $sku
+ * @param int $qty
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $sku, int $qty): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/AddVirtualProductToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/AddVirtualProductToCartTest.php
new file mode 100644
index 0000000000000..4ec25bb030079
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/AddVirtualProductToCartTest.php
@@ -0,0 +1,179 @@
+customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/virtual_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testAddVirtualProductToCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('cart', $response['addVirtualProductsToCart']);
+ self::assertEquals($qty, $response['addVirtualProductsToCart']['cart']['items'][0]['qty']);
+ self::assertEquals($sku, $response['addVirtualProductsToCart']['cart']['items'][0]['product']['sku']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/virtual_product.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testAddVirtualToNonExistentCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 2;
+ $nonExistentMaskedQuoteId = 'non_existent_masked_id';
+
+ $query = $this->getQuery($nonExistentMaskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a product with SKU "virtual_product"
+ */
+ public function testNonExistentProductToCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/virtual_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ */
+ public function testAddVirtualProductToGuestCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/virtual_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testAddVirtualProductToAnotherCustomerCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @param string $sku
+ * @param int $qty
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $sku, int $qty): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/ApplyCouponToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/ApplyCouponToCartTest.php
new file mode 100644
index 0000000000000..5a2221a184294
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/ApplyCouponToCartTest.php
@@ -0,0 +1,283 @@
+customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testApplyCouponToCart()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('applyCouponToCart', $response);
+ self::assertEquals($couponCode, $response['applyCouponToCart']['cart']['applied_coupon']['code']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage A coupon is already applied to the cart. Please remove it to apply another
+ */
+ public function testApplyCouponTwice()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey("applyCouponToCart", $response);
+ self::assertEquals($couponCode, $response['applyCouponToCart']['cart']['applied_coupon']['code']);
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart does not contain products.
+ */
+ public function testApplyCouponToCartWithoutItems()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @expectedException \Exception
+ */
+ public function testApplyCouponToGuestCart()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/Customer/_files/two_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @expectedException \Exception
+ */
+ public function testApplyCouponToAnotherCustomerCart()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer_two@example.com'));
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage The coupon code isn't valid. Verify the code and try again.
+ */
+ public function testApplyNonExistentCouponToCart()
+ {
+ $couponCode = 'non_existent_coupon_code';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @expectedException \Exception
+ */
+ public function testApplyCouponToNonExistentCart()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = 'non_existent_masked_id';
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ self::expectExceptionMessage('Could not find a cart with ID "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/make_coupon_expired.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage The coupon code isn't valid. Verify the code and try again.
+ */
+ public function testApplyExpiredCoupon()
+ {
+ $this->markTestIncomplete('https://github.com/magento/graphql-ce/issues/574');
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * Products in cart don't fit to the coupon
+ *
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage The coupon code isn't valid. Verify the code and try again.
+ */
+ public function testApplyCouponWhichIsNotApplicable()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @param string $input
+ * @param string $message
+ * @dataProvider dataProviderUpdateWithMissedRequiredParameters
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @expectedException \Exception
+ */
+ public function testApplyCouponWithMissedRequiredParameters(string $input, string $message)
+ {
+ $query = <<expectExceptionMessage($message);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @return array
+ */
+ public function dataProviderUpdateWithMissedRequiredParameters(): array
+ {
+ return [
+ 'missed_cart_id' => [
+ 'coupon_code: "test"',
+ 'Required parameter "cart_id" is missing'
+ ],
+ 'missed_coupon_code' => [
+ 'cart_id: "test"',
+ 'Required parameter "coupon_code" is missing'
+ ],
+ ];
+ }
+
+ /**
+ * Retrieve customer authorization headers
+ *
+ * @param string $username
+ * @param string $password
+ * @return array
+ * @throws AuthenticationException
+ */
+ private function getHeaderMap(string $username = 'customer@example.com', string $password = 'password'): array
+ {
+ $customerToken = $this->customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @param string $couponCode
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $couponCode): string
+ {
+ return <<getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ */
+ public function testGetCartTotalsWithTaxApplied()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('prices', $response['cart']);
+ $pricesResponse = $response['cart']['prices'];
+ self::assertEquals(21.5, $pricesResponse['grand_total']['value']);
+ self::assertEquals(21.5, $pricesResponse['subtotal_including_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_excluding_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_with_discount_excluding_tax']['value']);
+
+ $appliedTaxesResponse = $pricesResponse['applied_taxes'];
+
+ self::assertEquals('US-TEST-*-Rate-1', $appliedTaxesResponse[0]['label']);
+ self::assertEquals(1.5, $appliedTaxesResponse[0]['amount']['value']);
+ self::assertEquals('USD', $appliedTaxesResponse[0]['amount']['currency']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ */
+ public function testGetTotalsWithNoTaxApplied()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+
+ $pricesResponse = $response['cart']['prices'];
+ self::assertEquals(20, $pricesResponse['grand_total']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_including_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_excluding_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_with_discount_excluding_tax']['value']);
+ self::assertEmpty($pricesResponse['applied_taxes']);
+ }
+
+ /**
+ * The totals calculation is based on quote address.
+ * But the totals should be calculated even if no address is set
+ *
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testGetCartTotalsWithNoAddressSet()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+
+ $pricesResponse = $response['cart']['prices'];
+ self::assertEquals(20, $pricesResponse['grand_total']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_including_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_excluding_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_with_discount_excluding_tax']['value']);
+ self::assertEmpty($pricesResponse['applied_taxes']);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ */
+ public function testGetTotalsFromGuestCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+ $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ */
+ public function testGetTotalsFromAnotherCustomerCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+ $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer3@search.example.com'));
+ }
+
+ /**
+ * Generates GraphQl query for retrieving cart totals
+ *
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CheckoutEndToEndTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CheckoutEndToEndTest.php
new file mode 100644
index 0000000000000..8592a986c5dce
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CheckoutEndToEndTest.php
@@ -0,0 +1,530 @@
+registry = $objectManager->get(Registry::class);
+ $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class);
+ $this->quoteResource = $objectManager->get(QuoteResource::class);
+ $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class);
+ $this->customerRepository = Bootstrap::getObjectManager()->get(CustomerRepositoryInterface::class);
+ $this->orderCollectionFactory = $objectManager->get(CollectionFactory::class);
+ $this->orderRepository = $objectManager->get(OrderRepositoryInterface::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Catalog/_files/products_with_layered_navigation_attribute.php
+ */
+ public function testCheckoutWorkflow()
+ {
+ $qty = 2;
+
+ $this->createCustomer();
+ $token = $this->loginCustomer();
+ $this->headers = ['Authorization' => 'Bearer ' . $token];
+
+ $sku = $this->findProduct();
+ $cartId = $this->createEmptyCart();
+ $this->addProductToCart($cartId, $qty, $sku);
+
+ $this->setBillingAddress($cartId);
+ $shippingAddress = $this->setShippingAddress($cartId);
+
+ $shippingMethod = current($shippingAddress['available_shipping_methods']);
+ $paymentMethod = $this->setShippingMethod($cartId, $shippingAddress['address_id'], $shippingMethod);
+ $this->setPaymentMethod($cartId, $paymentMethod);
+
+ $orderId = $this->placeOrder($cartId);
+ $this->checkOrderInHistory($orderId);
+ }
+
+ /**
+ * @return void
+ */
+ private function createCustomer(): void
+ {
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * @return string
+ */
+ private function loginCustomer(): string
+ {
+ $query = <<graphQlMutation($query);
+ self::assertArrayHasKey('generateCustomerToken', $response);
+ self::assertArrayHasKey('token', $response['generateCustomerToken']);
+ self::assertNotEmpty($response['generateCustomerToken']['token']);
+
+ return $response['generateCustomerToken']['token'];
+ }
+
+ /**
+ * @return string
+ */
+ private function findProduct(): string
+ {
+ $query = <<graphQlQuery($query);
+ self::assertArrayHasKey('products', $response);
+ self::assertArrayHasKey('items', $response['products']);
+ self::assertCount(1, $response['products']['items']);
+
+ $product = current($response['products']['items']);
+ self::assertArrayHasKey('sku', $product);
+ self::assertNotEmpty($product['sku']);
+
+ return $product['sku'];
+ }
+
+ /**
+ * @return string
+ */
+ private function createEmptyCart(): string
+ {
+ $query = <<graphQlMutation($query, [], '', $this->headers);
+ self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertNotEmpty($response['createEmptyCart']);
+
+ return $response['createEmptyCart'];
+ }
+
+ /**
+ * @param string $cartId
+ * @param float $qty
+ * @param string $sku
+ * @return void
+ */
+ private function addProductToCart(string $cartId, float $qty, string $sku): void
+ {
+ $query = <<graphQlMutation($query, [], '', $this->headers);
+ }
+
+ /**
+ * @param string $cartId
+ * @param array $auth
+ * @return array
+ */
+ private function setBillingAddress(string $cartId): void
+ {
+ $query = <<graphQlMutation($query, [], '', $this->headers);
+ }
+
+ /**
+ * @param string $cartId
+ * @return array
+ */
+ private function setShippingAddress(string $cartId): array
+ {
+ $query = <<graphQlMutation($query, [], '', $this->headers);
+ self::assertArrayHasKey('setShippingAddressesOnCart', $response);
+ self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
+ self::assertArrayHasKey('shipping_addresses', $response['setShippingAddressesOnCart']['cart']);
+ self::assertCount(1, $response['setShippingAddressesOnCart']['cart']['shipping_addresses']);
+
+ $shippingAddress = current($response['setShippingAddressesOnCart']['cart']['shipping_addresses']);
+ self::assertArrayHasKey('address_id', $shippingAddress);
+ self::assertNotEmpty($shippingAddress['address_id']);
+ self::assertArrayHasKey('available_shipping_methods', $shippingAddress);
+ self::assertCount(1, $shippingAddress['available_shipping_methods']);
+
+ $availableShippingMethod = current($shippingAddress['available_shipping_methods']);
+ self::assertArrayHasKey('carrier_code', $availableShippingMethod);
+ self::assertNotEmpty($availableShippingMethod['carrier_code']);
+
+ self::assertArrayHasKey('method_code', $availableShippingMethod);
+ self::assertNotEmpty($availableShippingMethod['method_code']);
+
+ self::assertArrayHasKey('amount', $availableShippingMethod);
+ self::assertNotEmpty($availableShippingMethod['amount']);
+
+ return $shippingAddress;
+ }
+
+ /**
+ * @param string $cartId
+ * @param int $addressId
+ * @param array $method
+ * @return array
+ */
+ private function setShippingMethod(string $cartId, int $addressId, array $method): array
+ {
+ $query = <<graphQlMutation($query, [], '', $this->headers);
+ self::assertArrayHasKey('setShippingMethodsOnCart', $response);
+ self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
+ self::assertArrayHasKey('available_payment_methods', $response['setShippingMethodsOnCart']['cart']);
+ self::assertCount(1, $response['setShippingMethodsOnCart']['cart']['available_payment_methods']);
+
+ $availablePaymentMethod = current($response['setShippingMethodsOnCart']['cart']['available_payment_methods']);
+ self::assertArrayHasKey('code', $availablePaymentMethod);
+ self::assertNotEmpty($availablePaymentMethod['code']);
+ self::assertArrayHasKey('title', $availablePaymentMethod);
+ self::assertNotEmpty($availablePaymentMethod['title']);
+
+ return $availablePaymentMethod;
+ }
+
+ /**
+ * @param string $cartId
+ * @param array $method
+ * @return void
+ */
+ private function setPaymentMethod(string $cartId, array $method): void
+ {
+ $query = <<graphQlMutation($query, [], '', $this->headers);
+ }
+
+ /**
+ * @param string $cartId
+ * @return string
+ */
+ private function placeOrder(string $cartId): string
+ {
+ $query = <<graphQlMutation($query, [], '', $this->headers);
+ self::assertArrayHasKey('placeOrder', $response);
+ self::assertArrayHasKey('order', $response['placeOrder']);
+ self::assertArrayHasKey('order_id', $response['placeOrder']['order']);
+ self::assertNotEmpty($response['placeOrder']['order']['order_id']);
+
+ return $response['placeOrder']['order']['order_id'];
+ }
+
+ /**
+ * @param string $orderId
+ * @return void
+ */
+ private function checkOrderInHistory(string $orderId): void
+ {
+ $query = <<graphQlQuery($query, [], '', $this->headers);
+ self::assertArrayHasKey('customerOrders', $response);
+ self::assertArrayHasKey('items', $response['customerOrders']);
+ self::assertCount(1, $response['customerOrders']['items']);
+
+ $order = current($response['customerOrders']['items']);
+ self::assertArrayHasKey('increment_id', $order);
+ self::assertEquals($orderId, $order['increment_id']);
+
+ self::assertArrayHasKey('grand_total', $order);
+ }
+
+ public function tearDown()
+ {
+ $this->deleteCustomer();
+ $this->deleteQuote();
+ $this->deleteOrder();
+ parent::tearDown();
+ }
+
+ /**
+ * @return void
+ */
+ private function deleteCustomer(): void
+ {
+ $email = 'customer@example.com';
+ try {
+ $customer = $this->customerRepository->get($email);
+ } catch (\Exception $exception) {
+ return;
+ }
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', true);
+ $this->customerRepository->delete($customer);
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', false);
+ }
+
+ /**
+ * @return void
+ */
+ private function deleteQuote(): void
+ {
+ $quoteCollection = $this->quoteCollectionFactory->create();
+ foreach ($quoteCollection as $quote) {
+ $this->quoteResource->delete($quote);
+
+ $quoteIdMask = $this->quoteIdMaskFactory->create();
+ $quoteIdMask->setQuoteId($quote->getId())
+ ->delete();
+ }
+ }
+
+ /**
+ * @return void
+ */
+ private function deleteOrder()
+ {
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', true);
+
+ $orderCollection = $this->orderCollectionFactory->create();
+ foreach ($orderCollection as $order) {
+ $this->orderRepository->delete($order);
+ }
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', false);
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php
index 0cb8a38b0cb5e..fbd0cf19740d7 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/CreateEmptyCartTest.php
@@ -8,6 +8,9 @@
namespace Magento\GraphQl\Quote\Customer;
use Magento\Integration\Api\CustomerTokenServiceInterface;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+use Magento\Quote\Model\ResourceModel\Quote\CollectionFactory as QuoteCollectionFactory;
+use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\Quote\Api\GuestCartRepositoryInterface;
@@ -27,11 +30,29 @@ class CreateEmptyCartTest extends GraphQlAbstract
*/
private $customerTokenService;
+ /**
+ * @var QuoteCollectionFactory
+ */
+ private $quoteCollectionFactory;
+
+ /**
+ * @var QuoteResource
+ */
+ private $quoteResource;
+
+ /**
+ * @var QuoteIdMaskFactory
+ */
+ private $quoteIdMaskFactory;
+
protected function setUp()
{
$objectManager = Bootstrap::getObjectManager();
+ $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class);
$this->guestCartRepository = $objectManager->get(GuestCartRepositoryInterface::class);
$this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ $this->quoteResource = $objectManager->get(QuoteResource::class);
+ $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class);
}
/**
@@ -39,23 +60,137 @@ protected function setUp()
*/
public function testCreateEmptyCart()
{
+ $query = $this->getQuery();
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken());
+
+ self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertNotEmpty($response['createEmptyCart']);
+
+ $guestCart = $this->guestCartRepository->get($response['createEmptyCart']);
+
+ self::assertNotNull($guestCart->getId());
+ self::assertEquals(1, $guestCart->getCustomer()->getId());
+ self::assertEquals('default', $guestCart->getStore()->getCode());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Store/_files/second_store.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testCreateEmptyCartWithNotDefaultStore()
+ {
+ $query = $this->getQuery();
+
+ $headerMap = $this->getHeaderMapWithCustomerToken();
+ $headerMap['Store'] = 'fixture_second_store';
+ $response = $this->graphQlMutation($query, [], '', $headerMap);
+
+ self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertNotEmpty($response['createEmptyCart']);
+
+ /* guestCartRepository is used for registered customer to get the cart hash */
+ $guestCart = $this->guestCartRepository->get($response['createEmptyCart']);
+
+ self::assertNotNull($guestCart->getId());
+ self::assertEquals(1, $guestCart->getCustomer()->getId());
+ self::assertEquals('fixture_second_store', $guestCart->getStore()->getCode());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testCreateEmptyCartWithPredefinedCartId()
+ {
+ $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4';
+
$query = <<customerTokenService->createCustomerAccessToken('customer@example.com', 'password');
- $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
-
- $response = $this->graphQlQuery($query, [], '', $headerMap);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken());
self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertEquals($predefinedCartId, $response['createEmptyCart']);
- $maskedCartId = $response['createEmptyCart'];
- $guestCart = $this->guestCartRepository->get($maskedCartId);
-
+ $guestCart = $this->guestCartRepository->get($response['createEmptyCart']);
self::assertNotNull($guestCart->getId());
self::assertEquals(1, $guestCart->getCustomer()->getId());
}
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart with ID "572cda51902b5b517c0e1a2b2fd004b4" already exists.
+ */
+ public function testCreateEmptyCartIfPredefinedCartIdAlreadyExists()
+ {
+ $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4';
+
+ $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart ID length should to be 32 symbols.
+ */
+ public function testCreateEmptyCartWithWrongPredefinedCartId()
+ {
+ $predefinedCartId = '572';
+
+ $query = <<graphQlMutation($query, [], '', $this->getHeaderMapWithCustomerToken());
+ }
+
+ /**
+ * @return string
+ */
+ private function getQuery(): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+
+ public function tearDown()
+ {
+ $quoteCollection = $this->quoteCollectionFactory->create();
+ foreach ($quoteCollection as $quote) {
+ $this->quoteResource->delete($quote);
+
+ $quoteIdMask = $this->quoteIdMaskFactory->create();
+ $quoteIdMask->setQuoteId($quote->getId())
+ ->delete();
+ }
+ parent::tearDown();
+ }
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailablePaymentMethodsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailablePaymentMethodsTest.php
index ba640bc3402ba..673d496302662 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailablePaymentMethodsTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailablePaymentMethodsTest.php
@@ -39,7 +39,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -60,7 +60,7 @@ public function testGetAvailablePaymentMethods()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -79,7 +79,7 @@ public function testGetAvailablePaymentMethodsFromGuestCart()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/three_customers.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -97,7 +97,7 @@ public function testGetAvailablePaymentMethodsFromAnotherCustomerCart()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailableShippingMethodsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailableShippingMethodsTest.php
index 71cf0201951a3..2b647f61c4c63 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailableShippingMethodsTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetAvailableShippingMethodsTest.php
@@ -41,7 +41,7 @@ protected function setUp()
* Test case: get available shipping methods from current customer quote
*
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -77,7 +77,7 @@ public function testGetAvailableShippingMethods()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -98,7 +98,7 @@ public function testGetAvailableShippingMethodsFromGuestCart()
*
* _security
* @magentoApiDataFixture Magento/Customer/_files/three_customers.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -118,7 +118,7 @@ public function testGetAvailableShippingMethodsFromAnotherCustomerCart()
* Test case: get available shipping methods when all shipping methods are disabled
*
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetCartEmailTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetCartEmailTest.php
new file mode 100644
index 0000000000000..951fe08db5e3d
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetCartEmailTest.php
@@ -0,0 +1,125 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testGetCartEmail()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+
+ $this->assertArrayHasKey('cart', $response);
+ $this->assertArrayHasKey('email', $response['cart']);
+ $this->assertEquals('customer@example.com', $response['cart']['email']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testGetCartEmailFromNonExistentCart()
+ {
+ $maskedQuoteId = 'non_existent_masked_id';
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ */
+ public function testGetEmailFromGuestCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"{$maskedQuoteId}\""
+ );
+ $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testGetEmailFromAnotherCustomerCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"{$maskedQuoteId}\""
+ );
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer3@search.example.com'));
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetCartTest.php
index eb62b8c92f310..19b72b9e3ca4c 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetCartTest.php
@@ -36,7 +36,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
@@ -55,7 +55,7 @@ public function testGetCart()
self::assertNotEmpty($response['cart']['items'][0]['id']);
self::assertEquals(2, $response['cart']['items'][0]['qty']);
- self::assertEquals('simple', $response['cart']['items'][0]['product']['sku']);
+ self::assertEquals('simple_product', $response['cart']['items'][0]['product']['sku']);
self::assertNotEmpty($response['cart']['items'][1]['id']);
self::assertEquals(2, $response['cart']['items'][1]['qty']);
@@ -124,6 +124,58 @@ public function testGetInactiveCart()
$this->graphQlQuery($query, [], '', $this->getHeaderMap());
}
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote_customer_not_default_store.php
+ */
+ public function testGetCartWithNotDefaultStore()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1_not_default_store');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $headerMap = $this->getHeaderMap();
+ $headerMap['Store'] = 'fixture_second_store';
+
+ $response = $this->graphQlQuery($query, [], '', $headerMap);
+
+ self::assertArrayHasKey('cart', $response);
+ self::assertArrayHasKey('items', $response['cart']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
+ * @magentoApiDataFixture Magento/Store/_files/second_store.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Wrong store code specified for cart
+ */
+ public function testGetCartWithWrongStore()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $headerMap = $this->getHeaderMap();
+ $headerMap['Store'] = 'fixture_second_store';
+
+ $this->graphQlQuery($query, [], '', $headerMap);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote_customer_not_default_store.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Store code not_existing_store does not exist
+ */
+ public function testGetCartWithNotExistingStore()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1_not_default_store');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $headerMap = $this->getHeaderMap();
+ $headerMap['Store'] = 'not_existing_store';
+
+ $this->graphQlQuery($query, [], '', $headerMap);
+ }
+
/**
* @param string $maskedQuoteId
* @return string
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSelectedShippingMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSelectedShippingMethodTest.php
index 16d085c1d09be..ba169d7a5bbc9 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSelectedShippingMethodTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSelectedShippingMethodTest.php
@@ -39,7 +39,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -69,7 +69,7 @@ public function testGetSelectedShippingMethod()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -89,7 +89,7 @@ public function testGetSelectedShippingMethodFromGuestCart()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/three_customers.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -108,7 +108,7 @@ public function testGetSelectedShippingMethodFromAnotherCustomerCart()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSpecifiedBillingAddressTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSpecifiedBillingAddressTest.php
index 4396f5fbac189..1ba94346073db 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSpecifiedBillingAddressTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/GetSpecifiedBillingAddressTest.php
@@ -39,7 +39,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
@@ -79,7 +79,7 @@ public function testGeSpecifiedBillingAddress()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -132,7 +132,7 @@ public function testGeSpecifiedBillingAddressOfNonExistentCart()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
@@ -150,7 +150,7 @@ public function testGeSpecifiedBillingAddressFromAnotherGuestCart()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/three_customers.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/PlaceOrderTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/PlaceOrderTest.php
new file mode 100644
index 0000000000000..47d0d661fb33c
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/PlaceOrderTest.php
@@ -0,0 +1,295 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ $this->orderCollectionFactory = $objectManager->get(CollectionFactory::class);
+ $this->orderRepository = $objectManager->get(OrderRepositoryInterface::class);
+ $this->registry = Bootstrap::getObjectManager()->get(Registry::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_checkmo_payment_method.php
+ */
+ public function testPlaceOrder()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('placeOrder', $response);
+ self::assertArrayHasKey('order_id', $response['placeOrder']['order']);
+ self::assertEquals($reservedOrderId, $response['placeOrder']['order']['order_id']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testPlaceOrderWithNoItemsInCart()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage(
+ 'Unable to place order: A server error stopped your order from being placed. ' .
+ 'Please try to place your order again'
+ );
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testPlaceOrderWithNoShippingAddress()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage(
+ 'Unable to place order: Some addresses can\'t be used due to the configurations for specific countries'
+ );
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ */
+ public function testPlaceOrderWithNoShippingMethod()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage(
+ 'Unable to place order: The shipping method is missing. Select the shipping method and try again'
+ );
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ */
+ public function testPlaceOrderWithNoBillingAddress()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessageRegExp(
+ '/Unable to place order: Please check the billing address information*/'
+ );
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ */
+ public function testPlaceOrderWithNoPaymentMethod()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage('Unable to place order: Enter a valid payment method and try again');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/set_simple_product_out_of_stock.php
+ */
+ public function testPlaceOrderWithOutOfStockProduct()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage('Unable to place order: Some of the products are out of stock');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_checkmo_payment_method.php
+ */
+ public function testPlaceOrderOfGuestCart()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessageRegExp('/The current user cannot perform operations on cart*/');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_checkmo_payment_method.php
+ */
+ public function testPlaceOrderOfAnotherCustomerCart()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessageRegExp('/The current user cannot perform operations on cart*/');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer3@search.example.com'));
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function tearDown()
+ {
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', true);
+
+ $orderCollection = $this->orderCollectionFactory->create();
+ foreach ($orderCollection as $order) {
+ $this->orderRepository->delete($order);
+ }
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', false);
+
+ parent::tearDown();
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveCouponFromCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveCouponFromCartTest.php
new file mode 100644
index 0000000000000..ce1c85417b165
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveCouponFromCartTest.php
@@ -0,0 +1,169 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/apply_coupon.php
+ */
+ public function testRemoveCouponFromCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('removeCouponFromCart', $response);
+ self::assertNull($response['removeCouponFromCart']['cart']['applied_coupon']['code']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testRemoveCouponFromNonExistentCart()
+ {
+ $maskedQuoteId = 'non_existent_masked_id';
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart does not contain products
+ */
+ public function testRemoveCouponFromEmptyCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testRemoveCouponFromCartIfCouponWasNotSet()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+
+ self::assertArrayHasKey('removeCouponFromCart', $response);
+ self::assertNull($response['removeCouponFromCart']['cart']['applied_coupon']['code']);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/apply_coupon.php
+ */
+ public function testRemoveCouponFromGuestCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/apply_coupon.php
+ */
+ public function testRemoveCouponFromAnotherCustomerCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer3@search.example.com'));
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php
index e80a2127ad420..39803f8d58447 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/RemoveItemFromCartTest.php
@@ -7,11 +7,9 @@
namespace Magento\GraphQl\Quote\Customer;
-use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId;
+use Magento\GraphQl\Quote\GetQuoteItemIdByReservedQuoteIdAndSku;
use Magento\Integration\Api\CustomerTokenServiceInterface;
-use Magento\Quote\Model\QuoteFactory;
-use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
-use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
@@ -26,47 +24,38 @@ class RemoveItemFromCartTest extends GraphQlAbstract
private $customerTokenService;
/**
- * @var QuoteResource
+ * @var GetMaskedQuoteIdByReservedOrderId
*/
- private $quoteResource;
+ private $getMaskedQuoteIdByReservedOrderId;
/**
- * @var QuoteFactory
+ * @var GetQuoteItemIdByReservedQuoteIdAndSku
*/
- private $quoteFactory;
-
- /**
- * @var QuoteIdToMaskedQuoteIdInterface
- */
- private $quoteIdToMaskedId;
-
- /**
- * @var ProductRepositoryInterface
- */
- private $productRepository;
+ private $getQuoteItemIdByReservedQuoteIdAndSku;
protected function setUp()
{
$objectManager = Bootstrap::getObjectManager();
- $this->quoteResource = $objectManager->get(QuoteResource::class);
- $this->quoteFactory = $objectManager->get(QuoteFactory::class);
- $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
$this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
- $this->productRepository = $objectManager->get(ProductRepositoryInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->getQuoteItemIdByReservedQuoteIdAndSku = $objectManager->get(
+ GetQuoteItemIdByReservedQuoteIdAndSku::class
+ );
}
/**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
public function testRemoveItemFromCart()
{
- $quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id');
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId());
- $itemId = (int)$quote->getItemByProduct($this->productRepository->get('simple'))->getId();
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $itemId = $this->getQuoteItemIdByReservedQuoteIdAndSku->execute('test_quote', 'simple_product');
- $query = $this->prepareMutationQuery($maskedQuoteId, $itemId);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $query = $this->getQuery($maskedQuoteId, $itemId);
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
$this->assertArrayHasKey('removeItemFromCart', $response);
$this->assertArrayHasKey('cart', $response['removeItemFromCart']);
@@ -80,106 +69,25 @@ public function testRemoveItemFromCart()
*/
public function testRemoveItemFromNonExistentCart()
{
- $query = $this->prepareMutationQuery('non_existent_masked_id', 1);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $query = $this->getQuery('non_existent_masked_id', 1);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
public function testRemoveNonExistentItem()
{
- $quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id');
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId());
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$notExistentItemId = 999;
$this->expectExceptionMessage("Cart doesn't contain the {$notExistentItemId} item.");
- $query = $this->prepareMutationQuery($maskedQuoteId, $notExistentItemId);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
- }
-
- /**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php
- */
- public function testRemoveItemIfItemIsNotBelongToCart()
- {
- $firstQuote = $this->quoteFactory->create();
- $this->quoteResource->load($firstQuote, 'test_order_1', 'reserved_order_id');
- $firstQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$firstQuote->getId());
-
- $secondQuote = $this->quoteFactory->create();
- $this->quoteResource->load(
- $secondQuote,
- 'test_order_with_virtual_product_without_address',
- 'reserved_order_id'
- );
- $secondQuote->setCustomerId(1);
- $this->quoteResource->save($secondQuote);
- $secondQuoteItemId = (int)$secondQuote
- ->getItemByProduct($this->productRepository->get('virtual-product'))
- ->getId();
-
- $this->expectExceptionMessage("Cart doesn't contain the {$secondQuoteItemId} item.");
-
- $query = $this->prepareMutationQuery($firstQuoteMaskedId, $secondQuoteItemId);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
- }
-
- /**
- * @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php
- */
- public function testRemoveItemFromGuestCart()
- {
- $guestQuote = $this->quoteFactory->create();
- $this->quoteResource->load(
- $guestQuote,
- 'test_order_with_virtual_product_without_address',
- 'reserved_order_id'
- );
- $guestQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$guestQuote->getId());
- $guestQuoteItemId = (int)$guestQuote
- ->getItemByProduct($this->productRepository->get('virtual-product'))
- ->getId();
-
- $this->expectExceptionMessage(
- "The current user cannot perform operations on cart \"$guestQuoteMaskedId\""
- );
-
- $query = $this->prepareMutationQuery($guestQuoteMaskedId, $guestQuoteItemId);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
- }
-
- /**
- * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php
- */
- public function testRemoveItemFromAnotherCustomerCart()
- {
- $anotherCustomerQuote = $this->quoteFactory->create();
- $this->quoteResource->load(
- $anotherCustomerQuote,
- 'test_order_with_virtual_product_without_address',
- 'reserved_order_id'
- );
- $anotherCustomerQuote->setCustomerId(2);
- $this->quoteResource->save($anotherCustomerQuote);
-
- $anotherCustomerQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$anotherCustomerQuote->getId());
- $anotherCustomerQuoteItemId = (int)$anotherCustomerQuote
- ->getItemByProduct($this->productRepository->get('virtual-product'))
- ->getId();
-
- $this->expectExceptionMessage(
- "The current user cannot perform operations on cart \"$anotherCustomerQuoteMaskedId\""
- );
-
- $query = $this->prepareMutationQuery($anotherCustomerQuoteMaskedId, $anotherCustomerQuoteItemId);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $query = $this->getQuery($maskedQuoteId, $notExistentItemId);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -206,7 +114,7 @@ public function testUpdateWithMissedItemRequiredParameters(string $input, string
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -226,12 +134,77 @@ public function dataProviderUpdateWithMissedRequiredParameters(): array
];
}
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_and_address.php
+ */
+ public function testRemoveItemIfItemIsNotBelongToCart()
+ {
+ $firstQuoteMaskedId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $secondQuoteItemId = $this->getQuoteItemIdByReservedQuoteIdAndSku->execute(
+ 'test_order_with_virtual_product',
+ 'virtual-product'
+ );
+
+ $this->expectExceptionMessage("Cart doesn't contain the {$secondQuoteItemId} item.");
+
+ $query = $this->getQuery($firstQuoteMaskedId, $secondQuoteItemId);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testRemoveItemFromGuestCart()
+ {
+ $guestQuoteMaskedId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $guestQuoteItemId = $this->getQuoteItemIdByReservedQuoteIdAndSku->execute('test_quote', 'simple_product');
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$guestQuoteMaskedId\""
+ );
+
+ $query = $this->getQuery($guestQuoteMaskedId, $guestQuoteItemId);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testRemoveItemFromAnotherCustomerCart()
+ {
+ $anotherCustomerQuoteMaskedId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $anotherCustomerQuoteItemId = $this->getQuoteItemIdByReservedQuoteIdAndSku->execute(
+ 'test_quote',
+ 'simple_product'
+ );
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$anotherCustomerQuoteMaskedId\""
+ );
+
+ $query = $this->getQuery($anotherCustomerQuoteMaskedId, $anotherCustomerQuoteItemId);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ }
+
/**
* @param string $maskedQuoteId
* @param int $itemId
* @return string
*/
- private function prepareMutationQuery(string $maskedQuoteId, int $itemId): string
+ private function getQuery(string $maskedQuoteId, int $itemId): string
{
return <<graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
$cartResponse = $response['setBillingAddressOnCart']['cart'];
@@ -116,7 +116,7 @@ public function testSetNewBillingAddress()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -179,7 +179,7 @@ public function testSetNewBillingAddressWithUseForShippingParameter()
}
}
QUERY;
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
$cartResponse = $response['setBillingAddressOnCart']['cart'];
@@ -194,7 +194,7 @@ public function testSetNewBillingAddressWithUseForShippingParameter()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -230,7 +230,7 @@ public function testSetBillingAddressFromAddressBook()
}
}
QUERY;
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
$cartResponse = $response['setBillingAddressOnCart']['cart'];
@@ -241,7 +241,7 @@ public function testSetBillingAddressFromAddressBook()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -270,13 +270,13 @@ public function testSetNotExistedBillingAddressFromAddressBook()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -318,14 +318,14 @@ public function testSetNewBillingAddressAndFromAddressBookAtSameTime()
self::expectExceptionMessage(
'The billing address cannot contain "customer_address_id" and "address" at the same time.'
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @magentoApiDataFixture Magento/Customer/_files/customer_address.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -355,7 +355,7 @@ public function testSetBillingAddressToGuestCart()
"The current user cannot perform operations on cart \"{$maskedQuoteId}\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -390,7 +390,7 @@ public function testSetBillingAddressToAnotherCustomerCart()
"The current user cannot perform operations on cart \"{$maskedQuoteId}\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer@search.example.com'));
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer@search.example.com'));
}
/**
@@ -424,7 +424,7 @@ public function testSetBillingAddressIfCustomerIsNotOwnerOfAddress()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
}
/**
@@ -454,12 +454,12 @@ public function testSetBillingAddressOnNonExistentCart()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -490,7 +490,7 @@ public function testSetBillingAddressWithoutRequiredParameters(string $input, st
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -511,6 +511,49 @@ public function dataProviderSetWithoutRequiredParameters(): array
];
}
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testSetNewBillingAddressWithRedundantStreetLine()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = <<graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
/**
* Verify the all the whitelisted fields for a New Address Object
*
@@ -568,16 +611,16 @@ private function getHeaderMap(string $username = 'customer@example.com', string
}
/**
- * @param string $reversedOrderId
+ * @param string $reservedOrderId
* @param int $customerId
* @return string
*/
private function assignQuoteToCustomer(
- string $reversedOrderId = 'test_order_with_simple_product_without_address',
+ string $reservedOrderId = 'test_order_with_simple_product_without_address',
int $customerId = 1
): string {
$quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, $reversedOrderId, 'reserved_order_id');
+ $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id');
$quote->setCustomerId($customerId);
$this->quoteResource->save($quote);
return $this->quoteIdToMaskedId->execute((int)$quote->getId());
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetGuestEmailOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetGuestEmailOnCartTest.php
new file mode 100644
index 0000000000000..a4a84c2f8c740
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetGuestEmailOnCartTest.php
@@ -0,0 +1,104 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage The request is not allowed for logged in customers
+ */
+ public function testSetGuestEmailOnCartForLoggedInCustomer()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $email = 'some@user.com';
+
+ $query = $this->getQuery($maskedQuoteId, $email);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage The request is not allowed for logged in customers
+ */
+ public function testSetGuestEmailOnGuestCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $email = 'some@user.com';
+
+ $query = $this->getQuery($maskedQuoteId, $email);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * Returns GraphQl mutation query for setting email address for a guest
+ *
+ * @param string $maskedQuoteId
+ * @param string $email
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $email): string
+ {
+ return <<customerTokenService->createCustomerAccessToken($username, $password);
+ $headerMap = ['Authorization' => 'Bearer ' . $customerToken];
+ return $headerMap;
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetOfflineShippingMethodsOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetOfflineShippingMethodsOnCartTest.php
index bd147cc4a197e..20462220ff6f7 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetOfflineShippingMethodsOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetOfflineShippingMethodsOnCartTest.php
@@ -48,7 +48,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -72,7 +72,7 @@ public function testSetOfflineShippingMethod(string $carrierCode, string $method
$carrierCode,
$quoteAddressId
);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('setShippingMethodsOnCart', $response);
self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php
index 98eded8300665..2604ec5f0a0f9 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetPaymentMethodOnCartTest.php
@@ -7,10 +7,12 @@
namespace Magento\GraphQl\Quote\Customer;
+use Exception;
use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId;
use Magento\Integration\Api\CustomerTokenServiceInterface;
use Magento\OfflinePayments\Model\Cashondelivery;
use Magento\OfflinePayments\Model\Checkmo;
+use Magento\OfflinePayments\Model\Purchaseorder;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
@@ -41,7 +43,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -52,7 +54,7 @@ public function testSetPaymentOnCartWithSimpleProduct()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('setPaymentMethodOnCart', $response);
self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']);
@@ -62,11 +64,11 @@ public function testSetPaymentOnCartWithSimpleProduct()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage The shipping address is missing. Set the address and try again.
*/
public function testSetPaymentOnCartWithSimpleProductAndWithoutAddress()
@@ -75,7 +77,7 @@ public function testSetPaymentOnCartWithSimpleProductAndWithoutAddress()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -90,7 +92,7 @@ public function testSetPaymentOnCartWithVirtualProduct()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('setPaymentMethodOnCart', $response);
self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']);
@@ -100,12 +102,12 @@ public function testSetPaymentOnCartWithVirtualProduct()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
*
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage The requested Payment Method is not available.
*/
public function testSetNonExistentPaymentMethod()
@@ -114,13 +116,13 @@ public function testSetNonExistentPaymentMethod()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
*
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
*/
public function testSetPaymentOnNonExistentCart()
@@ -129,13 +131,13 @@ public function testSetPaymentOnNonExistentCart()
$methodCode = Checkmo::PAYMENT_METHOD_CHECKMO_CODE;
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -149,13 +151,13 @@ public function testSetPaymentMethodToGuestCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/three_customers.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -169,18 +171,18 @@ public function testSetPaymentMethodToAnotherCustomerCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
* @param string $input
* @param string $message
- * @throws \Exception
+ * @throws Exception
* @dataProvider dataProviderSetPaymentMethodWithoutRequiredParameters
*/
public function testSetPaymentMethodWithoutRequiredParameters(string $input, string $message)
@@ -201,7 +203,25 @@ public function testSetPaymentMethodWithoutRequiredParameters(string $input, str
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @expectedException Exception
+ * @expectedExceptionMessage The requested Payment Method is not available.
+ */
+ public function testSetDisabledPaymentOnCart()
+ {
+ $methodCode = Purchaseorder::PAYMENT_METHOD_PURCHASEORDER_CODE;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $methodCode);
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -227,7 +247,7 @@ public function dataProviderSetPaymentMethodWithoutRequiredParameters(): array
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
@@ -240,7 +260,7 @@ public function testReSetPayment()
$methodCode = Cashondelivery::PAYMENT_METHOD_CASHONDELIVERY_CODE;
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('setPaymentMethodOnCart', $response);
self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']);
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php
index 5ff29d20b34d7..6b097e028ffe5 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingAddressOnCartTest.php
@@ -57,7 +57,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -107,7 +107,7 @@ public function testSetNewShippingAddressOnCartWithSimpleProduct()
}
}
QUERY;
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
$cartResponse = $response['setShippingAddressesOnCart']['cart'];
@@ -160,13 +160,13 @@ public function testSetNewShippingAddressOnCartWithVirtualProduct()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -200,7 +200,7 @@ public function testSetShippingAddressFromAddressBook()
}
}
QUERY;
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
$cartResponse = $response['setShippingAddressesOnCart']['cart'];
@@ -211,7 +211,7 @@ public function testSetShippingAddressFromAddressBook()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -242,13 +242,13 @@ public function testSetNonExistentShippingAddressFromAddressBook()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @magentoApiDataFixture Magento/Customer/_files/customer_two_addresses.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -291,7 +291,7 @@ public function testSetNewShippingAddressAndFromAddressBookAtSameTime()
self::expectExceptionMessage(
'The shipping address cannot contain "customer_address_id" and "address" at the same time.'
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -328,7 +328,7 @@ public function testSetShippingAddressIfCustomerIsNotOwnerOfAddress()
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
}
/**
@@ -366,12 +366,12 @@ public function testSetShippingAddressToAnotherCustomerCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -405,7 +405,7 @@ public function testSetNewShippingAddressWithMissedRequiredParameters(string $in
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -427,7 +427,7 @@ public function dataProviderUpdateWithMissedRequiredParameters(): array
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -483,7 +483,53 @@ public function testSetMultipleNewShippingAddresses()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testSetNewShippingAddressOnCartWithRedundantStreetLine()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = <<graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -541,16 +587,16 @@ private function getHeaderMap(string $username = 'customer@example.com', string
}
/**
- * @param string $reversedOrderId
+ * @param string $reservedOrderId
* @param int $customerId
* @return string
*/
private function assignQuoteToCustomer(
- string $reversedOrderId = 'test_order_with_simple_product_without_address',
+ string $reservedOrderId = 'test_order_with_simple_product_without_address',
int $customerId = 1
): string {
$quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, $reversedOrderId, 'reserved_order_id');
+ $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id');
$quote->setCustomerId($customerId);
$this->quoteResource->save($quote);
return $this->quoteIdToMaskedId->execute((int)$quote->getId());
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingMethodsOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingMethodsOnCartTest.php
index 29ddbefd8e405..0fc52443e86b9 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingMethodsOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/SetShippingMethodsOnCartTest.php
@@ -7,6 +7,7 @@
namespace Magento\GraphQl\Quote\Customer;
+use Exception;
use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId;
use Magento\GraphQl\Quote\GetQuoteShippingAddressIdByReservedQuoteId;
use Magento\Integration\Api\CustomerTokenServiceInterface;
@@ -48,7 +49,7 @@ protected function setUp()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -66,7 +67,7 @@ public function testSetShippingMethodOnCartWithSimpleProduct()
$carrierCode,
$quoteAddressId
);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('setShippingMethodsOnCart', $response);
self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
@@ -86,7 +87,7 @@ public function testSetShippingMethodOnCartWithSimpleProduct()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -105,7 +106,7 @@ public function testReSetShippingMethod()
$carrierCode,
$quoteAddressId
);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
self::assertArrayHasKey('setShippingMethodsOnCart', $response);
self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
@@ -124,7 +125,7 @@ public function testReSetShippingMethod()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -132,7 +133,7 @@ public function testReSetShippingMethod()
* @param string $input
* @param string $message
* @dataProvider dataProviderSetShippingMethodWithWrongParameters
- * @throws \Exception
+ * @throws Exception
*/
public function testSetShippingMethodWithWrongParameters(string $input, string $message)
{
@@ -156,7 +157,7 @@ public function testSetShippingMethodWithWrongParameters(string $input, string $
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -251,17 +252,25 @@ public function dataProviderSetShippingMethodWithWrongParameters(): array
}]',
'Could not find a cart with ID "non_existent_masked_id"'
],
+ 'disabled_shipping_method' => [
+ 'cart_id: "cart_id_value", shipping_methods: [{
+ cart_address_id: cart_address_id_value
+ carrier_code: "freeshipping"
+ method_code: "freeshipping"
+ }]',
+ 'Carrier with such method not found: freeshipping, freeshipping'
+ ]
];
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage You cannot specify multiple shipping methods.
*/
public function testSetMultipleShippingMethods()
@@ -296,18 +305,18 @@ public function testSetMultipleShippingMethods()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
*
- * @expectedException \Exception
+ * @expectedException Exception
*/
public function testSetShippingMethodToGuestCart()
{
@@ -325,18 +334,18 @@ public function testSetShippingMethodToGuestCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/three_customers.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
*
- * @expectedException \Exception
+ * @expectedException Exception
*/
public function testSetShippingMethodToAnotherCustomerCart()
{
@@ -354,13 +363,13 @@ public function testSetShippingMethodToAnotherCustomerCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap('customer2@search.example.com'));
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -382,7 +391,7 @@ public function testSetShippingMethodIfCustomerIsNotOwnerOfAddress()
$this->expectExceptionMessage(
"Cart does not contain address with ID \"{$anotherQuoteAddressId}\""
);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -422,6 +431,30 @@ private function getQuery(
QUERY;
}
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ *
+ * @expectedException Exception
+ * @expectedExceptionMessage The shipping method can't be set for an empty cart. Add an item to cart and try again.
+ */
+ public function testSetShippingMethodOnAnEmptyCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $carrierCode = 'flatrate';
+ $methodCode = 'flatrate';
+ $quoteAddressId = $this->getQuoteShippingAddressIdByReservedQuoteId->execute('test_quote');
+
+ $query = $this->getQuery(
+ $maskedQuoteId,
+ $methodCode,
+ $carrierCode,
+ $quoteAddressId
+ );
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
+ }
+
/**
* @param string $username
* @param string $password
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/UpdateCartItemsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/UpdateCartItemsTest.php
index 74e7aa8b5d0a4..35e2d62214fb2 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/UpdateCartItemsTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Customer/UpdateCartItemsTest.php
@@ -67,7 +67,7 @@ public function testUpdateCartItemQty()
$qty = 2;
$query = $this->getQuery($maskedQuoteId, $itemId, $qty);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
$this->assertArrayHasKey('updateCartItems', $response);
$this->assertArrayHasKey('cart', $response['updateCartItems']);
@@ -91,7 +91,7 @@ public function testRemoveCartItemIfQuantityIsZero()
$qty = 0;
$query = $this->getQuery($maskedQuoteId, $itemId, $qty);
- $response = $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
$this->assertArrayHasKey('updateCartItems', $response);
$this->assertArrayHasKey('cart', $response['updateCartItems']);
@@ -108,7 +108,7 @@ public function testRemoveCartItemIfQuantityIsZero()
public function testUpdateItemInNonExistentCart()
{
$query = $this->getQuery('non_existent_masked_id', 1, 2);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -124,7 +124,7 @@ public function testUpdateNonExistentItem()
$this->expectExceptionMessage("Could not find cart item with id: {$notExistentItemId}.");
$query = $this->getQuery($maskedQuoteId, $notExistentItemId, 2);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -152,7 +152,7 @@ public function testUpdateItemIfItemIsNotBelongToCart()
$this->expectExceptionMessage("Could not find cart item with id: {$secondQuoteItemId}.");
$query = $this->getQuery($firstQuoteMaskedId, $secondQuoteItemId, 2);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -177,7 +177,7 @@ public function testUpdateItemInGuestCart()
);
$query = $this->getQuery($guestQuoteMaskedId, $guestQuoteItemId, 2);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -206,7 +206,7 @@ public function testUpdateItemInAnotherCustomerCart()
);
$query = $this->getQuery($anotherCustomerQuoteMaskedId, $anotherCustomerQuoteItemId, 2);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -235,7 +235,7 @@ public function testUpdateWithMissedCartItemId()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
@@ -266,7 +266,7 @@ public function testUpdateWithMissedItemRequiredParameters(string $input, string
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query, [], '', $this->getHeaderMap());
+ $this->graphQlMutation($query, [], '', $this->getHeaderMap());
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php
index eab362c3a0a6f..9bb9bef9bdb09 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetMaskedQuoteIdByReservedOrderId.php
@@ -50,14 +50,14 @@ public function __construct(
/**
* Get masked quote id by reserved order id
*
- * @param string $reversedOrderId
+ * @param string $reservedOrderId
* @return string
* @throws NoSuchEntityException
*/
- public function execute(string $reversedOrderId): string
+ public function execute(string $reservedOrderId): string
{
$quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, $reversedOrderId, 'reserved_order_id');
+ $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id');
return $this->quoteIdToMaskedId->execute((int)$quote->getId());
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetQuoteItemIdByReservedQuoteIdAndSku.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetQuoteItemIdByReservedQuoteIdAndSku.php
new file mode 100644
index 0000000000000..6f027babc0e27
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetQuoteItemIdByReservedQuoteIdAndSku.php
@@ -0,0 +1,66 @@
+quoteFactory = $quoteFactory;
+ $this->quoteResource = $quoteResource;
+ $this->productRepository = $productRepository;
+ }
+
+ /**
+ * Get quote item id by reserved order id and product sku
+ *
+ * @param string $reservedOrderId
+ * @param string $sku
+ * @return int
+ * @throws NoSuchEntityException
+ */
+ public function execute(string $reservedOrderId, string $sku): int
+ {
+ $quote = $this->quoteFactory->create();
+ $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id');
+ $product = $this->productRepository->get($sku);
+
+ return (int)$quote->getItemByProduct($product)->getId();
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetQuoteShippingAddressIdByReservedQuoteId.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetQuoteShippingAddressIdByReservedQuoteId.php
index fa42ad4d71fb2..a56949b6f563a 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetQuoteShippingAddressIdByReservedQuoteId.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/GetQuoteShippingAddressIdByReservedQuoteId.php
@@ -40,13 +40,13 @@ public function __construct(
/**
* Get quote shipping address id by reserved order id
*
- * @param string $reversedOrderId
+ * @param string $reservedOrderId
* @return int
*/
- public function execute(string $reversedOrderId): int
+ public function execute(string $reservedOrderId): int
{
$quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, $reversedOrderId, 'reserved_order_id');
+ $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id');
return (int)$quote->getShippingAddress()->getId();
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/AddSimpleProductToCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/AddSimpleProductToCartTest.php
new file mode 100644
index 0000000000000..9e0693b160851
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/AddSimpleProductToCartTest.php
@@ -0,0 +1,137 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ */
+ public function testAddSimpleProductToCart()
+ {
+ $sku = 'simple_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $response = $this->graphQlMutation($query);
+ self::assertArrayHasKey('cart', $response['addSimpleProductsToCart']);
+
+ self::assertEquals($qty, $response['addSimpleProductsToCart']['cart']['items'][0]['qty']);
+ self::assertEquals($sku, $response['addSimpleProductsToCart']['cart']['items'][0]['product']['sku']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testAddProductToNonExistentCart()
+ {
+ $sku = 'simple_product';
+ $qty = 1;
+ $maskedQuoteId = 'non_existent_masked_id';
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a product with SKU "simple_product"
+ */
+ public function testNonExistentProductToCart()
+ {
+ $sku = 'simple_product';
+ $qty = 1;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testAddSimpleProductToCustomerCart()
+ {
+ $sku = 'simple_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @param string $sku
+ * @param int $qty
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $sku, int $qty): string
+ {
+ return <<getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/virtual_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ */
+ public function testAddVirtualProductToCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey('cart', $response['addVirtualProductsToCart']);
+ self::assertEquals($qty, $response['addVirtualProductsToCart']['cart']['items'][0]['qty']);
+ self::assertEquals($sku, $response['addVirtualProductsToCart']['cart']['items'][0]['product']['sku']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/virtual_product.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testAddVirtualToNonExistentCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 1;
+ $maskedQuoteId = 'non_existent_masked_id';
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a product with SKU "virtual_product"
+ */
+ public function testNonExistentProductToCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 1;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/virtual_product.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testAddVirtualProductToCustomerCart()
+ {
+ $sku = 'virtual_product';
+ $qty = 2;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $sku, $qty);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @param string $sku
+ * @param int $qty
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $sku, int $qty): string
+ {
+ return <<getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ */
+ public function testApplyCouponToCart()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey('applyCouponToCart', $response);
+ self::assertEquals($couponCode, $response['applyCouponToCart']['cart']['applied_coupon']['code']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage A coupon is already applied to the cart. Please remove it to apply another
+ */
+ public function testApplyCouponTwice()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey("applyCouponToCart", $response);
+ self::assertEquals($couponCode, $response['applyCouponToCart']['cart']['applied_coupon']['code']);
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart does not contain products.
+ */
+ public function testApplyCouponToCartWithoutItems()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @expectedException \Exception
+ */
+ public function testApplyCouponToCustomerCart()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage The coupon code isn't valid. Verify the code and try again.
+ */
+ public function testApplyNonExistentCouponToCart()
+ {
+ $couponCode = 'non_existent_coupon_code';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @expectedException \Exception
+ */
+ public function testApplyCouponToNonExistentCart()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = 'non_existent_masked_id';
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ self::expectExceptionMessage('Could not find a cart with ID "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/make_coupon_expired.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage The coupon code isn't valid. Verify the code and try again.
+ */
+ public function testApplyExpiredCoupon()
+ {
+ $this->markTestIncomplete('https://github.com/magento/graphql-ce/issues/574');
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * Products in cart don't fit to the coupon
+ *
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage The coupon code isn't valid. Verify the code and try again.
+ */
+ public function testApplyCouponWhichIsNotApplicable()
+ {
+ $couponCode = '2?ds5!2d';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId, $couponCode);
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @param string $input
+ * @param string $message
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @dataProvider dataProviderUpdateWithMissedRequiredParameters
+ * @expectedException \Exception
+ */
+ public function testApplyCouponWithMissedRequiredParameters(string $input, string $message)
+ {
+ $query = <<expectExceptionMessage($message);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @return array
+ */
+ public function dataProviderUpdateWithMissedRequiredParameters(): array
+ {
+ return [
+ 'missed_cart_id' => [
+ 'coupon_code: "test"',
+ 'Required parameter "cart_id" is missing'
+ ],
+ 'missed_coupon_code' => [
+ 'cart_id: "test"',
+ 'Required parameter "coupon_code" is missing'
+ ],
+ ];
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @param string $couponCode
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $couponCode): string
+ {
+ return <<getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ */
+ public function testGetCartTotalsWithTaxApplied()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ self::assertArrayHasKey('prices', $response['cart']);
+ $pricesResponse = $response['cart']['prices'];
+ self::assertEquals(21.5, $pricesResponse['grand_total']['value']);
+ self::assertEquals(21.5, $pricesResponse['subtotal_including_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_excluding_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_with_discount_excluding_tax']['value']);
+
+ $appliedTaxesResponse = $pricesResponse['applied_taxes'];
+
+ self::assertEquals('US-TEST-*-Rate-1', $appliedTaxesResponse[0]['label']);
+ self::assertEquals(1.5, $appliedTaxesResponse[0]['amount']['value']);
+ self::assertEquals('USD', $appliedTaxesResponse[0]['amount']['currency']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ */
+ public function testGetTotalsWithNoTaxApplied()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ $pricesResponse = $response['cart']['prices'];
+ self::assertEquals(20, $pricesResponse['grand_total']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_including_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_excluding_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_with_discount_excluding_tax']['value']);
+ self::assertEmpty($pricesResponse['applied_taxes']);
+ }
+
+ /**
+ * The totals calculation is based on quote address.
+ * But the totals should be calculated even if no address is set
+ *
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @group recent
+ */
+ public function testGetCartTotalsWithNoAddressSet()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ $pricesResponse = $response['cart']['prices'];
+ self::assertEquals(20, $pricesResponse['grand_total']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_including_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_excluding_tax']['value']);
+ self::assertEquals(20, $pricesResponse['subtotal_with_discount_excluding_tax']['value']);
+ self::assertEmpty($pricesResponse['applied_taxes']);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ */
+ public function testGetSelectedShippingMethodFromCustomerCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+ $this->graphQlQuery($query);
+ }
+
+ /**
+ * Generates GraphQl query for retrieving cart totals
+ *
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<registry = $objectManager->get(Registry::class);
+ $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class);
+ $this->quoteResource = $objectManager->get(QuoteResource::class);
+ $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class);
+ $this->orderCollectionFactory = $objectManager->get(CollectionFactory::class);
+ $this->orderRepository = $objectManager->get(OrderRepositoryInterface::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Catalog/_files/products_with_layered_navigation_attribute.php
+ */
+ public function testCheckoutWorkflow()
+ {
+ $qty = 2;
+
+ $sku = $this->findProduct();
+ $cartId = $this->createEmptyCart();
+ $this->setGuestEmailOnCart($cartId);
+ $this->addProductToCart($cartId, $qty, $sku);
+
+ $this->setBillingAddress($cartId);
+ $shippingAddress = $this->setShippingAddress($cartId);
+
+ $shippingMethod = current($shippingAddress['available_shipping_methods']);
+ $paymentMethod = $this->setShippingMethod($cartId, $shippingAddress['address_id'], $shippingMethod);
+ $this->setPaymentMethod($cartId, $paymentMethod);
+
+ $this->placeOrder($cartId);
+ }
+
+ /**
+ * @return string
+ */
+ private function findProduct(): string
+ {
+ $query = <<graphQlQuery($query);
+ self::assertArrayHasKey('products', $response);
+ self::assertArrayHasKey('items', $response['products']);
+ self::assertCount(1, $response['products']['items']);
+
+ $product = current($response['products']['items']);
+ self::assertArrayHasKey('sku', $product);
+ self::assertNotEmpty($product['sku']);
+
+ return $product['sku'];
+ }
+
+ /**
+ * @return string
+ */
+ private function createEmptyCart(): string
+ {
+ $query = <<graphQlMutation($query);
+ self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertNotEmpty($response['createEmptyCart']);
+
+ return $response['createEmptyCart'];
+ }
+
+ /**
+ * @param string $cartId
+ * @return void
+ */
+ private function setGuestEmailOnCart(string $cartId): void
+ {
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * @param string $cartId
+ * @param float $qty
+ * @param string $sku
+ * @return void
+ */
+ private function addProductToCart(string $cartId, float $qty, string $sku): void
+ {
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * @param string $cartId
+ * @param array $auth
+ * @return array
+ */
+ private function setBillingAddress(string $cartId): void
+ {
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * @param string $cartId
+ * @return array
+ */
+ private function setShippingAddress(string $cartId): array
+ {
+ $query = <<graphQlMutation($query);
+ self::assertArrayHasKey('setShippingAddressesOnCart', $response);
+ self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
+ self::assertArrayHasKey('shipping_addresses', $response['setShippingAddressesOnCart']['cart']);
+ self::assertCount(1, $response['setShippingAddressesOnCart']['cart']['shipping_addresses']);
+
+ $shippingAddress = current($response['setShippingAddressesOnCart']['cart']['shipping_addresses']);
+ self::assertArrayHasKey('address_id', $shippingAddress);
+ self::assertNotEmpty($shippingAddress['address_id']);
+ self::assertArrayHasKey('available_shipping_methods', $shippingAddress);
+ self::assertCount(1, $shippingAddress['available_shipping_methods']);
+
+ $availableShippingMethod = current($shippingAddress['available_shipping_methods']);
+ self::assertArrayHasKey('carrier_code', $availableShippingMethod);
+ self::assertNotEmpty($availableShippingMethod['carrier_code']);
+
+ self::assertArrayHasKey('method_code', $availableShippingMethod);
+ self::assertNotEmpty($availableShippingMethod['method_code']);
+
+ self::assertArrayHasKey('amount', $availableShippingMethod);
+ self::assertNotEmpty($availableShippingMethod['amount']);
+
+ return $shippingAddress;
+ }
+
+ /**
+ * @param string $cartId
+ * @param int $addressId
+ * @param array $method
+ * @return array
+ */
+ private function setShippingMethod(string $cartId, int $addressId, array $method): array
+ {
+ $query = <<graphQlMutation($query);
+ self::assertArrayHasKey('setShippingMethodsOnCart', $response);
+ self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
+ self::assertArrayHasKey('available_payment_methods', $response['setShippingMethodsOnCart']['cart']);
+ self::assertCount(1, $response['setShippingMethodsOnCart']['cart']['available_payment_methods']);
+
+ $availablePaymentMethod = current($response['setShippingMethodsOnCart']['cart']['available_payment_methods']);
+ self::assertArrayHasKey('code', $availablePaymentMethod);
+ self::assertNotEmpty($availablePaymentMethod['code']);
+ self::assertArrayHasKey('title', $availablePaymentMethod);
+ self::assertNotEmpty($availablePaymentMethod['title']);
+
+ return $availablePaymentMethod;
+ }
+
+ /**
+ * @param string $cartId
+ * @param array $method
+ * @return void
+ */
+ private function setPaymentMethod(string $cartId, array $method): void
+ {
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * @param string $cartId
+ * @return void
+ */
+ private function placeOrder(string $cartId): void
+ {
+ $query = <<graphQlMutation($query);
+ self::assertArrayHasKey('placeOrder', $response);
+ self::assertArrayHasKey('order', $response['placeOrder']);
+ self::assertArrayHasKey('order_id', $response['placeOrder']['order']);
+ self::assertNotEmpty($response['placeOrder']['order']['order_id']);
+ }
+
+ public function tearDown()
+ {
+ $this->deleteQuote();
+ $this->deleteOrder();
+ parent::tearDown();
+ }
+
+ /**
+ * @return void
+ */
+ private function deleteQuote(): void
+ {
+ $quoteCollection = $this->quoteCollectionFactory->create();
+ foreach ($quoteCollection as $quote) {
+ $this->quoteResource->delete($quote);
+
+ $quoteIdMask = $this->quoteIdMaskFactory->create();
+ $quoteIdMask->setQuoteId($quote->getId())
+ ->delete();
+ }
+ }
+
+ /**
+ * @return void
+ */
+ private function deleteOrder()
+ {
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', true);
+
+ $orderCollection = $this->orderCollectionFactory->create();
+ foreach ($orderCollection as $order) {
+ $this->orderRepository->delete($order);
+ }
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', false);
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php
index 4fd398439913e..6ed91d21f0ae2 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/CreateEmptyCartTest.php
@@ -7,6 +7,9 @@
namespace Magento\GraphQl\Quote\Guest;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+use Magento\Quote\Model\ResourceModel\Quote\CollectionFactory as QuoteCollectionFactory;
+use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
use Magento\Quote\Api\GuestCartRepositoryInterface;
@@ -21,27 +24,146 @@ class CreateEmptyCartTest extends GraphQlAbstract
*/
private $guestCartRepository;
+ /**
+ * @var QuoteCollectionFactory
+ */
+ private $quoteCollectionFactory;
+
+ /**
+ * @var QuoteResource
+ */
+ private $quoteResource;
+
+ /**
+ * @var QuoteIdMaskFactory
+ */
+ private $quoteIdMaskFactory;
+
protected function setUp()
{
$objectManager = Bootstrap::getObjectManager();
$this->guestCartRepository = $objectManager->get(GuestCartRepositoryInterface::class);
+ $this->quoteCollectionFactory = $objectManager->get(QuoteCollectionFactory::class);
+ $this->quoteResource = $objectManager->get(QuoteResource::class);
+ $this->quoteIdMaskFactory = $objectManager->get(QuoteIdMaskFactory::class);
}
public function testCreateEmptyCart()
{
+ $query = $this->getQuery();
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertNotEmpty($response['createEmptyCart']);
+
+ $guestCart = $this->guestCartRepository->get($response['createEmptyCart']);
+
+ self::assertNotNull($guestCart->getId());
+ self::assertNull($guestCart->getCustomer()->getId());
+ self::assertEquals('default', $guestCart->getStore()->getCode());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Store/_files/second_store.php
+ */
+ public function testCreateEmptyCartWithNotDefaultStore()
+ {
+ $query = $this->getQuery();
+ $headerMap = ['Store' => 'fixture_second_store'];
+ $response = $this->graphQlMutation($query, [], '', $headerMap);
+
+ self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertNotEmpty($response['createEmptyCart']);
+
+ $guestCart = $this->guestCartRepository->get($response['createEmptyCart']);
+ $this->maskedQuoteId = $response['createEmptyCart'];
+
+ self::assertNotNull($guestCart->getId());
+ self::assertNull($guestCart->getCustomer()->getId());
+ self::assertSame('fixture_second_store', $guestCart->getStore()->getCode());
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ */
+ public function testCreateEmptyCartWithPredefinedCartId()
+ {
+ $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4';
+
$query = <<graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('createEmptyCart', $response);
+ self::assertEquals($predefinedCartId, $response['createEmptyCart']);
- $maskedCartId = $response['createEmptyCart'];
- $guestCart = $this->guestCartRepository->get($maskedCartId);
-
+ $guestCart = $this->guestCartRepository->get($response['createEmptyCart']);
self::assertNotNull($guestCart->getId());
self::assertNull($guestCart->getCustomer()->getId());
}
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart with ID "572cda51902b5b517c0e1a2b2fd004b4" already exists.
+ */
+ public function testCreateEmptyCartIfPredefinedCartIdAlreadyExists()
+ {
+ $predefinedCartId = '572cda51902b5b517c0e1a2b2fd004b4';
+
+ $query = <<graphQlMutation($query);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart ID length should to be 32 symbols.
+ */
+ public function testCreateEmptyCartWithWrongPredefinedCartId()
+ {
+ $predefinedCartId = '572';
+
+ $query = <<graphQlMutation($query);
+ }
+
+ /**
+ * @return string
+ */
+ private function getQuery(): string
+ {
+ return <<quoteCollectionFactory->create();
+ foreach ($quoteCollection as $quote) {
+ $this->quoteResource->delete($quote);
+
+ $quoteIdMask = $this->quoteIdMaskFactory->create();
+ $quoteIdMask->setQuoteId($quote->getId())
+ ->delete();
+ }
+ parent::tearDown();
+ }
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailablePaymentMethodsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailablePaymentMethodsTest.php
index 8271a76d88f12..af1f72fe71620 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailablePaymentMethodsTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailablePaymentMethodsTest.php
@@ -31,7 +31,7 @@ protected function setUp()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -52,7 +52,7 @@ public function testGetAvailablePaymentMethods()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -69,7 +69,7 @@ public function testGetAvailablePaymentMethodsFromCustomerCart()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailableShippingMethodsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailableShippingMethodsTest.php
index 38fda50ba5836..a8113657eff6e 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailableShippingMethodsTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetAvailableShippingMethodsTest.php
@@ -33,7 +33,7 @@ protected function setUp()
/**
* Test case: get available shipping methods from current customer quote
*
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -69,7 +69,7 @@ public function testGetAvailableShippingMethods()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -87,7 +87,7 @@ public function testGetAvailableShippingMethodsFromCustomerCart()
/**
* Test case: get available shipping methods when all shipping methods are disabled
*
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetCartEmailTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetCartEmailTest.php
new file mode 100644
index 0000000000000..8c6ecd075049f
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetCartEmailTest.php
@@ -0,0 +1,88 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ */
+ public function testGetCartEmail()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlQuery($query);
+
+ $this->assertArrayHasKey('cart', $response);
+ $this->assertArrayHasKey('email', $response['cart']);
+ $this->assertEquals('guest@example.com', $response['cart']['email']);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testGetCartEmailFromNonExistentCart()
+ {
+ $maskedQuoteId = 'non_existent_masked_id';
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->graphQlQuery($query);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testGetCartEmailFromCustomerCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"{$maskedQuoteId}\""
+ );
+ $this->graphQlQuery($query);
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<graphQlQuery($query);
}
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote_guest_not_default_store.php
+ */
+ public function testGetCartWithNotDefaultStore()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1_not_default_store_guest');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $headerMap = ['Store' => 'fixture_second_store'];
+ $response = $this->graphQlQuery($query, [], '', $headerMap);
+
+ self::assertArrayHasKey('cart', $response);
+ self::assertArrayHasKey('items', $response['cart']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php
+ * @magentoApiDataFixture Magento/Store/_files/second_store.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Wrong store code specified for cart
+ */
+ public function testGetCartWithWrongStore()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $headerMap = ['Store' => 'fixture_second_store'];
+ $this->graphQlQuery($query, [], '', $headerMap);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/Checkout/_files/active_quote_guest_not_default_store.php
+ *
+ * @expectedException \Exception
+ * @expectedExceptionMessage Store code not_existing_store does not exist
+ */
+ public function testGetCartWithNotExistingStore()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_order_1_not_default_store_guest');
+
+ $headerMap['Store'] = 'not_existing_store';
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->graphQlQuery($query, [], '', $headerMap);
+ }
+
/**
* @param string $maskedQuoteId
* @return string
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSelectedShippingMethodTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSelectedShippingMethodTest.php
index c31b48ccc1087..bfdecca782319 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSelectedShippingMethodTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSelectedShippingMethodTest.php
@@ -31,7 +31,7 @@ protected function setUp()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -61,7 +61,7 @@ public function testGetSelectedShippingMethod()
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -79,7 +79,7 @@ public function testGetSelectedShippingMethodFromCustomerCart()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSpecifiedBillingAddressTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSpecifiedBillingAddressTest.php
index 0110384b8f605..d592443aed499 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSpecifiedBillingAddressTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/GetSpecifiedBillingAddressTest.php
@@ -31,7 +31,7 @@ protected function setUp()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
@@ -69,7 +69,7 @@ public function testGeSpecifiedBillingAddress()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -118,7 +118,7 @@ public function testGetBillingAddressOfNonExistentCart()
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/PlaceOrderTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/PlaceOrderTest.php
new file mode 100644
index 0000000000000..30ad69eada29d
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/PlaceOrderTest.php
@@ -0,0 +1,273 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->orderCollectionFactory = $objectManager->get(CollectionFactory::class);
+ $this->orderRepository = $objectManager->get(OrderRepositoryInterface::class);
+ $this->registry = Bootstrap::getObjectManager()->get(Registry::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_checkmo_payment_method.php
+ */
+ public function testPlaceOrder()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey('placeOrder', $response);
+ self::assertArrayHasKey('order_id', $response['placeOrder']['order']);
+ self::assertEquals($reservedOrderId, $response['placeOrder']['order']['order_id']);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_checkmo_payment_method.php
+ */
+ public function testPlaceOrderWithNoEmail()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage("Guest email for cart is missing. Please enter");
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ */
+ public function testPlaceOrderWithNoItemsInCart()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage(
+ 'Unable to place order: A server error stopped your order from being placed. ' .
+ 'Please try to place your order again'
+ );
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testPlaceOrderWithNoShippingAddress()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage(
+ 'Unable to place order: Some addresses can\'t be used due to the configurations for specific countries'
+ );
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ */
+ public function testPlaceOrderWithNoShippingMethod()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage(
+ 'Unable to place order: The shipping method is missing. Select the shipping method and try again'
+ );
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ */
+ public function testPlaceOrderWithNoBillingAddress()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessageRegExp(
+ '/Unable to place order: Please check the billing address information*/'
+ );
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ */
+ public function testPlaceOrderWithNoPaymentMethod()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage('Unable to place order: Enter a valid payment method and try again');
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/set_simple_product_out_of_stock.php
+ */
+ public function testPlaceOrderWithOutOfStockProduct()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage('Unable to place order: Some of the products are out of stock');
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/three_customers.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_checkmo_payment_method.php
+ */
+ public function testPlaceOrderOfCustomerCart()
+ {
+ $reservedOrderId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId);
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessageRegExp('/The current user cannot perform operations on cart*/');
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', true);
+
+ $orderCollection = $this->orderCollectionFactory->create();
+ foreach ($orderCollection as $order) {
+ $this->orderRepository->delete($order);
+ }
+ $this->registry->unregister('isSecureArea');
+ $this->registry->register('isSecureArea', false);
+
+ parent::tearDown();
+ }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/RemoveCouponFromCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/RemoveCouponFromCartTest.php
new file mode 100644
index 0000000000000..5adb6ce65db6f
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/RemoveCouponFromCartTest.php
@@ -0,0 +1,128 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/SalesRule/_files/coupon_code_with_wildcard.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/apply_coupon.php
+ */
+ public function testRemoveCouponFromCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey('removeCouponFromCart', $response);
+ self::assertNull($response['removeCouponFromCart']['cart']['applied_coupon']['code']);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testRemoveCouponFromNonExistentCart()
+ {
+ $maskedQuoteId = 'non_existent_masked_id';
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @expectedException \Exception
+ * @expectedExceptionMessage Cart does not contain products
+ */
+ public function testRemoveCouponFromEmptyCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testRemoveCouponFromCartIfCouponWasNotSet()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId);
+ $response = $this->graphQlMutation($query);
+
+ self::assertArrayHasKey('removeCouponFromCart', $response);
+ self::assertNull($response['removeCouponFromCart']['cart']['applied_coupon']['code']);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/Checkout/_files/discount_10percent_generalusers.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/apply_coupon.php
+ */
+ public function testRemoveCouponFromCustomerCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $query = $this->getQuery($maskedQuoteId);
+
+ self::expectExceptionMessage('The current user cannot perform operations on cart "' . $maskedQuoteId . '"');
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @param string $maskedQuoteId
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId): string
+ {
+ return <<quoteResource = $objectManager->get(QuoteResource::class);
- $this->quoteFactory = $objectManager->get(QuoteFactory::class);
- $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
- $this->productRepository = $objectManager->get(ProductRepositoryInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->getQuoteItemIdByReservedQuoteIdAndSku = $objectManager->get(
+ GetQuoteItemIdByReservedQuoteIdAndSku::class
+ );
}
/**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
public function testRemoveItemFromCart()
{
- $quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, 'test_order_with_simple_product_without_address', 'reserved_order_id');
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId());
- $itemId = (int)$quote->getItemByProduct($this->productRepository->get('simple'))->getId();
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $itemId = $this->getQuoteItemIdByReservedQuoteIdAndSku->execute('test_quote', 'simple_product');
- $query = $this->prepareMutationQuery($maskedQuoteId, $itemId);
- $response = $this->graphQlQuery($query);
+ $query = $this->getQuery($maskedQuoteId, $itemId);
+ $response = $this->graphQlMutation($query);
$this->assertArrayHasKey('removeItemFromCart', $response);
$this->assertArrayHasKey('cart', $response['removeItemFromCart']);
@@ -72,70 +60,24 @@ public function testRemoveItemFromCart()
*/
public function testRemoveItemFromNonExistentCart()
{
- $query = $this->prepareMutationQuery('non_existent_masked_id', 1);
- $this->graphQlQuery($query);
+ $query = $this->getQuery('non_existent_masked_id', 1);
+ $this->graphQlMutation($query);
}
/**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
public function testRemoveNonExistentItem()
{
- $quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, 'test_order_with_simple_product_without_address', 'reserved_order_id');
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId());
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$notExistentItemId = 999;
$this->expectExceptionMessage("Cart doesn't contain the {$notExistentItemId} item.");
- $query = $this->prepareMutationQuery($maskedQuoteId, $notExistentItemId);
- $this->graphQlQuery($query);
- }
-
- /**
- * Test mutation is only able to remove quote item belonging to the requested cart
- *
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_simple_product_saved.php
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php
- */
- public function testRemoveItemIfItemIsNotBelongToCart()
- {
- $firstQuote = $this->quoteFactory->create();
- $this->quoteResource->load($firstQuote, 'test_order_with_simple_product_without_address', 'reserved_order_id');
- $firstQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$firstQuote->getId());
-
- $secondQuote = $this->quoteFactory->create();
- $this->quoteResource->load(
- $secondQuote,
- 'test_order_with_virtual_product_without_address',
- 'reserved_order_id'
- );
- $secondQuoteItemId = (int)$secondQuote
- ->getItemByProduct($this->productRepository->get('virtual-product'))
- ->getId();
-
- $this->expectExceptionMessage("Cart doesn't contain the {$secondQuoteItemId} item.");
-
- $query = $this->prepareMutationQuery($firstQuoteMaskedId, $secondQuoteItemId);
- $this->graphQlQuery($query);
- }
-
- /**
- * Test mutation is only able to remove quote item belonging to the requested cart
- *
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
- */
- public function testRemoveItemFromCustomerCart()
- {
- $customerQuote = $this->quoteFactory->create();
- $this->quoteResource->load($customerQuote, 'test_order_1', 'reserved_order_id');
- $customerQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$customerQuote->getId());
- $customerQuoteItemId = (int)$customerQuote->getItemByProduct($this->productRepository->get('simple'))->getId();
-
- $this->expectExceptionMessage("The current user cannot perform operations on cart \"$customerQuoteMaskedId\"");
-
- $query = $this->prepareMutationQuery($customerQuoteMaskedId, $customerQuoteItemId);
- $this->graphQlQuery($query);
+ $query = $this->getQuery($maskedQuoteId, $notExistentItemId);
+ $this->graphQlMutation($query);
}
/**
@@ -161,7 +103,7 @@ public function testUpdateWithMissedItemRequiredParameters(string $input, string
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -181,12 +123,51 @@ public function dataProviderUpdateWithMissedRequiredParameters(): array
];
}
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php
+ */
+ public function testRemoveItemIfItemIsNotBelongToCart()
+ {
+ $firstQuoteMaskedId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $secondQuoteItemId = $this->getQuoteItemIdByReservedQuoteIdAndSku->execute(
+ 'test_order_with_virtual_product_without_address',
+ 'virtual-product'
+ );
+
+ $this->expectExceptionMessage("Cart doesn't contain the {$secondQuoteItemId} item.");
+
+ $query = $this->getQuery($firstQuoteMaskedId, $secondQuoteItemId);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testRemoveItemFromCustomerCart()
+ {
+ $customerQuoteMaskedId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $customerQuoteItemId = $this->getQuoteItemIdByReservedQuoteIdAndSku->execute('test_quote', 'simple_product');
+
+ $this->expectExceptionMessage("The current user cannot perform operations on cart \"$customerQuoteMaskedId\"");
+
+ $query = $this->getQuery($customerQuoteMaskedId, $customerQuoteItemId);
+ $this->graphQlMutation($query);
+ }
+
/**
* @param string $maskedQuoteId
* @param int $itemId
* @return string
*/
- private function prepareMutationQuery(string $maskedQuoteId, int $itemId): string
+ private function getQuery(string $maskedQuoteId, int $itemId): string
{
return <<graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
$cartResponse = $response['setBillingAddressOnCart']['cart'];
@@ -86,7 +86,7 @@ public function testSetNewBillingAddress()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -149,7 +149,7 @@ public function testSetNewBillingAddressWithUseForShippingParameter()
}
}
QUERY;
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('cart', $response['setBillingAddressOnCart']);
$cartResponse = $response['setBillingAddressOnCart']['cart'];
@@ -203,12 +203,12 @@ public function testSetBillingAddressToCustomerCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
* _security
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -237,7 +237,7 @@ public function testSetBillingAddressFromAddressBook()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -276,11 +276,11 @@ public function testSetBillingAddressOnNonExistentCart()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -310,7 +310,7 @@ public function testSetBillingAddressWithoutRequiredParameters(string $input, st
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -331,6 +331,49 @@ public function dataProviderSetWithoutRequiredParameters(): array
];
}
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testSetNewBillingAddressRedundantStreetLine()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = <<graphQlMutation($query);
+ }
+
/**
* Verify the all the whitelisted fields for a New Address Object
*
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php
new file mode 100644
index 0000000000000..b877dccdeba37
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php
@@ -0,0 +1,141 @@
+getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ */
+ public function testSetGuestEmailOnCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $email = 'some@user.com';
+
+ $query = $this->getQuery($maskedQuoteId, $email);
+ $response = $this->graphQlMutation($query);
+
+ $this->assertArrayHasKey('setGuestEmailOnCart', $response);
+ $this->assertArrayHasKey('cart', $response['setGuestEmailOnCart']);
+ $this->assertEquals($email, $response['setGuestEmailOnCart']['cart']['email']);
+ }
+
+ /**
+ * _security
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ */
+ public function testSetGuestEmailOnCustomerCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $email = 'some@user.com';
+
+ $query = $this->getQuery($maskedQuoteId, $email);
+
+ $this->expectExceptionMessage(
+ "The current user cannot perform operations on cart \"$maskedQuoteId\""
+ );
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ *
+ * @dataProvider incorrectEmailDataProvider
+ * @param string $email
+ * @param string $exceptionMessage
+ */
+ public function testSetGuestEmailOnCartWithIncorrectEmail(
+ string $email,
+ string $exceptionMessage
+ ) {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $email);
+ $this->expectExceptionMessage($exceptionMessage);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @return array
+ */
+ public function incorrectEmailDataProvider(): array
+ {
+ return [
+ 'wrong_email' => ['some', 'Invalid email format'],
+ 'no_email' => ['', 'Required parameter "email" is missing'],
+ ];
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
+ */
+ public function testSetGuestEmailOnNonExistentCart()
+ {
+ $maskedQuoteId = 'non_existent_masked_id';
+ $email = 'some@user.com';
+
+ $query = $this->getQuery($maskedQuoteId, $email);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Required parameter "cart_id" is missing
+ */
+ public function testSetGuestEmailWithEmptyCartId()
+ {
+ $maskedQuoteId = '';
+ $email = 'some@user.com';
+
+ $query = $this->getQuery($maskedQuoteId, $email);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * Returns GraphQl mutation query for setting email address for a guest
+ *
+ * @param string $maskedQuoteId
+ * @param string $email
+ * @return string
+ */
+ private function getQuery(string $maskedQuoteId, string $email): string
+ {
+ return <<graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('setShippingMethodsOnCart', $response);
self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php
index c9078fd84f6bc..4ea7eac290f80 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetPaymentMethodOnCartTest.php
@@ -7,9 +7,11 @@
namespace Magento\GraphQl\Quote\Guest;
+use Exception;
use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId;
use Magento\OfflinePayments\Model\Cashondelivery;
use Magento\OfflinePayments\Model\Checkmo;
+use Magento\OfflinePayments\Model\Purchaseorder;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
@@ -33,7 +35,7 @@ protected function setUp()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -44,7 +46,7 @@ public function testSetPaymentOnCartWithSimpleProduct()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('setPaymentMethodOnCart', $response);
self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']);
@@ -53,11 +55,11 @@ public function testSetPaymentOnCartWithSimpleProduct()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage The shipping address is missing. Set the address and try again.
*/
public function testSetPaymentOnCartWithSimpleProductAndWithoutAddress()
@@ -66,7 +68,7 @@ public function testSetPaymentOnCartWithSimpleProductAndWithoutAddress()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -80,7 +82,7 @@ public function testSetPaymentOnCartWithVirtualProduct()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('setPaymentMethodOnCart', $response);
self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']);
@@ -89,12 +91,12 @@ public function testSetPaymentOnCartWithVirtualProduct()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
*
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage The requested Payment Method is not available.
*/
public function testSetNonExistentPaymentMethod()
@@ -103,11 +105,11 @@ public function testSetNonExistentPaymentMethod()
$maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage Could not find a cart with ID "non_existent_masked_id"
*/
public function testSetPaymentOnNonExistentCart()
@@ -116,13 +118,13 @@ public function testSetPaymentOnNonExistentCart()
$methodCode = Checkmo::PAYMENT_METHOD_CHECKMO_CODE;
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -137,11 +139,11 @@ public function testSetPaymentMethodToCustomerCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -149,7 +151,7 @@ public function testSetPaymentMethodToCustomerCart()
* @param string $input
* @param string $message
* @dataProvider dataProviderSetPaymentMethodWithoutRequiredParameters
- * @throws \Exception
+ * @throws Exception
*/
public function testSetPaymentMethodWithoutRequiredParameters(string $input, string $message)
{
@@ -169,7 +171,7 @@ public function testSetPaymentMethodWithoutRequiredParameters(string $input, str
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -194,7 +196,7 @@ public function dataProviderSetPaymentMethodWithoutRequiredParameters(): array
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_payment_methods.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
@@ -207,7 +209,7 @@ public function testReSetPayment()
$methodCode = Cashondelivery::PAYMENT_METHOD_CASHONDELIVERY_CODE;
$query = $this->getQuery($maskedQuoteId, $methodCode);
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('setPaymentMethodOnCart', $response);
self::assertArrayHasKey('cart', $response['setPaymentMethodOnCart']);
@@ -216,6 +218,23 @@ public function testReSetPayment()
self::assertEquals($methodCode, $response['setPaymentMethodOnCart']['cart']['selected_payment_method']['code']);
}
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @expectedException Exception
+ * @expectedExceptionMessage The requested Payment Method is not available.
+ */
+ public function testSetDisabledPaymentOnCart()
+ {
+ $methodCode = Purchaseorder::PAYMENT_METHOD_PURCHASEORDER_CODE;
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = $this->getQuery($maskedQuoteId, $methodCode);
+ $this->graphQlMutation($query);
+ }
+
/**
* @param string $maskedQuoteId
* @param string $methodCode
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingAddressOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingAddressOnCartTest.php
index e21d9ed64d491..888b0e87734b6 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingAddressOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingAddressOnCartTest.php
@@ -28,7 +28,7 @@ protected function setUp()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*/
@@ -78,7 +78,7 @@ public function testSetNewShippingAddressOnCartWithSimpleProduct()
}
}
QUERY;
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('cart', $response['setShippingAddressesOnCart']);
$cartResponse = $response['setShippingAddressesOnCart']['cart'];
@@ -130,12 +130,12 @@ public function testSetNewShippingAddressOnCartWithVirtualProduct()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
* _security
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -166,13 +166,13 @@ public function testSetShippingAddressFromAddressBook()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -205,11 +205,11 @@ public function testSetShippingAddressToCustomerCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -243,7 +243,51 @@ public function testSetNewShippingAddressWithMissedRequiredParameters(string $in
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ */
+ public function testSetNewShippingAddressOnCartWithRedundantStreetLine()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+
+ $query = <<graphQlMutation($query);
}
/**
@@ -264,7 +308,7 @@ public function dataProviderUpdateWithMissedRequiredParameters(): array
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
*
@@ -320,7 +364,7 @@ public function testSetMultipleNewShippingAddresses()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingMethodsOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingMethodsOnCartTest.php
index ca26f8fe5aaf0..59f53d2ad6856 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingMethodsOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetShippingMethodsOnCartTest.php
@@ -7,6 +7,7 @@
namespace Magento\GraphQl\Quote\Guest;
+use Exception;
use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId;
use Magento\GraphQl\Quote\GetQuoteShippingAddressIdByReservedQuoteId;
use Magento\TestFramework\Helper\Bootstrap;
@@ -40,7 +41,7 @@ protected function setUp()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -58,7 +59,7 @@ public function testSetShippingMethodOnCartWithSimpleProduct()
$carrierCode,
$quoteAddressId
);
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('setShippingMethodsOnCart', $response);
self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
@@ -79,13 +80,13 @@ public function testSetShippingMethodOnCartWithSimpleProduct()
* Shipping address for quote will be created automatically BUT with NULL values (considered that address
* is not set)
*
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/Catalog/_files/product_virtual.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_virtual_product.php
*
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage The shipping address is missing. Set the address and try again.
*/
public function testSetShippingMethodOnCartWithSimpleProductAndWithoutAddress()
@@ -101,12 +102,12 @@ public function testSetShippingMethodOnCartWithSimpleProductAndWithoutAddress()
$carrierCode,
$quoteAddressId
);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -125,7 +126,7 @@ public function testReSetShippingMethod()
$carrierCode,
$quoteAddressId
);
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertArrayHasKey('setShippingMethodsOnCart', $response);
self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
@@ -143,7 +144,7 @@ public function testReSetShippingMethod()
}
/**
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -151,7 +152,7 @@ public function testReSetShippingMethod()
* @param string $input
* @param string $message
* @dataProvider dataProviderSetShippingMethodWithWrongParameters
- * @throws \Exception
+ * @throws Exception
*/
public function testSetShippingMethodWithWrongParameters(string $input, string $message)
{
@@ -175,7 +176,7 @@ public function testSetShippingMethodWithWrongParameters(string $input, string $
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -270,16 +271,24 @@ public function dataProviderSetShippingMethodWithWrongParameters(): array
}]',
'Could not find a cart with ID "non_existent_masked_id"'
],
+ 'disabled_shipping_method' => [
+ 'cart_id: "cart_id_value", shipping_methods: [{
+ cart_address_id: cart_address_id_value
+ carrier_code: "freeshipping"
+ method_code: "freeshipping"
+ }]',
+ 'Carrier with such method not found: freeshipping, freeshipping'
+ ],
];
}
/**
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/enable_offline_shipping_methods.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
- * @expectedException \Exception
+ * @expectedException Exception
* @expectedExceptionMessage You cannot specify multiple shipping methods.
*/
public function testSetMultipleShippingMethods()
@@ -314,18 +323,18 @@ public function testSetMultipleShippingMethods()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
* _security
* @magentoApiDataFixture Magento/Customer/_files/customer.php
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
*
- * @expectedException \Exception
+ * @expectedException Exception
*/
public function testSetShippingMethodToCustomerCart()
{
@@ -343,12 +352,12 @@ public function testSetShippingMethodToCustomerCart()
$this->expectExceptionMessage(
"The current user cannot perform operations on cart \"$maskedQuoteId\""
);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
* _security
- * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -370,7 +379,31 @@ public function testSetShippingMethodIfGuestIsNotOwnerOfAddress()
$this->expectExceptionMessage(
"Cart does not contain address with ID \"{$anotherQuoteAddressId}\""
);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/quote_with_address.php
+ *
+ * @expectedException Exception
+ * @expectedExceptionMessage The shipping method can't be set for an empty cart. Add an item to cart and try again.
+ */
+ public function testSetShippingMethodOnAnEmptyCart()
+ {
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute('test_quote');
+ $carrierCode = 'flatrate';
+ $methodCode = 'flatrate';
+ $quoteAddressId = $this->getQuoteShippingAddressIdByReservedQuoteId->execute('test_quote');
+
+ $query = $this->getQuery(
+ $maskedQuoteId,
+ $methodCode,
+ $carrierCode,
+ $quoteAddressId
+ );
+ $this->graphQlMutation($query);
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/UpdateCartItemsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/UpdateCartItemsTest.php
index fca7a4287620b..1b8cf2e1c57f7 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/UpdateCartItemsTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/UpdateCartItemsTest.php
@@ -60,7 +60,7 @@ public function testUpdateCartItemQty()
$qty = 2;
$query = $this->getQuery($maskedQuoteId, $itemId, $qty);
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
$this->assertArrayHasKey('updateCartItems', $response);
$this->assertArrayHasKey('cart', $response['updateCartItems']);
@@ -84,7 +84,7 @@ public function testRemoveCartItemIfQuantityIsZero()
$qty = 0;
$query = $this->getQuery($maskedQuoteId, $itemId, $qty);
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
$this->assertArrayHasKey('updateCartItems', $response);
$this->assertArrayHasKey('cart', $response['updateCartItems']);
@@ -100,7 +100,7 @@ public function testRemoveCartItemIfQuantityIsZero()
public function testUpdateItemInNonExistentCart()
{
$query = $this->getQuery('non_existent_masked_id', 1, 2);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -116,7 +116,7 @@ public function testUpdateNonExistentItem()
$this->expectExceptionMessage("Could not find cart item with id: {$notExistentItemId}.");
$query = $this->getQuery($maskedQuoteId, $notExistentItemId, 2);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -142,7 +142,7 @@ public function testUpdateItemIfItemIsNotBelongToCart()
$this->expectExceptionMessage("Could not find cart item with id: {$secondQuoteItemId}.");
$query = $this->getQuery($firstQuoteMaskedId, $secondQuoteItemId, 2);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -158,7 +158,7 @@ public function testUpdateItemFromCustomerCart()
$this->expectExceptionMessage("The current user cannot perform operations on cart \"$customerQuoteMaskedId\"");
$query = $this->getQuery($customerQuoteMaskedId, $customerQuoteItemId, 2);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -186,7 +186,7 @@ public function testUpdateWithMissedCartItemId()
}
}
QUERY;
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -217,7 +217,7 @@ public function testUpdateWithMissedItemRequiredParameters(string $input, string
}
QUERY;
$this->expectExceptionMessage($message);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php
index 05e3e608c5e52..ae6faae7650b9 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/SendFriend/SendFriendTest.php
@@ -12,6 +12,9 @@
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
+/**
+ * Tests for send email to friend
+ */
class SendFriendTest extends GraphQlAbstract
{
@@ -66,7 +69,7 @@ public function testSendFriend()
}
QUERY;
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
self::assertEquals('Name', $response['sendEmailToFriend']['sender']['name']);
self::assertEquals('e@mail.com', $response['sendEmailToFriend']['sender']['email']);
self::assertEquals('Lorem Ipsum', $response['sendEmailToFriend']['sender']['message']);
@@ -117,7 +120,7 @@ public function testSendWithoutExistProduct()
$this->expectExceptionMessage(
'The product that was requested doesn\'t exist. Verify the product and try again.'
);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -181,7 +184,7 @@ public function testMaxSendEmailToFriend()
QUERY;
$this->expectException(\Exception::class);
$this->expectExceptionMessage("No more than {$sendFriend->getMaxRecipients()} emails can be sent at a time.");
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -214,7 +217,7 @@ public function testErrors(string $input, string $errorMessage)
QUERY;
$this->expectException(\Exception::class);
$this->expectExceptionMessage($errorMessage);
- $this->graphQlQuery($query);
+ $this->graphQlMutation($query);
}
/**
@@ -269,8 +272,9 @@ public function testLimitMessagesPerHour()
"You can't send messages more than {$sendFriend->getMaxSendsToFriend()} times an hour."
);
- for ($i = 0; $i <= $sendFriend->getMaxSendsToFriend() + 1; $i++) {
- $this->graphQlQuery($query);
+ $maxSendToFriends = $sendFriend->getMaxSendsToFriend();
+ for ($i = 0; $i <= $maxSendToFriends + 1; $i++) {
+ $this->graphQlMutation($query);
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlMutationTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlMutationTest.php
index b6e1a61f0357c..c85f63c083700 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlMutationTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlMutationTest.php
@@ -28,10 +28,31 @@ public function testMutation()
}
MUTATION;
- $response = $this->graphQlQuery($query);
+ $response = $this->graphQlMutation($query);
$this->assertArrayHasKey('testItem', $response);
$testItem = $response['testItem'];
$this->assertArrayHasKey('integer_list', $testItem);
$this->assertEquals([4, 5, 6], $testItem['integer_list']);
}
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Mutation requests allowed only for POST requests
+ */
+ public function testMutationIsNotAllowedViaGetRequest()
+ {
+ $id = 3;
+
+ $query = <<graphQlQuery($query, [], '', []);
+ }
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlQueryTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlQueryTest.php
index d59e255daa109..2db06e383758f 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlQueryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/TestModule/GraphQlQueryTest.php
@@ -58,4 +58,46 @@ public function testQueryTestModuleExtensionAttribute()
$this->assertArrayHasKey('integer_list', $testItem);
$this->assertEquals([3, 4, 5], $testItem['integer_list']);
}
+
+ public function testQueryViaGetRequestReturnsResults()
+ {
+ $id = 1;
+
+ $query = <<graphQlQuery($query, [], '', []);
+
+ $this->assertArrayHasKey('testItem', $response);
+ }
+
+ public function testQueryViaGetRequestWithVariablesReturnsResults()
+ {
+ $id = 1;
+
+ $query = << $id
+ ];
+
+ $response = $this->graphQlQuery($query, $variables, '', []);
+
+ $this->assertArrayHasKey('testItem', $response);
+ }
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Ups/SetUpsShippingMethodsOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Ups/SetUpsShippingMethodsOnCartTest.php
index 463f2c4af101f..fb0c205c86a2c 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Ups/SetUpsShippingMethodsOnCartTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Ups/SetUpsShippingMethodsOnCartTest.php
@@ -7,32 +7,56 @@
namespace Magento\GraphQl\Ups;
+use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId;
+use Magento\GraphQl\Quote\GetQuoteShippingAddressIdByReservedQuoteId;
use Magento\Integration\Api\CustomerTokenServiceInterface;
-use Magento\Quote\Model\QuoteFactory;
-use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
-use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
/**
- * Test for setting "UPS" shipping method on cart
+ * Test for setting "UPS" shipping method on cart. Current class covers the next UPS shipping methods:
+ *
+ * | Code | Label
+ * --------------------------------------
+ * | 1DM | Next Day Air Early AM
+ * | 1DA | Next Day Air
+ * | 2DA | 2nd Day Air
+ * | 3DS | 3 Day Select
+ * | GND | Ground
+ * | STD | Canada Standard
+ * | XPR | Worldwide Express
+ * | WXS | Worldwide Express Saver
+ * | XDM | Worldwide Express Plus
+ * | XPD | Worldwide Expedited
+ *
+ * Current class does not cover these UPS shipping methods (depends on address and sandbox settings)
+ *
+ * | Code | Label
+ * --------------------------------------
+ * | 1DML | Next Day Air Early AM Letter
+ * | 1DAL | Next Day Air Letter
+ * | 1DAPI | Next Day Air Intra (Puerto Rico)
+ * | 1DP | Next Day Air Saver
+ * | 1DPL | Next Day Air Saver Letter
+ * | 2DM | 2nd Day Air AM
+ * | 2DML | 2nd Day Air AM Letter
+ * | 2DAL | 2nd Day Air Letter
+ * | GNDCOM | Ground Commercial
+ * | GNDRES | Ground Residential
+ * | XPRL | Worldwide Express Letter
+ * | XDML | Worldwide Express Plus Letter
*/
class SetUpsShippingMethodsOnCartTest extends GraphQlAbstract
{
/**
- * Defines carrier code for "UPS" shipping method
- */
- const CARRIER_CODE = 'ups';
-
- /**
- * Defines method code for the "Ground" UPS shipping
+ * Defines carrier label for "UPS" shipping method
*/
- const CARRIER_METHOD_CODE_GROUND = 'GND';
+ const CARRIER_LABEL = 'United Parcel Service';
/**
- * @var QuoteFactory
+ * Defines carrier code for "UPS" shipping method
*/
- private $quoteFactory;
+ const CARRIER_CODE = 'ups';
/**
* @var CustomerTokenServiceInterface
@@ -40,14 +64,14 @@ class SetUpsShippingMethodsOnCartTest extends GraphQlAbstract
private $customerTokenService;
/**
- * @var QuoteResource
+ * @var GetMaskedQuoteIdByReservedOrderId
*/
- private $quoteResource;
+ private $getMaskedQuoteIdByReservedOrderId;
/**
- * @var QuoteIdToMaskedQuoteIdInterface
+ * @var GetQuoteShippingAddressIdByReservedQuoteId
*/
- private $quoteIdToMaskedId;
+ private $getQuoteShippingAddressIdByReservedQuoteId;
/**
* @inheritdoc
@@ -55,38 +79,123 @@ class SetUpsShippingMethodsOnCartTest extends GraphQlAbstract
protected function setUp()
{
$objectManager = Bootstrap::getObjectManager();
- $this->quoteResource = $objectManager->get(QuoteResource::class);
- $this->quoteFactory = $objectManager->get(QuoteFactory::class);
- $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
$this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class);
+ $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class);
+ $this->getQuoteShippingAddressIdByReservedQuoteId = $objectManager->get(
+ GetQuoteShippingAddressIdByReservedQuoteId::class
+ );
}
/**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
- * @magentoApiDataFixture Magento/Ups/_files/enable_ups_shipping_method.php
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Ups/_files/enable_ups_shipping_method.php
+ *
+ * @dataProvider dataProviderShippingMethods
+ * @param string $methodCode
+ * @param string $methodLabel
*/
- public function testSetUpsShippingMethod()
+ public function testSetUpsShippingMethod(string $methodCode, string $methodLabel)
{
- $quote = $this->quoteFactory->create();
- $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id');
- $maskedQuoteId = $this->quoteIdToMaskedId->execute((int)$quote->getId());
- $shippingAddressId = (int)$quote->getShippingAddress()->getId();
-
- $query = $this->getAddUpsShippingMethodQuery(
- $maskedQuoteId,
- $shippingAddressId,
- self::CARRIER_CODE,
- self::CARRIER_METHOD_CODE_GROUND
+ $quoteReservedId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($quoteReservedId);
+ $shippingAddressId = $this->getQuoteShippingAddressIdByReservedQuoteId->execute($quoteReservedId);
+
+ $query = $this->getQuery($maskedQuoteId, $shippingAddressId, self::CARRIER_CODE, $methodCode);
+ $response = $this->sendRequestWithToken($query);
+
+ self::assertArrayHasKey('setShippingMethodsOnCart', $response);
+ self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
+ self::assertArrayHasKey('shipping_addresses', $response['setShippingMethodsOnCart']['cart']);
+ self::assertCount(1, $response['setShippingMethodsOnCart']['cart']['shipping_addresses']);
+
+ $shippingAddress = current($response['setShippingMethodsOnCart']['cart']['shipping_addresses']);
+ self::assertArrayHasKey('selected_shipping_method', $shippingAddress);
+
+ self::assertArrayHasKey('carrier_code', $shippingAddress['selected_shipping_method']);
+ self::assertEquals(self::CARRIER_CODE, $shippingAddress['selected_shipping_method']['carrier_code']);
+
+ self::assertArrayHasKey('method_code', $shippingAddress['selected_shipping_method']);
+ self::assertEquals($methodCode, $shippingAddress['selected_shipping_method']['method_code']);
+
+ self::assertArrayHasKey('label', $shippingAddress['selected_shipping_method']);
+ self::assertEquals(
+ self::CARRIER_LABEL . ' - ' . $methodLabel,
+ $shippingAddress['selected_shipping_method']['label']
);
+ }
+ /**
+ * @return array
+ */
+ public function dataProviderShippingMethods(): array
+ {
+ return [
+ 'Next Day Air Early AM' => ['1DM', 'Next Day Air Early AM'],
+ 'Next Day Air' => ['1DA', 'Next Day Air'],
+ '2nd Day Air' => ['2DA', '2nd Day Air'],
+ '3 Day Select' => ['3DS', '3 Day Select'],
+ 'Ground' => ['GND', 'Ground'],
+ ];
+ }
+
+ /**
+ * @magentoApiDataFixture Magento/Customer/_files/customer.php
+ * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
+ * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_canada_address.php
+ * @magentoApiDataFixture Magento/GraphQl/Ups/_files/enable_ups_shipping_method.php
+ *
+ * @dataProvider dataProviderShippingMethodsBasedOnCanadaAddress
+ * @param string $methodCode
+ * @param string $methodLabel
+ */
+ public function testSetUpsShippingMethodBasedOnCanadaAddress(string $methodCode, string $methodLabel)
+ {
+ $quoteReservedId = 'test_quote';
+ $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($quoteReservedId);
+ $shippingAddressId = $this->getQuoteShippingAddressIdByReservedQuoteId->execute($quoteReservedId);
+
+ $query = $this->getQuery($maskedQuoteId, $shippingAddressId, self::CARRIER_CODE, $methodCode);
$response = $this->sendRequestWithToken($query);
- $addressesInformation = $response['setShippingMethodsOnCart']['cart']['shipping_addresses'];
- $expectedResult = [
- 'carrier_code' => self::CARRIER_CODE,
- 'method_code' => self::CARRIER_METHOD_CODE_GROUND,
- 'label' => 'United Parcel Service - Ground',
+
+ self::assertArrayHasKey('setShippingMethodsOnCart', $response);
+ self::assertArrayHasKey('cart', $response['setShippingMethodsOnCart']);
+ self::assertArrayHasKey('shipping_addresses', $response['setShippingMethodsOnCart']['cart']);
+ self::assertCount(1, $response['setShippingMethodsOnCart']['cart']['shipping_addresses']);
+
+ $shippingAddress = current($response['setShippingMethodsOnCart']['cart']['shipping_addresses']);
+ self::assertArrayHasKey('selected_shipping_method', $shippingAddress);
+
+ self::assertArrayHasKey('carrier_code', $shippingAddress['selected_shipping_method']);
+ self::assertEquals(self::CARRIER_CODE, $shippingAddress['selected_shipping_method']['carrier_code']);
+
+ self::assertArrayHasKey('method_code', $shippingAddress['selected_shipping_method']);
+ self::assertEquals($methodCode, $shippingAddress['selected_shipping_method']['method_code']);
+
+ self::assertArrayHasKey('label', $shippingAddress['selected_shipping_method']);
+ self::assertEquals(
+ self::CARRIER_LABEL . ' - ' . $methodLabel,
+ $shippingAddress['selected_shipping_method']['label']
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function dataProviderShippingMethodsBasedOnCanadaAddress(): array
+ {
+ return [
+ 'Canada Standard' => ['STD', 'Canada Standard'],
+ 'Worldwide Express' => ['XPR', 'Worldwide Express'],
+ 'Worldwide Express Saver' => ['WXS', 'Worldwide Express Saver'],
+ 'Worldwide Express Plus' => ['XDM', 'Worldwide Express Plus'],
+ 'Worldwide Expedited' => ['XPD', 'Worldwide Expedited'],
];
- self::assertEquals($addressesInformation[0]['selected_shipping_method'], $expectedResult);
}
/**
@@ -98,7 +207,7 @@ public function testSetUpsShippingMethod()
* @param string $methodCode
* @return string
*/
- private function getAddUpsShippingMethodQuery(
+ private function getQuery(
string $maskedQuoteId,
int $shippingAddressId,
string $carrierCode,
@@ -142,6 +251,6 @@ private function sendRequestWithToken(string $query): array
$customerToken = $this->customerTokenService->createCustomerAccessToken('customer@example.com', 'password');
$headerMap = ['Authorization' => 'Bearer ' . $customerToken];
- return $this->graphQlQuery($query, [], '', $headerMap);
+ return $this->graphQlMutation($query, [], '', $headerMap);
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Vault/CustomerPaymentTokensTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Vault/CustomerPaymentTokensTest.php
index 89fbbb9c49ed3..45c82906d255d 100644
--- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Vault/CustomerPaymentTokensTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Vault/CustomerPaymentTokensTest.php
@@ -14,6 +14,9 @@
use Magento\Vault\Model\ResourceModel\PaymentToken as TokenResource;
use Magento\Vault\Model\ResourceModel\PaymentToken\CollectionFactory;
+/**
+ * Tests for customer payment tokens
+ */
class CustomerPaymentTokensTest extends GraphQlAbstract
{
/**
@@ -139,7 +142,12 @@ public function testDeletePaymentToken()
}
}
QUERY;
- $response = $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $response = $this->graphQlMutation(
+ $query,
+ [],
+ '',
+ $this->getCustomerAuthHeaders($currentEmail, $currentPassword)
+ );
$this->assertTrue($response['deletePaymentToken']['result']);
$this->assertEquals(1, count($response['deletePaymentToken']['customerPaymentTokens']['items']));
@@ -168,7 +176,7 @@ public function testDeletePaymentTokenIfUserIsNotAuthorized()
}
}
QUERY;
- $this->graphQlQuery($query, [], '');
+ $this->graphQlMutation($query, [], '');
}
/**
@@ -190,7 +198,7 @@ public function testDeletePaymentTokenInvalidPublicHash()
}
}
QUERY;
- $this->graphQlQuery($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
+ $this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword));
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CouponManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CouponManagementTest.php
index 1aee493d8e0cb..1fb8fc43b0db6 100644
--- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CouponManagementTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CouponManagementTest.php
@@ -9,6 +9,9 @@
use Magento\TestFramework\TestCase\WebapiAbstract;
+/**
+ * Coupon management service tests
+ */
class CouponManagementTest extends WebapiAbstract
{
const SERVICE_VERSION = 'V1';
@@ -93,7 +96,7 @@ public function testSetCouponThrowsExceptionIfCouponDoesNotExist()
$serviceInfo = [
'rest' => [
- 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons/' . $couponCode,
+ 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons/' . urlencode($couponCode),
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
],
'soap' => [
@@ -129,7 +132,7 @@ public function testSetCouponSuccess()
$couponCode = $salesRule->getPrimaryCoupon()->getCode();
$serviceInfo = [
'rest' => [
- 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons/' . $couponCode,
+ 'resourcePath' => self::RESOURCE_PATH . $cartId . '/coupons/' . urlencode($couponCode),
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
],
'soap' => [
@@ -232,7 +235,7 @@ public function testSetMyCouponThrowsExceptionIfCouponDoesNotExist()
$serviceInfo = [
'rest' => [
- 'resourcePath' => self::RESOURCE_PATH . 'mine/coupons/' . $couponCode,
+ 'resourcePath' => self::RESOURCE_PATH . 'mine/coupons/' . urlencode($couponCode),
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
'token' => $token,
],
@@ -280,7 +283,7 @@ public function testSetMyCouponSuccess()
$serviceInfo = [
'rest' => [
- 'resourcePath' => self::RESOURCE_PATH . 'mine/coupons/' . $couponCode,
+ 'resourcePath' => self::RESOURCE_PATH . 'mine/coupons/' . urlencode($couponCode),
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
'token' => $token,
],
diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php
index 8e5373ea76576..92942d7acc6f2 100644
--- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Sales\Service\V1;
use Magento\Sales\Model\Order;
@@ -201,6 +202,73 @@ public function testFullRequest()
}
}
+ /**
+ * Test order will keep same(custom) status after partial refund, if state has not been changed.
+ *
+ * @magentoApiDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
+ */
+ public function testOrderStatusPartialRefund()
+ {
+ /** @var \Magento\Sales\Model\Order $existingOrder */
+ $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+ ->loadByIncrementId('100000001');
+
+ $items = $this->getOrderItems($existingOrder);
+ $items[0]['qty'] -= 1;
+ $result = $this->_webApiCall(
+ $this->getServiceData($existingOrder),
+ [
+ 'orderId' => $existingOrder->getEntityId(),
+ 'items' => $items,
+ ]
+ );
+
+ $this->assertNotEmpty(
+ $result,
+ 'Failed asserting that the received response is correct'
+ );
+
+ /** @var \Magento\Sales\Model\Order $updatedOrder */
+ $updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+ ->loadByIncrementId($existingOrder->getIncrementId());
+
+ $this->assertSame('custom_processing', $updatedOrder->getStatus());
+ $this->assertSame('processing', $updatedOrder->getState());
+ }
+
+ /**
+ * Test order will change custom status after total refund, when state has been changed.
+ *
+ * @magentoApiDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
+ */
+ public function testOrderStatusTotalRefund()
+ {
+ /** @var \Magento\Sales\Model\Order $existingOrder */
+ $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+ ->loadByIncrementId('100000001');
+
+ $items = $this->getOrderItems($existingOrder);
+ $result = $this->_webApiCall(
+ $this->getServiceData($existingOrder),
+ [
+ 'orderId' => $existingOrder->getEntityId(),
+ 'items' => $items,
+ ]
+ );
+
+ $this->assertNotEmpty(
+ $result,
+ 'Failed asserting that the received response is correct'
+ );
+
+ /** @var \Magento\Sales\Model\Order $updatedOrder */
+ $updatedOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class)
+ ->loadByIncrementId($existingOrder->getIncrementId());
+
+ $this->assertSame('complete', $updatedOrder->getStatus());
+ $this->assertSame('complete', $updatedOrder->getState());
+ }
+
/**
* Prepares and returns info for API service.
*
diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/JoinDirectivesTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/JoinDirectivesTest.php
index 5f967758e21bd..8beb14e81be71 100644
--- a/dev/tests/api-functional/testsuite/Magento/Webapi/JoinDirectivesTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Webapi/JoinDirectivesTest.php
@@ -6,12 +6,14 @@
namespace Magento\Webapi;
+use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\SearchCriteriaBuilder;
-use Magento\Framework\Api\SortOrderBuilder;
use Magento\Framework\Api\SortOrder;
-use Magento\Framework\Api\SearchCriteria;
-use Magento\Framework\Api\FilterBuilder;
+use Magento\Framework\Api\SortOrderBuilder;
+/**
+ * Test join directives.
+ */
class JoinDirectivesTest extends \Magento\TestFramework\TestCase\WebapiAbstract
{
/**
@@ -44,7 +46,8 @@ protected function setUp()
}
/**
- * Rollback rules
+ * Rollback rules.
+ *
* @magentoApiDataFixture Magento/SalesRule/_files/rules_rollback.php
* @magentoApiDataFixture Magento/Sales/_files/quote.php
*/
@@ -124,6 +127,49 @@ public function testAutoGeneratedGetList()
$this->assertEquals($expectedExtensionAttributes['email'], $testAttribute['email']);
}
+ /**
+ * Test get list of orders with extension attributes.
+ *
+ * @magentoApiDataFixture Magento/Sales/_files/order.php
+ */
+ public function testGetOrdertList()
+ {
+ $filter = $this->filterBuilder
+ ->setField('increment_id')
+ ->setValue('100000001')
+ ->setConditionType('eq')
+ ->create();
+ $this->searchBuilder->addFilters([$filter]);
+ $searchData = $this->searchBuilder->create()->__toArray();
+
+ $requestData = ['searchCriteria' => $searchData];
+
+ $restResourcePath = '/V1/orders/';
+ $soapService = 'salesOrderRepositoryV1';
+ $expectedExtensionAttributes = $this->getExpectedExtensionAttributes();
+
+ $serviceInfo = [
+ 'rest' => [
+ 'resourcePath' => $restResourcePath . '?' . http_build_query($requestData),
+ 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
+ ],
+ 'soap' => [
+ 'service' => $soapService,
+ 'operation' => $soapService . 'GetList',
+ ],
+ ];
+ $searchResult = $this->_webApiCall($serviceInfo, $requestData);
+
+ $this->assertArrayHasKey('items', $searchResult);
+ $itemData = array_pop($searchResult['items']);
+ $this->assertArrayHasKey('extension_attributes', $itemData);
+ $this->assertArrayHasKey('order_api_test_attribute', $itemData['extension_attributes']);
+ $testAttribute = $itemData['extension_attributes']['order_api_test_attribute'];
+ $this->assertEquals($expectedExtensionAttributes['firstname'], $testAttribute['first_name']);
+ $this->assertEquals($expectedExtensionAttributes['lastname'], $testAttribute['last_name']);
+ $this->assertEquals($expectedExtensionAttributes['email'], $testAttribute['email']);
+ }
+
/**
* Retrieve the admin user's information.
*
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
index f0abd280f3ebc..8fa22122cce89 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
@@ -8,7 +8,6 @@
use Magento\Mtf\Util\Protocol\CurlInterface;
use Magento\Mtf\Util\Protocol\CurlTransport;
-use Magento\Mtf\Util\Protocol\CurlTransport\WebapiDecorator;
/**
* Perform bin/magento commands from command line for functional tests executions.
@@ -18,7 +17,7 @@ class Cli
/**
* Url to command.php.
*/
- const URL = '/dev/tests/functional/utils/command.php';
+ const URL = 'dev/tests/functional/utils/command.php';
/**
* Curl transport protocol.
@@ -27,21 +26,12 @@ class Cli
*/
private $transport;
- /**
- * Webapi handler.
- *
- * @var WebapiDecorator
- */
- private $webapiHandler;
-
/**
* @param CurlTransport $transport
- * @param WebapiDecorator $webapiHandler
*/
- public function __construct(CurlTransport $transport, WebapiDecorator $webapiHandler)
+ public function __construct(CurlTransport $transport)
{
$this->transport = $transport;
- $this->webapiHandler = $webapiHandler;
}
/**
@@ -53,31 +43,22 @@ public function __construct(CurlTransport $transport, WebapiDecorator $webapiHan
*/
public function execute($command, $options = [])
{
- $this->transport->write(
- rtrim(str_replace('index.php', '', $_ENV['app_frontend_url']), '/') . self::URL,
- $this->prepareParamArray($command, $options),
- CurlInterface::POST,
- []
- );
- $this->transport->read();
- $this->transport->close();
+ $curl = $this->transport;
+ $curl->write($this->prepareUrl($command, $options), [], CurlInterface::GET);
+ $curl->read();
+ $curl->close();
}
/**
- * Prepare parameter array.
+ * Prepare url.
*
* @param string $command
* @param array $options [optional]
- * @return array
+ * @return string
*/
- private function prepareParamArray($command, $options = [])
+ private function prepareUrl($command, $options = [])
{
- if (!empty($options)) {
- $command .= ' ' . implode(' ', $options);
- }
- return [
- 'token' => urlencode($this->webapiHandler->getWebapiToken()),
- 'command' => urlencode($command)
- ];
+ $command .= ' ' . implode(' ', $options);
+ return $_ENV['app_frontend_url'] . self::URL . '?command=' . urlencode($command);
}
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Reader.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Reader.php
index 69df78a5cad64..d7336b51a18e2 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Reader.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/Reader.php
@@ -3,12 +3,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Mtf\Util\Command\File\Export;
use Magento\Mtf\ObjectManagerInterface;
use Magento\Mtf\Util\Protocol\CurlTransport;
use Magento\Mtf\Util\Protocol\CurlInterface;
-use Magento\Mtf\Util\Protocol\CurlTransport\WebapiDecorator;
/**
* File reader for Magento export files.
@@ -36,29 +36,16 @@ class Reader implements ReaderInterface
*/
private $transport;
- /**
- * Webapi handler.
- *
- * @var WebapiDecorator
- */
- private $webapiHandler;
-
/**
* @param ObjectManagerInterface $objectManager
* @param CurlTransport $transport
- * @param WebapiDecorator $webapiHandler
* @param string $template
*/
- public function __construct(
- ObjectManagerInterface $objectManager,
- CurlTransport $transport,
- WebapiDecorator $webapiHandler,
- $template
- ) {
+ public function __construct(ObjectManagerInterface $objectManager, CurlTransport $transport, $template)
+ {
$this->objectManager = $objectManager;
$this->template = $template;
$this->transport = $transport;
- $this->webapiHandler = $webapiHandler;
}
/**
@@ -83,27 +70,20 @@ public function getData()
*/
private function getFiles()
{
- $this->transport->write(
- rtrim(str_replace('index.php', '', $_ENV['app_frontend_url']), '/') . self::URL,
- $this->prepareParamArray(),
- CurlInterface::POST,
- []
- );
+ $this->transport->write($this->prepareUrl(), [], CurlInterface::GET);
$serializedFiles = $this->transport->read();
$this->transport->close();
- return unserialize($serializedFiles);
+ // phpcs:ignore Magento2.Security.InsecureFunction
+ return unserialize($serializedFiles, ['allowed_classes' => false]);
}
/**
- * Prepare parameter array.
+ * Prepare url.
*
- * @return array
+ * @return string
*/
- private function prepareParamArray()
+ private function prepareUrl()
{
- return [
- 'token' => urlencode($this->webapiHandler->getWebapiToken()),
- 'template' => urlencode($this->template)
- ];
+ return $_ENV['app_frontend_url'] . self::URL . '?template=' . urlencode($this->template);
}
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/ReaderInterface.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/ReaderInterface.php
index 3666e8643efa3..93f7cf1ce9764 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/ReaderInterface.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Export/ReaderInterface.php
@@ -14,7 +14,7 @@ interface ReaderInterface
/**
* Url to export.php.
*/
- const URL = '/dev/tests/functional/utils/export.php';
+ const URL = 'dev/tests/functional/utils/export.php';
/**
* Exporting files as Data object from Magento.
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Log.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Log.php
index 820a5b0a82228..f4e55682857a2 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Log.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/File/Log.php
@@ -7,7 +7,6 @@
namespace Magento\Mtf\Util\Command\File;
use Magento\Mtf\Util\Protocol\CurlTransport;
-use Magento\Mtf\Util\Protocol\CurlTransport\WebapiDecorator;
/**
* Get content of log file in var/log folder.
@@ -17,7 +16,7 @@ class Log
/**
* Url to log.php.
*/
- const URL = '/dev/tests/functional/utils/log.php';
+ const URL = 'dev/tests/functional/utils/log.php';
/**
* Curl transport protocol.
@@ -26,21 +25,12 @@ class Log
*/
private $transport;
- /**
- * Webapi handler.
- *
- * @var WebapiDecorator
- */
- private $webapiHandler;
-
/**
* @param CurlTransport $transport
- * @param WebapiDecorator $webapiHandler
*/
- public function __construct(CurlTransport $transport, WebapiDecorator $webapiHandler)
+ public function __construct(CurlTransport $transport)
{
$this->transport = $transport;
- $this->webapiHandler = $webapiHandler;
}
/**
@@ -51,28 +41,22 @@ public function __construct(CurlTransport $transport, WebapiDecorator $webapiHan
*/
public function getFileContent($name)
{
- $this->transport->write(
- rtrim(str_replace('index.php', '', $_ENV['app_frontend_url']), '/') . self::URL,
- $this->prepareParamArray($name),
- CurlInterface::POST,
- []
- );
- $data = $this->transport->read();
- $this->transport->close();
+ $curl = $this->transport;
+ $curl->write($this->prepareUrl($name), [], CurlTransport::GET);
+ $data = $curl->read();
+ $curl->close();
+ // phpcs:ignore Magento2.Security.InsecureFunction
return unserialize($data);
}
/**
- * Prepare parameter array.
+ * Prepare url.
*
* @param string $name
- * @return array
+ * @return string
*/
- private function prepareParamArray($name)
+ private function prepareUrl($name)
{
- return [
- 'token' => urlencode($this->webapiHandler->getWebapiToken()),
- 'name' => urlencode($name)
- ];
+ return $_ENV['app_frontend_url'] . self::URL . '?name=' . urlencode($name);
}
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/GeneratedCode.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/GeneratedCode.php
index a9fefa25ffa24..dde3409ed1562 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/GeneratedCode.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/GeneratedCode.php
@@ -7,7 +7,6 @@
use Magento\Mtf\Util\Protocol\CurlInterface;
use Magento\Mtf\Util\Protocol\CurlTransport;
-use Magento\Mtf\Util\Protocol\CurlTransport\WebapiDecorator;
/**
* GeneratedCode removes generated code of Magento (like generated/code and generated/metadata).
@@ -17,7 +16,7 @@ class GeneratedCode
/**
* Url to deleteMagentoGeneratedCode.php.
*/
- const URL = '/dev/tests/functional/utils/deleteMagentoGeneratedCode.php';
+ const URL = 'dev/tests/functional/utils/deleteMagentoGeneratedCode.php';
/**
* Curl transport protocol.
@@ -26,21 +25,12 @@ class GeneratedCode
*/
private $transport;
- /**
- * Webapi handler.
- *
- * @var WebapiDecorator
- */
- private $webapiHandler;
-
/**
* @param CurlTransport $transport
- * @param WebapiDecorator $webapiHandler
*/
- public function __construct(CurlTransport $transport, WebapiDecorator $webapiHandler)
+ public function __construct(CurlTransport $transport)
{
$this->transport = $transport;
- $this->webapiHandler = $webapiHandler;
}
/**
@@ -50,25 +40,10 @@ public function __construct(CurlTransport $transport, WebapiDecorator $webapiHan
*/
public function delete()
{
- $this->transport->write(
- rtrim(str_replace('index.php', '', $_ENV['app_frontend_url']), '/') . self::URL,
- $this->prepareParamArray(),
- CurlInterface::POST,
- []
- );
- $this->transport->read();
- $this->transport->close();
- }
-
- /**
- * Prepare parameter array.
- *
- * @return array
- */
- private function prepareParamArray()
- {
- return [
- 'token' => urlencode($this->webapiHandler->getWebapiToken())
- ];
+ $url = $_ENV['app_frontend_url'] . self::URL;
+ $curl = $this->transport;
+ $curl->write($url, [], CurlInterface::GET);
+ $curl->read();
+ $curl->close();
}
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Locales.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Locales.php
index a55d803f43087..f669d91f2f2e5 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Locales.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Locales.php
@@ -7,7 +7,6 @@
use Magento\Mtf\Util\Protocol\CurlInterface;
use Magento\Mtf\Util\Protocol\CurlTransport;
-use Magento\Mtf\Util\Protocol\CurlTransport\WebapiDecorator;
/**
* Returns array of locales depends on fetching type.
@@ -27,7 +26,7 @@ class Locales
/**
* Url to locales.php.
*/
- const URL = '/dev/tests/functional/utils/locales.php';
+ const URL = 'dev/tests/functional/utils/locales.php';
/**
* Curl transport protocol.
@@ -36,21 +35,12 @@ class Locales
*/
private $transport;
- /**
- * Webapi handler.
- *
- * @var WebapiDecorator
- */
- private $webapiHandler;
-
/**
* @param CurlTransport $transport Curl transport protocol
- * @param WebapiDecorator $webapiHandler
*/
- public function __construct(CurlTransport $transport, WebapiDecorator $webapiHandler)
+ public function __construct(CurlTransport $transport)
{
$this->transport = $transport;
- $this->webapiHandler = $webapiHandler;
}
/**
@@ -61,28 +51,12 @@ public function __construct(CurlTransport $transport, WebapiDecorator $webapiHan
*/
public function getList($type = self::TYPE_ALL)
{
- $this->transport->write(
- rtrim(str_replace('index.php', '', $_ENV['app_frontend_url']), '/') . self::URL,
- $this->prepareParamArray($type),
- CurlInterface::POST,
- []
- );
- $result = $this->transport->read();
- $this->transport->close();
- return explode('|', $result);
- }
+ $url = $_ENV['app_frontend_url'] . self::URL . '?type=' . $type;
+ $curl = $this->transport;
+ $curl->write($url, [], CurlInterface::GET);
+ $result = $curl->read();
+ $curl->close();
- /**
- * Prepare parameter array.
- *
- * @param string $type
- * @return array
- */
- private function prepareParamArray($type)
- {
- return [
- 'token' => urlencode($this->webapiHandler->getWebapiToken()),
- 'type' => urlencode($type)
- ];
+ return explode('|', $result);
}
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/PathChecker.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/PathChecker.php
index 4b12f6eec87aa..fd1f746a6f09c 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/PathChecker.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/PathChecker.php
@@ -7,7 +7,6 @@
use Magento\Mtf\Util\Protocol\CurlInterface;
use Magento\Mtf\Util\Protocol\CurlTransport;
-use Magento\Mtf\Util\Protocol\CurlTransport\WebapiDecorator;
/**
* PathChecker checks that path to file or directory exists.
@@ -17,7 +16,7 @@ class PathChecker
/**
* Url to checkPath.php.
*/
- const URL = '/dev/tests/functional/utils/pathChecker.php';
+ const URL = 'dev/tests/functional/utils/pathChecker.php';
/**
* Curl transport protocol.
@@ -27,21 +26,11 @@ class PathChecker
private $transport;
/**
- * Webapi handler.
- *
- * @var WebapiDecorator
- */
- private $webapiHandler;
-
- /**
- * @constructor
* @param CurlTransport $transport
- * @param WebapiDecorator $webapiHandler
*/
- public function __construct(CurlTransport $transport, WebapiDecorator $webapiHandler)
+ public function __construct(CurlTransport $transport)
{
$this->transport = $transport;
- $this->webapiHandler = $webapiHandler;
}
/**
@@ -52,28 +41,12 @@ public function __construct(CurlTransport $transport, WebapiDecorator $webapiHan
*/
public function pathExists($path)
{
- $this->transport->write(
- rtrim(str_replace('index.php', '', $_ENV['app_frontend_url']), '/') . self::URL,
- $this->prepareParamArray($path),
- CurlInterface::POST,
- []
- );
- $result = $this->transport->read();
- $this->transport->close();
- return strpos($result, 'path exists: true') !== false;
- }
+ $url = $_ENV['app_frontend_url'] . self::URL . '?path=' . urlencode($path);
+ $curl = $this->transport;
+ $curl->write($url, [], CurlInterface::GET);
+ $result = $curl->read();
+ $curl->close();
- /**
- * Prepare parameter array.
- *
- * @param string $path
- * @return array
- */
- private function prepareParamArray($path)
- {
- return [
- 'token' => urlencode($this->webapiHandler->getWebapiToken()),
- 'path' => urlencode($path)
- ];
+ return strpos($result, 'path exists: true') !== false;
}
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php
index fec20bb2a8715..7d73634c0360d 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php
@@ -3,11 +3,11 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Mtf\Util\Command;
use Magento\Mtf\Util\Protocol\CurlInterface;
use Magento\Mtf\Util\Protocol\CurlTransport;
-use Magento\Mtf\Util\Protocol\CurlTransport\WebapiDecorator;
/**
* Perform Website folder creation for functional tests executions.
@@ -17,7 +17,7 @@ class Website
/**
* Url to website.php.
*/
- const URL = '/dev/tests/functional/utils/website.php';
+ const URL = 'dev/tests/functional/utils/website.php';
/**
* Curl transport protocol.
@@ -26,22 +26,13 @@ class Website
*/
private $transport;
- /**
- * Webapi handler.
- *
- * @var WebapiDecorator
- */
- private $webapiHandler;
-
/**
* @constructor
* @param CurlTransport $transport
- * @param WebapiDecorator $webapiHandler
*/
- public function __construct(CurlTransport $transport, WebapiDecorator $webapiHandler)
+ public function __construct(CurlTransport $transport)
{
$this->transport = $transport;
- $this->webapiHandler = $webapiHandler;
}
/**
@@ -52,28 +43,21 @@ public function __construct(CurlTransport $transport, WebapiDecorator $webapiHan
*/
public function create($websiteCode)
{
- $this->transport->addOption(CURLOPT_HEADER, 1);
- $this->transport->write(
- rtrim(str_replace('index.php', '', $_ENV['app_frontend_url']), '/') . self::URL,
- $this->prepareParamArray($websiteCode),
- CurlInterface::POST,
- []
- );
- $this->transport->read();
- $this->transport->close();
+ $curl = $this->transport;
+ $curl->addOption(CURLOPT_HEADER, 1);
+ $curl->write($this->prepareUrl($websiteCode), [], CurlInterface::GET);
+ $curl->read();
+ $curl->close();
}
/**
- * Prepare parameter array.
+ * Prepare url.
*
* @param string $websiteCode
- * @return array
+ * @return string
*/
- private function prepareParamArray($websiteCode)
+ private function prepareUrl($websiteCode)
{
- return [
- 'token' => urlencode($this->webapiHandler->getWebapiToken()),
- 'website_code' => urlencode($websiteCode)
- ];
+ return $_ENV['app_frontend_url'] . self::URL . '?website_code=' . urlencode($websiteCode);
}
}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/BackendDecorator.php b/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/BackendDecorator.php
index d7026e9b8efb3..b1c552370835c 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/BackendDecorator.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/BackendDecorator.php
@@ -63,56 +63,24 @@ public function __construct(CurlTransport $transport, DataInterface $configurati
*/
protected function authorize()
{
- // There are situations where magento application backend url could be slightly different from the environment
- // variable we know. It could be intentionally (e.g. InstallTest) or unintentionally. We would still want tests
- // to run in this case.
- // When the original app_backend_url does not work, we will try 4 variants of the it. i.e. with and without
- // url rewrite, http and https.
- $urls = [];
- $originalUrl = rtrim($_ENV['app_backend_url'], '/') . '/';
- $urls[] = $originalUrl;
- // It could be the case that the page needs a refresh, so we will try the original one twice.
- $urls[] = $originalUrl;
- if (strpos($originalUrl, '/index.php') !== false) {
- $url2 = str_replace('/index.php', '', $originalUrl);
- } else {
- $url2 = $originalUrl . 'index.php/';
- }
- $urls[] = $url2;
- if (strpos($originalUrl, 'https') !== false) {
- $urls[] = str_replace('https', 'http', $originalUrl);
- } else {
- $urls[] = str_replace('http', 'https', $url2);
- }
-
- $isAuthorized = false;
- foreach ($urls as $url) {
- try {
- // Perform GET to backend url so form_key is set
- $this->transport->write($url, [], CurlInterface::GET);
- $this->read();
-
- $authUrl = $url . $this->configuration->get('application/0/backendLoginUrl/0/value');
- $data = [
- 'login[username]' => $this->configuration->get('application/0/backendLogin/0/value'),
- 'login[password]' => $this->configuration->get('application/0/backendPassword/0/value'),
- 'form_key' => $this->formKey,
- ];
-
- $this->transport->write($authUrl, $data, CurlInterface::POST);
- $response = $this->read();
- if (strpos($response, 'login-form') !== false) {
- continue;
- }
- $isAuthorized = true;
- $_ENV['app_backend_url'] = $url;
- break;
- } catch (\Exception $e) {
- continue;
- }
- }
- if ($isAuthorized == false) {
- throw new \Exception('Admin user cannot be logged in by curl handler!');
+ // Perform GET to backend url so form_key is set
+ $url = $_ENV['app_backend_url'];
+ $this->transport->write($url, [], CurlInterface::GET);
+ $this->read();
+
+ $url = $_ENV['app_backend_url'] . $this->configuration->get('application/0/backendLoginUrl/0/value');
+ $data = [
+ 'login[username]' => $this->configuration->get('application/0/backendLogin/0/value'),
+ 'login[password]' => $this->configuration->get('application/0/backendPassword/0/value'),
+ 'form_key' => $this->formKey,
+ ];
+ $this->transport->write($url, $data, CurlInterface::POST);
+ $response = $this->read();
+ if (strpos($response, 'login-form') !== false) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
+ throw new \Exception(
+ 'Admin user cannot be logged in by curl handler!'
+ );
}
}
@@ -144,6 +112,7 @@ public function write($url, $params = [], $method = CurlInterface::POST, $header
if ($this->formKey) {
$params['form_key'] = $this->formKey;
} else {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
throw new \Exception(sprintf('Form key is absent! Url: "%s" Response: "%s"', $url, $this->response));
}
$this->transport->write($url, http_build_query($params), $method, $headers);
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/WebapiDecorator.php b/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/WebapiDecorator.php
index df5ab45a3f96d..3aa756904ab00 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/WebapiDecorator.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Protocol/CurlTransport/WebapiDecorator.php
@@ -70,13 +70,6 @@ class WebapiDecorator implements CurlInterface
*/
protected $response;
- /**
- * Webapi token.
- *
- * @var string
- */
- protected $webapiToken;
-
/**
* @construct
* @param ObjectManager $objectManager
@@ -117,9 +110,6 @@ protected function init()
$integration->persist();
$this->setConfiguration($integration);
- $this->webapiToken = $integration->getToken();
- } else {
- $this->webapiToken = $integrationToken;
}
}
@@ -171,13 +161,7 @@ protected function setConfiguration(Integration $integration)
*/
protected function isValidIntegration()
{
- $url = rtrim($_ENV['app_frontend_url'], '/');
- if (strpos($url, 'index.php') === false) {
- $url .= '/index.php/rest/V1/modules';
- } else {
- $url .= '/rest/V1/modules';
- }
- $this->write($url, [], CurlInterface::GET);
+ $this->write($_ENV['app_frontend_url'] . 'rest/V1/modules', [], CurlInterface::GET);
$response = json_decode($this->read(), true);
return (null !== $response) && !isset($response['message']);
@@ -235,18 +219,4 @@ public function close()
{
$this->transport->close();
}
-
- /**
- * Return webapiToken.
- *
- * @return string
- */
- public function getWebapiToken()
- {
- // Request token if integration is no longer valid
- if (!$this->isValidIntegration()) {
- $this->init();
- }
- return $this->webapiToken;
- }
}
diff --git a/dev/tests/functional/tests/app/Magento/AdminNotification/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/TestCase/NavigateMenuTest.xml
index f2f56eb74f704..99bd9c6d9d220 100644
--- a/dev/tests/functional/tests/app/Magento/AdminNotification/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
System > Notifications
Notifications
diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ExportAdvancedPricingTest.php b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ExportAdvancedPricingTest.php
index fefe0d2c126e5..c2c684c89d06b 100644
--- a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ExportAdvancedPricingTest.php
+++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ExportAdvancedPricingTest.php
@@ -140,9 +140,9 @@ public function test(
if ($website) {
$website->persist();
$this->setupCurrencyForCustomWebsite($website, $currencyCustomWebsite);
- $this->cron->run();
- $this->cron->run();
}
+ $this->cron->run();
+ $this->cron->run();
$products = $this->prepareProducts($products, $website);
$this->cron->run();
$this->cron->run();
@@ -165,7 +165,8 @@ public function test(
if (!empty($advancedPricingAttributes)) {
$products = [$products[0]];
}
-
+ $this->cron->run();
+ $this->cron->run();
return [
'products' => $products
];
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
index cdb73c5d36f25..8f7b07c8c14c4 100644
--- a/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
MAGETWO-97261: Magento\Backend\Test\TestCase\NavigateMenuTest fails on Jenkins
Reports > BI Essentials
false
@@ -15,6 +16,7 @@
+ mftf_migrated:yes
Reports > Advanced Reporting
false
https://advancedreporting.rjmetrics.com/report
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.xml
index dca6e1d15024f..6d9c50b4317c8 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/GlobalSearchEntityTest.xml
@@ -8,31 +8,26 @@
- stable:no
search shows admin preview
Some search term
- stable:no
search with 2 sign return no results
:)
- stable:no
search product by sku
orderInjectable::default::product::sku
- stable:no
search existed customer
customer::johndoe_unique::lastname
- stable:no
search order (by order id)
orderInjectable::default::id
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.xml
index 67842f62d7c92..afdf70704a984 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/TestCase/NavigateMenuTest.xml
@@ -8,26 +8,31 @@
+ mftf_migrated:yes
Dashboard
Dashboard
+ mftf_migrated:yes
Content > Schedule
Store Design Schedule
+ mftf_migrated:yes
Stores > All Stores
Stores
+ mftf_migrated:yes
Stores > Configuration
Configuration
+ mftf_migrated:yes
System > Cache Management
Cache Management
diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaEditCustomerTest.xml b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaEditCustomerTest.xml
index 12b9808adb9e0..0c0e06d63b6c9 100644
--- a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaEditCustomerTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaEditCustomerTest.xml
@@ -14,6 +14,7 @@
3
111
captcha_storefront_user_edit_failures_number, customer_max_login_failures_number
+ mftf_migrated:yes
diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnAdminLoginTest.xml b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnAdminLoginTest.xml
index 186439bb9f157..9242bfbef2374 100644
--- a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnAdminLoginTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnAdminLoginTest.xml
@@ -12,6 +12,7 @@
111
Dashboard
captcha_backend_login
+ mftf_migrated:yes
diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnContactUsTest.xml b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnContactUsTest.xml
index a88cd98e3c31b..1a25afeabc5de 100644
--- a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnContactUsTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnContactUsTest.xml
@@ -12,6 +12,7 @@
111
default
captcha_storefront_contact_us
+ mftf_migrated:yes
diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontLoginTest.xml b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontLoginTest.xml
index 8e4327db5eddc..8068b2cbc050e 100644
--- a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontLoginTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontLoginTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
default
111
captcha_storefront_login
diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontRegisterTest.xml b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontRegisterTest.xml
index 8e83c189efc2f..b0ce6dfa561ae 100644
--- a/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontRegisterTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/TestCase/CaptchaOnStoreFrontRegisterTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
register_customer
111
captcha_storefront_register
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php
index dcc8cce970098..4e8e0f97d70d5 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View/CustomOptions.php
@@ -128,7 +128,8 @@ class CustomOptions extends Form
*
* @var string
*/
- private $validationErrorMessage = '//div[@class="mage-error"][contains(text(), "required field")]';
+ private $validationErrorMessage = '//div[@class="mage-error"][contains(text(), "required field")' .
+ 'and not(contains(@style,\'display\'))]';
/**
* Get product options
@@ -148,6 +149,7 @@ public function getOptions(FixtureInterface $product)
foreach ($dataOptions as $option) {
$title = $option['title'];
if (!isset($listCustomOptions[$title])) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
throw new \Exception("Can't find option: \"{$title}\"");
}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml
index ea6808ee2a7f5..69093b8adb8db 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/CreateCategoryEntityTest.xml
@@ -17,7 +17,6 @@
- MAGETWO-60635: [CE][Categories] Design update dates are incorrect after save
Create root category with all fields
addRootCategory
Yes
@@ -58,7 +57,6 @@
- MAGETWO-60635: [CE][Categories] Design update dates are incorrect after save
Create not anchor subcategory specifying all fields
addSubcategory
default_category
@@ -146,7 +144,7 @@
- test_type:acceptance_test, test_type:extended_acceptance_test, stable:no
+ test_type:acceptance_test, test_type:extended_acceptance_test
addSubcategory
default_category
Yes
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml
index 260095048431e..08bff9f70708a 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/NavigateMenuTest.xml
@@ -8,21 +8,25 @@
+ mftf_migrated:yes
Catalog > Products
Products
+ mftf_migrated:yes
Catalog > Categories
Default Category (ID: 2)
+ mftf_migrated:yes
Stores > Product
Product Attributes
+ mftf_migrated:yes
Stores > Attribute Set
Attribute Sets
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.xml
index 11ba7266ce564..0dd47942c8fe0 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/DeleteProductAttributeEntityTest.xml
@@ -16,7 +16,6 @@
- stable:no
attribute_type_dropdown
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.xml
index 40cf8e40ae33f..d6420ff431ce6 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/ProductAttribute/UpdateProductAttributeEntityTest.xml
@@ -8,7 +8,6 @@
- to_maintain:yes
custom_attribute_set
attribute_type_text_field
Text_Field_%isolation%
@@ -29,7 +28,6 @@
- to_maintain:yes
custom_attribute_set
attribute_type_dropdown
Dropdown_%isolation%
@@ -55,6 +53,8 @@
+ MAGETWO-46494: [FT] UpdateProductAttributeEntityTestVariation3 does not actually create an attribute to check
+ to_maintain:yes
custom_attribute_set
tax_class_id
Yes
@@ -62,7 +62,6 @@
- FPC
- to_maintain:yes
diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml
index 659d76eabccbe..4a965d5708947 100644
--- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
Marketing > Catalog Price Rule
Catalog Price Rule
diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml
index 493d427dd0ac2..d9bb0f65e704e 100644
--- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/NavigateMenuTest.xml
@@ -8,11 +8,13 @@
+ mftf_migrated:yes
Marketing > Search Terms
Search Terms
+ mftf_migrated:yes
Reports > Search Terms
Search Terms Report
diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml
index 9a6a66091d427..42dd7b6c96e2e 100644
--- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml
+++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/TestCase/SearchEntityResultsTest.xml
@@ -8,66 +8,76 @@
- test_type:acceptance_test, test_type:extended_acceptance_test
+ test_type:acceptance_test, test_type:extended_acceptance_test, mftf_migrated:yes
catalogProductSimple::default::sku
+ mftf_migrated:yes
catalogProductSimple::default::simple
+ mftf_migrated:yes
catalogProductVirtual::default::virtual
+ mftf_migrated:yes
configurableProduct::default::configurable
+ mftf_migrated:yes
downloadableProduct::default::downloadable
+ mftf_migrated:yes
groupedProduct::withSimpleProducts_without_qty::grouped
+ mftf_migrated:yes
bundleProduct::bundle_dynamic_product::bundle
+ mftf_migrated:yes
bundleProduct::bundle_fixed_product::bundle
+ mftf_migrated:yes
catalogProductSimple::default::name
+ mftf_migrated:yes
catalogProductSimple::product_with_special_symbols_in_name::name
+ mftf_migrated:yes
TryToFindMeAndI'llFindYOU
catalogProductSimple::default
+ mftf_migrated:yes
catalogProductSimple::default::name
2
-
-
+
- MAGETWO-65509: [FT] Magento\CatalogSearch\Test\TestCase\SearchEntityResultsTest fails on Jenkins
stable:no
catalogProductSimple::default::name
3
+ mftf_migrated:yes
catalogProductSimple::product_with_long_name::name
128
@@ -82,6 +92,7 @@
+ mftf_migrated:yes
alaska
- catalogProductSimple::search_weight_term_twice_weight_1
@@ -92,6 +103,7 @@
+ mftf_migrated:yes
alaska
- catalogProductSimple::search_weight_term_once_weight_5
@@ -100,6 +112,7 @@
+ mftf_migrated:yes
configurableProduct::one_simple_product_not_visible_individually::name
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php
index 0bf9b37c75e12..1013404f42df1 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.php
@@ -102,7 +102,7 @@ class Shipping extends Form
*
* @var string
*/
- private $emailError = '#customer-email-error';
+ private $emailError = '#checkout-customer-email-error';
/**
* Get email error.
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml
index 71115e402880c..0973b968cba95 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Onepage/Shipping.xml
@@ -8,7 +8,7 @@
- #customer-email
+ #checkout-customer-email
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml
index 8d054c0230873..c0df4b16b92e6 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/AddProductsToShoppingCartEntityTest.xml
@@ -22,7 +22,6 @@
- to_maintain:yes, severity:S2
bundleProduct::bundle_fixed_product
761
756
@@ -35,7 +34,6 @@
- to_maintain:yes, severity:S0
catalogProductSimple::with_two_custom_option
345
340
@@ -48,7 +46,6 @@
- to_maintain:yes, severity:S1
catalogProductVirtual::product_50_dollar
50
50
@@ -100,8 +97,7 @@
- to_maintain:yes, severity:S0
- Errors on configuration step. Skipped.
+ severity:S0
catalogProductSimple::with_two_custom_option
catalogProductVirtual::product_50_dollar
downloadableProduct::with_two_separately_links
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
index 0edd8f4183f30..daf9aaae50580 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/OnePageCheckoutTest.xml
@@ -15,13 +15,11 @@
- 1
-
- - 1
-
- 565.00
Flat Rate
+ false
Fixed
checkmo
checkmo
@@ -43,6 +41,7 @@
- 565.00
Flat Rate
+ false
Fixed
checkmo
checkmo
@@ -61,7 +60,7 @@
UK_address_without_email
Flat Rate
Fixed
- Yes
+ false
US_address_1_without_email
checkmo
checkmo
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.xml
index 90c42505585a2..8290d825593af 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/ValidateEmailOnCheckoutTest.xml
@@ -10,17 +10,20 @@
johndoe
John
+ mftf_migrated:yes
johndoe#example.com
John
+ mftf_migrated:yes
johndoe@example.c
John
+ mftf_migrated:yes
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php
index aa7eba634145f..52b296c2e01fa 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/FillBillingInformationStep.php
@@ -126,11 +126,15 @@ public function run()
if ($this->billingCheckboxState) {
$this->assertBillingAddressCheckbox->processAssert($this->checkoutOnepage, $this->billingCheckboxState);
}
- if ($this->billingCheckboxState === 'Yes' && !$this->editBillingInformation) {
- return [
- 'billingAddress' => $this->shippingAddress
- ];
+
+ if (!$this->editBillingInformation) {
+ $billingAddress = $this->billingCheckboxState === 'Yes'
+ ? $this->shippingAddress
+ : $this->getDefaultBillingAddress();
+
+ return ['billingAddress' => $billingAddress];
}
+
if ($this->billingAddress) {
$selectedPaymentMethod = $this->checkoutOnepage->getPaymentBlock()->getSelectedPaymentMethodBlock();
if ($this->shippingAddress) {
@@ -139,9 +143,11 @@ public function run()
$selectedPaymentMethod->getBillingBlock()->fillBilling($this->billingAddress);
$billingAddress = $this->billingAddress;
}
+
if (isset($this->billingAddressCustomer['added'])) {
$addressIndex = $this->billingAddressCustomer['added'];
- $billingAddress = $this->customer->getDataFieldConfig('address')['source']->getAddresses()[$addressIndex];
+ $billingAddress = $this->customer->getDataFieldConfig('address')['source']
+ ->getAddresses()[$addressIndex];
$address = $this->objectManager->create(
\Magento\Customer\Test\Block\Address\Renderer::class,
['address' => $billingAddress, 'type' => 'html_for_select_element']
@@ -156,4 +162,25 @@ public function run()
'billingAddress' => $billingAddress
];
}
+
+ /**
+ * Get default billing address
+ *
+ * @return Address|null
+ */
+ private function getDefaultBillingAddress()
+ {
+ $addresses = $this->customer->hasData('address')
+ ? $this->customer->getDataFieldConfig('address')['source']->getAddresses()
+ : [];
+ $defaultAddress = null;
+ foreach ($addresses as $address) {
+ if ($address->getDefaultBilling() === 'Yes') {
+ $defaultAddress = $address;
+ break;
+ }
+ }
+
+ return $defaultAddress;
+ }
}
diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml
index 18cbf32ded5c1..3458e2944a9ec 100644
--- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/TestCase/NavigateMenuTest.xml
@@ -8,7 +8,7 @@
- severity:S2
+ severity:S2, mftf_migrated:yes
Stores > Terms and Conditions
Terms and Conditions
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml
index f9f0a11c0a475..cff5f7f2a5622 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/TestCase/NavigateMenuTest.xml
@@ -8,13 +8,13 @@
- severity:S2
+ severity:S2, mftf_migrated:yes
Content > Pages
Pages
- severity:S2
+ severity:S2, mftf_migrated:yes
Content > Blocks
Blocks
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php
index c7d66781738b7..bb88bc854f756 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/UpdateConfigurableProductEntityTest.php
@@ -32,7 +32,6 @@ class UpdateConfigurableProductEntityTest extends Scenario
{
/* tags */
const MVP = 'yes';
- const TO_MAINTAIN = 'yes';
/* end tags */
/**
diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml
index 0a061eb4be6c7..fc031a77ff53f 100644
--- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/TestCase/NavigateMenuTest.xml
@@ -8,11 +8,13 @@
+ mftf_migrated:yes
Stores > Currency Rates
Currency Rates
+ mftf_migrated:yes
Stores > Currency Symbols
Currency Symbols
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.xml
index cffbbca8ad5cb..4251a1c5ee9c5 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/DeleteCustomerGroupEntityTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
customer_with_new_customer_group
default
General
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml
index 404e62dcad648..a4a3aa34f9f1c 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/NavigateMenuTest.xml
@@ -8,16 +8,19 @@
+ mftf_migrated:yes
Customers > All Customers
Customers
+ mftf_migrated:yes
Customers > Now Online
Customers Now Online
+ mftf_migrated:yes
Customers > Customer Groups
Customer Groups
diff --git a/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/TestCase/ExportCustomerAddressesTest.php b/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/TestCase/ExportCustomerAddressesTest.php
index 6b92891ada2b4..17dfb4fb8cdaf 100644
--- a/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/TestCase/ExportCustomerAddressesTest.php
+++ b/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/TestCase/ExportCustomerAddressesTest.php
@@ -87,7 +87,8 @@ public function test(
$exportData->persist();
$this->adminExportIndex->getExportForm()->fill($exportData);
$this->adminExportIndex->getFilterExport()->clickContinue();
-
+ $this->cron->run();
+ $this->cron->run();
return [
'customer' => $customer
];
diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml
index f6dcdd5b65d02..4e98019c25317 100644
--- a/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Email/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
Marketing > Email Templates
Email Templates
diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml
index 6ce4d01d177db..d396a364a3f42 100644
--- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/NavigateMenuTest.xml
@@ -8,11 +8,13 @@
+ mftf_migrated:yes
System > Import
Import
+ mftf_migrated:yes
System > Export
Export
diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml
index 883e9bde47bf8..16ae092e62cad 100644
--- a/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
System > Index Management
Index Management
diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml
index 22def36751f53..265790ed4b763 100644
--- a/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Integration/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
System > Integrations
Integrations
diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml
index 13843a50868e7..b1a6b3e0c4386 100644
--- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/NavigateMenuTest.xml
@@ -8,21 +8,25 @@
+ mftf_migrated:yes
Marketing > Newsletter Template
Newsletter Templates
+ mftf_migrated:yes
Marketing > Newsletter Queue
Newsletter Queue
+ mftf_migrated:yes
Marketing > Newsletter Subscribers
Newsletter Subscribers
+ mftf_migrated:yes
Reports > Newsletter Problem Reports
Newsletter Problems Report
diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/NavigateMenuTest.xml
index d7d031f559f82..114235e75524f 100644
--- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/NavigateMenuTest.xml
@@ -8,13 +8,13 @@
- severity:S0
+ severity:S0, mftf_migrated:yes
Reports > PayPal Settlement
PayPal Settlement Reports
- severity:S0
+ severity:S0, mftf_migrated:yes
Sales > Billing Agreements
Billing Agreements
diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml
index 08cce1ffe7d23..4e3cd1824767a 100644
--- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/NavigateMenuTest.xml
@@ -8,76 +8,91 @@
+ mftf_migrated:yes
Reports > Products in Cart
Products in Carts
+ mftf_migrated:yes
Reports > Abandoned Carts
Abandoned Carts
+ mftf_migrated:yes
Reports > Orders
Orders Report
+ mftf_migrated:yes
Reports > Tax
Tax Report
+ mftf_migrated:yes
Reports > Invoiced
Invoice Report
+ mftf_migrated:yes
Reports > Coupons
Coupons Report
+ mftf_migrated:yes
Reports > Order Total
Order Total Report
+ mftf_migrated:yes
Reports > Order Count
Order Count Report
+ mftf_migrated:yes
Reports > New
New Accounts Report
+ mftf_migrated:yes
Reports > Views
Product Views Report
+ mftf_migrated:yes
Reports > Bestsellers
Bestsellers Report
+ mftf_migrated:yes
Reports > Low Stock
Low Stock Report
+ mftf_migrated:yes
Reports > Ordered
Ordered Products Report
+ mftf_migrated:yes
Reports > Downloads
Downloads Report
+ mftf_migrated:yes
Reports > Refresh Statistics
Refresh Statistics
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml
index 4d96ebd2edbe3..334497cc2f77e 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/NavigateMenuTest.xml
@@ -8,21 +8,25 @@
+ mftf_migrated:yes
Marketing > All Reviews
Reviews
+ mftf_migrated:yes
Reports > By Customers
Customer Reviews Report
+ mftf_migrated:yes
Reports > By Products
Product Reviews Report
+ mftf_migrated:yes
Stores > Rating
Ratings
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml
index e45609bb90c83..fdb396bbbd052 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CancelCreatedOrderTest.xml
@@ -18,7 +18,6 @@
- stable:no
default
free
freeshipping_freeshipping
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendPartOneTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendPartOneTest.xml
index 3e7b8fad1f04d..880c66483d5f2 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendPartOneTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/CreateOrderBackendPartOneTest.xml
@@ -8,7 +8,6 @@
- https://github.com/magento-engcom/msi/issues/1624
Create order with simple product for registered US customer using Fixed shipping method and Cash on Delivery payment method
catalogProductSimple::with_one_custom_option
default
@@ -70,7 +69,6 @@
- to_maintain:yes
Create order with virtual product for registered UK customer using Bank Transfer payment method
catalogProductVirtual::default
default
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml
index 316ba33f19fdb..5cc673f4b4fa5 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/NavigateMenuTest.xml
@@ -8,31 +8,37 @@
+ mftf_migrated:yes
Sales > Orders
Orders
+ mftf_migrated:yes
Sales > Invoices
Invoices
+ mftf_migrated:yes
Sales > Shipments
Shipments
+ mftf_migrated:yes
Sales > Credit Memos
Credit Memos
+ mftf_migrated:yes
Sales > Transactions
Transactions
+ mftf_migrated:yes
Stores > Order Status
Order Status
diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml
index 0a100eabcff46..1eeaeaaa483c0 100644
--- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
Marketing > Cart Price Rules
Cart Price Rules
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml
index c4cfe3f7f274c..3bb370a15e977 100644
--- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/LockAdminUserWhenCreatingNewUserTest.xml
@@ -9,7 +9,7 @@
user_lockout_failures
- severity:S2
+ severity:S2,mftf_migrated:yes
custom_admin_with_default_role
AdminUser%isolation%
FirstName%isolation%
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.xml
index 0b5b8a059cbbd..b4fbe7bb92929 100644
--- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetCustomerPasswordFailedTest.xml
@@ -8,7 +8,7 @@
- severity:S1
+ severity:S1,mftf_migrated:yes
customer_US
2
captcha_storefront_disable
diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.xml b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.xml
index 55f1b69504363..f43469358aa9c 100644
--- a/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Security/Test/TestCase/ResetUserPasswordFailedTest.xml
@@ -8,7 +8,7 @@
- severity:S1
+ severity:S1,mftf_migrated:yes
custom_admin_with_default_role
2
diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml
index cbef8fd52fd80..0f9514ffc7a00 100644
--- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/TestCase/NavigateMenuTest.xml
@@ -8,7 +8,7 @@
- severity:S2
+ severity:S2, mftf_migrated:yes
Marketing > Site Map
Site Map
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.xml
index a4abfc5daf29e..4d3677076d303 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/AccessAdminWithStoreCodeInUrlTest.xml
@@ -11,6 +11,7 @@
add_store_code_to_urls
default
default
+ mftf_migrated:yes
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.xml
index 8cdeb48bb1c98..dcfe22eb0d5f8 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/CreateStoreGroupEntityTest.xml
@@ -8,7 +8,7 @@
- severity:S1
+ severity:S1, mftf_migrated:yes
main_website
store_name_%isolation%
store_code_%isolation%
@@ -18,7 +18,7 @@
- severity:S1
+ severity:S1, mftf_migrated:yes
custom_website
store_name_%isolation%
store_code_%isolation%
@@ -29,6 +29,7 @@
+ mftf_migrated:yes
custom_new_group
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.xml
index 8da208bc3f0f1..ab702dfdd4b78 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/MoveStoreToOtherGroupSameWebsiteTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
custom_group_custom_store
custom_group_custom_store
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.xml
index 4a73986673c60..6053352386203 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreEntityTest.xml
@@ -8,7 +8,7 @@
- severity:S2
+ severity:S2, mftf_migrated:yes
custom
default
storename_updated%isolation%
@@ -21,7 +21,7 @@
- severity:S1
+ severity:S1, mftf_migrated:yes
default
storename_updated%isolation%
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.xml b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.xml
index 593d9c365a92e..9ff67a9ba9fec 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestCase/UpdateStoreGroupEntityTest.xml
@@ -8,7 +8,7 @@
- severity:S2
+ severity:S2, mftf_migrated:yes
custom
main_website
store_name_updated_%isolation%
@@ -20,7 +20,7 @@
- severity:S2
+ severity:S2, mftf_migrated:yes
custom
custom_website
store_name_updated_%isolation%
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml
index ee225f21462ea..ecf202ddae3a8 100644
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/NavigateMenuTest.xml
@@ -8,16 +8,19 @@
+ mftf_migrated:yes
Stores > Tax Rules
Tax Rules
+ mftf_migrated:yes
Stores > Tax Zones and Rates
Tax Zones and Rates
+ mftf_migrated:yes
System > Import/Export Tax Rates
Import and Export Tax Rates
diff --git a/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml
index 71964fc926499..ee38659122301 100644
--- a/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Theme/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
Content > Themes
Themes
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml
index cdf1d9e3617d8..30d9e57602af1 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
Marketing > URL Rewrites
URL Rewrites
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensErrorRevokeMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensErrorRevokeMessage.php
deleted file mode 100644
index b1a64c7c7e713..0000000000000
--- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensErrorRevokeMessage.php
+++ /dev/null
@@ -1,46 +0,0 @@
-getMessagesBlock()->getErrorMessage()
- );
- }
-
- /**
- * Return string representation of object
- *
- * @return string
- */
- public function toString()
- {
- return self::ERROR_MESSAGE . ' error message is present on UserEdit page.';
- }
-}
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensSuccessfullyRevoked.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensSuccessfullyRevoked.php
new file mode 100644
index 0000000000000..b2e52f6a15a10
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensSuccessfullyRevoked.php
@@ -0,0 +1,45 @@
+getMessagesBlock()->getSuccessMessage()
+ );
+ }
+
+ /**
+ * Return string representation of object
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return self::SUCCESS_MESSAGE . ' message is present on UserEdit page.';
+ }
+}
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml
index d196bebca0e9a..4572738b6cb48 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/NavigateMenuTest.xml
@@ -8,21 +8,25 @@
+ mftf_migrated:yes
System > Locked Users
Locked Users
+ mftf_migrated:yes
System > Manage Encryption Key
Encryption Key
+ mftf_migrated:yes
System > All Users
Users
+ mftf_migrated:yes
System > User Roles
Roles
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.xml
index e5fcba9b72c25..afdb72d8c561e 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.xml
+++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/RevokeAllAccessTokensForAdminWithoutTokensTest.xml
@@ -9,7 +9,7 @@
custom_admin
-
+
diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml
index 3fceddf1a807a..0a9c74cd92bc6 100644
--- a/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Variable/Test/TestCase/NavigateMenuTest.xml
@@ -8,6 +8,7 @@
+ mftf_migrated:yes
System > Custom Variables
Custom Variables
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml
index 6b3215dd30d16..6a2a533c59df2 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/NavigateMenuTest.xml
@@ -8,7 +8,7 @@
- severity:S2
+ severity:S2, mftf_migrated:yes
Content > Widgets
Widgets
diff --git a/dev/tests/functional/utils/authenticate.php b/dev/tests/functional/utils/authenticate.php
deleted file mode 100644
index 15851f6e8000a..0000000000000
--- a/dev/tests/functional/utils/authenticate.php
+++ /dev/null
@@ -1,29 +0,0 @@
-create($_SERVER);
- $tokenModel = $magentoObjectManager->get(\Magento\Integration\Model\Oauth\Token::class);
-
- $tokenPassedIn = $token;
- // Token returned will be null if the token we passed in is invalid
- $tokenFromMagento = $tokenModel->loadByToken($tokenPassedIn)->getToken();
- if (!empty($tokenFromMagento) && ($tokenFromMagento == $tokenPassedIn)) {
- return true;
- } else {
- return false;
- }
-}
diff --git a/dev/tests/functional/utils/command.php b/dev/tests/functional/utils/command.php
index 4e18598a935ad..99025dd1cffcc 100644
--- a/dev/tests/functional/utils/command.php
+++ b/dev/tests/functional/utils/command.php
@@ -3,25 +3,26 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-include __DIR__ . '/authenticate.php';
+
+// phpcs:ignore Magento2.Security.IncludeFile
require_once __DIR__ . '/../../../../app/bootstrap.php';
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\NullOutput;
-if (!empty($_POST['token']) && !empty($_POST['command'])) {
- if (authenticate(urldecode($_POST['token']))) {
- $command = urldecode($_POST['command']);
- $magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER);
- $magentoObjectManager = $magentoObjectManagerFactory->create($_SERVER);
- $cli = $magentoObjectManager->create(\Magento\Framework\Console\Cli::class);
- $input = new StringInput(escapeshellcmd($command));
- $input->setInteractive(false);
- $output = new NullOutput();
- $cli->doRun($input, $output);
- } else {
- echo "Command not unauthorized.";
- }
+// phpcs:ignore Magento2.Security.Superglobal
+if (isset($_GET['command'])) {
+ // phpcs:ignore Magento2.Security.Superglobal
+ $command = urldecode($_GET['command']);
+ // phpcs:ignore Magento2.Security.Superglobal
+ $magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER);
+ // phpcs:ignore Magento2.Security.Superglobal
+ $magentoObjectManager = $magentoObjectManagerFactory->create($_SERVER);
+ $cli = $magentoObjectManager->create(\Magento\Framework\Console\Cli::class);
+ $input = new StringInput($command);
+ $input->setInteractive(false);
+ $output = new NullOutput();
+ $cli->doRun($input, $output);
} else {
- echo "'token' or 'command' parameter is not set.";
+ throw new \InvalidArgumentException("Command GET parameter is not set.");
}
diff --git a/dev/tests/functional/utils/deleteMagentoGeneratedCode.php b/dev/tests/functional/utils/deleteMagentoGeneratedCode.php
index 17e3575c87686..17260bd1da635 100644
--- a/dev/tests/functional/utils/deleteMagentoGeneratedCode.php
+++ b/dev/tests/functional/utils/deleteMagentoGeneratedCode.php
@@ -3,14 +3,6 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-include __DIR__ . '/authenticate.php';
-if (!empty($_POST['token']) && !empty($_POST['path'])) {
- if (authenticate(urldecode($_POST['token']))) {
- exec('rm -rf ../../../../generated/*');
- } else {
- echo "Command not unauthorized.";
- }
-} else {
- echo "'token' parameter is not set.";
-}
+// phpcs:ignore Magento2.Security.InsecureFunction
+exec('rm -rf ../../../../generated/*');
diff --git a/dev/tests/functional/utils/export.php b/dev/tests/functional/utils/export.php
index e3eff6e3fec17..fa50bc729d0f6 100644
--- a/dev/tests/functional/utils/export.php
+++ b/dev/tests/functional/utils/export.php
@@ -3,30 +3,32 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-include __DIR__ . '/authenticate.php';
-if (!empty($_POST['token']) && !empty($_POST['template'])) {
- if (authenticate(urldecode($_POST['token']))) {
- $varDir = '../../../../var/export/';
- $template = urldecode($_POST['template']);
- $fileList = scandir($varDir, SCANDIR_SORT_NONE);
- $files = [];
+// phpcs:ignore Magento2.Security.Superglobal
+if (!isset($_GET['template'])) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
+ throw new \InvalidArgumentException('Argument "template" must be set.');
+}
- foreach ($fileList as $fileName) {
- if (preg_match("`$template`", $fileName) === 1) {
- $filePath = $varDir . $fileName;
- $files[] = [
- 'content' => file_get_contents($filePath),
- 'name' => $fileName,
- 'date' => filectime($filePath),
- ];
- }
- }
+$varDir = '../../../../var/export/';
+// phpcs:ignore Magento2.Security.Superglobal
+$template = urldecode($_GET['template']);
+// phpcs:ignore Magento2.Functions.DiscouragedFunction
+$fileList = scandir($varDir, SCANDIR_SORT_NONE);
+$files = [];
- echo serialize($files);
- } else {
- echo "Command not unauthorized.";
+foreach ($fileList as $fileName) {
+ if (preg_match("`$template`", $fileName) === 1) {
+ $filePath = $varDir . $fileName;
+ $files[] = [
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'content' => file_get_contents($filePath),
+ 'name' => $fileName,
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ 'date' => filectime($filePath),
+ ];
}
-} else {
- echo "'token' or 'template' parameter is not set.";
}
+
+// phpcs:ignore Magento2.Security.LanguageConstruct, Magento2.Security.InsecureFunction
+echo serialize($files);
diff --git a/dev/tests/functional/utils/locales.php b/dev/tests/functional/utils/locales.php
index a3b4ec05eed65..11e1e2b70fa50 100644
--- a/dev/tests/functional/utils/locales.php
+++ b/dev/tests/functional/utils/locales.php
@@ -3,23 +3,20 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-include __DIR__ . '/authenticate.php';
-if (!empty($_POST['token'])) {
- if (authenticate(urldecode($_POST['token']))) {
- if ($_POST['type'] == 'deployed') {
- $themePath = isset($_POST['theme_path']) ? $_POST['theme_path'] : 'adminhtml/Magento/backend';
- $directory = __DIR__ . '/../../../../pub/static/' . $themePath;
- $locales = array_diff(scandir($directory), ['..', '.']);
- } else {
- require_once __DIR__ . DIRECTORY_SEPARATOR . 'bootstrap.php';
- $localeConfig = $magentoObjectManager->create(\Magento\Framework\Locale\Config::class);
- $locales = $localeConfig->getAllowedLocales();
- }
- echo implode('|', $locales);
- } else {
- echo "Command not unauthorized.";
- }
+// phpcs:ignore Magento2.Security.Superglobal
+if (isset($_GET['type']) && $_GET['type'] == 'deployed') {
+ // phpcs:ignore Magento2.Security.Superglobal
+ $themePath = isset($_GET['theme_path']) ? $_GET['theme_path'] : 'adminhtml/Magento/backend';
+ $directory = __DIR__ . '/../../../../pub/static/' . $themePath;
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ $locales = array_diff(scandir($directory), ['..', '.']);
} else {
- echo "'token' parameter is not set.";
+ // phpcs:ignore Magento2.Security.IncludeFile
+ require_once __DIR__ . DIRECTORY_SEPARATOR . 'bootstrap.php';
+ $localeConfig = $magentoObjectManager->create(\Magento\Framework\Locale\Config::class);
+ $locales = $localeConfig->getAllowedLocales();
}
+
+// phpcs:ignore Magento2.Security.LanguageConstruct
+echo implode('|', $locales);
diff --git a/dev/tests/functional/utils/log.php b/dev/tests/functional/utils/log.php
index 889056bfbdd63..30783ae8e1d28 100644
--- a/dev/tests/functional/utils/log.php
+++ b/dev/tests/functional/utils/log.php
@@ -3,20 +3,21 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-declare(strict_types=1);
-include __DIR__ . '/authenticate.php';
-if (!empty($_POST['token']) && !empty($_POST['name'])) {
- if (authenticate(urldecode($_POST['token']))) {
- $name = urldecode($_POST['name']);
- if (preg_match('/\.\.(\\\|\/)/', $name)) {
- throw new \InvalidArgumentException('Invalid log file name');
- }
+declare(strict_types=1);
+// phpcs:ignore Magento2.Security.Superglobal
+if (!isset($_GET['name'])) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
+ throw new \InvalidArgumentException(
+ 'The name of log file is required for getting logs.'
+ );
+}
- echo serialize(file_get_contents('../../../../var/log' . '/' . $name));
- } else {
- echo "Command not unauthorized.";
- }
-} else {
- echo "'token' or 'name' parameter is not set.";
+// phpcs:ignore Magento2.Security.Superglobal
+$name = urldecode($_GET['name']);
+if (preg_match('/\.\.(\\\|\/)/', $name)) {
+ throw new \InvalidArgumentException('Invalid log file name');
}
+
+// phpcs:ignore Magento2.Security.InsecureFunction, Magento2.Functions.DiscouragedFunction, Magento2.Security.LanguageConstruct
+echo serialize(file_get_contents('../../../../var/log' .'/' .$name));
diff --git a/dev/tests/functional/utils/pathChecker.php b/dev/tests/functional/utils/pathChecker.php
index b5a2ddb405bde..217cf90af0a56 100644
--- a/dev/tests/functional/utils/pathChecker.php
+++ b/dev/tests/functional/utils/pathChecker.php
@@ -3,20 +3,20 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-include __DIR__ . '/authenticate.php';
-if (!empty($_POST['token']) && !empty($_POST['path'])) {
- if (authenticate(urldecode($_POST['token']))) {
- $path = urldecode($_POST['path']);
-
- if (file_exists('../../../../' . $path)) {
- echo 'path exists: true';
- } else {
- echo 'path exists: false';
- }
+// phpcs:ignore Magento2.Security.Superglobal
+if (isset($_GET['path'])) {
+ // phpcs:ignore Magento2.Security.Superglobal
+ $path = urldecode($_GET['path']);
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ if (file_exists('../../../../' . $path)) {
+ // phpcs:ignore Magento2.Security.LanguageConstruct
+ echo 'path exists: true';
} else {
- echo "Command not unauthorized.";
+ // phpcs:ignore Magento2.Security.LanguageConstruct
+ echo 'path exists: false';
}
} else {
- echo "'token' or 'path' parameter is not set.";
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
+ throw new \InvalidArgumentException("GET parameter 'path' is not set.");
}
diff --git a/dev/tests/functional/utils/website.php b/dev/tests/functional/utils/website.php
index ab8e3742f55ae..720b4962aedd4 100644
--- a/dev/tests/functional/utils/website.php
+++ b/dev/tests/functional/utils/website.php
@@ -3,35 +3,36 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-include __DIR__ . '/authenticate.php';
-if (!empty($_POST['token']) && !empty($_POST['website_code'])) {
- if (authenticate(urldecode($_POST['token']))) {
- $websiteCode = urldecode($_POST['website_code']);
- $rootDir = '../../../../';
- $websiteDir = $rootDir . 'websites/' . $websiteCode . '/';
- $contents = file_get_contents($rootDir . 'index.php');
+// phpcs:ignore Magento2.Security.Superglobal
+if (!isset($_GET['website_code'])) {
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
+ throw new \Exception("website_code GET parameter is not set.");
+}
+
+// phpcs:ignore Magento2.Security.Superglobal
+$websiteCode = urldecode($_GET['website_code']);
+$rootDir = '../../../../';
+$websiteDir = $rootDir . 'websites/' . $websiteCode . '/';
+// phpcs:ignore Magento2.Functions.DiscouragedFunction
+$contents = file_get_contents($rootDir . 'index.php');
- $websiteParam = <<setData('entity_id', $entityId);
}
+
+ /**
+ * @return string
+ */
+ public function getOutputPath()
+ {
+ return $this->_get('outputPath');
+ }
+
+ /**
+ * @param string $path
+ * @return $this
+ */
+ public function setOutputPath($path)
+ {
+ return $this->setData('outputPath', $path);
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObjectRepository.php b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/DataObjectRepository.php
similarity index 62%
rename from dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObjectRepository.php
rename to dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/DataObjectRepository.php
index 879872315ec51..942298e49972f 100644
--- a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObjectRepository.php
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/DataObjectRepository.php
@@ -3,7 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-namespace Magento\MysqlMq\Model;
+namespace Magento\TestModuleMysqlMq\Model;
class DataObjectRepository
{
@@ -11,15 +11,17 @@ class DataObjectRepository
* @param DataObject $dataObject
* @param string $requiredParam
* @param int|null $optionalParam
- * @return bool
+ * @return null
*/
public function delayedOperation(
- \Magento\MysqlMq\Model\DataObject $dataObject,
+ \Magento\TestModuleMysqlMq\Model\DataObject $dataObject,
$requiredParam,
$optionalParam = null
) {
- echo "Processed '{$dataObject->getEntityId()}'; "
+ $output = "Processed '{$dataObject->getEntityId()}'; "
. "Required param '{$requiredParam}'; Optional param '{$optionalParam}'\n";
- return true;
+ file_put_contents($dataObject->getOutputPath(), $output);
+
+ return null;
}
}
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/Processor.php b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/Processor.php
new file mode 100644
index 0000000000000..fb6fd4c5c2802
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/Processor.php
@@ -0,0 +1,71 @@
+getOutputPath(),
+ "Processed {$message->getEntityId()}" . PHP_EOL,
+ FILE_APPEND
+ );
+ }
+
+ /**
+ * @param \Magento\TestModuleMysqlMq\Model\DataObject $message
+ */
+ public function processObjectCreated($message)
+ {
+ file_put_contents(
+ $message->getOutputPath(),
+ "Processed object created {$message->getEntityId()}" . PHP_EOL,
+ FILE_APPEND
+ );
+ }
+
+ /**
+ * @param \Magento\TestModuleMysqlMq\Model\DataObject $message
+ */
+ public function processCustomObjectCreated($message)
+ {
+ file_put_contents(
+ $message->getOutputPath(),
+ "Processed custom object created {$message->getEntityId()}" . PHP_EOL,
+ FILE_APPEND
+ );
+ }
+
+ /**
+ * @param \Magento\TestModuleMysqlMq\Model\DataObject $message
+ */
+ public function processObjectUpdated($message)
+ {
+ file_put_contents(
+ $message->getOutputPath(),
+ "Processed object updated {$message->getEntityId()}" . PHP_EOL,
+ FILE_APPEND
+ );
+ }
+
+ /**
+ * @param \Magento\TestModuleMysqlMq\Model\DataObject $message
+ */
+ public function processMessageWithException($message)
+ {
+ file_put_contents($message->getOutputPath(), "Exception processing {$message->getEntityId()}");
+ throw new \LogicException(
+ "Exception during message processing happened. Entity: {{$message->getEntityId()}}"
+ );
+ }
+}
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/communication.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/communication.xml
new file mode 100644
index 0000000000000..4d6269dbb7920
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/communication.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/module.xml
new file mode 100644
index 0000000000000..8b6ea0f44ce9c
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/module.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue.xml
new file mode 100644
index 0000000000000..362237c0c5e62
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_consumer.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_consumer.xml
new file mode 100644
index 0000000000000..bb495a123a05d
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_consumer.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_publisher.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_publisher.xml
new file mode 100644
index 0000000000000..a665e10ef5f14
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_publisher.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_topology.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_topology.xml
new file mode 100644
index 0000000000000..2df5485ee3447
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_topology.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/registration.php b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/registration.php
new file mode 100644
index 0000000000000..4250e95bd7cc3
--- /dev/null
+++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/registration.php
@@ -0,0 +1,12 @@
+getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleMysqlMq') === null) {
+ ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleMysqlMq', __DIR__);
+}
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/GraphTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/GraphTest.php
index 17863cd709580..497deb2c99110 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/GraphTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Dashboard/GraphTest.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Backend\Block\Dashboard;
/**
@@ -27,6 +29,6 @@ protected function setUp()
public function testGetChartUrl()
{
- $this->assertStringStartsWith('http://chart.apis.google.com/chart', $this->_block->getChartUrl());
+ $this->assertStringStartsWith('https://image-charts.com/chart', $this->_block->getChartUrl());
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewedTest.php b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewedTest.php
index 595a33344c7e8..bd4dd0c8daf0c 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewedTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/Dashboard/ProductsViewedTest.php
@@ -4,8 +4,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Backend\Controller\Adminhtml\Dashboard;
+/**
+ * Test product viewed backend controller.
+ */
class ProductsViewedTest extends \Magento\TestFramework\TestCase\AbstractBackendController
{
/**
@@ -14,6 +18,7 @@ class ProductsViewedTest extends \Magento\TestFramework\TestCase\AbstractBackend
*/
public function testExecute()
{
+ $this->getRequest()->setMethod("POST");
$this->dispatch('backend/admin/dashboard/productsViewed/');
$this->assertEquals(200, $this->getResponse()->getHttpResponseCode());
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/DashboardTest.php b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/DashboardTest.php
index 89f1e5e5d53d6..0eb98379b4571 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/DashboardTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Controller/Adminhtml/DashboardTest.php
@@ -3,6 +3,8 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\Backend\Controller\Adminhtml;
/**
@@ -19,10 +21,15 @@ public function testAjaxBlockAction()
$this->assertContains('dashboard-diagram', $actual);
}
+ /**
+ * Tests tunnelAction
+ *
+ * @throws \Exception
+ * @return void
+ */
public function testTunnelAction()
{
- $this->markTestSkipped('MAGETWO-98800: TunnelAction fails when Google Chart API is not available');
-
+ // phpcs:disable Magento2.Functions.DiscouragedFunction
$testUrl = \Magento\Backend\Block\Dashboard\Graph::API_URL . '?cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World';
$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, $testUrl);
@@ -36,6 +43,7 @@ public function testTunnelAction()
curl_close($handle);
throw $e;
}
+ // phpcs:enable
$gaData = [
'cht' => 'lc',
diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/assign_items_per_address.php b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/assign_items_per_address.php
new file mode 100644
index 0000000000000..91cea7dc96602
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/assign_items_per_address.php
@@ -0,0 +1,40 @@
+getStore();
+$quote->setReservedOrderId('multishipping_quote_id_braintree')
+ ->setStoreId($store->getId())
+ ->setCustomerEmail('customer001@test.com');
+
+/** @var CartRepositoryInterface $quoteRepository */
+$quoteRepository = $objectManager->get(CartRepositoryInterface::class);
+$quote->collectTotals();
+$quoteRepository->save($quote);
+
+$items = $quote->getAllItems();
+$addressList = $quote->getAllShippingAddresses();
+
+foreach ($addressList as $key => $address) {
+ $item = $items[$key];
+ // set correct quantity per shipping address
+ $item->setQty(1);
+ $address->setTotalQty(1);
+ $address->addItem($item);
+}
+
+// assign virtual product to the billing address
+$billingAddress = $quote->getBillingAddress();
+$virtualItem = $items[sizeof($items) - 1];
+$billingAddress->setTotalQty(1);
+$billingAddress->addItem($virtualItem);
+
+// need to recollect totals
+$quote->setTotalsCollectedFlag(false);
+$quote->collectTotals();
+$quoteRepository->save($quote);
diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/payment_braintree.php b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/payment_braintree.php
new file mode 100644
index 0000000000000..3e1db90f1f2c8
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/payment_braintree.php
@@ -0,0 +1,28 @@
+create(Payment::class);
+$payment->setMethod(ConfigProvider::CODE);
+$quote->setPayment($payment);
diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/payment_braintree_paypal.php b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/payment_braintree_paypal.php
new file mode 100644
index 0000000000000..e4bba222078b0
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/payment_braintree_paypal.php
@@ -0,0 +1,28 @@
+create(Payment::class);
+$payment->setMethod(ConfigProvider::PAYPAL_CODE);
+$quote->setPayment($payment);
diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/quote_with_split_items_braintree.php b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/quote_with_split_items_braintree.php
new file mode 100644
index 0000000000000..1c56e611dd6db
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/quote_with_split_items_braintree.php
@@ -0,0 +1,26 @@
+get(StoreManagerInterface::class);
+
+/** @var Quote $quote */
+$quote = $objectManager->create(Quote::class);
+
+require __DIR__ . '/../../../Magento/Multishipping/Fixtures/shipping_address_list.php';
+require __DIR__ . '/../../../Magento/Multishipping/Fixtures/billing_address.php';
+require __DIR__ . '/payment_braintree.php';
+require __DIR__ . '/../../../Magento/Multishipping/Fixtures/items.php';
+require __DIR__ . '/assign_items_per_address.php';
diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/quote_with_split_items_braintree_paypal.php b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/quote_with_split_items_braintree_paypal.php
new file mode 100644
index 0000000000000..4bd8e926abb76
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/quote_with_split_items_braintree_paypal.php
@@ -0,0 +1,26 @@
+get(StoreManagerInterface::class);
+
+/** @var Quote $quote */
+$quote = $objectManager->create(Quote::class);
+
+require __DIR__ . '/../../../Magento/Multishipping/Fixtures/shipping_address_list.php';
+require __DIR__ . '/../../../Magento/Multishipping/Fixtures/billing_address.php';
+require __DIR__ . '/payment_braintree_paypal.php';
+require __DIR__ . '/../../../Magento/Multishipping/Fixtures/items.php';
+require __DIR__ . '/assign_items_per_address.php';
diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Model/MultishippingTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Model/MultishippingTest.php
new file mode 100644
index 0000000000000..91bc0388d8551
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Braintree/Model/MultishippingTest.php
@@ -0,0 +1,254 @@
+objectManager = Bootstrap::getObjectManager();
+
+ $orderSender = $this->getMockBuilder(OrderSender::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->adapter = $this->getMockBuilder(BraintreeAdapter::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $adapterFactory->method('create')
+ ->willReturn($this->adapter);
+
+ $this->objectManager->addSharedInstance($adapterFactory, BraintreeAdapterFactory::class);
+ $this->objectManager->addSharedInstance($this->getPaymentNonceMock(), GetPaymentNonceCommand::class);
+
+ $this->model = $this->objectManager->create(
+ Multishipping::class,
+ ['orderSender' => $orderSender]
+ );
+ }
+
+ /**
+ * Checks a case when multiple orders are created successfully using Braintree payment method.
+ *
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/Braintree/Fixtures/quote_with_split_items_braintree.php
+ * @magentoConfigFixture current_store payment/braintree/active 1
+ * @return void
+ */
+ public function testCreateOrdersWithBraintree()
+ {
+ $this->adapter->method('sale')
+ ->willReturn(
+ $this->getTransactionStub()
+ );
+ $this->createOrders();
+ }
+
+ /**
+ * Checks a case when multiple orders are created successfully using Braintree PayPal payment method.
+ *
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/Braintree/Fixtures/quote_with_split_items_braintree_paypal.php
+ * @magentoConfigFixture current_store payment/braintree_paypal/active 1
+ * @return void
+ */
+ public function testCreateOrdersWithBraintreePaypal()
+ {
+ $this->adapter->method('sale')
+ ->willReturn(
+ $this->getTransactionPaypalStub()
+ );
+ $this->createOrders();
+ }
+
+ /**
+ * Creates orders for multishipping checkout flow.
+ *
+ * @return void
+ */
+ private function createOrders()
+ {
+ $expectedPlacedOrdersNumber = 3;
+ $quote = $this->getQuote('multishipping_quote_id_braintree');
+
+ /** @var CheckoutSession $session */
+ $session = $this->objectManager->get(CheckoutSession::class);
+ $session->replaceQuote($quote);
+
+ $this->model->createOrders();
+
+ $orderList = $this->getOrderList((int)$quote->getId());
+ self::assertCount(
+ $expectedPlacedOrdersNumber,
+ $orderList,
+ 'Total successfully placed orders number mismatch'
+ );
+ }
+
+ /**
+ * Creates stub for Braintree capture Transaction.
+ *
+ * @return Successful
+ */
+ private function getTransactionStub(): Successful
+ {
+ $transaction = $this->getMockBuilder(Transaction::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $transaction->status = 'submitted_for_settlement';
+ $transaction->creditCard = [
+ 'last4' => '1111',
+ 'cardType' => 'Visa',
+ 'expirationMonth' => '12',
+ 'expirationYear' => '2021'
+ ];
+
+ $creditCardDetails = new \stdClass();
+ $creditCardDetails->token = '4fdg';
+ $creditCardDetails->expirationMonth = '12';
+ $creditCardDetails->expirationYear = '2021';
+ $creditCardDetails->cardType = 'Visa';
+ $creditCardDetails->last4 = '1111';
+ $creditCardDetails->expirationDate = '12/2021';
+ $transaction->creditCardDetails = $creditCardDetails;
+
+ $response = new Successful();
+ $response->success = true;
+ $response->transaction = $transaction;
+
+ return $response;
+ }
+
+ /**
+ * Creates stub for BraintreePaypal capture Transaction.
+ *
+ * @return Successful
+ */
+ private function getTransactionPaypalStub(): Successful
+ {
+ $transaction = $this->getMockBuilder(Transaction::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $transaction->status = 'submitted_for_settlement';
+ $transaction->paypal = [
+ 'token' => 'fchxqx',
+ 'payerEmail' => 'payer@example.com',
+ 'paymentId' => 'PAY-33ac47a28e7f54791f6cda45',
+ ];
+ $paypalDetails = new \stdClass();
+ $paypalDetails->token = 'fchxqx';
+ $paypalDetails->payerEmail = 'payer@example.com';
+ $paypalDetails->paymentId = '33ac47a28e7f54791f6cda45';
+ $transaction->paypalDetails = $paypalDetails;
+
+ $response = new Successful();
+ $response->success = true;
+ $response->transaction = $transaction;
+
+ return $response;
+ }
+
+ /**
+ * Retrieves quote by reserved order id.
+ *
+ * @param string $reservedOrderId
+ * @return Quote
+ */
+ private function getQuote(string $reservedOrderId): Quote
+ {
+ /** @var SearchCriteriaBuilder $searchCriteriaBuilder */
+ $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class);
+ $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId)
+ ->create();
+
+ /** @var CartRepositoryInterface $quoteRepository */
+ $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class);
+ $items = $quoteRepository->getList($searchCriteria)->getItems();
+
+ return array_pop($items);
+ }
+
+ /**
+ * Get list of orders by quote id.
+ *
+ * @param int $quoteId
+ * @return array
+ */
+ private function getOrderList(int $quoteId): array
+ {
+ /** @var SearchCriteriaBuilder $searchCriteriaBuilder */
+ $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class);
+ $searchCriteria = $searchCriteriaBuilder->addFilter('quote_id', $quoteId)
+ ->create();
+
+ /** @var OrderRepositoryInterface $orderRepository */
+ $orderRepository = $this->objectManager->get(OrderRepositoryInterface::class);
+ return $orderRepository->getList($searchCriteria)->getItems();
+ }
+
+ /**
+ * Returns GetPaymentNonceCommand command mock.
+ *
+ * @return MockObject
+ */
+ private function getPaymentNonceMock(): MockObject
+ {
+ $commandResult = $this->createMock(CommandResultInterface::class);
+ $commandResult->method('get')
+ ->willReturn(['paymentMethodNonce' => 'testNonce']);
+ $paymentNonce = $this->createMock(GetPaymentNonceCommand::class);
+ $paymentNonce->method('execute')
+ ->willReturn($commandResult);
+
+ return $paymentNonce;
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php
index 2a68ff48e5f9a..4a5757aae3134 100644
--- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php
+++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/PriceTest.php
@@ -6,7 +6,7 @@
namespace Magento\Bundle\Model\Product;
/**
- * @magentoDataFixture Magento/Bundle/_files/product_with_tier_pricing.php
+ * Class to test bundle prices
*/
class PriceTest extends \PHPUnit\Framework\TestCase
{
@@ -22,6 +22,9 @@ protected function setUp()
);
}
+ /**
+ * @magentoDataFixture Magento/Bundle/_files/product_with_tier_pricing.php
+ */
public function testGetTierPrice()
{
/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
@@ -37,4 +40,50 @@ public function testGetTierPrice()
$this->assertEquals(20.0, $this->_model->getTierPrice(4, $product));
$this->assertEquals(30.0, $this->_model->getTierPrice(5, $product));
}
+
+ /**
+ * Test calculation final price for bundle product with tire price in simple product
+ *
+ * @param float $bundleQty
+ * @param float $selectionQty
+ * @param float $finalPrice
+ * @magentoDataFixture Magento/Bundle/_files/product_with_simple_tier_pricing.php
+ * @dataProvider getSelectionFinalTotalPriceWithSimpleTierPriceDataProvider
+ */
+ public function testGetSelectionFinalTotalPriceWithSimpleTierPrice(
+ float $bundleQty,
+ float $selectionQty,
+ float $finalPrice
+ ) {
+ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+ $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+ $bundleProduct = $productRepository->get('bundle-product');
+ $simpleProduct = $productRepository->get('simple');
+ $simpleProduct->setCustomerGroupId(\Magento\Customer\Model\Group::CUST_GROUP_ALL);
+
+ $this->assertEquals(
+ $finalPrice,
+ $this->_model->getSelectionFinalTotalPrice(
+ $bundleProduct,
+ $simpleProduct,
+ $bundleQty,
+ $selectionQty,
+ false
+ ),
+ 'Tier price calculation for Simple product is wrong'
+ );
+ }
+
+ /**
+ * @return array
+ */
+ public function getSelectionFinalTotalPriceWithSimpleTierPriceDataProvider(): array
+ {
+ return [
+ [1, 1, 10],
+ [2, 1, 8],
+ [5, 1, 5],
+ ];
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_simple_tier_pricing.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_simple_tier_pricing.php
new file mode 100644
index 0000000000000..30f0978480701
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_simple_tier_pricing.php
@@ -0,0 +1,43 @@
+create(\Magento\Catalog\Model\ProductFactory::class);
+/** @var $bundleProduct \Magento\Catalog\Model\Product */
+$bundleProduct = $productFactory->create();
+$bundleProduct->setTypeId('bundle')
+ ->setAttributeSetId($product->getDefaultAttributeSetId())
+ ->setWebsiteIds([1])
+ ->setPriceType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC)
+ ->setPriceView(1)
+ ->setName('Bundle Product')
+ ->setSku('bundle-product')
+ ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+ ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+ ->setStockData([
+ 'use_config_manage_stock' => 1,
+ 'qty' => 100,
+ 'is_qty_decimal' => 0,
+ 'is_in_stock' => 1,
+ ])
+ ->setBundleOptionsData(
+ [
+ [
+ 'title' => 'Bundle Product Items',
+ 'default_title' => 'Bundle Product Items',
+ 'type' => 'checkbox',
+ 'required' => 1,
+ 'delete' => '',
+ ],
+ ]
+ )
+ ->setBundleSelectionsData(
+ [[['product_id' => $product->getId(), 'selection_qty' => 1, 'delete' => '']]]
+ );
+$productRepository->save($bundleProduct);
diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_simple_tier_pricing_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_simple_tier_pricing_rollback.php
new file mode 100644
index 0000000000000..aa661c7412d42
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_simple_tier_pricing_rollback.php
@@ -0,0 +1,24 @@
+get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+try {
+ $product = $productRepository->get('bundle-product');
+ $productRepository->delete($product);
+} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) {
+ //Product already removed
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_options.php
new file mode 100644
index 0000000000000..a401db8eb2bf7
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_options.php
@@ -0,0 +1,107 @@
+create(\Magento\Catalog\Model\Product::class);
+
+$product->setTypeId(
+ 'simple'
+)->setAttributeSetId(
+ 4
+)->setWebsiteIds(
+ [1]
+)->setName(
+ 'Virtual Product With Custom Options'
+)->setSku(
+ 'simple'
+)->setPrice(
+ 10
+)->setMetaTitle(
+ 'meta title'
+)->setMetaKeyword(
+ 'meta keyword'
+)->setMetaDescription(
+ 'meta description'
+)->setVisibility(
+ \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
+)->setStatus(
+ \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
+)->setCanSaveCustomOptions(
+ true
+)->setStockData(
+ [
+ 'qty' => 100,
+ 'is_in_stock' => 1,
+ 'manage_stock' => 1,
+ ]
+)->setHasOptions(true);
+
+$options = [
+ [
+ 'title' => 'test_option_code_1',
+ 'type' => 'field',
+ 'is_require' => true,
+ 'sort_order' => 1,
+ 'price' => -10.0,
+ 'price_type' => 'fixed',
+ 'sku' => 'sku1',
+ 'max_characters' => 10,
+ ],
+ [
+ 'title' => 'area option',
+ 'type' => 'area',
+ 'is_require' => true,
+ 'sort_order' => 2,
+ 'price' => 20.0,
+ 'price_type' => 'percent',
+ 'sku' => 'sku2',
+ 'max_characters' => 20
+ ],
+ [
+ 'title' => 'drop_down option',
+ 'type' => 'drop_down',
+ 'is_require' => false,
+ 'sort_order' => 4,
+ 'values' => [
+ [
+ 'title' => 'drop_down option 1',
+ 'price' => 10,
+ 'price_type' => 'fixed',
+ 'sku' => 'drop_down option 1 sku',
+ 'sort_order' => 1,
+ ],
+ [
+ 'title' => 'drop_down option 2',
+ 'price' => 20,
+ 'price_type' => 'fixed',
+ 'sku' => 'drop_down option 2 sku',
+ 'sort_order' => 2,
+ ],
+ ],
+ ]
+];
+
+$customOptions = [];
+
+/** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory $customOptionFactory */
+$customOptionFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory::class);
+
+foreach ($options as $option) {
+ /** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterface $customOption */
+ $customOption = $customOptionFactory->create(['data' => $option]);
+ $customOption->setProductSku($product->getSku());
+
+ $customOptions[] = $customOption;
+}
+
+$product->setOptions($customOptions);
+
+/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepositoryFactory */
+$productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_options_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_options_rollback.php
new file mode 100644
index 0000000000000..8863da1cd2782
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_options_rollback.php
@@ -0,0 +1,25 @@
+get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+$repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+ \Magento\Catalog\Model\ProductRepository::class
+);
+try {
+ $product = $repository->get('simple', false, null, true);
+ $repository->delete($product);
+} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ //Entity already deleted
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php
index 38e8c404dc002..838ae2b9a2aa6 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual.php
@@ -3,9 +3,14 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
-/** @var $product \Magento\Catalog\Model\Product */
-$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+use Magento\Catalog\Api\Data\ProductInterfaceFactory;
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\Catalog\Model\ResourceModel\Product as ProductResource;
+
+$productFactory = Bootstrap::getObjectManager()->get(ProductInterfaceFactory::class);
+$product = $productFactory->create();
$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_VIRTUAL)
->setId(21)
->setAttributeSetId(4)
@@ -22,4 +27,7 @@
'is_in_stock' => 1,
'manage_stock' => 1,
]
- )->save();
+ );
+/** @var ProductResource $productResource */
+$productResource = Bootstrap::getObjectManager()->get(ProductResource::class);
+$productResource->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_rollback.php
index 7fdeca846885a..f5568ced2c96a 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_rollback.php
@@ -3,23 +3,27 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
-/** @var \Magento\Framework\Registry $registry */
-$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Framework\Exception\StateException;
+use Magento\TestFramework\Helper\Bootstrap;
+
+$registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
$registry->unregister('isSecureArea');
$registry->register('isSecureArea', true);
-/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
-$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
- ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+$productRepository = Bootstrap::getObjectManager()
+ ->get(ProductRepositoryInterface::class);
try {
$product = $productRepository->get('virtual-product', false, null, true);
$productRepository->delete($product);
-} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) {
+} catch (NoSuchEntityException $exception) {
//Product already removed
-} catch (\Magento\Framework\Exception\StateException $exception) {
+} catch (StateException $exception) {
}
$registry->unregister('isSecureArea');
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_with_options.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_with_options.php
new file mode 100644
index 0000000000000..c1f981cefa646
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_with_options.php
@@ -0,0 +1,107 @@
+create(\Magento\Catalog\Model\Product::class);
+
+$product->setTypeId(
+ 'virtual'
+)->setAttributeSetId(
+ 4
+)->setWebsiteIds(
+ [1]
+)->setName(
+ 'Virtual Product With Custom Options'
+)->setSku(
+ 'virtual'
+)->setPrice(
+ 10
+)->setMetaTitle(
+ 'meta title'
+)->setMetaKeyword(
+ 'meta keyword'
+)->setMetaDescription(
+ 'meta description'
+)->setVisibility(
+ \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
+)->setStatus(
+ \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
+)->setCanSaveCustomOptions(
+ true
+)->setStockData(
+ [
+ 'qty' => 100,
+ 'is_in_stock' => 1,
+ 'manage_stock' => 1,
+ ]
+)->setHasOptions(true);
+
+$options = [
+ [
+ 'title' => 'test_option_code_1',
+ 'type' => 'field',
+ 'is_require' => true,
+ 'sort_order' => 1,
+ 'price' => -10.0,
+ 'price_type' => 'fixed',
+ 'sku' => 'sku1',
+ 'max_characters' => 10,
+ ],
+ [
+ 'title' => 'area option',
+ 'type' => 'area',
+ 'is_require' => true,
+ 'sort_order' => 2,
+ 'price' => 20.0,
+ 'price_type' => 'percent',
+ 'sku' => 'sku2',
+ 'max_characters' => 20
+ ],
+ [
+ 'title' => 'drop_down option',
+ 'type' => 'drop_down',
+ 'is_require' => false,
+ 'sort_order' => 4,
+ 'values' => [
+ [
+ 'title' => 'drop_down option 1',
+ 'price' => 10,
+ 'price_type' => 'fixed',
+ 'sku' => 'drop_down option 1 sku',
+ 'sort_order' => 1,
+ ],
+ [
+ 'title' => 'drop_down option 2',
+ 'price' => 20,
+ 'price_type' => 'fixed',
+ 'sku' => 'drop_down option 2 sku',
+ 'sort_order' => 2,
+ ],
+ ],
+ ]
+];
+
+$customOptions = [];
+
+/** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory $customOptionFactory */
+$customOptionFactory = $objectManager->get(\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory::class);
+
+foreach ($options as $option) {
+ /** @var \Magento\Catalog\Api\Data\ProductCustomOptionInterface $customOption */
+ $customOption = $customOptionFactory->create(['data' => $option]);
+ $customOption->setProductSku($product->getSku());
+
+ $customOptions[] = $customOption;
+}
+
+$product->setOptions($customOptions);
+
+/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepositoryFactory */
+$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_with_options_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_with_options_rollback.php
new file mode 100644
index 0000000000000..f46cdc13d3263
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_virtual_with_options_rollback.php
@@ -0,0 +1,25 @@
+get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+$repository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+ \Magento\Catalog\Model\ProductRepository::class
+);
+try {
+ $product = $repository->get('virtual', false, null, true);
+ $repository->delete($product);
+} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ //Entity already deleted
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
index c4c6d3ba2d1d2..67446960e15dc 100644
--- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php
@@ -34,6 +34,7 @@
* @magentoDataFixtureBeforeTransaction Magento/Catalog/_files/enable_catalog_product_reindex_schedule.php
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
+ * phpcs:disable Generic.PHP.NoSilencedErrors, Generic.Metrics.NestingLevel, Magento2.Functions.StaticFunction
*/
class ProductTest extends \Magento\TestFramework\Indexer\TestCase
{
@@ -567,6 +568,7 @@ public function testSaveDatetimeAttribute()
*/
protected function getExpectedOptionsData(string $pathToFile, string $storeCode = ''): array
{
+ // phpcs:disable Magento2.Functions.DiscouragedFunction
$productData = $this->csvToArray(file_get_contents($pathToFile));
$expectedOptionId = 0;
$expectedOptions = [];
@@ -1590,6 +1592,28 @@ public function testAddUpdateProductWithInvalidUrlKeys() : void
}
}
+ /**
+ * Make sure the non existing image in the csv file won't erase the qty key of the existing products.
+ *
+ * @magentoDbIsolation enabled
+ * @magentoAppIsolation enabled
+ */
+ public function testImportWithNonExistingImage()
+ {
+ $products = [
+ 'simple_new' => 100,
+ ];
+
+ $this->importFile('products_to_import_with_non_existing_image.csv');
+
+ $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+ foreach ($products as $productSku => $productQty) {
+ $product = $productRepository->get($productSku);
+ $stockItem = $product->getExtensionAttributes()->getStockItem();
+ $this->assertEquals($productQty, $stockItem->getQty());
+ }
+ }
+
/**
* @magentoDataFixture Magento/Catalog/_files/product_simple_with_url_key.php
* @magentoDbIsolation disabled
@@ -1781,6 +1805,7 @@ function (ProductInterface $item) {
if ($product->getId()) {
$productRepository->delete($product);
}
+ // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
//Product already removed
}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_non_existing_image.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_non_existing_image.csv
new file mode 100644
index 0000000000000..8122433a8c9e1
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_non_existing_image.csv
@@ -0,0 +1,2 @@
+sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus
+simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,/no/exists/image/magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,,
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_customer_not_default_store.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_customer_not_default_store.php
new file mode 100644
index 0000000000000..6448a570424e2
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_customer_not_default_store.php
@@ -0,0 +1,23 @@
+create(\Magento\Quote\Model\Quote::class);
+$quote->setStoreId($store->getId())
+ ->setIsActive(true)
+ ->setIsMultiShipping(false)
+ ->setReservedOrderId('test_order_1_not_default_store')
+ ->setCustomerId($customer->getId())
+ ->save();
+
+/** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */
+$quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class)
+ ->create();
+$quoteIdMask->setQuoteId($quote->getId());
+$quoteIdMask->setDataChanges(true);
+$quoteIdMask->save();
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_customer_not_default_store_rollback.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_customer_not_default_store_rollback.php
new file mode 100644
index 0000000000000..e3e1513cb6144
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_customer_not_default_store_rollback.php
@@ -0,0 +1,8 @@
+create(\Magento\Quote\Model\Quote::class);
+$quote->load('test_order_1_not_default_store', 'reserved_order_id')->delete();
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_guest_not_default_store.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_guest_not_default_store.php
new file mode 100644
index 0000000000000..bbd3d5efbe8c8
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_guest_not_default_store.php
@@ -0,0 +1,21 @@
+create(\Magento\Quote\Model\Quote::class);
+$quote->setStoreId($store->getId())
+ ->setIsActive(true)
+ ->setIsMultiShipping(false)
+ ->setReservedOrderId('test_order_1_not_default_store_guest')
+ ->save();
+
+/** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */
+$quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class)
+ ->create();
+$quoteIdMask->setQuoteId($quote->getId());
+$quoteIdMask->setDataChanges(true);
+$quoteIdMask->save();
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_guest_not_default_store_rollback.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_guest_not_default_store_rollback.php
new file mode 100644
index 0000000000000..f511133280e7f
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/active_quote_guest_not_default_store_rollback.php
@@ -0,0 +1,8 @@
+create(\Magento\Quote\Model\Quote::class);
+$quote->load('test_order_1_not_default_store_guest', 'reserved_order_id')->delete();
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/discount_10percent_generalusers.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/discount_10percent_generalusers.php
index 507f6b755bcda..e66227a60e8f0 100644
--- a/dev/tests/integration/testsuite/Magento/Checkout/_files/discount_10percent_generalusers.php
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/discount_10percent_generalusers.php
@@ -21,7 +21,7 @@
],
'customer_group_ids' => [1],
'coupon_type' => \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC,
- 'coupon_code' => uniqid(),
+ 'coupon_code' => '2?ds5!2d',
'simple_action' => \Magento\SalesRule\Model\Rule::BY_PERCENT_ACTION,
'discount_amount' => 10,
'discount_step' => 1
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_virtual_product_saved.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_virtual_product_saved.php
index 835b2ab812856..833e5a57ac34f 100644
--- a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_virtual_product_saved.php
+++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_virtual_product_saved.php
@@ -13,6 +13,7 @@
->setIsMultiShipping(false)
->setReservedOrderId('test_order_with_virtual_product_without_address')
->setEmail('store@example.com')
+ ->setCustomerEmail('store@example.com')
->addProduct(
$product->load($product->getId()),
1
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ConverterStub.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ConverterStub.php
similarity index 63%
rename from dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ConverterStub.php
rename to dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ConverterStub.php
index 223ef35c0dcd3..7493d31f02b31 100644
--- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ConverterStub.php
+++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ConverterStub.php
@@ -3,14 +3,20 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-namespace Magento\Paypal\Model\Config\Structure\Reader;
+declare(strict_types=1);
+
+namespace Magento\Config\Model\Config\Structure\Reader;
+
+use Magento\Config\Model\Config\Structure\Converter;
/**
- * Class ConverterStub
+ * Class ConverterStub used for ReaderTest.
*/
-class ConverterStub extends \Magento\Config\Model\Config\Structure\Converter
+class ConverterStub extends Converter
{
/**
+ * Convert dom document wrapper.
+ *
* @param \DOMDocument $document
* @return array|null
*/
@@ -20,7 +26,7 @@ public function getArrayData(\DOMDocument $document)
}
/**
- * Convert dom document
+ * Convert dom document.
*
* @param \DOMNode $source
* @return array
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ReaderStub.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ReaderStub.php
similarity index 53%
rename from dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ReaderStub.php
rename to dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ReaderStub.php
index ed1366ad737f9..866ff91678ec4 100644
--- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ReaderStub.php
+++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ReaderStub.php
@@ -3,14 +3,20 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-namespace Magento\Paypal\Model\Config\Structure\Reader;
+declare(strict_types=1);
+
+namespace Magento\Config\Model\Config\Structure\Reader;
+
+use Magento\Config\Model\Config\Structure\Reader;
/**
- * Class ReaderStub
+ * Class ReaderStub used for testing protected Reader::_readFiles() method.
*/
-class ReaderStub extends \Magento\Config\Model\Config\Structure\Reader
+class ReaderStub extends Reader
{
/**
+ * Wrapper for protected Reader::_readFiles() method.
+ *
* @param array $fileList
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
diff --git a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ReaderTest.php
new file mode 100644
index 0000000000000..eef8e68458d91
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/ReaderTest.php
@@ -0,0 +1,146 @@
+objectManager = Bootstrap::getObjectManager();
+ $this->fileUtility = Files::init();
+
+ $this->validationStateMock = $this->getMockBuilder(ValidationStateInterface::class)
+ ->setMethods(['isValidationRequired'])
+ ->getMockForAbstractClass();
+ $this->schemaLocatorMock = $this->getMockBuilder(SchemaLocator::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getPerFileSchema'])
+ ->getMock();
+ $this->fileResolverMock = $this->getMockBuilder(FileResolverInterface::class)
+ ->getMockForAbstractClass();
+
+ $this->validationStateMock->expects($this->atLeastOnce())
+ ->method('isValidationRequired')
+ ->willReturn(false);
+ $this->schemaLocatorMock->expects($this->atLeastOnce())
+ ->method('getPerFileSchema')
+ ->willReturn(false);
+
+ $this->converter = $this->objectManager->create(ConverterStub::class);
+
+ //Isolate test from actual configuration, and leave only sample data.
+ $this->compiler = $this->getMockBuilder(CompilerInterface::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['compile'])
+ ->getMockForAbstractClass();
+
+ $this->reader = $this->objectManager->create(
+ ReaderStub::class,
+ [
+ 'fileResolver' => $this->fileResolverMock,
+ 'converter' => $this->converter,
+ 'schemaLocator' => $this->schemaLocatorMock,
+ 'validationState' => $this->validationStateMock,
+ 'fileName' => 'no_existing_file.xml',
+ 'compiler' => $this->compiler,
+ 'domDocumentClass' => Dom::class
+ ]
+ );
+ }
+
+ /**
+ * The test checks the file structure after processing the nodes responsible for inserting content.
+ *
+ * @return void
+ */
+ public function testXmlConvertedConfigurationAndCompereStructure()
+ {
+ $actual = $this->reader->readFiles(['actual' => $this->getContent()]);
+
+ $document = new \DOMDocument();
+ $document->loadXML($this->getContent());
+
+ $expected = $this->converter->getArrayData($document);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+ /**
+ * Get config sample data for test.
+ *
+ * @return string
+ */
+ protected function getContent()
+ {
+ $files = $this->fileUtility->getFiles([BP . static::CONFIG], 'config.xml');
+
+ return file_get_contents(reset($files));
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/actual/config.xml b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/_files/config.xml
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/actual/config.xml
rename to dev/tests/integration/testsuite/Magento/Config/Model/Config/Structure/Reader/_files/config.xml
diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/CartTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/CartTest.php
index 3bb10baff6572..3ade17d90fe99 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/CartTest.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/View/CartTest.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Customer\Block\Adminhtml\Edit\Tab\View;
use Magento\Customer\Controller\RegistryConstants;
@@ -100,15 +101,4 @@ public function testToHtmlCartItem()
$this->assertContains('$10.00', $html);
$this->assertContains('catalog/product/edit/id/1', $html);
}
-
- /**
- * Verify that the customer has a single item in his cart.
- *
- * @magentoDataFixture Magento/Customer/_files/customer.php
- * @magentoDataFixture Magento/Customer/_files/quote.php
- */
- public function testGetCollection()
- {
- $this->assertEquals(1, $this->block->getCollection()->getSize());
- }
}
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Data/Form/Element/DateTest.php b/dev/tests/integration/testsuite/Magento/Framework/Data/Form/Element/DateTest.php
index a934372bfd907..9980f40239f8c 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Data/Form/Element/DateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Data/Form/Element/DateTest.php
@@ -4,41 +4,51 @@
* See COPYING.txt for license details.
*/
+namespace Magento\Framework\Data\Form\Element;
+
+use Magento\Framework\Data\Form\ElementFactory;
+use Magento\TestFramework\Helper\Bootstrap;
+
/**
* Tests for \Magento\Framework\Data\Form\Element\Date
*/
-namespace Magento\Framework\Data\Form\Element;
-
class DateTest extends \PHPUnit\Framework\TestCase
{
/**
- * @var \Magento\Framework\Data\Form\ElementFactory
+ * @var ElementFactory
*/
- protected $_elementFactory;
+ private $elementFactory;
/**
- * SetUp method
+ * @inheritdoc
*/
protected function setUp()
{
- $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
- $this->_elementFactory = $objectManager->create(\Magento\Framework\Data\Form\ElementFactory::class);
+ $objectManager = Bootstrap::getObjectManager();
+ $this->elementFactory = $objectManager->create(ElementFactory::class);
}
/**
+ * Test get value
+ *
+ * @param array $data
+ * @param string $expect
+ * @return void
* @dataProvider getValueDataProvider
*/
- public function testGetValue(array $data, $expect)
+ public function testGetValue(array $data, string $expect): void
{
- /** @var $date \Magento\Framework\Data\Form\Element\Date */
- $date = $this->_elementFactory->create(\Magento\Framework\Data\Form\Element\Date::class, $data);
+ /** @var $date Date */
+ $date = $this->elementFactory->create(Date::class, $data);
$this->assertEquals($expect, $date->getValue());
}
/**
+ * Get value test data provider
+ *
* @return array
*/
- public function getValueDataProvider()
+ public function getValueDataProvider(): array
{
$testTimestamp = strtotime('2014-05-18 12:08:16');
$date = new \DateTime('@' . $testTimestamp);
@@ -56,15 +66,22 @@ public function getValueDataProvider()
'time_format' => 'h:mm a',
'value' => $testTimestamp,
],
- $date->format('g:i A')
+ $date->format('g:i A'),
],
[
[
'date_format' => 'MM/d/yy',
'value' => $testTimestamp,
],
- $date->format('m/j/y')
- ]
+ $date->format('m/j/y'),
+ ],
+ [
+ [
+ 'date_format' => 'd-MM-Y',
+ 'value' => $date->format('d-m-Y'),
+ ],
+ $date->format('d-m-Y'),
+ ],
];
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php b/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php
index 7f8996daa6e97..10a6b9d8caae4 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/GraphQl/Config/GraphQlReaderTest.php
@@ -8,6 +8,7 @@
namespace Magento\Framework\GraphQl\Config;
use Magento\Framework\App\Cache;
+use Magento\Framework\App\Request\Http;
use Magento\Framework\GraphQl\Config;
use Magento\Framework\GraphQl\Schema\SchemaGenerator;
use Magento\Framework\ObjectManagerInterface;
@@ -175,8 +176,9 @@ enumValues(includeDeprecated: true) {
'operationName' => 'IntrospectionQuery'
];
/** @var Http $request */
- $request = $this->objectManager->get(\Magento\Framework\App\Request\Http::class);
+ $request = $this->objectManager->get(Http::class);
$request->setPathInfo('/graphql');
+ $request->setMethod('POST');
$request->setContent(json_encode($postData));
$headers = $this->objectManager->create(\Zend\Http\Headers::class)
->addHeaders(['Content-Type' => 'application/json']);
diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/communication.xml b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/communication.xml
index 0fc50f0432b93..1cc5d6cd3b714 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/communication.xml
+++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/communication.xml
@@ -7,6 +7,6 @@
-->
-
+
diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_expected_queue.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_expected_queue.php
index b5f5145c32c72..9a813b4424eaa 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_expected_queue.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_expected_queue.php
@@ -40,7 +40,7 @@
"name" => "publisher5.topic",
"schema" => [
"schema_type" => "object",
- "schema_value" => '\\' . \Magento\MysqlMq\Model\DataObject::class
+ "schema_value" => '\\' . \Magento\TestModuleMysqlMq\Model\DataObject::class
],
"response_schema" => [
"schema_type" => "object",
@@ -58,7 +58,7 @@
"handlers" => [
"topic.broker.test" => [
"0" => [
- "type" => \Magento\MysqlMq\Model\Processor::class,
+ "type" => \Magento\TestModuleMysqlMq\Model\Processor::class,
"method" => "processMessage"
]
]
diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_queue_input.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_queue_input.php
index fdd4a7d3007a7..ed6e13cfe9fae 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_queue_input.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_queue_input.php
@@ -23,11 +23,11 @@
"name" => "publisher5.topic",
"schema" => [
"schema_type" => "object",
- "schema_value" => "Magento\\MysqlMq\\Model\\DataObject"
+ "schema_value" => \Magento\TestModuleMysqlMq\Model\DataObject::class
],
"response_schema" => [
"schema_type" => "object",
- "schema_value" => "Magento\\Customer\\Api\\Data\\CustomerInterface"
+ "schema_value" => \Magento\Customer\Api\Data\CustomerInterface::class
],
"publisher" => "test-publisher-5"
]
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php
new file mode 100644
index 0000000000000..9968704517ecd
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/apply_tax_for_simple_product.php
@@ -0,0 +1,26 @@
+get(ProductRepositoryInterface::class);
+$product = $productRepository->get('simple_product');
+
+/** @var TaxClassCollectionFactory $taxClassCollectionFactory */
+$taxClassCollectionFactory = $objectManager->get(TaxClassCollectionFactory::class);
+$taxClassCollection = $taxClassCollectionFactory->create();
+
+/** @var TaxClassModel $taxClass */
+$taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT);
+$taxClass = $taxClassCollection->getFirstItem();
+
+$product->setCustomAttribute('tax_class_id', $taxClass->getClassId());
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/set_simple_product_out_of_stock.php b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/set_simple_product_out_of_stock.php
new file mode 100644
index 0000000000000..f465f482275c1
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/set_simple_product_out_of_stock.php
@@ -0,0 +1,19 @@
+get(ProductRepositoryInterface::class);
+
+$product = $productRepository->get('simple_product');
+$extensionAttributes = $product->getExtensionAttributes();
+$stockItem = $extensionAttributes->getStockItem();
+$stockItem->setIsInStock(false);
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/simple_product.php b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/simple_product.php
new file mode 100644
index 0000000000000..732c18d4d7340
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/simple_product.php
@@ -0,0 +1,45 @@
+get(ProductInterfaceFactory::class);
+/** @var DataObjectHelper $dataObjectHelper */
+$dataObjectHelper = Bootstrap::getObjectManager()->get(DataObjectHelper::class);
+/** @var ProductRepositoryInterface $productRepository */
+$productRepository = $objectManager->get(ProductRepositoryInterface::class);
+
+$product = $productFactory->create();
+$productData = [
+ ProductInterface::TYPE_ID => Type::TYPE_SIMPLE,
+ ProductInterface::ATTRIBUTE_SET_ID => 4,
+ ProductInterface::SKU => 'simple_product',
+ ProductInterface::NAME => 'Simple Product',
+ ProductInterface::PRICE => 10,
+ ProductInterface::VISIBILITY => Visibility::VISIBILITY_BOTH,
+ ProductInterface::STATUS => Status::STATUS_ENABLED,
+];
+$dataObjectHelper->populateWithArray($product, $productData, ProductInterface::class);
+/** Out of interface */
+$product
+ ->setWebsiteIds([1])
+ ->setStockData([
+ 'qty' => 85.5,
+ 'is_in_stock' => true,
+ 'manage_stock' => true,
+ 'is_qty_decimal' => true
+ ]);
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/simple_product_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/simple_product_rollback.php
new file mode 100644
index 0000000000000..9a54f663c9c13
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/simple_product_rollback.php
@@ -0,0 +1,31 @@
+get(ProductRepositoryInterface::class);
+/** @var Registry $registry */
+$registry = $objectManager->get(Registry::class);
+
+$currentArea = $registry->registry('isSecureArea');
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+try {
+ $productRepository->deleteById('simple_product');
+} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ /**
+ * Tests which are wrapped with MySQL transaction clear all data by transaction rollback.
+ */
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', $currentArea);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/virtual_product.php b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/virtual_product.php
new file mode 100644
index 0000000000000..e4472464e17ae
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/virtual_product.php
@@ -0,0 +1,45 @@
+get(ProductInterfaceFactory::class);
+/** @var DataObjectHelper $dataObjectHelper */
+$dataObjectHelper = Bootstrap::getObjectManager()->get(DataObjectHelper::class);
+/** @var ProductRepositoryInterface $productRepository */
+$productRepository = $objectManager->get(ProductRepositoryInterface::class);
+
+$product = $productFactory->create();
+$productData = [
+ ProductInterface::TYPE_ID => Type::TYPE_VIRTUAL,
+ ProductInterface::ATTRIBUTE_SET_ID => 4,
+ ProductInterface::SKU => 'virtual_product',
+ ProductInterface::NAME => 'Virtual Product',
+ ProductInterface::PRICE => 10,
+ ProductInterface::VISIBILITY => Visibility::VISIBILITY_BOTH,
+ ProductInterface::STATUS => Status::STATUS_ENABLED,
+];
+$dataObjectHelper->populateWithArray($product, $productData, ProductInterface::class);
+/** Out of interface */
+$product
+ ->setWebsiteIds([1])
+ ->setStockData([
+ 'qty' => 85.5,
+ 'is_in_stock' => true,
+ 'manage_stock' => true,
+ 'is_qty_decimal' => true
+ ]);
+$productRepository->save($product);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/virtual_product_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/virtual_product_rollback.php
new file mode 100644
index 0000000000000..f8d329f574626
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Catalog/_files/virtual_product_rollback.php
@@ -0,0 +1,31 @@
+get(ProductRepositoryInterface::class);
+/** @var Registry $registry */
+$registry = $objectManager->get(Registry::class);
+
+$currentArea = $registry->registry('isSecureArea');
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+try {
+ $productRepository->deleteById('virtual_product');
+} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ /**
+ * Tests which are wrapped with MySQL transaction clear all data by transaction rollback.
+ */
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', $currentArea);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php b/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php
index 384892d6fd5d2..d0d746812ec44 100644
--- a/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Controller/GraphQlControllerTest.php
@@ -38,6 +38,9 @@ class GraphQlControllerTest extends \Magento\TestFramework\Indexer\TestCase
/** @var MetadataPool */
private $metadataPool;
+ /** @var Http */
+ private $request;
+
public static function setUpBeforeClass()
{
$db = Bootstrap::getInstance()->getBootstrap()
@@ -57,6 +60,7 @@ protected function setUp() : void
$this->graphql = $this->objectManager->get(\Magento\GraphQl\Controller\GraphQl::class);
$this->jsonSerializer = $this->objectManager->get(SerializerInterface::class);
$this->metadataPool = $this->objectManager->get(MetadataPool::class);
+ $this->request = $this->objectManager->get(Http::class);
}
/**
@@ -86,27 +90,120 @@ public function testDispatch() : void
}
QUERY;
$postData = [
- 'query' => $query,
- 'variables' => null,
+ 'query' => $query,
+ 'variables' => null,
'operationName' => null
];
- /** @var Http $request */
- $request = $this->objectManager->get(\Magento\Framework\App\Request\Http::class);
- $request->setPathInfo('/graphql');
- $request->setContent(json_encode($postData));
+
+ $this->request->setPathInfo('/graphql');
+ $this->request->setMethod('POST');
+ $this->request->setContent(json_encode($postData));
$headers = $this->objectManager->create(\Zend\Http\Headers::class)
->addHeaders(['Content-Type' => 'application/json']);
- $request->setHeaders($headers);
- $response = $this->graphql->dispatch($request);
+ $this->request->setHeaders($headers);
+ $response = $this->graphql->dispatch($this->request);
$output = $this->jsonSerializer->unserialize($response->getContent());
$linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
$this->assertArrayNotHasKey('errors', $output, 'Response has errors');
- $this->assertTrue(!empty($output['data']['products']['items']), 'Products array has items');
- $this->assertTrue(!empty($output['data']['products']['items'][0]), 'Products array has items');
- $this->assertEquals($output['data']['products']['items'][0]['id'], $product->getData($linkField));
- $this->assertEquals($output['data']['products']['items'][0]['sku'], $product->getSku());
- $this->assertEquals($output['data']['products']['items'][0]['name'], $product->getName());
+ $this->assertNotEmpty($output['data']['products']['items'], 'Products array has items');
+ $this->assertNotEmpty($output['data']['products']['items'][0], 'Products array has items');
+ $this->assertEquals($product->getData($linkField), $output['data']['products']['items'][0]['id']);
+ $this->assertEquals($product->getSku(), $output['data']['products']['items'][0]['sku']);
+ $this->assertEquals($product->getName(), $output['data']['products']['items'][0]['name']);
+ }
+
+ /**
+ * Test request is dispatched and response generated when using GET request with query string
+ *
+ * @return void
+ */
+ public function testDispatchWithGet() : void
+ {
+ /** @var ProductRepositoryInterface $productRepository */
+ $productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
+
+ /** @var ProductInterface $product */
+ $product = $productRepository->get('simple1');
+
+ $query
+ = <<request->setPathInfo('/graphql');
+ $this->request->setMethod('GET');
+ $this->request->setQueryValue('query', $query);
+ $response = $this->graphql->dispatch($this->request);
+ $output = $this->jsonSerializer->unserialize($response->getContent());
+ $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
+
+ $this->assertArrayNotHasKey('errors', $output, 'Response has errors');
+ $this->assertNotEmpty($output['data']['products']['items'], 'Products array has items');
+ $this->assertNotEmpty($output['data']['products']['items'][0], 'Products array has items');
+ $this->assertEquals($product->getData($linkField), $output['data']['products']['items'][0]['id']);
+ $this->assertEquals($product->getSku(), $output['data']['products']['items'][0]['sku']);
+ $this->assertEquals($product->getName(), $output['data']['products']['items'][0]['name']);
+ }
+
+ /** Test request is dispatched and response generated when using GET request with parameterized query string
+ *
+ * @return void
+ */
+ public function testDispatchGetWithParameterizedVariables() : void
+ {
+ /** @var ProductRepositoryInterface $productRepository */
+ $productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
+
+ /** @var ProductInterface $product */
+ $product = $productRepository->get('simple1');
+ $query = << [
+ 'sku' => ['eq' => 'simple1']
+ ]
+ ];
+ $queryParams = [
+ 'query' => $query,
+ 'variables' => json_encode($variables),
+ 'operationName' => 'GetProducts'
+ ];
+
+ $this->request->setPathInfo('/graphql');
+ $this->request->setMethod('GET');
+ $this->request->setParams($queryParams);
+ $response = $this->graphql->dispatch($this->request);
+ $output = $this->jsonSerializer->unserialize($response->getContent());
+ $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField();
+
+ $this->assertArrayNotHasKey('errors', $output, 'Response has errors');
+ $this->assertNotEmpty($output['data']['products']['items'], 'Products array has items');
+ $this->assertNotEmpty($output['data']['products']['items'][0], 'Products array has items');
+ $this->assertEquals($product->getData($linkField), $output['data']['products']['items'][0]['id']);
+ $this->assertEquals($product->getSku(), $output['data']['products']['items'][0]['sku']);
+ $this->assertEquals($product->getName(), $output['data']['products']['items'][0]['name']);
}
/**
@@ -136,25 +233,25 @@ public function testError() : void
QUERY;
$postData = [
- 'query' => $query,
- 'variables' => null,
+ 'query' => $query,
+ 'variables' => null,
'operationName' => null
];
- /** @var Http $request */
- $request = $this->objectManager->get(\Magento\Framework\App\Request\Http::class);
- $request->setPathInfo('/graphql');
- $request->setContent(json_encode($postData));
+
+ $this->request->setPathInfo('/graphql');
+ $this->request->setMethod('POST');
+ $this->request->setContent(json_encode($postData));
$headers = $this->objectManager->create(\Zend\Http\Headers::class)
->addHeaders(['Content-Type' => 'application/json']);
- $request->setHeaders($headers);
- $response = $this->graphql->dispatch($request);
+ $this->request->setHeaders($headers);
+ $response = $this->graphql->dispatch($this->request);
$outputResponse = $this->jsonSerializer->unserialize($response->getContent());
if (isset($outputResponse['errors'][0])) {
if (is_array($outputResponse['errors'][0])) {
foreach ($outputResponse['errors'] as $error) {
$this->assertEquals(
- $error['category'],
- \Magento\Framework\GraphQl\Exception\GraphQlInputException::EXCEPTION_CATEGORY
+ \Magento\Framework\GraphQl\Exception\GraphQlInputException::EXCEPTION_CATEGORY,
+ $error['category']
);
if (isset($error['message'])) {
$this->assertEquals($error['message'], 'Invalid entity_type specified: invalid');
@@ -168,12 +265,4 @@ public function testError() : void
}
}
}
-
- /**
- * teardown
- */
- public function tearDown()
- {
- parent::tearDown();
- }
}
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/add_simple_product.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/add_simple_product.php
index d23381e33d436..f62b463d94003 100644
--- a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/add_simple_product.php
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/add_simple_product.php
@@ -20,7 +20,7 @@
/** @var CartRepositoryInterface $cartRepository */
$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class);
-$product = $productRepository->get('simple');
+$product = $productRepository->get('simple_product');
$quote = $quoteFactory->create();
$quoteResource->load($quote, 'test_quote', 'reserved_order_id');
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/apply_coupon.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/apply_coupon.php
new file mode 100644
index 0000000000000..c70efa9a12a5d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/apply_coupon.php
@@ -0,0 +1,22 @@
+get(CouponManagementInterface::class);
+/** @var QuoteFactory $quoteFactory */
+$quoteFactory = Bootstrap::getObjectManager()->get(QuoteFactory::class);
+/** @var QuoteResource $quoteResource */
+$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class);
+
+$quote = $quoteFactory->create();
+$quoteResource->load($quote, 'test_quote', 'reserved_order_id');
+$couponManagement->set($quote->getId(), '2?ds5!2d');
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/apply_coupon_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/apply_coupon_rollback.php
new file mode 100644
index 0000000000000..5431c25b7df53
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/apply_coupon_rollback.php
@@ -0,0 +1,22 @@
+get(CouponManagementInterface::class);
+/** @var QuoteFactory $quoteFactory */
+$quoteFactory = Bootstrap::getObjectManager()->get(QuoteFactory::class);
+/** @var QuoteResource $quoteResource */
+$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class);
+
+$quote = $quoteFactory->create();
+$quoteResource->load($quote, 'test_quote', 'reserved_order_id');
+$couponManagement->remove($quote->getId());
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/guest/set_guest_email.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/guest/set_guest_email.php
new file mode 100644
index 0000000000000..c8084b2552395
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/guest/set_guest_email.php
@@ -0,0 +1,24 @@
+get(QuoteFactory::class);
+/** @var CartRepositoryInterface $cartRepository */
+$cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class);
+/** @var QuoteResource $quoteResource */
+$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class);
+
+$quote = $quoteFactory->create();
+$quoteResource->load($quote, 'test_quote', 'reserved_order_id');
+
+$quote->setCustomerEmail('guest@example.com');
+$cartRepository->save($quote);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/make_coupon_expired.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/make_coupon_expired.php
new file mode 100644
index 0000000000000..5316b184ecd15
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/make_coupon_expired.php
@@ -0,0 +1,22 @@
+get(CouponResourceInterface::class);
+/** @var CouponFactory $couponFactory */
+$couponFactory = Bootstrap::getObjectManager()->get(CouponFactory::class);
+
+$coupon = $couponFactory->create();
+$coupon->loadByCode('2?ds5!2d');
+$yesterday = new \DateTime();
+$yesterday->add(\DateInterval::createFromDateString('-1 day'));
+$coupon->setExpirationDate($yesterday->format('Y-m-d'));
+$couponResource->save($coupon);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/make_coupon_expired_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/make_coupon_expired_rollback.php
new file mode 100644
index 0000000000000..32c3d78bafd09
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/make_coupon_expired_rollback.php
@@ -0,0 +1,23 @@
+get(CouponResourceInterface::class);
+/** @var CouponFactory $couponFactory */
+$couponFactory = Bootstrap::getObjectManager()->get(CouponFactory::class);
+
+$coupon = $couponFactory->create();
+$coupon->loadByCode('2?ds5!2d');
+
+if ($coupon->getId()) {
+ $coupon->setExpirationDate(null);
+ $couponResource->save($coupon);
+}
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product.php
new file mode 100644
index 0000000000000..e58c6b21d8d23
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product.php
@@ -0,0 +1,52 @@
+get(CouponFactory::class);
+/** @var ConditionInterfaceFactory $conditionFactory */
+$conditionFactory = Bootstrap::getObjectManager()->get(ConditionInterfaceFactory::class);
+/** @var RuleRepositoryInterface $ruleRepository */
+$ruleRepository = Bootstrap::getObjectManager()->get(RuleRepositoryInterface::class);
+
+$couponCode = '2?ds5!2d';
+$sku = 'simple_product';
+
+$coupon = $couponFactory->create();
+$coupon->loadByCode($couponCode);
+$ruleId = $coupon->getRuleId();
+$salesRule = $ruleRepository->getById($ruleId);
+
+/** @var ConditionInterface $conditionProductSku */
+$conditionProductSku = $conditionFactory->create();
+$conditionProductSku->setConditionType(\Magento\SalesRule\Model\Rule\Condition\Product::class);
+$conditionProductSku->setAttributeName('sku');
+$conditionProductSku->setValue('1');
+$conditionProductSku->setOperator('!=');
+$conditionProductSku->setValue($sku);
+
+/** @var ConditionInterface $conditionProductFound */
+$conditionProductFound = $conditionFactory->create();
+$conditionProductFound->setConditionType(\Magento\SalesRule\Model\Rule\Condition\Product\Found::class);
+$conditionProductFound->setValue('1');
+$conditionProductFound->setAggregatorType('all');
+$conditionProductFound->setConditions([$conditionProductSku]);
+
+/** @var ConditionInterface $conditionCombine */
+$conditionCombine = $conditionFactory->create();
+$conditionCombine->setConditionType(\Magento\SalesRule\Model\Rule\Condition\Combine::class);
+$conditionCombine->setValue('1');
+$conditionCombine->setAggregatorType('all');
+$conditionCombine->setConditions([$conditionProductFound]);
+
+$salesRule->setCondition($conditionCombine);
+$ruleRepository->save($salesRule);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product_rollback.php
new file mode 100644
index 0000000000000..86ab253f1d3c0
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/restrict_coupon_usage_for_simple_product_rollback.php
@@ -0,0 +1,37 @@
+get(CouponFactory::class);
+/** @var ConditionInterfaceFactory $conditionFactory */
+$conditionFactory = Bootstrap::getObjectManager()->get(ConditionInterfaceFactory::class);
+/** @var RuleRepositoryInterface $ruleRepository */
+$ruleRepository = Bootstrap::getObjectManager()->get(RuleRepositoryInterface::class);
+
+$couponCode = '2?ds5!2d';
+$sku = 'simple_product';
+
+$coupon = $couponFactory->create();
+$coupon->loadByCode($couponCode);
+
+if ($coupon->getId()) {
+ $ruleId = $coupon->getRuleId();
+ $salesRule = $ruleRepository->getById($ruleId);
+
+ /** @var ConditionInterface $conditionCombine */
+ $conditionCombine = $conditionFactory->create();
+ $conditionCombine->setConditions([]);
+
+ $salesRule->setCondition($conditionCombine);
+ $ruleRepository->save($salesRule);
+}
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_new_shipping_address.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_new_shipping_address.php
index e17b9e61f82db..54f4d8d0c6e75 100644
--- a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_new_shipping_address.php
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_new_shipping_address.php
@@ -26,7 +26,7 @@
$quoteAddressData = [
AddressInterface::KEY_TELEPHONE => 3468676,
- AddressInterface::KEY_POSTCODE => 75477,
+ AddressInterface::KEY_POSTCODE => '75477',
AddressInterface::KEY_COUNTRY_ID => 'US',
AddressInterface::KEY_CITY => 'CityM',
AddressInterface::KEY_COMPANY => 'CompanyName',
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_new_shipping_canada_address.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_new_shipping_canada_address.php
new file mode 100644
index 0000000000000..8e60dc904bd4e
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_new_shipping_canada_address.php
@@ -0,0 +1,43 @@
+get(QuoteFactory::class);
+/** @var QuoteResource $quoteResource */
+$quoteResource = Bootstrap::getObjectManager()->get(QuoteResource::class);
+/** @var AddressInterfaceFactory $quoteAddressFactory */
+$quoteAddressFactory = Bootstrap::getObjectManager()->get(AddressInterfaceFactory::class);
+/** @var DataObjectHelper $dataObjectHelper */
+$dataObjectHelper = Bootstrap::getObjectManager()->get(DataObjectHelper::class);
+/** @var ShippingAddressManagementInterface $shippingAddressManagement */
+$shippingAddressManagement = Bootstrap::getObjectManager()->get(ShippingAddressManagementInterface::class);
+
+$quoteAddressData = [
+ AddressInterface::KEY_TELEPHONE => 3468676,
+ AddressInterface::KEY_POSTCODE => 'M4L 1V3',
+ AddressInterface::KEY_COUNTRY_ID => 'CA',
+ AddressInterface::KEY_CITY => 'Toronto',
+ AddressInterface::KEY_COMPANY => 'CompanyName',
+ AddressInterface::KEY_STREET => '500 Kingston Rd',
+ AddressInterface::KEY_LASTNAME => 'Smith',
+ AddressInterface::KEY_FIRSTNAME => 'John',
+ AddressInterface::KEY_REGION_CODE => 'ON',
+];
+$quoteAddress = $quoteAddressFactory->create();
+$dataObjectHelper->populateWithArray($quoteAddress, $quoteAddressData, AddressInterfaceFactory::class);
+
+$quote = $quoteFactory->create();
+$quoteResource->load($quote, 'test_quote', 'reserved_order_id');
+$shippingAddressManagement->assign($quote->getId(), $quoteAddress);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php b/dev/tests/integration/testsuite/Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php
new file mode 100644
index 0000000000000..aca55bd8414f6
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php
@@ -0,0 +1,53 @@
+get(DataObjectHelper::class);
+/** @var RateFactory $rateFactory */
+$rateFactory = $objectManager->get(RateFactory::class);
+/** @var RuleFactory $ruleFactory */
+$ruleFactory = $objectManager->get(RuleFactory::class);
+/** @var RateRepository $rateRepository */
+$rateRepository = $objectManager->get(TaxRateRepositoryInterface::class);
+/** @var TaxRuleRepository $ruleRepository */
+$ruleRepository = $objectManager->get(TaxRuleRepositoryInterface::class);
+/** @var Rate $rate */
+$rate = $rateFactory->create();
+$rateData = [
+ Rate::KEY_COUNTRY_ID => 'US',
+ Rate::KEY_REGION_ID => '1',
+ Rate::KEY_POSTCODE => '*',
+ Rate::KEY_CODE => 'US-TEST-*-Rate-1',
+ Rate::KEY_PERCENTAGE_RATE => '7.5',
+];
+$dataObjectHelper->populateWithArray($rate, $rateData, TaxRateInterface::class);
+$rateRepository->save($rate);
+
+$rule = $ruleFactory->create();
+$ruleData = [
+ Rule::KEY_CODE=> 'GraphQl Test Rule',
+ Rule::KEY_PRIORITY => '0',
+ Rule::KEY_POSITION => '0',
+ Rule::KEY_CUSTOMER_TAX_CLASS_IDS => [3],
+ Rule::KEY_PRODUCT_TAX_CLASS_IDS => [2],
+ Rule::KEY_TAX_RATE_IDS => [$rate->getId()],
+];
+$dataObjectHelper->populateWithArray($rule, $ruleData, TaxRuleInterface::class);
+$ruleRepository->save($rule);
diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Tax/_files/tax_rule_for_region_1_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Tax/_files/tax_rule_for_region_1_rollback.php
new file mode 100644
index 0000000000000..aba1960624ed4
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Tax/_files/tax_rule_for_region_1_rollback.php
@@ -0,0 +1,38 @@
+get(RateFactory::class);
+/** @var RuleFactory $ruleFactory */
+$ruleFactory = $objectManager->get(RuleFactory::class);
+/** @var RateRepository $rateRepository */
+$rateRepository = $objectManager->get(TaxRateRepositoryInterface::class);
+/** @var TaxRuleRepository $ruleRepository */
+$ruleRepository = $objectManager->get(TaxRuleRepositoryInterface::class);
+/** @var RateResource $rateResource */
+$rateResource = $objectManager->get(RateResource::class);
+/** @var RuleResource $ruleResource */
+$ruleResource = $objectManager->get(RuleResource::class);
+
+$rate = $rateFactory->create();
+$rateResource->load($rate, 'US-TEST-*-Rate-1', Rate::KEY_CODE);
+$rule = $ruleFactory->create();
+$ruleResource->load($rule, 'GraphQl Test Rule', Rule::KEY_CODE);
+$ruleRepository->delete($rule);
+$rateRepository->delete($rate);
diff --git a/dev/tests/integration/testsuite/Magento/Ups/_files/enable_ups_shipping_method.php b/dev/tests/integration/testsuite/Magento/GraphQl/Ups/_files/enable_ups_shipping_method.php
similarity index 81%
rename from dev/tests/integration/testsuite/Magento/Ups/_files/enable_ups_shipping_method.php
rename to dev/tests/integration/testsuite/Magento/GraphQl/Ups/_files/enable_ups_shipping_method.php
index 5c6c60866fafb..42931db75a433 100644
--- a/dev/tests/integration/testsuite/Magento/Ups/_files/enable_ups_shipping_method.php
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Ups/_files/enable_ups_shipping_method.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+// TODO: Should be removed in scope of https://github.com/magento/graphql-ce/issues/167
declare(strict_types=1);
use Magento\Framework\App\Config\Storage\Writer;
@@ -15,6 +16,7 @@
$configWriter = $objectManager->get(WriterInterface::class);
$configWriter->save('carriers/ups/active', 1);
+$configWriter->save('carriers/ups/type', "UPS");
$scopeConfig = $objectManager->get(ScopeConfigInterface::class);
$scopeConfig->clean();
diff --git a/dev/tests/integration/testsuite/Magento/Ups/_files/enable_ups_shipping_method_rollback.php b/dev/tests/integration/testsuite/Magento/GraphQl/Ups/_files/enable_ups_shipping_method_rollback.php
similarity index 78%
rename from dev/tests/integration/testsuite/Magento/Ups/_files/enable_ups_shipping_method_rollback.php
rename to dev/tests/integration/testsuite/Magento/GraphQl/Ups/_files/enable_ups_shipping_method_rollback.php
index 6d7894879f97b..cf6dc08dd91a4 100644
--- a/dev/tests/integration/testsuite/Magento/Ups/_files/enable_ups_shipping_method_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/GraphQl/Ups/_files/enable_ups_shipping_method_rollback.php
@@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+// TODO: Should be removed in scope of https://github.com/magento/graphql-ce/issues/167
declare(strict_types=1);
use Magento\Framework\App\Config\Storage\Writer;
@@ -14,3 +15,4 @@
$configWriter = $objectManager->create(WriterInterface::class);
$configWriter->delete('carriers/ups/active');
+$configWriter->delete('carriers/ups/type');
diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Processor.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Processor.php
deleted file mode 100644
index 3b2a76104a2cd..0000000000000
--- a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Processor.php
+++ /dev/null
@@ -1,28 +0,0 @@
-getEntityId()}\n";
- }
-
- /**
- * @param \Magento\MysqlMq\Model\DataObject $message
- */
- public function processMessageWithException($message)
- {
- throw new \LogicException("Exception during message processing happened. Entity: {{$message->getEntityId()}}");
- }
-}
diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/PublisherConsumerTest.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/PublisherConsumerTest.php
index f03d03d3a25fd..f911165bd27fb 100644
--- a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/PublisherConsumerTest.php
+++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/PublisherConsumerTest.php
@@ -3,87 +3,45 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\MysqlMq\Model;
-use Magento\Framework\MessageQueue\PublisherInterface;
+use Magento\Framework\MessageQueue\UseCase\QueueTestCaseAbstract;
+use Magento\MysqlMq\Model\ResourceModel\MessageCollection;
+use Magento\MysqlMq\Model\ResourceModel\MessageStatusCollection;
/**
* Test for MySQL publisher class.
*
* @magentoDbIsolation disabled
*/
-class PublisherConsumerTest extends \PHPUnit\Framework\TestCase
+class PublisherConsumerTest extends QueueTestCaseAbstract
{
const MAX_NUMBER_OF_TRIALS = 3;
/**
- * @var \Magento\Framework\MessageQueue\PublisherInterface
+ * @var string[]
*/
- protected $publisher;
-
- /**
- * @var \Magento\Framework\ObjectManagerInterface
- */
- protected $objectManager;
-
- protected function setUp()
- {
- $this->markTestIncomplete('Should be converted to queue config v2.');
- $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-
- $configPath = __DIR__ . '/../etc/queue.xml';
- $fileResolverMock = $this->createMock(\Magento\Framework\Config\FileResolverInterface::class);
- $fileResolverMock->expects($this->any())
- ->method('get')
- ->willReturn([$configPath => file_get_contents(($configPath))]);
-
- /** @var \Magento\Framework\MessageQueue\Config\Reader\Xml $xmlReader */
- $xmlReader = $this->objectManager->create(
- \Magento\Framework\MessageQueue\Config\Reader\Xml::class,
- ['fileResolver' => $fileResolverMock]
- );
-
- $newData = $xmlReader->read();
-
- /** @var \Magento\Framework\MessageQueue\Config\Data $configData */
- $configData = $this->objectManager->get(\Magento\Framework\MessageQueue\Config\Data::class);
- $configData->reset();
- $configData->merge($newData);
-
- $this->publisher = $this->objectManager->create(\Magento\Framework\MessageQueue\PublisherInterface::class);
- }
-
- protected function tearDown()
- {
- $this->markTestIncomplete('Should be converted to queue config v2.');
- $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX);
- $this->consumeMessages('demoConsumerQueueTwo', PHP_INT_MAX);
- $this->consumeMessages('demoConsumerQueueThree', PHP_INT_MAX);
- $this->consumeMessages('demoConsumerQueueFour', PHP_INT_MAX);
- $this->consumeMessages('demoConsumerQueueFive', PHP_INT_MAX);
- $this->consumeMessages('demoConsumerQueueOneWithException', PHP_INT_MAX);
-
- $objectManagerConfiguration = [\Magento\Framework\MessageQueue\Config\Reader\Xml::class => [
- 'arguments' => [
- 'fileResolver' => ['instance' => \Magento\Framework\Config\FileResolverInterface::class],
- ],
- ],
- ];
- $this->objectManager->configure($objectManagerConfiguration);
- /** @var \Magento\Framework\MessageQueue\Config\Data $queueConfig */
- $queueConfig = $this->objectManager->get(\Magento\Framework\MessageQueue\Config\Data::class);
- $queueConfig->reset();
- }
+ protected $consumers = [
+ 'demoConsumerQueueOne',
+ 'demoConsumerQueueTwo',
+ 'demoConsumerQueueThree',
+ 'delayedOperationConsumer',
+ 'demoConsumerWithException'
+ ];
/**
* @magentoDataFixture Magento/MysqlMq/_files/queues.php
*/
public function testPublishConsumeFlow()
{
- /** @var \Magento\MysqlMq\Model\DataObjectFactory $objectFactory */
- $objectFactory = $this->objectManager->create(\Magento\MysqlMq\Model\DataObjectFactory::class);
- /** @var \Magento\MysqlMq\Model\DataObject $object */
+ /** @var \Magento\TestModuleMysqlMq\Model\DataObjectFactory $objectFactory */
+ $objectFactory = $this->objectManager->create(\Magento\TestModuleMysqlMq\Model\DataObjectFactory::class);
+ /** @var \Magento\TestModuleMysqlMq\Model\DataObject $object */
$object = $objectFactory->create();
+ $object->setOutputPath($this->logFilePath);
+ file_put_contents($this->logFilePath, '');
for ($i = 0; $i < 10; $i++) {
$object->setName('Object name ' . $i)->setEntityId($i);
$this->publisher->publish('demo.object.created', $object);
@@ -96,105 +54,87 @@ public function testPublishConsumeFlow()
$object->setName('Object name ' . $i)->setEntityId($i);
$this->publisher->publish('demo.object.custom.created', $object);
}
-
- $outputPattern = '/(Processed \d+\s)/';
- /** There are total of 10 messages in the first queue, total expected consumption is 7, 3 then 0 */
- $this->consumeMessages('demoConsumerQueueOne', 7, 7, $outputPattern);
- /** Consumer all messages which left in this queue */
- $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX, 3, $outputPattern);
- $this->consumeMessages('demoConsumerQueueOne', 7, 0, $outputPattern);
-
- /** Verify that messages were added correctly to second queue for update and create topics */
- $this->consumeMessages('demoConsumerQueueTwo', 20, 15, $outputPattern);
-
- /** Verify that messages were NOT added to fourth queue */
- $this->consumeMessages('demoConsumerQueueFour', 11, 0, $outputPattern);
-
- /** Verify that messages were added correctly by '*' pattern in bind config to third queue */
- $this->consumeMessages('demoConsumerQueueThree', 20, 15, $outputPattern);
-
- /** Verify that messages were added correctly by '#' pattern in bind config to fifth queue */
- $this->consumeMessages('demoConsumerQueueFive', 20, 18, $outputPattern);
+ $this->waitForAsynchronousResult(18, $this->logFilePath);
+
+ //Check lines in file
+ $createdPattern = '/Processed object created \d+/';
+ $updatedPattern = '/Processed object updated \d+/';
+ $customCreatedPattern = '/Processed custom object created \d+/';
+ $logFileContents = file_get_contents($this->logFilePath);
+
+ preg_match_all($createdPattern, $logFileContents, $createdMatches);
+ $this->assertEquals(10, count($createdMatches[0]));
+ preg_match_all($updatedPattern, $logFileContents, $updatedMatches);
+ $this->assertEquals(5, count($updatedMatches[0]));
+ preg_match_all($customCreatedPattern, $logFileContents, $customCreatedMatches);
+ $this->assertEquals(3, count($customCreatedMatches[0]));
}
/**
* @magentoDataFixture Magento/MysqlMq/_files/queues.php
*/
- public function testPublishAndConsumeWithFailedJobs()
+ public function testPublishAndConsumeSchemaDefinedByMethod()
{
- /** @var \Magento\MysqlMq\Model\DataObjectFactory $objectFactory */
- $objectFactory = $this->objectManager->create(\Magento\MysqlMq\Model\DataObjectFactory::class);
- /** @var \Magento\MysqlMq\Model\DataObject $object */
- /** Try consume messages for MAX_NUMBER_OF_TRIALS and then consumer them without exception */
+ $topic = 'test.schema.defined.by.method';
+ /** @var \Magento\TestModuleMysqlMq\Model\DataObjectFactory $objectFactory */
+ $objectFactory = $this->objectManager->create(\Magento\TestModuleMysqlMq\Model\DataObjectFactory::class);
+ /** @var \Magento\TestModuleMysqlMq\Model\DataObject $object */
$object = $objectFactory->create();
- for ($i = 0; $i < 5; $i++) {
- $object->setName('Object name ' . $i)->setEntityId($i);
- $this->publisher->publish('demo.object.created', $object);
- }
- $outputPattern = '/(Processed \d+\s)/';
- for ($i = 0; $i < self::MAX_NUMBER_OF_TRIALS; $i++) {
- $this->consumeMessages('demoConsumerQueueOneWithException', PHP_INT_MAX, 0, $outputPattern);
- }
- $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX, 0, $outputPattern);
+ $id = 33;
+ $object->setName('Object name ' . $id)->setEntityId($id);
+ $object->setOutputPath($this->logFilePath);
+ $requiredStringParam = 'Required value';
+ $optionalIntParam = 44;
+ $this->publisher->publish($topic, [$object, $requiredStringParam, $optionalIntParam]);
- /** Try consume messages for MAX_NUMBER_OF_TRIALS+1 and then consumer them without exception */
- for ($i = 0; $i < 5; $i++) {
- $object->setName('Object name ' . $i)->setEntityId($i);
- $this->publisher->publish('demo.object.created', $object);
- }
- /** Try consume messages for MAX_NUMBER_OF_TRIALS and then consumer them without exception */
- for ($i = 0; $i < self::MAX_NUMBER_OF_TRIALS + 1; $i++) {
- $this->consumeMessages('demoConsumerQueueOneWithException', PHP_INT_MAX, 0, $outputPattern);
- }
- /** Make sure that messages are not accessible anymore after number of trials is exceeded */
- $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX, 0, $outputPattern);
+ $expectedOutput = "Processed '{$object->getEntityId()}'; "
+ . "Required param '{$requiredStringParam}'; Optional param '{$optionalIntParam}'";
+
+ $this->waitForAsynchronousResult(1, $this->logFilePath);
+
+ $this->assertEquals($expectedOutput, trim(file_get_contents($this->logFilePath)));
}
/**
* @magentoDataFixture Magento/MysqlMq/_files/queues.php
*/
- public function testPublishAndConsumeSchemaDefinedByMethod()
+ public function testConsumeWithException()
{
- /** @var \Magento\MysqlMq\Model\DataObjectFactory $objectFactory */
- $objectFactory = $this->objectManager->create(\Magento\MysqlMq\Model\DataObjectFactory::class);
- /** @var \Magento\MysqlMq\Model\DataObject $object */
+ $topic = 'demo.exception';
+ /** @var \Magento\TestModuleMysqlMq\Model\DataObjectFactory $objectFactory */
+ $objectFactory = $this->objectManager->create(\Magento\TestModuleMysqlMq\Model\DataObjectFactory::class);
+ /** @var \Magento\TestModuleMysqlMq\Model\DataObject $object */
$object = $objectFactory->create();
- $id = 33;
+ $id = 99;
+
$object->setName('Object name ' . $id)->setEntityId($id);
- $requiredStringParam = 'Required value';
- $optionalIntParam = 44;
- $this->publisher->publish('test.schema.defined.by.method', [$object, $requiredStringParam, $optionalIntParam]);
- $outputPattern = "/Processed '{$object->getEntityId()}'; "
- . "Required param '{$requiredStringParam}'; Optional param '{$optionalIntParam}'/";
- $this->consumeMessages('delayedOperationConsumer', PHP_INT_MAX, 1, $outputPattern);
+ $object->setOutputPath($this->logFilePath);
+ $this->publisher->publish($topic, $object);
+ $expectedOutput = "Exception processing {$id}";
+ $this->waitForAsynchronousResult(1, $this->logFilePath);
+ $message = $this->getTopicLatestMessage($topic);
+ $this->assertEquals($expectedOutput, trim(file_get_contents($this->logFilePath)));
+ $this->assertEquals(QueueManagement::MESSAGE_STATUS_ERROR, $message->getStatus());
}
/**
- * Make sure that consumers consume correct number of messages.
- *
- * @param string $consumerName
- * @param int|null $messagesToProcess
- * @param int|null $expectedNumberOfProcessedMessages
- * @param string|null $outputPattern
+ * @param string $topic
+ * @return Message
*/
- protected function consumeMessages(
- $consumerName,
- $messagesToProcess,
- $expectedNumberOfProcessedMessages = null,
- $outputPattern = null
- ) {
- /** @var \Magento\Framework\MessageQueue\ConsumerFactory $consumerFactory */
- $consumerFactory = $this->objectManager->create(\Magento\Framework\MessageQueue\ConsumerFactory::class);
- $consumer = $consumerFactory->get($consumerName);
- ob_start();
- $consumer->process($messagesToProcess);
- $consumersOutput = ob_get_contents();
- ob_end_clean();
- if ($outputPattern) {
- $this->assertEquals(
- $expectedNumberOfProcessedMessages,
- preg_match_all($outputPattern, $consumersOutput)
- );
- }
+ private function getTopicLatestMessage(string $topic) : Message
+ {
+ // Assert message status is error
+ $messageCollection = $this->objectManager->create(MessageCollection::class);
+ $messageStatusCollection = $this->objectManager->create(MessageStatusCollection::class);
+
+ $messageCollection->addFilter('topic_name', $topic);
+ $messageCollection->join(
+ ['status' => $messageStatusCollection->getMainTable()],
+ "status.message_id = main_table.id"
+ );
+ $messageCollection->addOrder('updated_at', MessageCollection::SORT_ORDER_DESC);
+
+ $message = $messageCollection->getFirstItem();
+ return $message;
}
}
diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/QueueManagementTest.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/QueueManagementTest.php
index 197df29233297..56dd77d3da17c 100644
--- a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/QueueManagementTest.php
+++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/QueueManagementTest.php
@@ -5,8 +5,6 @@
*/
namespace Magento\MysqlMq\Model;
-use Magento\MysqlMq\Model\QueueManagement;
-
/**
* Test for Queue Management class.
*/
diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/etc/queue.xml b/dev/tests/integration/testsuite/Magento/MysqlMq/etc/queue.xml
deleted file mode 100644
index fd618d504df07..0000000000000
--- a/dev/tests/integration/testsuite/Magento/MysqlMq/etc/queue.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/dev/tests/integration/testsuite/Magento/NewRelicReporting/Model/Module/CollectTest.php b/dev/tests/integration/testsuite/Magento/NewRelicReporting/Model/Module/CollectTest.php
new file mode 100644
index 0000000000000..5e5051163cc1f
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/NewRelicReporting/Model/Module/CollectTest.php
@@ -0,0 +1,38 @@
+collect = Bootstrap::getObjectManager()->create(Collect::class);
+ }
+
+ /**
+ * @return void
+ */
+ public function testReport()
+ {
+ $this->collect->getModuleData();
+ $moduleData = $this->collect->getModuleData();
+ $this->assertEmpty($moduleData['changes']);
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Controller/Transparent/ResponseTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Transparent/ResponseTest.php
new file mode 100644
index 0000000000000..17464b6d65861
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Transparent/ResponseTest.php
@@ -0,0 +1,134 @@
+ $paypalExpDate,
+ 'AMT' => '0.00',
+ 'RESPMSG' => 'Verified',
+ 'CVV2MATCH' => 'Y',
+ 'PNREF' => 'A10AAD866C87',
+ 'SECURETOKEN' => '3HYEHfG06skydAdBXbpIl8QJZ',
+ 'AVSDATA' => 'YNY',
+ 'RESULT' => '0',
+ 'IAVS' => 'N',
+ 'AVSADDR' => 'Y',
+ 'SECURETOKENID' => 'yqanLisRZbI0HAG8q3SbbKbhiwjNZAGf',
+ ];
+
+ $quote = $this->getQuote($reservedOrderId);
+ $this->getRequest()->setPostValue($postData);
+
+ /** @var Session $checkoutSession */
+ $checkoutSession = $this->_objectManager->get(GenericSession::class);
+ $checkoutSession->setQuoteId($quote->getId());
+ $this->setCurrentDateTime($currentDateTime);
+
+ $this->dispatch('paypal/transparent/response');
+
+ /** @var PaymentMethodManagementInterface $paymentManagment */
+ $paymentManagment = $this->_objectManager->get(PaymentMethodManagementInterface::class);
+ $payment = $paymentManagment->get($quote->getId());
+
+ $this->assertEquals($expectedCcMonth, $payment->getCcExpMonth());
+ $this->assertEquals($expectedCcYear, $payment->getCcExpYear());
+ }
+
+ /**
+ * @return array
+ */
+ public function paymentCcExpirationDateDataProvider(): array
+ {
+ return [
+ 'Expiration year in current century' => [
+ 'currentDateTime' => '2019-07-05 00:00:00',
+ 'paypalExpDate' => '0321',
+ 'expectedCcMonth' => 3,
+ 'expectedCcYear' => 2021
+ ],
+ 'Expiration year in next century' => [
+ 'currentDateTime' => '2099-01-01 00:00:00',
+ 'paypalExpDate' => '1002',
+ 'expectedCcMonth' => 10,
+ 'expectedCcYear' => 2102
+ ]
+ ];
+ }
+
+ /**
+ * Sets current date and time.
+ *
+ * @param string $date
+ */
+ private function setCurrentDateTime(string $dateTime): void
+ {
+ $dateTime = new \DateTime($dateTime, new \DateTimeZone('UTC'));
+ $dateTimeFactory = $this->getMockBuilder(DateTimeFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $dateTimeFactory->method('create')
+ ->willReturn($dateTime);
+
+ $this->_objectManager->addSharedInstance($dateTimeFactory, DateTimeFactory::class);
+ }
+
+ /**
+ * Gets quote by reserved order ID.
+ *
+ * @param string $reservedOrderId
+ * @return CartInterface
+ */
+ private function getQuote(string $reservedOrderId): CartInterface
+ {
+ $searchCriteria = $this->_objectManager->get(SearchCriteriaBuilder::class)
+ ->addFilter('reserved_order_id', $reservedOrderId)
+ ->create();
+
+ /** @var CartRepositoryInterface $quoteRepository */
+ $quoteRepository = $this->_objectManager->get(CartRepositoryInterface::class);
+ $items = $quoteRepository->getList($searchCriteria)
+ ->getItems();
+
+ return array_pop($items);
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ReaderTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ReaderTest.php
deleted file mode 100644
index 6b966a045c982..0000000000000
--- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/ReaderTest.php
+++ /dev/null
@@ -1,135 +0,0 @@
-objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
- $this->fileUtility = \Magento\Framework\App\Utility\Files::init();
-
- $this->validationStateMock = $this->getMockBuilder(\Magento\Framework\Config\ValidationStateInterface::class)
- ->setMethods(['isValidationRequired'])
- ->getMockForAbstractClass();
- $this->schemaLocatorMock = $this->getMockBuilder(\Magento\Config\Model\Config\SchemaLocator::class)
- ->disableOriginalConstructor()
- ->setMethods(['getPerFileSchema'])
- ->getMock();
- $this->fileResolverMock = $this->getMockBuilder(\Magento\Framework\Config\FileResolverInterface::class)
- ->getMockForAbstractClass();
-
- $this->validationStateMock->expects($this->atLeastOnce())
- ->method('isValidationRequired')
- ->willReturn(false);
- $this->schemaLocatorMock->expects($this->atLeastOnce())
- ->method('getPerFileSchema')
- ->willReturn(false);
-
- /** @var \Magento\Paypal\Model\Config\Structure\Reader\ConverterStub $converter */
- $this->converter = $this->objectManager->create(
- \Magento\Paypal\Model\Config\Structure\Reader\ConverterStub::class
- );
-
- $this->reader = $this->objectManager->create(
- \Magento\Paypal\Model\Config\Structure\Reader\ReaderStub::class,
- [
- 'fileResolver' => $this->fileResolverMock,
- 'converter' => $this->converter,
- 'schemaLocator' => $this->schemaLocatorMock,
- 'validationState' => $this->validationStateMock,
- 'fileName' => 'no_existing_file.xml',
- 'domDocumentClass' => \Magento\Framework\Config\Dom::class
- ]
- );
- }
-
- /**
- * The test checks the file structure after processing the nodes responsible for inserting content
- *
- * @return void
- */
- public function testXmlConvertedConfigurationAndCompereStructure()
- {
- $actual = $this->reader->readFiles(['actual' => $this->getActualContent()]);
-
- $document = new \DOMDocument();
- $document->loadXML($this->getExpectedContent());
-
- $expected = $this->converter->getArrayData($document);
-
- $this->assertEquals($expected, $actual);
- }
-
- /**
- * @return string
- */
- protected function getActualContent()
- {
- $files = $this->fileUtility->getFiles([BP . static::ACTUAL], 'config.xml');
-
- return file_get_contents(reset($files));
- }
-
- /**
- * @return string
- */
- protected function getExpectedContent()
- {
- $files = $this->fileUtility->getFiles([BP . static::EXPECTED], 'config.xml');
-
- return file_get_contents(reset($files));
- }
-}
diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml b/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
deleted file mode 100644
index 222b9974177de..0000000000000
--- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Config/Structure/Reader/_files/expected/config.xml
+++ /dev/null
@@ -1,2626 +0,0 @@
-
-
-
-
-
-
- Merchant Location
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Merchant Country
- If not specified, Default Country from General Config will be used
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Country
- Magento\Paypal\Model\System\Config\Source\MerchantCountry
- Magento\Paypal\Model\System\Config\Backend\MerchantCountry
- paypal/general/merchant_country
-
-
-
- Recommended Solutions:
- paypal-top-section paypal-recommended-header
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
-
- Other PayPal Payment Solutions:
- paypal-top-section paypal-other-header
- \Magento\Config\Block\System\Config\Form\Fieldset
-
-
- Other Payment Methods:
- paypal-top-section payments-other-header
- \Magento\Config\Block\System\Config\Form\Fieldset
-
-
-
-
- Payflow Pro
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- paypal-other-section
- Includes Express Checkout)]]>
- payment/payflowpro/active
- 1
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payflow-pro.html
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Hint
-
-
- Required PayPal Settings
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Payflow Pro
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Partner
- payment/payflowpro/partner
- 1
-
-
- User
- payment/payflowpro/user
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Vendor
- payment/payflowpro/vendor
- 1
-
-
- Password
- payment/payflowpro/pwd
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Test Mode
- payment/payflowpro/sandbox_flag
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Use Proxy
- payment/payflowpro/use_proxy
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Proxy Host
- payment/payflowpro/proxy_host
-
- 1
-
- 1
-
-
- Proxy Port
- payment/payflowpro/proxy_port
-
- 1
-
- 1
-
-
-
- Enable this Solution
- payment/payflowpro/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Payment
-
-
-
-
-
- Vault Enabled
- Magento\Config\Model\Config\Source\Yesno
- payment/payflowpro_cc_vault/active
- 1
-
-
-
-
-
-
- Basic Settings - PayPal Payflow Pro
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Title
- It is recommended to set this value to "Debit or Credit Card" per store views.
- payment/payflowpro/title
- 1
-
-
- Vault Title
- payment/payflowpro_cc_vault/title
-
-
- Sort Order
- payment/payflowpro/sort_order
- validate-number
- 1
-
-
- Payment Action
- payment/payflowpro/payment_action
- Magento\Paypal\Model\System\Config\Source\PaymentActions
- 1
-
-
- Credit Card Settings
- Magento\Config\Block\System\Config\Form\Field\Heading
- 1
-
-
- Allowed Credit Card Types
-
- http://www.paypal.com/amexupdate .]]>
-
- payment/payflowpro/cctypes
- Magento\Paypal\Model\Config::getPayflowproCcTypesAsOptionArray
- 1
-
-
- Advanced Settings
- config-advanced
-
- Payment Applicable From
- payment/payflowpro/allowspecific
- Magento\Payment\Model\Config\Source\Allspecificcountries
- 1
-
-
- Countries Payment Applicable From
- payment/payflowpro/specificcountry
- Magento\Paypal\Model\System\Config\Source\BuyerCountry
-
- 1
-
- 1
-
-
- Debug Mode
- payment/payflowpro/debug
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Enable SSL verification
- payment/payflowpro/verify_peer
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Require CVV Entry
- payment/payflowpro/useccv
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- CVV and AVS Settings
-
- Reject Transaction if:
- Magento\Config\Block\System\Config\Form\Field\Heading
- 1
-
-
- AVS Street Does Not Match
- payment/payflowpro/avs_street
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- AVS Zip Does Not Match
- payment/payflowpro/avs_zip
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Card Issuer Is Outside The United States
- payment/payflowpro/avs_international
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Card Security Code Does Not Match
- payment/payflowpro/avs_security_code
- Magento\Config\Model\Config\Source\Yesno
- 0
-
-
-
- Settlement Report Settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Payflow Link
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- paypal-other-section
- Includes Express Checkout)]]>
- payment/payflow_link/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payflow-link.html
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Hint
-
-
- Required PayPal Settings
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Payflow Link and Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- not-required
- Email Associated with PayPal Merchant Account (Optional)
- 1
-
-
- Partner
- payment/payflow_link/partner
- 1
-
-
- Vendor
- payment/payflow_link/vendor
- 1
-
-
- User
- If you do not have multiple users set up on your account, please re-enter your Vendor/Merchant Login here.
- payment/payflow_link/user
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Password
- payment/payflow_link/pwd
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Test Mode
- payment/payflow_link/sandbox_flag
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Use Proxy
- payment/payflow_link/use_proxy
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Proxy Host
- payment/payflow_link/proxy_host
-
- 1
-
- 1
-
-
- Proxy Port
- payment/payflow_link/proxy_port
-
- 1
-
- 1
-
-
- Magento\Paypal\Block\Adminhtml\System\Config\Payflowlink\Info
- 1
-
-
-
-
-
-
- Enable Payflow Link
- payment/payflow_link/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Payment
-
-
-
-
-
- Enable Express Checkout
- payment/payflow_express/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Express
-
-
-
-
-
-
-
- Learn More]]>
-
- payment/payflow_express_bml/active
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Bml
-
-
-
-
-
- payment/payflow_express_bml/sort_order
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Depends\BmlSortOrder
-
- 1
-
-
-
-
-
-
- Advertise PayPal Credit
-
- Why Advertise Financing?
- Give your sales a boost when you advertise financing. PayPal helps turn browsers into buyers with financing
- from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you.
- Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal.
- The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15%
- or more. See Details .]]>
-
-
-
-
- Home Page
-
-
-
- Size
- payment/paypal_express_bml/homepage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPH
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPS
-
- 1
-
-
-
-
- Catalog Category Page
-
-
-
- Size
- payment/paypal_express_bml/categorypage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPS
-
- 1
-
-
-
-
- Catalog Product Page
-
-
-
- Size
- payment/paypal_express_bml/productpage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPN
-
- 1
-
-
-
-
- Checkout Cart Page
-
-
-
- Size
- payment/paypal_express_bml/checkout_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutN
- 1
-
- 1
-
-
-
-
-
-
- Basic Settings - PayPal Payflow Link
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Title
- It is recommended to set this value to "Debit or Credit Card" per store views.
- payment/payflow_link/title
- 1
-
-
- Sort Order
- payment/payflow_link/sort_order
- validate-number
- 1
-
-
- Payment Action
- payment/payflow_link/payment_action
- Magento\Paypal\Model\System\Config\Source\PaymentActions
- 1
-
-
- Advanced Settings
- config-advanced
-
- Payment Applicable From
- payment/payflow_link/allowspecific
- Magento\Payment\Model\Config\Source\Allspecificcountries
- 1
-
-
- Countries Payment Applicable From
- payment/payflow_link/specificcountry
- Magento\Paypal\Model\System\Config\Source\BuyerCountry
-
- 1
-
- 1
-
-
- Debug Mode
- payment/payflow_link/debug
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Enable SSL verification
- payment/payflow_link/verify_peer
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- CVV Entry is Editable
- payment/payflow_link/csc_editable
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Require CVV Entry
- payment/payflow_link/csc_required
- Magento\Config\Model\Config\Source\Yesno
-
- 1
-
- 1
-
-
- Send Email Confirmation
- payment/payflow_link/email_confirmation
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- URL method for Cancel URL and Return URL
- payment/payflow_link/url_method
- Magento\Paypal\Model\System\Config\Source\UrlMethod
- 1
-
-
- Settlement Report Settings
-
-
-
-
-
-
-
-
-
-
-
-
- Frontend Experience Settings
-
-
-
-
-
-
-
-
-
-
-
- Basic Settings - PayPal Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
-
-
-
-
-
-
-
- Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- paypal-other-section
- Add PayPal as an additional payment method to your checkout page.
- payment/paypal_express/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-express-checkout.html
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Hint
-
-
- Required PayPal Settings
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Email Associated with PayPal Merchant Account (Optional)
- not-required
-
- Start accepting payments via PayPal!]]>
-
- Don't have a PayPal account? Simply enter your email address.
- paypal/general/business_account
- validate-email
- 1
-
-
- API Authentication Methods
- paypal/wpp/api_authentication
- Magento\Paypal\Model\Config::getApiAuthenticationMethods
- 1
-
-
- API Username
- paypal/wpp/api_username
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- API Password
- paypal/wpp/api_password
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- API Signature
- paypal/wpp/api_signature
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
- 0
-
-
-
- API Certificate
- paypal/wpp/api_cert
- Magento\Paypal\Model\System\Config\Backend\Cert
- 1
-
- 1
-
-
-
-
- Get Credentials from PayPal
-
-
-
-
- Sandbox Credentials
-
-
-
-
-
- NB9WWHYEMVUMS
-
- Magento_Backend/web/images/logo-magento.png
-
- FALSE
-
- FALSE
-
- embedded
-
- pp_express
-
- Magento\Paypal\Block\Adminhtml\System\Config\ApiWizard
- 1
-
-
- Sandbox Mode
- paypal/wpp/sandbox_flag
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- API Uses Proxy
- paypal/wpp/use_proxy
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Proxy Host
- paypal/wpp/proxy_host
- 1
-
- 1
-
-
-
- Proxy Port
- paypal/wpp/proxy_port
- 1
-
- 1
-
-
-
-
- Enable this Solution
- payment/paypal_express/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Payment
-
-
-
-
-
- Enable In-Context Checkout Experience
-
- here.]]>
-
- payment/paypal_express/in_context
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\InContextApi
-
-
-
-
-
- Merchant Account ID
- You can look up your merchant ID by logging into https://www.paypal.com/. Click the profile icon on the top right side of the page and then select Profile and settings in the Business Profile menu. (If you do not see the profile icon at the top of the page, click Profile, which appears in the top menu when the My Account tab is selected.) Click My business info on the left, and the Merchant account ID is displayed in the list of profile items on the right.
- payment/paypal_express/merchant_id
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Depends\MerchantId
-
- 1
-
- required-entry
-
-
- Enable PayPal Credit
- Learn More]]>
-
- payment/paypal_express_bml/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\BmlApi
-
-
-
-
-
- Sort Order PayPal Credit
- payment/paypal_express_bml/sort_order
- validate-number
- 1
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Depends\BmlApiSortOrder
-
- 1
-
-
-
- Advertise PayPal Credit
-
- Why Advertise Financing?
- Give your sales a boost when you advertise financing. PayPal helps turn browsers into buyers with financing
- from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you.
- Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal.
- The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15%
- or more. See Details .]]>
-
-
- Publisher ID
-
- payment/paypal_express_bml/publisher_id
- 1
-
-
- Get Publisher ID from PayPal
-
- Magento\Paypal\Block\Adminhtml\System\Config\BmlApiWizard
-
-
- Home Page
-
- Display
- payment/paypal_express_bml/homepage_display
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Position
- payment/paypal_express_bml/homepage_position
- Magento\Paypal\Model\System\Config\Source\BmlPosition::getBmlPositionsHP
- 1
-
-
- Size
- payment/paypal_express_bml/homepage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPH
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPS
-
- 1
-
-
-
-
- Catalog Category Page
-
- Display
- payment/paypal_express_bml/categorypage_display
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Position
- payment/paypal_express_bml/categorypage_position
- Magento\Paypal\Model\System\Config\Source\BmlPosition::getBmlPositionsCCP
- 1
-
-
- Size
- payment/paypal_express_bml/categorypage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPC
- 1
- 0
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPS
- 1
-
-
-
- Catalog Product Page
-
- Display
- payment/paypal_express_bml/productpage_display
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Position
- payment/paypal_express_bml/productpage_position
- Magento\Paypal\Model\System\Config\Source\BmlPosition::getBmlPositionsCPP
- 1
-
-
- Size
- payment/paypal_express_bml/productpage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPC
- 1
- 0
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPN
- 1
-
-
-
- Checkout Cart Page
-
- Display
- payment/paypal_express_bml/checkout_display
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Position
- payment/paypal_express_bml/checkout_position
- Magento\Paypal\Model\System\Config\Source\BmlPosition::getBmlPositionsCheckout
- 1
-
-
- Size
- payment/paypal_express_bml/checkout_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutC
- 1
- 0
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutN
- 1
- 1
-
-
-
-
-
- Basic Settings - PayPal Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Title
- It is recommended to set this value to "PayPal" per store views.
- payment/paypal_express/title
- 1
-
-
- Sort Order
- payment/paypal_express/sort_order
- validate-number
- 1
-
-
- Payment Action
- payment/paypal_express/payment_action
- Magento\Paypal\Model\System\Config\Source\PaymentActions\Express
- 1
-
-
- Display on Product Details Page
- payment/paypal_express/visible_on_product
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Authorization Honor Period (days)
- Specifies what the Authorization Honor Period is on the merchant’s PayPal account. It must mirror the setting in PayPal.
- payment/paypal_express/authorization_honor_period
- 1
-
- Order
-
-
-
- Order Valid Period (days)
- Specifies what the Order Valid Period is on the merchant’s PayPal account. It must mirror the setting in PayPal.
- payment/paypal_express/order_valid_period
- 1
-
- Order
-
-
-
- Number of Child Authorizations
- The default number of child authorizations in your PayPal account is 1. To do multiple authorizations please contact PayPal to request an increase.
- payment/paypal_express/child_authorization_number
- 1
-
- Order
-
-
-
- Advanced Settings
- config-advanced
-
- Display on Shopping Cart
- payment/paypal_express/visible_on_cart
- Also affects mini-shopping cart.
- Magento\Paypal\Model\System\Config\Source\Yesnoshortcut
- 1
-
-
- Payment Applicable From
- payment/paypal_express/allowspecific
- Magento\Payment\Model\Config\Source\Allspecificcountries
- 1
-
-
- Countries Payment Applicable From
- payment/paypal_express/specificcountry
- Magento\Paypal\Model\System\Config\Source\BuyerCountry
- 1
-
- 1
-
-
-
- Debug Mode
- payment/paypal_express/debug
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Enable SSL verification
- payment/paypal_express/verify_peer
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Transfer Cart Line Items
- payment/paypal_express/line_items_enabled
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Transfer Shipping Options
- payment/paypal_express/transfer_shipping_options
- If this option is enabled, customer can change shipping address and shipping method on PayPal website. In live mode works via HTTPS protocol only.
- Notice that PayPal can handle up to 10 shipping options. That is why Magento will transfer only first 10 cheapest shipping options if there are more than 10 available.
- Magento\Config\Model\Config\Source\Yesno
- 1
-
- 1
-
-
-
- Shortcut Buttons Flavor
- paypal/wpp/button_flavor
- Magento\Paypal\Model\Config::getExpressCheckoutButtonFlavors
- 1
-
-
- Enable PayPal Guest Checkout
- Ability for buyer to purchase without PayPal account.
- payment/paypal_express/solution_type
- Magento\Paypal\Model\Config::getExpressCheckoutSolutionTypes
- 1
-
-
- Require Customer's Billing Address
- This feature needs be enabled first for the merchant account through PayPal technical support.
- payment/paypal_express/require_billing_address
- Magento\Paypal\Model\System\Config\Source\RequireBillingAddress
- 1
-
-
- Billing Agreement Signup
- Whether to create a billing agreement, if there are no active billing agreements available.
-
-
-
- payment/paypal_express/allow_ba_signup
- Magento\Paypal\Model\Config::getExpressCheckoutBASignupOptions
- 1
-
-
- Skip Order Review Step
- payment/paypal_express/skip_order_review_step
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- PayPal Billing Agreement Settings
-
- Enabled
-
-
-
- payment/paypal_billing_agreement/active
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Title
- payment/paypal_billing_agreement/title
- 1
-
-
- Sort Order
- payment/paypal_billing_agreement/sort_order
- validate-number
- 1
-
-
- Payment Action
- payment/paypal_billing_agreement/payment_action
- Magento\Paypal\Model\System\Config\Source\PaymentActions
- 1
-
-
- Payment Applicable From
- payment/paypal_billing_agreement/allowspecific
- Magento\Payment\Model\Config\Source\Allspecificcountries
- 1
-
-
- Countries Payment Applicable From
- payment/paypal_billing_agreement/specificcountry
- Magento\Paypal\Model\System\Config\Source\BuyerCountry
- 1
-
- 1
-
-
-
- Debug Mode
- payment/paypal_billing_agreement/debug
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Enable SSL verification
- payment/paypal_billing_agreement/verify_peer
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Transfer Cart Line Items
- payment/paypal_billing_agreement/line_items_enabled
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Allow in Billing Agreement Wizard
- payment/paypal_billing_agreement/allow_billing_agreement_wizard
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
-
- Settlement Report Settings
-
- SFTP Credentials
- Magento\Config\Block\System\Config\Form\Field\Heading
- 1
-
-
- Login
- paypal/fetch_reports/ftp_login
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Password
- paypal/fetch_reports/ftp_password
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Sandbox Mode
- paypal/fetch_reports/ftp_sandbox
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Custom Endpoint Hostname or IP-Address
- By default it is "reports.paypal.com".
- Use colon to specify port. For example: "test.example.com:5224".
- paypal/fetch_reports/ftp_ip
- 1
-
- 0
-
-
-
- Custom Path
- By default it is "/ppreports/outgoing".
- paypal/fetch_reports/ftp_path
- 1
-
- 0
-
-
-
- Scheduled Fetching
- Magento\Config\Block\System\Config\Form\Field\Heading
- 1
-
-
- Enable Automatic Fetching
- paypal/fetch_reports/active
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Schedule
- PayPal retains reports for 45 days.
- paypal/fetch_reports/schedule
- Magento\Paypal\Model\System\Config\Source\FetchingSchedule
- 1
-
-
- Time of Day
- paypal/fetch_reports/time
- 1
-
-
-
- Frontend Experience Settings
-
- PayPal Product Logo
- Displays on catalog pages and homepage.
- paypal/style/logo
- Magento\Paypal\Model\System\Config\Source\Logo
- 1
-
-
- PayPal Merchant Pages Style
- Magento\Config\Block\System\Config\Form\Field\Heading
- 1
-
-
- Page Style
- paypal/style/page_style
-
-
-
- 1
-
-
- Header Image URL
- paypal/style/paypal_hdrimg
-
- https is highly encouraged.]]>
-
- 1
-
-
- Header Background Color
- paypal/style/paypal_hdrbackcolor
-
-
-
- 1
-
-
- Header Border Color
- paypal/style/paypal_hdrbordercolor
- 2-pixel perimeter around the header space.
- 1
-
-
- Page Background Color
- paypal/style/paypal_payflowcolor
-
-
-
- 1
-
-
- Customize Smart Buttons
- Magento\Config\Block\System\Config\Form\Field\Heading
- 1
-
-
- Checkout Page
-
- Customize Button
- paypal/style/checkout_page_button_customize
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Label
-
- paypal/style/checkout_page_button_label
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Depends\ButtonStylesLabel
- Magento\Paypal\Model\System\Config\Source\ButtonStyles::getLabel
-
- 1
-
- 1
-
-
- Mexico Installment Period
- paypal/style/checkout_page_button_mx_installment_period
- Magento\Paypal\Model\System\Config\Source\ButtonStyles::getMxInstallmentPeriod
-
- 1
- installment
-
- 1
-
-
- Brazil Installment Period
- paypal/style/checkout_page_button_br_installment_period
- Magento\Paypal\Model\System\Config\Source\ButtonStyles::getBrInstallmentPeriod
-
- 1
- installment
-
- 1
-
-
- Layout
- paypal/style/checkout_page_button_layout
- Magento\Paypal\Model\System\Config\Source\ButtonStyles::getLayout
-
- 1
- credit
-
- 1
-
-
- Size
- paypal/style/checkout_page_button_size
- Magento\Paypal\Model\System\Config\Source\ButtonStyles::getSize
- Select Responsive to ensure the PayPal button renders correctly on mobile devices.
-
- 1
-
- 1
-
-
- Shape
- paypal/style/checkout_page_button_shape
- Magento\Paypal\Model\System\Config\Source\ButtonStyles::getShape
-
- 1
-
- 1
-
-
- Color
- paypal/style/checkout_page_button_color
- Magento\Paypal\Model\System\Config\Source\ButtonStyles::getColor
-
- 1
- credit
-
- 1
-
-
-
- Product Pages
-
- paypal/style/product_page_button_customize
-
-
- paypal/style/product_page_button_label
-
- 1
-
-
-
- paypal/style/product_page_button_mx_installment_period
-
- 1
- installment
-
-
-
- paypal/style/product_page_button_br_installment_period
-
- 1
- installment
-
-
-
- paypal/style/product_page_button_layout
-
- 1
- credit
-
-
-
- paypal/style/product_page_button_size
-
- 1
-
-
-
- paypal/style/product_page_button_shape
-
- 1
-
-
-
- paypal/style/product_page_button_color
-
- 1
- credit
-
-
-
-
- Cart Page
-
- paypal/style/cart_page_button_customize
-
-
- paypal/style/cart_page_button_label
-
- 1
-
-
-
- paypal/style/cart_page_button_mx_installment_period
-
- 1
- installment
-
-
-
- paypal/style/cart_page_button_br_installment_period
-
- 1
- installment
-
-
-
- paypal/style/cart_page_button_layout
-
- 1
- credit
-
-
-
- paypal/style/cart_page_button_size
-
- 1
-
-
-
- paypal/style/cart_page_button_shape
-
- 1
-
-
-
- paypal/style/cart_page_button_color
-
- 1
- credit
-
-
-
-
- Mini Cart
-
- paypal/style/mini_cart_page_button_customize
-
-
- paypal/style/mini_cart_page_button_label
-
- 1
-
-
-
- paypal/style/mini_cart_page_button_mx_installment_period
-
- 1
- installment
-
-
-
- paypal/style/mini_cart_page_button_br_installment_period
-
- 1
- installment
-
-
-
- paypal/style/mini_cart_page_button_layout
-
- 1
- credit
-
-
-
- paypal/style/mini_cart_page_button_size
-
- 1
-
-
-
- paypal/style/mini_cart_page_button_shape
-
- 1
-
-
-
- paypal/style/mini_cart_page_button_color
-
- 1
- credit
-
-
-
-
- Features
-
- Disable Funding Options
-
-
-
- paypal/style/disable_funding_options
- Magento\Paypal\Block\Adminhtml\System\Config\MultiSelect\DisabledFundingOptions
- Magento\Paypal\Model\System\Config\Source\DisableFundingOptions
- 1
- 1
-
-
-
-
-
-
-
- Website Payments Pro Hosted Solution
- paypal-other-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- payment/hosted_pro/active
- Includes Express Checkout)]]>
- 1
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payments-pro.html
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Hint
-
-
- Required PayPal Settings
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Payments Pro Hosted Solution
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
-
-
-
-
-
-
-
-
-
-
-
-
- Enable this Solution
- payment/hosted_pro/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Payment
-
-
-
- paypal-enabler paypal-ec-separate
-
-
-
- Learn More]]>
-
-
-
-
-
-
- Advertise PayPal Credit
-
- Why Advertise Financing?
- Give your sales a boost when you advertise financing. PayPal helps turn browsers into buyers with financing
- from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you.
- Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal.
- The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15%
- or more. See Details .]]>
-
-
-
-
- Home Page
-
-
-
- Size
- payment/paypal_express_bml/homepage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPH
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPS
-
- 1
-
-
-
-
- Catalog Category Page
-
-
-
- Size
- payment/paypal_express_bml/categorypage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPS
-
- 1
-
-
-
-
- Catalog Product Page
-
-
-
- Size
- payment/paypal_express_bml/productpage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPN
-
- 1
-
-
-
-
- Checkout Cart Page
-
-
-
- Size
- payment/paypal_express_bml/checkout_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutN
- 1
-
- 1
-
-
-
-
-
-
- Basic Settings - PayPal Payments Pro Hosted Solution
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Title
- It is recommended to set this value to "PayPal" per store views.
- payment/hosted_pro/title
-
-
- Sort Order
- payment/hosted_pro/sort_order
- validate-number
-
-
- Payment Action
- payment/hosted_pro/payment_action
- Magento\Paypal\Model\System\Config\Source\PaymentActions
-
-
- Display Express Checkout in the Payment Information step
- payment/hosted_pro/display_ec
- Magento\Config\Model\Config\Source\Yesno
-
-
- Advanced Settings
- config-advanced
-
- Payment Applicable From
- payment/hosted_pro/allowspecific
- Magento\Payment\Model\Config\Source\Allspecificcountries
-
-
- Countries Payment Applicable From
- payment/hosted_pro/specificcountry
- Magento\Paypal\Model\System\Config\Source\BuyerCountry
-
- 1
-
-
-
- Debug Mode
- payment/hosted_pro/debug
- Magento\Config\Model\Config\Source\Yesno
-
-
- Enable SSL verification
- payment/hosted_pro/verify_peer
- Magento\Config\Model\Config\Source\Yesno
-
-
- Settlement Report Settings
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Accept and process credit cards and PayPal payments.]]>
- complex paypal-other-section paypal-all-in-one-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
- Choose a secure bundled payment solution for your business.
- other_paypal_payment_solutions
-
- Payments Advanced
- paypal-other-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- Includes Express Checkout)]]>
- payment/payflow_advanced/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payments-advanced.html
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Hint
-
-
- Required PayPal Settings
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Payments Advanced and Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Email Associated with PayPal Merchant Account (Optional)
-
-
- Partner
- payment/payflow_advanced/partner
- 1
-
-
- Vendor
- payment/payflow_advanced/vendor
- 1
-
-
- User
- PayPal recommends that you set up an additional User on your account at manager.paypal.com
- PayPal recommends you set up an additional User on your account at manager.paypal.com, instead of entering your admin username and password here. This will enhance your security and prevent service interruptions if you later change your password. If you do not want to set up an additional User, you can re-enter your Merchant Login here.
- payment/payflow_advanced/user
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Password
- payment/payflow_advanced/pwd
- Magento\Config\Model\Config\Backend\Encrypted
- 1
-
-
- Test Mode
- payment/payflow_advanced/sandbox_flag
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Use Proxy
- payment/payflow_advanced/use_proxy
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Proxy Host
- payment/payflow_advanced/proxy_host
-
- 1
-
- 1
-
-
- Proxy Port
- payment/payflow_advanced/proxy_port
-
- 1
-
- 1
-
-
- Magento\Paypal\Block\Adminhtml\System\Config\Payflowlink\Advanced
- 1
-
-
-
- Enable this Solution
- payment/payflow_advanced/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Payment
-
-
-
-
-
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Hidden
-
-
-
-
-
- Learn More]]>
-
- payment/payflow_express_bml/active
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Bml
-
-
-
-
-
- payment/payflow_express_bml/sort_order
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Depends\BmlSortOrder
-
- 1
-
-
-
- Advertise PayPal Credit
-
- Why Advertise Financing?
- Give your sales a boost when you advertise financing. PayPal helps turn browsers into buyers with financing
- from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you.
- Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal.
- The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15%
- or more. See Details .]]>
-
-
-
-
- Home Page
-
-
-
- Size
- payment/paypal_express_bml/homepage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPH
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPS
-
- 1
-
-
-
-
- Catalog Category Page
-
-
-
- Size
- payment/paypal_express_bml/categorypage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPS
-
- 1
-
-
-
-
- Catalog Product Page
-
-
-
- Size
- payment/paypal_express_bml/productpage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPN
-
- 1
-
-
-
-
-
- Checkout Cart Page
-
-
-
- Size
- payment/paypal_express_bml/checkout_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutN
- 1
-
- 1
-
-
-
-
-
-
- Basic Settings - PayPal Payments Advanced
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Title
- It is recommended to set this value to "Debit or Credit Card" per store views.
- payment/payflow_advanced/title
- 1
-
-
- Sort Order
- payment/payflow_advanced/sort_order
- validate-number
- 1
-
-
- Payment Action
- payment/payflow_advanced/payment_action
- Magento\Paypal\Model\System\Config\Source\PaymentActions
- 1
-
-
- Advanced Settings
- config-advanced
-
- Payment Applicable From
- payment/payflow_advanced/allowspecific
- Magento\Payment\Model\Config\Source\Allspecificcountries
- 1
-
-
- Countries Payment Applicable From
- payment/payflow_advanced/specificcountry
- Magento\Paypal\Model\System\Config\Source\BuyerCountry
-
- 1
-
- 1
-
-
- Debug Mode
- payment/payflow_advanced/debug
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Enable SSL verification
- payment/payflow_advanced/verify_peer
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- CVV Entry is Editable
- payment/payflow_advanced/csc_editable
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Require CVV Entry
- payment/payflow_advanced/csc_required
- Magento\Config\Model\Config\Source\Yesno
-
- 1
-
- 1
-
-
- Send Email Confirmation
- payment/payflow_advanced/email_confirmation
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- URL method for Cancel URL and Return URL
- payment/payflow_advanced/url_method
- Magento\Paypal\Model\System\Config\Source\UrlMethod
- 1
-
-
- Settlement Report Settings
-
-
-
-
-
-
-
-
-
-
-
-
- Frontend Experience Settings
-
-
-
-
-
-
-
-
-
-
-
- Basic Settings - PayPal Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
-
-
-
-
-
-
-
- Payments Pro
- payment/paypal_payment_pro/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payments-pro.html
-
-
-
- 0
- payment/paypal_payment_pro/active
-
-
- Payments Pro and Express Checkout
-
-
-
- Basic Settings - PayPal Payments Pro
-
-
-
- Payments Standard
- Accept credit card and PayPal payments securely.
- payment/wps_express/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payments-standard.html
-
-
-
-
-
- Payments Standard
-
-
- payment/wps_express/active
-
-
- payment/wps_express_bml/active
-
-
-
- Basic Settings - PayPal Website Payments Standard
-
-
-
-
- Process payments using your own internet merchant account.]]>
- complex paypal-other-section paypal-gateways-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
- other_paypal_payment_solutions
-
- Payflow Pro
- 0
-
- Required PayPal Settings
-
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Payment
-
-
-
-
- Payflow Pro and Express Checkout
-
- not-required
- Email Associated with PayPal Merchant Account (Optional)
- 1
-
-
-
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Hidden
-
-
-
-
-
- Enable PayPal Credit
- Learn More]]>
-
- payment/payflow_express_bml/active
- Magento\Config\Model\Config\Source\Yesno
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Bml
-
-
-
-
-
- payment/payflow_express_bml/sort_order
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Depends\BmlSortOrder
-
- 1
-
-
-
- Advertise PayPal Credit
-
- Why Advertise Financing?
- Give your sales a boost when you advertise financing. PayPal helps turn browsers into buyers with financing
- from PayPal Credit®. Your customers have more time to pay, while you get paid up front – at no additional cost to you.
- Use PayPal’s free banner ads that let you advertise PayPal Credit® financing as a payment option when your customers check out with PayPal.
- The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15%
- or more. See Details .]]>
-
-
-
-
- Home Page
-
-
-
- Size
- payment/paypal_express_bml/homepage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPH
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeHPS
-
- 1
-
-
-
-
- Catalog Category Page
-
-
-
- Size
- payment/paypal_express_bml/categorypage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCCPS
-
- 1
-
-
-
-
- Catalog Product Page
-
-
-
- Size
- payment/paypal_express_bml/productpage_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCPPN
-
- 1
-
-
-
-
- Checkout Cart Page
-
-
-
- Size
- payment/paypal_express_bml/checkout_size
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutC
- 1
-
- 0
-
-
-
- Magento\Paypal\Model\System\Config\Source\BmlSize::getBmlSizeCheckoutN
- 1
-
- 1
-
-
-
-
-
-
-
-
- Frontend Experience Settings
-
-
-
-
-
-
-
-
-
-
-
- Basic Settings - PayPal Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
- Title
- payment/payflow_express/title
- 1
-
-
- Sort Order
- payment/payflow_express/sort_order
- validate-number
- 1
-
-
- Payment Action
- payment/payflow_express/payment_action
- Magento\Paypal\Model\System\Config\Source\PaymentActions
- 1
-
-
- Display on Product Details Page
- payment/payflow_express/visible_on_product
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Advanced Settings
- config-advanced
-
- Display on Shopping Cart
- Also affects mini-shopping cart.
- payment/payflow_express/visible_on_cart
- Magento\Paypal\Model\System\Config\Source\Yesnoshortcut
- 1
-
-
- Payment Applicable From
- payment/payflow_express/allowspecific
- Magento\Payment\Model\Config\Source\Allspecificcountries
- 1
-
-
- Countries Payment Applicable From
- payment/payflow_express/specificcountry
- Magento\Paypal\Model\System\Config\Source\BuyerCountry
-
- 1
-
- 1
-
-
- Debug Mode
- payment/payflow_express/debug
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Enable SSL verification
- payment/payflow_express/verify_peer
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
- Transfer Cart Line Items
- payment/payflow_express/line_items_enabled
- Magento\Config\Model\Config\Source\Yesno
- 1
-
-
-
-
-
-
-
-
-
- PayPal Express Checkout
- complex paypal-express-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- Add another payment method to your existing solution or as a stand-alone option.
- https://merchant.paypal.com/cgi-bin/marketingweb?cmd=_render-content
- 0
- payment/paypal_express/active
- payment/payflow_express/active
- recommended_solutions
-
-
-
-
-
- Accept and process credit cards and PayPal payments.]]>
- complex paypal-other-section paypal-all-in-one-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
- Choose a secure bundled payment solution for your business.
- https://www.paypal-marketing.com/emarketing/partner/na/merchantlineup/home.page#mainTab=checkoutlineup&subTab=newlineup
- other_paypal_payment_solutions
-
- pp-general-uk
- http://www.youtube.com/watch?v=LBe-TW87eGI&list=PLF18B1094ABCD7CE8&index=1&feature=plpp_video
- Accept payments with a completely customizable checkout page.
-
-
-
-
-
-
-
- Website Payments Pro Hosted Solution
- 0
-
-
- Website Payments Pro Hosted Solution and Express Checkout
-
-
-
-
-
- paypal-enabler
-
-
-
- Basic Settings - PayPal Website Payments Pro Hosted Solution
-
-
- PayPal Billing Agreement Settings
-
-
-
-
-
-
-
-
-
-
-
-
- Frontend Experience Settings
-
-
-
-
-
-
-
-
-
-
-
- Basic Settings - PayPal Express Checkout
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
-
-
-
-
-
-
-
-
- Advanced Settings
- config-advanced
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Website Payments Standard
- Accept credit card and PayPal payments securely.
- payment/wps_express/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payments-standard.html
-
-
-
- Website Payments Standard
-
-
- payment/wps_express/active
-
-
-
-
-
-
-
-
- Basic Settings - PayPal Website Payments Standard
-
-
-
-
-
- PayPal Express Checkout
- complex paypal-express-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- Add another payment method to your existing solution or as a stand-alone option.
- https://merchant.paypal.com/cgi-bin/marketingweb?cmd=_render-content
- recommended_solutions
-
-
-
-
-
-
-
-
-
-
-
- PayPal Express Checkout
- complex paypal-express-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- Add another payment method to your existing solution or as a stand-alone option.
- https://www.paypal-marketing.com/emarketing/partner/na/merchantlineup/home.page#mainTab=checkoutlineup&subTab=newlineup
- recommended_solutions
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- PayPal Express Checkout
- complex paypal-express-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- Add another payment method to your existing solution or as a stand-alone option.
- https://www.paypal-marketing.com/emarketing/partner/na/merchantlineup/home.page#mainTab=checkoutlineup&subTab=newlineup
- recommended_solutions
-
-
-
-
-
-
-
- Accept and process credit cards and PayPal payments.]]>
- complex paypal-other-section paypal-all-in-one-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
- Choose a secure bundled payment solution for your business.
- https://www.paypal-marketing.com/emarketing/partner/na/merchantlineup/home.page#mainTab=checkoutlineup&subTab=newlineup
- other_paypal_payment_solutions
-
- Website Payments Standard
- complex
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment
- Accept credit card and PayPal payments securely.
- payment/wps_express/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payments-standard.html
-
-
-
- Website Payments Standard
-
-
-
-
- payment/wps_express/active
-
-
-
-
-
-
- Basic Settings - PayPal Website Payments Standard
-
-
-
-
- Process payments using your own internet merchant account.]]>
- complex paypal-other-section paypal-gateways-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
- Process payments using your own internet merchant account.
- https://merchant.paypal.com/cgi-bin/marketingweb?cmd=_render-content
- other_paypal_payment_solutions
-
-
-
-
- payment/paypal_express/active
- payment/payflow_express/active
-
-
-
-
-
- complex paypal-other-section paypal-gateways-section
- Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Expanded
- Process payments using your own internet merchant account.]]>
-
- Website Payments Pro
- payment/paypal_payment_pro/active
-
- http://docs.magento.com/m2/ce/user_guide/payment/paypal-payments-pro.html
-
-
-
- Payments Pro
-
-
-
-
- paypal-enabler paypal-ec-pe
- 0
- payment/paypal_payment_pro/active
- Magento\Paypal\Block\Adminhtml\System\Config\Field\Enable\Payment
-
-
-
- Basic Settings - PayPal Payments Pro
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Website Payments Plus
-
-
-
-
-
-
-
-
- Integral Evolution
-
-
-
-
-
-
-
-
-
- Pasarela integral
-
-
-
-
-
-
-
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/TotalsTest.php b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/TotalsTest.php
new file mode 100644
index 0000000000000..1125fc1730718
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/TotalsTest.php
@@ -0,0 +1,59 @@
+layout = $this->_objectManager->get(LayoutInterface::class);
+ $this->block = $this->layout->createBlock(Totals::class, 'totals_block');
+ $this->orderFactory = $this->_objectManager->get(OrderFactory::class);
+ }
+
+ /**
+ * @magentoDataFixture Magento/Sales/_files/order_with_free_shipping_by_coupon.php
+ */
+ public function testShowShippingCoupon()
+ {
+ /** @var Order $order */
+ $order = $this->orderFactory->create();
+ $order->loadByIncrementId('100000001');
+
+ $this->block->setOrder($order);
+ $this->block->toHtml();
+
+ $shippingTotal = $this->block->getTotal('shipping');
+ $this->assertNotFalse($shippingTotal, 'Shipping method is absent on the total\'s block.');
+ $this->assertContains(
+ '1234567890',
+ $shippingTotal->getLabel(),
+ 'Coupon code is absent in the shipping method label name.'
+ );
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php
index fa5da2e0e50d1..f589a0f5a1c74 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php
@@ -7,10 +7,13 @@
namespace Magento\Sales\Controller\Adminhtml\Order\Creditmemo;
+use Magento\Framework\App\Request\Http as HttpRequest;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Model\Order;
use PHPUnit\Framework\Constraint\StringContains;
/**
- * Class tests creditmemo creation in backend.
+ * Provide tests for CreditMemo save controller.
*
* @magentoDbIsolation enabled
* @magentoAppArea adminhtml
@@ -24,6 +27,8 @@ class SaveTest extends AbstractCreditmemoControllerTest
protected $uri = 'backend/sales/order_creditmemo/save';
/**
+ * @magentoDbIsolation enabled
+ * @magentoDataFixture Magento/Sales/_files/invoice.php
* @return void
*/
public function testSendEmailOnCreditmemoSave(): void
@@ -54,6 +59,91 @@ public function testSendEmailOnCreditmemoSave(): void
$this->assertThat($message->getRawMessage(), $messageConstraint);
}
+ /**
+ * Test order will keep same(custom) status after partial refund, if state has not been changed.
+ *
+ * @magentoDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
+ */
+ public function testOrderStatusPartialRefund()
+ {
+ /** @var Order $existingOrder */
+ $existingOrder = $this->_objectManager->create(Order::class)->loadByIncrementId('100000001');
+ $items = $this->getOrderItems($existingOrder, 1);
+ $requestParams = [
+ 'creditmemo' => [
+ 'items' => $items,
+ 'do_offline' => '1',
+ 'comment_text' => '',
+ 'shipping_amount' => '0',
+ 'adjustment_positive' => '0',
+ 'adjustment_negative' => '0',
+ ],
+ 'order_id' => $existingOrder->getId(),
+ ];
+ $this->getRequest()->setMethod(HttpRequest::METHOD_POST);
+ $this->getRequest()->setParams($requestParams);
+ $this->dispatch('backend/sales/order_creditmemo/save');
+
+ /** @var Order $updatedOrder */
+ $updatedOrder = $this->_objectManager->create(Order::class)
+ ->loadByIncrementId($existingOrder->getIncrementId());
+
+ $this->assertSame('custom_processing', $updatedOrder->getStatus());
+ $this->assertSame('processing', $updatedOrder->getState());
+ }
+
+ /**
+ * Test order will change custom status after total refund, when state has been changed.
+ *
+ * @magentoDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
+ */
+ public function testOrderStatusTotalRefund()
+ {
+ /** @var Order $existingOrder */
+ $existingOrder = $this->_objectManager->create(Order::class)->loadByIncrementId('100000001');
+ $requestParams = [
+ 'creditmemo' => [
+ 'items' => $this->getOrderItems($existingOrder),
+ 'do_offline' => '1',
+ 'comment_text' => '',
+ 'shipping_amount' => '0',
+ 'adjustment_positive' => '0',
+ 'adjustment_negative' => '0',
+ ],
+ 'order_id' => $existingOrder->getId(),
+ ];
+ $this->getRequest()->setMethod(HttpRequest::METHOD_POST);
+ $this->getRequest()->setParams($requestParams);
+ $this->dispatch('backend/sales/order_creditmemo/save');
+
+ /** @var Order $updatedOrder */
+ $updatedOrder = $this->_objectManager->create(Order::class)
+ ->loadByIncrementId($existingOrder->getIncrementId());
+
+ $this->assertSame('complete', $updatedOrder->getStatus());
+ $this->assertSame('complete', $updatedOrder->getState());
+ }
+
+ /**
+ * Gets all items of given Order in proper format.
+ *
+ * @param Order $order
+ * @param int $subQty
+ * @return array
+ */
+ private function getOrderItems(Order $order, int $subQty = 0)
+ {
+ $items = [];
+ /** @var OrderItemInterface $item */
+ foreach ($order->getAllItems() as $item) {
+ $items[$item->getItemId()] = [
+ 'qty' => $item->getQtyOrdered() - $subQty,
+ ];
+ }
+
+ return $items;
+ }
+
/**
* @inheritdoc
*/
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_list.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_list.php
index 1f4253f18487c..99122d72df4b7 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_list.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_list.php
@@ -9,6 +9,7 @@
use Magento\Sales\Model\Order\Address as OrderAddress;
use Magento\Sales\Model\Order\Payment;
+// phpcs:ignore Magento2.Security.IncludeFile
require 'order.php';
/** @var Order $order */
/** @var Order\Payment $payment */
@@ -24,8 +25,7 @@
'subtotal' => 120.00,
'base_grand_total' => 120.00,
'store_id' => 1,
- 'website_id' => 1,
- 'payment' => $payment
+ 'website_id' => 1
],
[
'increment_id' => '100000003',
@@ -35,8 +35,7 @@
'base_grand_total' => 140.00,
'subtotal' => 140.00,
'store_id' => 0,
- 'website_id' => 0,
- 'payment' => $payment
+ 'website_id' => 0
],
[
'increment_id' => '100000004',
@@ -46,8 +45,7 @@
'base_grand_total' => 140.00,
'subtotal' => 140.00,
'store_id' => 1,
- 'website_id' => 1,
- 'payment' => $payment
+ 'website_id' => 1
],
];
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_free_shipping_by_coupon.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_free_shipping_by_coupon.php
new file mode 100644
index 0000000000000..57ccffadaa4d0
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_free_shipping_by_coupon.php
@@ -0,0 +1,35 @@
+create(OrderItem::class);
+$orderItem->setProductId($product->getId())
+ ->setQtyOrdered(2)
+ ->setBasePrice($product->getPrice())
+ ->setPrice($product->getPrice())
+ ->setRowTotal($product->getPrice())
+ ->setProductType('simple')
+ ->setName($product->getName())
+ ->setFreeShipping('1');
+
+/** @var Order $order */
+$order->setShippingDescription('Flat Rate - Fixed')
+ ->setShippingAmount(0)
+ ->setCouponCode('1234567890')
+ ->setDiscountDescription('1234567890')
+ ->addItem($orderItem);
+
+/** @var OrderRepositoryInterface $orderRepository */
+$orderRepository = $objectManager->create(OrderRepositoryInterface::class);
+$orderRepository->save($order);
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_free_shipping_by_coupon_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_free_shipping_by_coupon_rollback.php
new file mode 100644
index 0000000000000..1fb4b4636ab29
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_free_shipping_by_coupon_rollback.php
@@ -0,0 +1,8 @@
+create(Status::class);
+$data = [
+ 'status' => 'custom_processing',
+ 'label' => 'Custom Processing Status',
+];
+$orderStatus->setData($data)->setStatus('custom_processing');
+$orderStatus->save();
+$orderStatus->assignState('processing');
+
+$order->setStatus('custom_processing');
+$order->save();
diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_and_custom_status_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_and_custom_status_rollback.php
new file mode 100644
index 0000000000000..274cb3c74395d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_invoice_and_custom_status_rollback.php
@@ -0,0 +1,17 @@
+create(Status::class);
+$orderStatus->load('custom_processing', 'status');
+$orderStatus->delete();
diff --git a/dev/tests/integration/testsuite/Magento/Store/App/FrontController/Plugin/RequestPreprocessorTest.php b/dev/tests/integration/testsuite/Magento/Store/App/FrontController/Plugin/RequestPreprocessorTest.php
index ebf302c16bd69..0e158821f1802 100644
--- a/dev/tests/integration/testsuite/Magento/Store/App/FrontController/Plugin/RequestPreprocessorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Store/App/FrontController/Plugin/RequestPreprocessorTest.php
@@ -56,7 +56,7 @@ public function testHttpsPassSecureLoginPost()
$this->prepareRequest(true);
$this->dispatch('customer/account/loginPost/');
$redirectUrl = str_replace('http://', 'https://', $this->baseUrl) .
- 'index.php/customer/account/';
+ 'customer/account/';
$this->assertResponseRedirect($this->getResponse(), $redirectUrl);
$this->assertTrue($this->_objectManager->get(Session::class)->isLoggedIn());
$this->setFrontendCompletelySecureRollback();
diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php
index bb6d1687052e3..00de5544d8fb7 100644
--- a/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php
+++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreTest.php
@@ -8,7 +8,6 @@
use Magento\Catalog\Model\ProductRepository;
use Magento\Framework\App\Bootstrap;
-use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\UrlInterface;
use Magento\Store\Api\StoreRepositoryInterface;
@@ -16,6 +15,7 @@
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * phpcs:disable Magento2.Security.Superglobal
*/
class StoreTest extends \PHPUnit\Framework\TestCase
{
@@ -201,7 +201,7 @@ public function testGetBaseUrlInPub()
*/
public function testGetBaseUrlForCustomEntryPoint($type, $useCustomEntryPoint, $useStoreCode, $expected)
{
- /* config operations require store to be loaded */
+ /* config operations require store to be loaded */
$this->model->load('default');
\Magento\TestFramework\Helper\Bootstrap::getObjectManager()
->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class)
@@ -213,6 +213,10 @@ public function testGetBaseUrlForCustomEntryPoint($type, $useCustomEntryPoint, $
// emulate custom entry point
$_SERVER['SCRIPT_FILENAME'] = 'custom_entry.php';
+ $request = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->get(\Magento\Framework\App\RequestInterface::class);
+ $request->setServer(new Parameters($_SERVER));
+
if ($useCustomEntryPoint) {
$property = new \ReflectionProperty($this->model, '_isCustomEntryPoint');
$property->setAccessible(true);
@@ -298,11 +302,11 @@ public function testGetCurrentUrl()
$url = $product->getUrlInStore();
$this->assertEquals(
- $secondStore->getBaseUrl().'catalog/product/view/id/1/s/simple-product/',
+ $secondStore->getBaseUrl() . 'catalog/product/view/id/1/s/simple-product/',
$url
);
$this->assertEquals(
- $secondStore->getBaseUrl().'?___from_store=default',
+ $secondStore->getBaseUrl() . '?___from_store=default',
$secondStore->getCurrentUrl()
);
$this->assertEquals(
@@ -332,25 +336,25 @@ public function testGetCurrentUrlWithUseStoreInUrlFalse()
$product->setStoreId($secondStore->getId());
$url = $product->getUrlInStore();
- /** @var \Magento\Catalog\Model\CategoryRepository $categoryRepository */
+ /** @var \Magento\Catalog\Model\CategoryRepository $categoryRepository */
$categoryRepository = $objectManager->get(\Magento\Catalog\Model\CategoryRepository::class);
$category = $categoryRepository->get(333, $secondStore->getStoreId());
$this->assertEquals(
- $secondStore->getBaseUrl().'catalog/category/view/s/category-1/id/333/',
+ $secondStore->getBaseUrl() . 'catalog/category/view/s/category-1/id/333/',
$category->getUrl()
);
$this->assertEquals(
- $secondStore->getBaseUrl().
+ $secondStore->getBaseUrl() .
'catalog/product/view/id/333/s/simple-product-three/?___store=fixture_second_store',
$url
);
$this->assertEquals(
- $secondStore->getBaseUrl().'?___store=fixture_second_store&___from_store=default',
+ $secondStore->getBaseUrl() . '?___store=fixture_second_store&___from_store=default',
$secondStore->getCurrentUrl()
);
$this->assertEquals(
- $secondStore->getBaseUrl().'?___store=fixture_second_store',
+ $secondStore->getBaseUrl() . '?___store=fixture_second_store',
$secondStore->getCurrentUrl(false)
);
}
@@ -405,7 +409,7 @@ public function testSaveValidation($badStoreData)
/**
* @return array
*/
- public static function saveValidationDataProvider()
+ public function saveValidationDataProvider()
{
return [
'empty store name' => [['name' => '']],
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php
index bd505fd4db035..985019b687ce0 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php
@@ -7,10 +7,19 @@
namespace Magento\Tax\Model\Sales\Total\Quote;
use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Quote\Model\Quote;
use Magento\Tax\Model\Config;
use Magento\Tax\Model\Calculation;
+use Magento\Quote\Model\Quote\Item\Updater;
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Framework\Api\Filter;
+use Magento\Framework\Api\Search\FilterGroup;
+use Magento\Framework\Api\SearchCriteriaInterface;
/**
+ * Setup utility for quote
+ *
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class SetupUtil
@@ -594,7 +603,7 @@ protected function createCartRule($ruleDataOverride)
*
* @param array $quoteData
* @param \Magento\Customer\Api\Data\CustomerInterface $customer
- * @return \Magento\Quote\Model\Quote
+ * @return Quote
*/
protected function createQuote($quoteData, $customer)
{
@@ -619,8 +628,8 @@ protected function createQuote($quoteData, $customer)
$quoteBillingAddress = $this->objectManager->create(\Magento\Quote\Model\Quote\Address::class);
$quoteBillingAddress->importCustomerAddressData($addressService->getById($billingAddress->getId()));
- /** @var \Magento\Quote\Model\Quote $quote */
- $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class);
+ /** @var Quote $quote */
+ $quote = $this->objectManager->create(Quote::class);
$quote->setStoreId(1)
->setIsActive(true)
->setIsMultiShipping(false)
@@ -634,7 +643,7 @@ protected function createQuote($quoteData, $customer)
/**
* Add products to quote
*
- * @param \Magento\Quote\Model\Quote $quote
+ * @param Quote $quote
* @param array $itemsData
* @return $this
*/
@@ -657,7 +666,8 @@ protected function addProductToQuote($quote, $itemsData)
* Create a quote based on given data
*
* @param array $quoteData
- * @return \Magento\Quote\Model\Quote
+ *
+ * @return Quote
*/
public function setupQuote($quoteData)
{
@@ -666,7 +676,9 @@ public function setupQuote($quoteData)
$quote = $this->createQuote($quoteData, $customer);
$this->addProductToQuote($quote, $quoteData['items']);
-
+ if (isset($quoteData['update_items'])) {
+ $this->updateItems($quote, $quoteData['update_items']);
+ }
//Set shipping amount
if (isset($quoteData['shipping_method'])) {
$quote->getShippingAddress()->setShippingMethod($quoteData['shipping_method']);
@@ -683,4 +695,33 @@ public function setupQuote($quoteData)
return $quote;
}
+
+ /**
+ * Update quote items
+ *
+ * @param Quote $quote
+ * @param array $items
+ *
+ * @return void
+ */
+ private function updateItems(Quote $quote, array $items): void
+ {
+ $updater = $this->objectManager->get(Updater::class);
+ $productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
+ $filter = $this->objectManager->create(Filter::class);
+ $filter->setField('sku')->setValue(array_keys($items));
+ $filterGroup = $this->objectManager->create(FilterGroup::class);
+ $filterGroup->setFilters([$filter]);
+ $searchCriteria = $this->objectManager->create(SearchCriteriaInterface::class);
+ $searchCriteria->setFilterGroups([$filterGroup]);
+ $products = $productRepository->getList($searchCriteria)->getItems();
+ /** @var ProductInterface $product */
+ foreach ($products as $product) {
+ $quoteItem = $quote->getItemByProduct($product);
+ $updater->update(
+ $quoteItem,
+ $items[$product->getSku()]
+ );
+ }
+ }
}
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_with_custom_price.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_with_custom_price.php
new file mode 100644
index 0000000000000..290c133f455f6
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_with_custom_price.php
@@ -0,0 +1,93 @@
+ [
+ SetupUtil::CONFIG_OVERRIDES => [
+ Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX => 1,
+ Config::CONFIG_XML_PATH_APPLY_ON => 0,
+ ],
+ SetupUtil::TAX_RATE_OVERRIDES => [
+ SetupUtil::TAX_RATE_TX => 8.25,
+ SetupUtil::TAX_STORE_RATE => 8.25,
+ ],
+ SetupUtil::TAX_RULE_OVERRIDES => [
+ ],
+ ],
+ 'quote_data' => [
+ 'billing_address' => [
+ 'region_id' => SetupUtil::REGION_TX,
+ ],
+ 'shipping_address' => [
+ 'region_id' => SetupUtil::REGION_TX,
+ ],
+ 'items' => [
+ [
+ 'sku' => 'simple1',
+ 'price' => 16.24,
+ 'qty' => 1,
+ ],
+ ],
+ 'update_items' => [
+ 'simple1' => [
+ 'custom_price' => 14,
+ 'qty' => 1,
+ ],
+ ],
+ ],
+ 'expected_results' => [
+ 'address_data' => [
+ 'subtotal' => 12.93,
+ 'base_subtotal' => 12.93,
+ 'subtotal_incl_tax' => 14,
+ 'base_subtotal_incl_tax' => 14,
+ 'tax_amount' => 1.07,
+ 'base_tax_amount' => 1.07,
+ 'shipping_amount' => 0,
+ 'base_shipping_amount' => 0,
+ 'shipping_incl_tax' => 0,
+ 'base_shipping_incl_tax' => 0,
+ 'shipping_taxable' => 0,
+ 'base_shipping_taxable' => 0,
+ 'shipping_tax_amount' => 0,
+ 'base_shipping_tax_amount' => 0,
+ 'discount_amount' => 0,
+ 'base_discount_amount' => 0,
+ 'discount_tax_compensation_amount' => 0,
+ 'base_discount_tax_compensation_amount' => 0,
+ 'shipping_discount_tax_compensation_amount' => 0,
+ 'base_shipping_discount_tax_compensation_amount' => 0,
+ 'grand_total' => 14,
+ 'base_grand_total' => 14,
+ ],
+ 'items_data' => [
+ 'simple1' => [
+ 'row_total' => 12.93,
+ 'base_row_total' => 12.93,
+ 'tax_percent' => 8.25,
+ 'price' => 12.93,
+ 'custom_price' => 12.93,
+ 'original_custom_price' => 14,
+ 'base_price' => 12.93,
+ 'price_incl_tax' => 14,
+ 'base_price_incl_tax' => 14,
+ 'row_total_incl_tax' => 14,
+ 'base_row_total_incl_tax' => 14,
+ 'tax_amount' => 1.07,
+ 'base_tax_amount' => 1.07,
+ 'discount_amount' => 0,
+ 'base_discount_amount' => 0,
+ 'discount_percent' => 0,
+ 'discount_tax_compensation_amount' => 0,
+ 'base_discount_tax_compensation_amount' => 0,
+ ],
+ ],
+ ],
+];
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php b/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php
index f22b48a259685..3c56b1bf815a6 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php
@@ -3,14 +3,15 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
/**
- * Global array that holds test scenarios data
+ * Global array that holds test scenarios data.
*
* @var array
*/
$taxCalculationData = [];
-
+//phpcs:disable Magento2.Security.IncludeFile
require_once __DIR__ . '/scenarios/excluding_tax_apply_tax_after_discount.php';
require_once __DIR__ . '/scenarios/excluding_tax_apply_tax_after_discount_discount_tax.php';
require_once __DIR__ . '/scenarios/excluding_tax_apply_tax_before_discount.php';
@@ -31,3 +32,4 @@
require_once __DIR__ . '/scenarios/multi_tax_rule_two_row_calculate_subtotal_yes_row.php';
require_once __DIR__ . '/scenarios/multi_tax_rule_two_row_calculate_subtotal_yes_total.php';
require_once __DIR__ . '/scenarios/including_tax_apply_tax_after_discount.php';
+require_once __DIR__ . '/scenarios/including_tax_with_custom_price.php';
diff --git a/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php b/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php
index 672cbd7a586ec..937a26fdf0a89 100644
--- a/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php
+++ b/dev/tests/integration/testsuite/Magento/User/Controller/Adminhtml/User/InvalidateTokenTest.php
@@ -89,10 +89,6 @@ public function testInvalidateTokenNoTokens()
// invalidate token
$this->getRequest()->setParam('user_id', $adminUserId);
$this->dispatch('backend/admin/user/invalidateToken');
- $this->assertSessionMessages(
- $this->equalTo(['This user has no tokens.']),
- MessageInterface::TYPE_ERROR
- );
}
public function testInvalidateTokenNoUser()
@@ -110,9 +106,5 @@ public function testInvalidateTokenInvalidUser()
// invalidate token
$this->getRequest()->setParam('user_id', $adminUserId);
$this->dispatch('backend/admin/user/invalidateToken');
- $this->assertSessionMessages(
- $this->equalTo(['This user has no tokens.']),
- MessageInterface::TYPE_ERROR
- );
}
}
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/cc-form.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/cc-form.test.js
index 8fdef2cbaadbb..429342b43bcb2 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/cc-form.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/cc-form.test.js
@@ -15,6 +15,18 @@ define([
describe('Magento_Braintree/js/view/payment/method-renderer/cc-form', function () {
var injector = new Squire(),
mocks = {
+ 'Magento_Checkout/js/model/checkout-data-resolver': {
+
+ /** Stub */
+ applyBillingAddress: function () {
+ return true;
+ },
+
+ /** Stub */
+ resolveBillingAddress: function () {
+ return true;
+ }
+ },
'Magento_Checkout/js/model/quote': {
billingAddress: ko.observable(),
shippingAddress: ko.observable(),
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js
index 4fc73caf7e14b..6ba0ed0b58f03 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Braintree/frontend/js/view/payment/method-renderer/paypal.test.js
@@ -14,6 +14,18 @@ define([
var injector = new Squire(),
mocks = {
+ 'Magento_Checkout/js/model/checkout-data-resolver': {
+
+ /** Stub */
+ applyBillingAddress: function () {
+ return true;
+ },
+
+ /** Stub */
+ resolveBillingAddress: function () {
+ return true;
+ }
+ },
'Magento_Checkout/js/model/quote': {
billingAddress: ko.observable(),
shippingAddress: ko.observable({
diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Paypal/frontend/js/view/payment/method-renderer/paypal-express-abstract.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Paypal/frontend/js/view/payment/method-renderer/paypal-express-abstract.test.js
index 29a2e8db914a7..7bc9a2a0113aa 100644
--- a/dev/tests/js/jasmine/tests/app/code/Magento/Paypal/frontend/js/view/payment/method-renderer/paypal-express-abstract.test.js
+++ b/dev/tests/js/jasmine/tests/app/code/Magento/Paypal/frontend/js/view/payment/method-renderer/paypal-express-abstract.test.js
@@ -24,6 +24,18 @@ define([
return true;
}).and.callThrough(),
mocks = {
+ 'Magento_Checkout/js/model/checkout-data-resolver': {
+
+ /** Stub */
+ applyBillingAddress: function () {
+ return true;
+ },
+
+ /** Stub */
+ resolveBillingAddress: function () {
+ return true;
+ }
+ },
'Magento_Checkout/js/model/quote': {
billingAddress: ko.observable(),
shippingAddress: ko.observable(),
diff --git a/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php b/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php
index ee56158a54509..707c3442d4056 100644
--- a/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php
+++ b/dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/CookieAndSessionMisuse.php
@@ -54,6 +54,19 @@ private function isUiDataProvider(\ReflectionClass $class): bool
);
}
+ /**
+ * Is given class a Layout Processor?
+ *
+ * @param \ReflectionClass $class
+ * @return bool
+ */
+ private function isLayoutProcessor(\ReflectionClass $class): bool
+ {
+ return $class->isSubclassOf(
+ \Magento\Checkout\Block\Checkout\LayoutProcessorInterface::class
+ );
+ }
+
/**
* Is given class an HTML UI Document?
*
@@ -159,6 +172,7 @@ private function doesUseRestrictedClasses(\ReflectionClass $class): bool
* @inheritdoc
*
* @param ClassNode|ASTClass $node
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function apply(AbstractNode $node)
{
@@ -176,6 +190,7 @@ public function apply(AbstractNode $node)
&& !$this->isUiDocument($class)
&& !$this->isControllerPlugin($class)
&& !$this->isBlockPlugin($class)
+ && !$this->isLayoutProcessor($class)
) {
$this->addViolation($node, [$node->getFullQualifiedName()]);
}
diff --git a/dev/tests/static/framework/Magento/Sniffs/Annotation/AnnotationFormatValidator.php b/dev/tests/static/framework/Magento/Sniffs/Annotation/AnnotationFormatValidator.php
index 49acd039a0960..33df6e8ae54f1 100644
--- a/dev/tests/static/framework/Magento/Sniffs/Annotation/AnnotationFormatValidator.php
+++ b/dev/tests/static/framework/Magento/Sniffs/Annotation/AnnotationFormatValidator.php
@@ -4,6 +4,7 @@
* See COPYING.txt for license details.
*/
declare(strict_types=1);
+
namespace Magento\Sniffs\Annotation;
use PHP_CodeSniffer\Files\File;
@@ -249,6 +250,60 @@ public function validateTagGroupingFormat(File $phpcsFile, int $commentStartPtr)
}
}
+ /**
+ * Validates tag aligning format
+ *
+ * @param File $phpcsFile
+ * @param int $commentStartPtr
+ */
+ public function validateTagAligningFormat(File $phpcsFile, int $commentStartPtr) : void
+ {
+ $tokens = $phpcsFile->getTokens();
+ $noAlignmentPositions = [];
+ $actualPositions = [];
+ $stackPtr = null;
+ foreach ($tokens[$commentStartPtr]['comment_tags'] as $tag) {
+ $content = $tokens[$tag]['content'];
+ if (preg_match('/^@/', $content) && ($tokens[$tag]['line'] === $tokens[$tag + 2]['line'])) {
+ $noAlignmentPositions[] = $tokens[$tag + 1]['column'] + 1;
+ $actualPositions[] = $tokens[$tag + 2]['column'];
+ $stackPtr = $stackPtr ?? $tag;
+ }
+ }
+
+ if (!$this->allTagsAligned($actualPositions)
+ && !$this->noneTagsAligned($actualPositions, $noAlignmentPositions)) {
+ $phpcsFile->addFixableError(
+ 'Tags visual alignment must be consistent',
+ $stackPtr,
+ 'MethodArguments'
+ );
+ }
+ }
+
+ /**
+ * Check whether all docblock params are aligned.
+ *
+ * @param array $actualPositions
+ * @return bool
+ */
+ private function allTagsAligned(array $actualPositions)
+ {
+ return count(array_unique($actualPositions)) === 1;
+ }
+
+ /**
+ * Check whether all docblock params are not aligned.
+ *
+ * @param array $actualPositions
+ * @param array $noAlignmentPositions
+ * @return bool
+ */
+ private function noneTagsAligned(array $actualPositions, array $noAlignmentPositions)
+ {
+ return $actualPositions === $noAlignmentPositions;
+ }
+
/**
* Validates extra newline before short description
*
@@ -301,8 +356,8 @@ public function validateDescriptionFormatStructure(
$this->validateShortDescriptionFormat(
$phpcsFile,
(int) $shortPtr,
- $commentStartPtr,
- $commentEndPtr,
+ (int)$commentStartPtr,
+ (int)$commentEndPtr,
$emptyTypeTokens
);
}
diff --git a/dev/tests/static/framework/Magento/Sniffs/Annotation/ClassAnnotationStructureSniff.php b/dev/tests/static/framework/Magento/Sniffs/Annotation/ClassAnnotationStructureSniff.php
index 01834ff81e81b..c37f0b500fe39 100644
--- a/dev/tests/static/framework/Magento/Sniffs/Annotation/ClassAnnotationStructureSniff.php
+++ b/dev/tests/static/framework/Magento/Sniffs/Annotation/ClassAnnotationStructureSniff.php
@@ -97,8 +97,8 @@ public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$previousCommentClosePtr = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr - 1, 0);
- $this->validateAnnotationBlockExists($phpcsFile, $previousCommentClosePtr, $stackPtr);
- $commentStartPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr - 1, 0);
+ $this->validateAnnotationBlockExists($phpcsFile, (int)$previousCommentClosePtr, (int)$stackPtr);
+ $commentStartPtr = (int)$phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr - 1, 0);
$commentCloserPtr = $tokens[$commentStartPtr]['comment_closer'];
$emptyTypeTokens = [
T_DOC_COMMENT_WHITESPACE,
@@ -111,7 +111,7 @@ public function process(File $phpcsFile, $stackPtr)
} else {
$this->annotationFormatValidator->validateDescriptionFormatStructure(
$phpcsFile,
- $commentStartPtr,
+ (int)$commentStartPtr,
(int) $shortPtr,
$previousCommentClosePtr,
$emptyTypeTokens
diff --git a/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodAnnotationStructureSniff.php b/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodAnnotationStructureSniff.php
index 445671d245e03..f05ae64a170d7 100644
--- a/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodAnnotationStructureSniff.php
+++ b/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodAnnotationStructureSniff.php
@@ -75,6 +75,7 @@ public function process(File $phpcsFile, $stackPtr)
$emptyTypeTokens
);
$this->annotationFormatValidator->validateTagGroupingFormat($phpcsFile, $commentStartPtr);
+ $this->annotationFormatValidator->validateTagAligningFormat($phpcsFile, $commentStartPtr);
}
}
}
diff --git a/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodArgumentsSniff.php b/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodArgumentsSniff.php
index 879334d8c553b..50efca9b1ed23 100644
--- a/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodArgumentsSniff.php
+++ b/dev/tests/static/framework/Magento/Sniffs/Annotation/MethodArgumentsSniff.php
@@ -8,8 +8,8 @@
namespace Magento\Sniffs\Annotation;
-use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;
+use PHP_CodeSniffer\Sniffs\Sniff;
/**
* Sniff to validate method arguments annotations
@@ -42,7 +42,7 @@ class MethodArgumentsSniff implements Sniff
/**
* @inheritdoc
*/
- public function register() : array
+ public function register(): array
{
return [
T_FUNCTION
@@ -55,7 +55,7 @@ public function register() : array
* @param string $type
* @return bool
*/
- private function isTokenBeforeClosingCommentTagValid(string $type) : bool
+ private function isTokenBeforeClosingCommentTagValid(string $type): bool
{
return in_array($type, $this->validTokensBeforeClosingCommentTag);
}
@@ -68,7 +68,7 @@ private function isTokenBeforeClosingCommentTagValid(string $type) : bool
* @param int $stackPtr
* @return bool
*/
- private function validateCommentBlockExists(File $phpcsFile, int $previousCommentClosePtr, int $stackPtr) : bool
+ private function validateCommentBlockExists(File $phpcsFile, int $previousCommentClosePtr, int $stackPtr): bool
{
$tokens = $phpcsFile->getTokens();
for ($tempPtr = $previousCommentClosePtr + 1; $tempPtr < $stackPtr; $tempPtr++) {
@@ -85,7 +85,7 @@ private function validateCommentBlockExists(File $phpcsFile, int $previousCommen
* @param string $type
* @return bool
*/
- private function isInvalidType(string $type) : bool
+ private function isInvalidType(string $type): bool
{
return in_array(strtolower($type), $this->invalidTypes);
}
@@ -98,7 +98,7 @@ private function isInvalidType(string $type) : bool
* @param int $closedParenthesisPtr
* @return array
*/
- private function getMethodArguments(File $phpcsFile, int $openParenthesisPtr, int $closedParenthesisPtr) : array
+ private function getMethodArguments(File $phpcsFile, int $openParenthesisPtr, int $closedParenthesisPtr): array
{
$tokens = $phpcsFile->getTokens();
$methodArguments = [];
@@ -121,10 +121,11 @@ private function getMethodArguments(File $phpcsFile, int $openParenthesisPtr, in
* @param array $paramDefinitions
* @return array
*/
- private function getMethodParameters(array $paramDefinitions) : array
+ private function getMethodParameters(array $paramDefinitions): array
{
$paramName = [];
- for ($i = 0; $i < count($paramDefinitions); $i++) {
+ $paramCount = count($paramDefinitions);
+ for ($i = 0; $i < $paramCount; $i++) {
if (isset($paramDefinitions[$i]['paramName'])) {
$paramName[] = $paramDefinitions[$i]['paramName'];
}
@@ -143,7 +144,7 @@ private function validateInheritdocAnnotationWithoutBracesExists(
File $phpcsFile,
int $previousCommentOpenPtr,
int $previousCommentClosePtr
- ) : bool {
+ ): bool {
return $this->validateInheritdocAnnotationExists(
$phpcsFile,
$previousCommentOpenPtr,
@@ -163,7 +164,7 @@ private function validateInheritdocAnnotationWithBracesExists(
File $phpcsFile,
int $previousCommentOpenPtr,
int $previousCommentClosePtr
- ) : bool {
+ ): bool {
return $this->validateInheritdocAnnotationExists(
$phpcsFile,
$previousCommentOpenPtr,
@@ -186,7 +187,7 @@ private function validateInheritdocAnnotationExists(
int $previousCommentOpenPtr,
int $previousCommentClosePtr,
string $inheritdocAnnotation
- ) : bool {
+ ): bool {
$tokens = $phpcsFile->getTokens();
for ($ptr = $previousCommentOpenPtr; $ptr < $previousCommentClosePtr; $ptr++) {
if (strtolower($tokens[$ptr]['content']) === $inheritdocAnnotation) {
@@ -213,7 +214,7 @@ private function validateParameterAnnotationForArgumentExists(
int $previousCommentOpenPtr,
int $previousCommentClosePtr,
int $stackPtr
- ) : void {
+ ): void {
if ($argumentsCount > 0 && $parametersCount === 0) {
$inheritdocAnnotationWithoutBracesExists = $this->validateInheritdocAnnotationWithoutBracesExists(
$phpcsFile,
@@ -256,7 +257,7 @@ private function validateCommentBlockDoesnotHaveExtraParameterAnnotation(
int $argumentsCount,
int $parametersCount,
int $stackPtr
- ) : void {
+ ): void {
if ($argumentsCount < $parametersCount && $argumentsCount > 0) {
$phpcsFile->addFixableError(
'Extra @param found in method annotation',
@@ -287,10 +288,10 @@ private function validateArgumentNameInParameterAnnotationExists(
File $phpcsFile,
array $methodArguments,
array $paramDefinitions
- ) : void {
+ ): void {
$parameterNames = $this->getMethodParameters($paramDefinitions);
if (!in_array($methodArguments[$ptr], $parameterNames)) {
- $error = $methodArguments[$ptr]. ' parameter is missing in method annotation';
+ $error = $methodArguments[$ptr] . ' parameter is missing in method annotation';
$phpcsFile->addFixableError($error, $stackPtr, 'MethodArguments');
}
}
@@ -310,7 +311,7 @@ private function validateParameterPresentInMethodSignature(
array $methodArguments,
File $phpcsFile,
array $paramPointers
- ) : void {
+ ): void {
if (!in_array($paramDefinitionsArguments, $methodArguments)) {
$phpcsFile->addFixableError(
$paramDefinitionsArguments . ' parameter is missing in method arguments signature',
@@ -333,7 +334,7 @@ private function validateParameterOrderIsCorrect(
array $methodArguments,
File $phpcsFile,
array $paramPointers
- ) : void {
+ ): void {
$parameterNames = $this->getMethodParameters($paramDefinitions);
$paramDefinitionsCount = count($paramDefinitions);
for ($ptr = 0; $ptr < $paramDefinitionsCount; $ptr++) {
@@ -342,7 +343,7 @@ private function validateParameterOrderIsCorrect(
) {
if ($methodArguments[$ptr] != $parameterNames[$ptr]) {
$phpcsFile->addFixableError(
- $methodArguments[$ptr].' parameter is not in order',
+ $methodArguments[$ptr] . ' parameter is not in order',
$paramPointers[$ptr],
'MethodArguments'
);
@@ -366,15 +367,16 @@ private function validateDuplicateAnnotationDoesnotExists(
array $paramPointers,
File $phpcsFile,
array $methodArguments
- ) : void {
+ ): void {
$argumentsCount = count($methodArguments);
$parametersCount = count($paramPointers);
if ($argumentsCount <= $parametersCount && $argumentsCount > 0) {
$duplicateParameters = [];
- for ($i = 0; $i < sizeof($paramDefinitions); $i++) {
+ $paramCount = count($paramDefinitions);
+ for ($i = 0; $i < $paramCount; $i++) {
if (isset($paramDefinitions[$i]['paramName'])) {
$parameterContent = $paramDefinitions[$i]['paramName'];
- for ($j = $i + 1; $j < count($paramDefinitions); $j++) {
+ for ($j = $i + 1; $j < $paramCount; $j++) {
if (isset($paramDefinitions[$j]['paramName'])
&& $parameterContent === $paramDefinitions[$j]['paramName']
) {
@@ -408,7 +410,7 @@ private function validateParameterAnnotationFormatIsCorrect(
array $methodArguments,
array $paramDefinitions,
array $paramPointers
- ) : void {
+ ): void {
switch (count($paramDefinitions)) {
case 0:
$phpcsFile->addFixableError(
@@ -429,7 +431,7 @@ private function validateParameterAnnotationFormatIsCorrect(
case 2:
if ($this->isInvalidType($paramDefinitions[0])) {
$phpcsFile->addFixableError(
- $paramDefinitions[0].' is not a valid PHP type',
+ $paramDefinitions[0] . ' is not a valid PHP type',
$paramPointers[$ptr],
'MethodArguments'
);
@@ -451,7 +453,7 @@ private function validateParameterAnnotationFormatIsCorrect(
);
if ($this->isInvalidType($paramDefinitions[0])) {
$phpcsFile->addFixableError(
- $paramDefinitions[0].' is not a valid PHP type',
+ $paramDefinitions[0] . ' is not a valid PHP type',
$paramPointers[$ptr],
'MethodArguments'
);
@@ -480,7 +482,7 @@ private function validateMethodParameterAnnotations(
array $methodArguments,
int $previousCommentOpenPtr,
int $previousCommentClosePtr
- ) : void {
+ ): void {
$argumentCount = count($methodArguments);
$paramCount = count($paramPointers);
$this->validateParameterAnnotationForArgumentExists(
@@ -510,8 +512,14 @@ private function validateMethodParameterAnnotations(
$phpcsFile,
$paramPointers
);
- for ($ptr = 0; $ptr < count($methodArguments); $ptr++) {
- $tokens = $phpcsFile->getTokens();
+ $this->validateFormattingConsistency(
+ $paramDefinitions,
+ $methodArguments,
+ $phpcsFile,
+ $paramPointers
+ );
+ $tokens = $phpcsFile->getTokens();
+ for ($ptr = 0; $ptr < $argumentCount; $ptr++) {
if (isset($paramPointers[$ptr])) {
$this->validateArgumentNameInParameterAnnotationExists(
$stackPtr,
@@ -520,7 +528,7 @@ private function validateMethodParameterAnnotations(
$methodArguments,
$paramDefinitions
);
- $paramContent = $tokens[$paramPointers[$ptr]+2]['content'];
+ $paramContent = $tokens[$paramPointers[$ptr] + 2]['content'];
$paramContentExplode = explode(' ', $paramContent);
$this->validateParameterAnnotationFormatIsCorrect(
$ptr,
@@ -540,36 +548,40 @@ public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
$numTokens = count($tokens);
- $previousCommentOpenPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr-1, 0);
- $previousCommentClosePtr = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr-1, 0);
+ $previousCommentOpenPtr = $phpcsFile->findPrevious(T_DOC_COMMENT_OPEN_TAG, $stackPtr - 1, 0);
+ $previousCommentClosePtr = $phpcsFile->findPrevious(T_DOC_COMMENT_CLOSE_TAG, $stackPtr - 1, 0);
if (!$this->validateCommentBlockExists($phpcsFile, $previousCommentClosePtr, $stackPtr)) {
$phpcsFile->addError('Comment block is missing', $stackPtr, 'MethodArguments');
return;
}
- $openParenthesisPtr = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr+1, $numTokens);
- $closedParenthesisPtr = $phpcsFile->findNext(T_CLOSE_PARENTHESIS, $stackPtr+1, $numTokens);
+ $openParenthesisPtr = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr + 1, $numTokens);
+ $closedParenthesisPtr = $phpcsFile->findNext(T_CLOSE_PARENTHESIS, $stackPtr + 1, $numTokens);
$methodArguments = $this->getMethodArguments($phpcsFile, $openParenthesisPtr, $closedParenthesisPtr);
$paramPointers = $paramDefinitions = [];
for ($tempPtr = $previousCommentOpenPtr; $tempPtr < $previousCommentClosePtr; $tempPtr++) {
if (strtolower($tokens[$tempPtr]['content']) === '@param') {
$paramPointers[] = $tempPtr;
- $paramAnnotationParts = explode(' ', $tokens[$tempPtr+2]['content']);
+ $content = preg_replace('/\s+/', ' ', $tokens[$tempPtr + 2]['content'], 2);
+ $paramAnnotationParts = explode(' ', $content, 3);
if (count($paramAnnotationParts) === 1) {
if ((preg_match('/^\$.*/', $paramAnnotationParts[0]))) {
$paramDefinitions[] = [
'type' => null,
- 'paramName' => rtrim(ltrim($tokens[$tempPtr+2]['content'], '&'), ',')
+ 'paramName' => rtrim(ltrim($tokens[$tempPtr + 2]['content'], '&'), ','),
+ 'comment' => null
];
} else {
$paramDefinitions[] = [
- 'type' => $tokens[$tempPtr+2]['content'],
- 'paramName' => null
+ 'type' => $tokens[$tempPtr + 2]['content'],
+ 'paramName' => null,
+ 'comment' => null
];
}
} else {
$paramDefinitions[] = [
'type' => $paramAnnotationParts[0],
- 'paramName' => rtrim(ltrim($paramAnnotationParts[1], '&'), ',')
+ 'paramName' => rtrim(ltrim($paramAnnotationParts[1], '&'), ','),
+ 'comment' => $paramAnnotationParts[2] ?? null,
];
}
}
@@ -584,4 +596,81 @@ public function process(File $phpcsFile, $stackPtr)
$previousCommentClosePtr
);
}
+
+ /**
+ * Validates function params format consistency.
+ *
+ * @param array $paramDefinitions
+ * @param array $methodArguments
+ * @param File $phpcsFile
+ * @param array $paramPointers
+ *
+ * @see https://devdocs.magento.com/guides/v2.3/coding-standards/docblock-standard-general.html#format-consistency
+ */
+ private function validateFormattingConsistency(
+ array $paramDefinitions,
+ array $methodArguments,
+ File $phpcsFile,
+ array $paramPointers
+ ): void {
+ $argumentPositions = [];
+ $commentPositions = [];
+ $tokens = $phpcsFile->getTokens();
+ $argumentCount = count($methodArguments);
+ for ($ptr = 0; $ptr < $argumentCount; $ptr++) {
+ if (isset($paramPointers[$ptr])) {
+ $paramContent = $tokens[$paramPointers[$ptr] + 2]['content'];
+ $paramDefinition = $paramDefinitions[$ptr];
+ $argumentPositions[] = strpos($paramContent, $paramDefinition['paramName']);
+ $commentPositions[] = $paramDefinition['comment']
+ ? strpos($paramContent, $paramDefinition['comment']) : null;
+ }
+ }
+ if (!$this->allParamsAligned($argumentPositions, $commentPositions)
+ && !$this->noneParamsAligned($argumentPositions, $commentPositions, $paramDefinitions)) {
+ $phpcsFile->addFixableError(
+ 'Visual alignment must be consistent',
+ $paramPointers[0],
+ 'MethodArguments'
+ );
+ }
+ }
+
+ /**
+ * Check all params are aligned.
+ *
+ * @param array $argumentPositions
+ * @param array $commentPositions
+ * @return bool
+ */
+ private function allParamsAligned(array $argumentPositions, array $commentPositions): bool
+ {
+ return count(array_unique($argumentPositions)) === 1
+ && count(array_unique(array_filter($commentPositions))) <= 1;
+ }
+
+ /**
+ * Check none of params are aligned.
+ *
+ * @param array $argumentPositions
+ * @param array $commentPositions
+ * @param array $paramDefinitions
+ * @return bool
+ */
+ private function noneParamsAligned(array $argumentPositions, array $commentPositions, array $paramDefinitions): bool
+ {
+ $flag = true;
+ foreach ($argumentPositions as $index => $argumentPosition) {
+ $commentPosition = $commentPositions[$index];
+ $type = $paramDefinitions[$index]['type'];
+ $paramName = $paramDefinitions[$index]['paramName'];
+ if (($argumentPosition !== strlen($type) + 1) ||
+ (isset($commentPosition) && ($commentPosition !== $argumentPosition + strlen($paramName) + 1))) {
+ $flag = false;
+ break;
+ }
+ }
+
+ return $flag;
+ }
}
diff --git a/lib/internal/Magento/Framework/App/Action/HttpHeadActionInterface.php b/lib/internal/Magento/Framework/App/Action/HttpHeadActionInterface.php
index d2f9b70913c1f..389bd8089967b 100644
--- a/lib/internal/Magento/Framework/App/Action/HttpHeadActionInterface.php
+++ b/lib/internal/Magento/Framework/App/Action/HttpHeadActionInterface.php
@@ -12,6 +12,8 @@
/**
* Marker for actions processing HEAD requests.
+ *
+ * @deprecated Both GET and HEAD requests map to HttpGetActionInterface
*/
interface HttpHeadActionInterface extends ActionInterface
{
diff --git a/lib/internal/Magento/Framework/App/DocRootLocator.php b/lib/internal/Magento/Framework/App/DocRootLocator.php
index 6fb35c42f1330..d73baf8e4e742 100644
--- a/lib/internal/Magento/Framework/App/DocRootLocator.php
+++ b/lib/internal/Magento/Framework/App/DocRootLocator.php
@@ -3,10 +3,12 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
namespace Magento\Framework\App;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\ReadFactory;
/**
@@ -20,18 +22,26 @@ class DocRootLocator
private $request;
/**
+ * @deprecated
* @var ReadFactory
*/
private $readFactory;
+ /**
+ * @var Filesystem
+ */
+ private $filesystem;
+
/**
* @param RequestInterface $request
* @param ReadFactory $readFactory
+ * @param Filesystem|null $filesystem
*/
- public function __construct(RequestInterface $request, ReadFactory $readFactory)
+ public function __construct(RequestInterface $request, ReadFactory $readFactory, Filesystem $filesystem = null)
{
$this->request = $request;
$this->readFactory = $readFactory;
+ $this->filesystem = $filesystem ?: ObjectManager::getInstance()->get(Filesystem::class);
}
/**
@@ -42,7 +52,8 @@ public function __construct(RequestInterface $request, ReadFactory $readFactory)
public function isPub()
{
$rootBasePath = $this->request->getServer('DOCUMENT_ROOT');
- $readDirectory = $this->readFactory->create(DirectoryList::ROOT);
- return (substr($rootBasePath, -strlen('/pub')) === '/pub') && !$readDirectory->isExist($rootBasePath . 'setup');
+ $readDirectory = $this->filesystem->getDirectoryRead(DirectoryList::ROOT);
+
+ return (substr($rootBasePath, -\strlen('/pub')) === '/pub') && ! $readDirectory->isExist('setup');
}
}
diff --git a/lib/internal/Magento/Framework/App/Http.php b/lib/internal/Magento/Framework/App/Http.php
index 23024a44c2def..ca3976da1df52 100644
--- a/lib/internal/Magento/Framework/App/Http.php
+++ b/lib/internal/Magento/Framework/App/Http.php
@@ -3,17 +3,18 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Framework\App;
use Magento\Framework\App\Filesystem\DirectoryList;
-use Magento\Framework\Debug;
-use Magento\Framework\ObjectManager\ConfigLoaderInterface;
use Magento\Framework\App\Request\Http as RequestHttp;
use Magento\Framework\App\Response\Http as ResponseHttp;
use Magento\Framework\App\Response\HttpInterface;
use Magento\Framework\Controller\ResultInterface;
+use Magento\Framework\Debug;
use Magento\Framework\Event;
use Magento\Framework\Filesystem;
+use Magento\Framework\ObjectManager\ConfigLoaderInterface;
/**
* HTTP web application. Called from webroot index.php to serve web requests.
@@ -143,12 +144,31 @@ public function launch()
} else {
throw new \InvalidArgumentException('Invalid return type');
}
+ if ($this->_request->isHead() && $this->_response->getHttpResponseCode() == 200) {
+ $this->handleHeadRequest();
+ }
// This event gives possibility to launch something before sending output (allow cookie setting)
$eventParams = ['request' => $this->_request, 'response' => $this->_response];
$this->_eventManager->dispatch('controller_front_send_response_before', $eventParams);
return $this->_response;
}
+ /**
+ * Handle HEAD requests by adding the Content-Length header and removing the body from the response.
+ *
+ * @return void
+ */
+ private function handleHeadRequest()
+ {
+ // It is possible that some PHP installations have overloaded strlen to use mb_strlen instead.
+ // This means strlen might return the actual number of characters in a non-ascii string instead
+ // of the number of bytes. Use mb_strlen explicitly with a single byte character encoding to ensure
+ // that the content length is calculated in bytes.
+ $contentLength = mb_strlen($this->_response->getContent(), '8bit');
+ $this->_response->clearBody();
+ $this->_response->setHeader('Content-Length', $contentLength);
+ }
+
/**
* @inheritdoc
*/
@@ -248,7 +268,7 @@ private function redirectToSetup(Bootstrap $bootstrap, \Exception $exception)
. "because the Magento setup directory cannot be accessed. \n"
. 'You can install Magento using either the command line or you must restore access '
. 'to the following directory: ' . $setupInfo->getDir($projectRoot) . "\n";
-
+ // phpcs:ignore Magento2.Exceptions.DirectThrow
throw new \Exception($newMessage, 0, $exception);
}
}
@@ -257,13 +277,14 @@ private function redirectToSetup(Bootstrap $bootstrap, \Exception $exception)
* Handler for bootstrap errors
*
* @param Bootstrap $bootstrap
- * @param \Exception &$exception
+ * @param \Exception $exception
* @return bool
*/
private function handleBootstrapErrors(Bootstrap $bootstrap, \Exception &$exception)
{
$bootstrapCode = $bootstrap->getErrorCode();
if (Bootstrap::ERR_MAINTENANCE == $bootstrapCode) {
+ // phpcs:ignore Magento2.Security.IncludeFile
require $this->_filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/503.php');
return true;
}
@@ -304,6 +325,7 @@ private function handleInitException(\Exception $exception)
{
if ($exception instanceof \Magento\Framework\Exception\State\InitException) {
$this->getLogger()->critical($exception);
+ // phpcs:ignore Magento2.Security.IncludeFile
require $this->_filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/404.php');
return true;
}
@@ -335,6 +357,7 @@ private function handleGenericReport(Bootstrap $bootstrap, \Exception $exception
if (isset($params['SCRIPT_NAME'])) {
$reportData['script_name'] = $params['SCRIPT_NAME'];
}
+ // phpcs:ignore Magento2.Security.IncludeFile
require $this->_filesystem->getDirectoryRead(DirectoryList::PUB)->getAbsolutePath('errors/report.php');
return true;
}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DocRootLocatorTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DocRootLocatorTest.php
index 23afbbc73d2b9..ef4152ba2e49e 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/DocRootLocatorTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DocRootLocatorTest.php
@@ -8,6 +8,9 @@
use Magento\Framework\App\DocRootLocator;
+/**
+ * Test for Magento\Framework\App\DocRootLocator class.
+ */
class DocRootLocatorTest extends \PHPUnit\Framework\TestCase
{
/**
@@ -21,11 +24,15 @@ public function testIsPub($path, $isExist, $result)
{
$request = $this->createMock(\Magento\Framework\App\Request\Http::class);
$request->expects($this->once())->method('getServer')->willReturn($path);
+
+ $readFactory = $this->createMock(\Magento\Framework\Filesystem\Directory\ReadFactory::class);
+
$reader = $this->createMock(\Magento\Framework\Filesystem\Directory\Read::class);
+ $filesystem = $this->createMock(\Magento\Framework\Filesystem::class);
+ $filesystem->expects($this->once())->method('getDirectoryRead')->willReturn($reader);
$reader->expects($this->any())->method('isExist')->willReturn($isExist);
- $readFactory = $this->createMock(\Magento\Framework\Filesystem\Directory\ReadFactory::class);
- $readFactory->expects($this->once())->method('create')->willReturn($reader);
- $model = new DocRootLocator($request, $readFactory);
+
+ $model = new DocRootLocator($request, $readFactory, $filesystem);
$this->assertSame($result, $model->isPub());
}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php b/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php
index a299e04e152cc..dbb315e88a526 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/HttpTest.php
@@ -92,7 +92,7 @@ protected function setUp()
'pathInfoProcessor' => $pathInfoProcessorMock,
'objectManager' => $objectManagerMock
])
- ->setMethods(['getFrontName'])
+ ->setMethods(['getFrontName', 'isHead'])
->getMock();
$this->areaListMock = $this->getMockBuilder(\Magento\Framework\App\AreaList::class)
->disableOriginalConstructor()
@@ -135,12 +135,17 @@ private function setUpLaunch()
{
$frontName = 'frontName';
$areaCode = 'areaCode';
- $this->requestMock->expects($this->once())->method('getFrontName')->will($this->returnValue($frontName));
+ $this->requestMock->expects($this->once())
+ ->method('getFrontName')
+ ->willReturn($frontName);
$this->areaListMock->expects($this->once())
->method('getCodeByFrontName')
- ->with($frontName)->will($this->returnValue($areaCode));
+ ->with($frontName)
+ ->willReturn($areaCode);
$this->configLoaderMock->expects($this->once())
- ->method('load')->with($areaCode)->will($this->returnValue([]));
+ ->method('load')
+ ->with($areaCode)
+ ->willReturn([]);
$this->objectManagerMock->expects($this->once())->method('configure')->with([]);
$this->objectManagerMock->expects($this->once())
->method('get')
@@ -149,12 +154,15 @@ private function setUpLaunch()
$this->frontControllerMock->expects($this->once())
->method('dispatch')
->with($this->requestMock)
- ->will($this->returnValue($this->responseMock));
+ ->willReturn($this->responseMock);
}
public function testLaunchSuccess()
{
$this->setUpLaunch();
+ $this->requestMock->expects($this->once())
+ ->method('isHead')
+ ->willReturn(false);
$this->eventManagerMock->expects($this->once())
->method('dispatch')
->with(
@@ -171,33 +179,101 @@ public function testLaunchSuccess()
public function testLaunchException()
{
$this->setUpLaunch();
- $this->frontControllerMock->expects($this->once())->method('dispatch')->with($this->requestMock)->will(
- $this->returnCallback(
- function () {
- throw new \Exception('Message');
- }
- )
- );
+ $this->frontControllerMock->expects($this->once())
+ ->method('dispatch')
+ ->with($this->requestMock)
+ ->willThrowException(
+ new \Exception('Message')
+ );
$this->http->launch();
}
+ /**
+ * Test that HEAD requests lead to an empty body and a Content-Length header matching the original body size.
+ * @dataProvider dataProviderForTestLaunchHeadRequest
+ * @param string $body
+ * @param int $expectedLength
+ */
+ public function testLaunchHeadRequest($body, $expectedLength)
+ {
+ $this->setUpLaunch();
+ $this->requestMock->expects($this->once())
+ ->method('isHead')
+ ->willReturn(true);
+ $this->responseMock->expects($this->once())
+ ->method('getHttpResponseCode')
+ ->willReturn(200);
+ $this->responseMock->expects($this->once())
+ ->method('getContent')
+ ->willReturn($body);
+ $this->responseMock->expects($this->once())
+ ->method('clearBody')
+ ->willReturn($this->responseMock);
+ $this->responseMock->expects($this->once())
+ ->method('setHeader')
+ ->with('Content-Length', $expectedLength)
+ ->willReturn($this->responseMock);
+ $this->eventManagerMock->expects($this->once())
+ ->method('dispatch')
+ ->with(
+ 'controller_front_send_response_before',
+ ['request' => $this->requestMock, 'response' => $this->responseMock]
+ );
+ $this->assertSame($this->responseMock, $this->http->launch());
+ }
+
+ /**
+ * Different test content for responseMock with their expected lengths in bytes.
+ * @return array
+ */
+ public function dataProviderForTestLaunchHeadRequest(): array
+ {
+ return [
+ [
+ "