diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php index a92df095036f3..fda6ae9530135 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php @@ -104,7 +104,6 @@ class AdvancedPricing extends \Magento\CatalogImportExport\Model\Export\Product * @param \Magento\CatalogImportExport\Model\Export\RowCustomizerInterface $rowCustomizer * @param ImportProduct\StoreResolver $storeResolver * @param \Magento\Customer\Api\GroupRepositoryInterface $groupRepository - * @throws \Magento\Framework\Exception\LocalizedException * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -193,6 +192,7 @@ protected function initTypeModels() * Export process * * @return string + * @throws \Magento\Framework\Exception\LocalizedException */ public function export() { @@ -586,8 +586,8 @@ protected function getTierPrices(array $listSku, $table) * Get Website code. * * @param int $websiteId - * * @return string + * @throws \Magento\Framework\Exception\LocalizedException */ protected function _getWebsiteCode(int $websiteId): string { @@ -617,8 +617,9 @@ protected function _getWebsiteCode(int $websiteId): string * * @param int $groupId * @param int $allGroups - * * @return string + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException */ protected function _getCustomerGroupById( int $groupId, diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php index 4663aea7a7dfc..2e17e734b1e60 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing.php @@ -8,7 +8,6 @@ use Magento\CatalogImportExport\Model\Import\Product as ImportProduct; use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as ValidatorInterface; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; -use Magento\Framework\App\ResourceConnection; /** * Class AdvancedPricing @@ -618,6 +617,7 @@ protected function processCountNewPrices(array $tierPrices) * Get product entity link field * * @return string + * @throws \Exception */ private function getProductEntityLinkField() { diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php index 25a9fc244fe51..d939a3f7c392e 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Import/AdvancedPricing/Validator.php @@ -28,6 +28,7 @@ public function __construct($validators = []) * * @param array $value * @return bool + * @throws \Zend_Validate_Exception */ public function isValid($value) { diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Export/AdvancedPricingTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Export/AdvancedPricingTest.php index 48b4c58918740..6b266c76c32f3 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Export/AdvancedPricingTest.php +++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Export/AdvancedPricingTest.php @@ -151,10 +151,13 @@ protected function setUp() ] ); $this->exportConfig = $this->createMock(\Magento\ImportExport\Model\Export\Config::class); - $this->productFactory = $this->createPartialMock(\Magento\Catalog\Model\ResourceModel\ProductFactory::class, [ + $this->productFactory = $this->createPartialMock( + \Magento\Catalog\Model\ResourceModel\ProductFactory::class, + [ 'create', 'getTypeId', - ]); + ] + ); $this->attrSetColFactory = $this->createPartialMock( \Magento\Eav\Model\ResourceModel\Entity\Attribute\Set\CollectionFactory::class, [ @@ -185,11 +188,14 @@ protected function setUp() \Magento\CatalogImportExport\Model\Import\Product\StoreResolver::class ); $this->groupRepository = $this->createMock(\Magento\Customer\Api\GroupRepositoryInterface::class); - $this->writer = $this->createPartialMock(\Magento\ImportExport\Model\Export\Adapter\AbstractAdapter::class, [ - 'setHeaderCols', - 'writeRow', - 'getContents', - ]); + $this->writer = $this->createPartialMock( + \Magento\ImportExport\Model\Export\Adapter\AbstractAdapter::class, + [ + 'setHeaderCols', + 'writeRow', + 'getContents', + ] + ); $constructorMethods = [ 'initTypeModels', 'initAttributes', @@ -347,6 +353,7 @@ protected function tearDown() * @param $object * @param $property * @return mixed + * @throws \ReflectionException */ protected function getPropertyValue($object, $property) { @@ -362,6 +369,8 @@ protected function getPropertyValue($object, $property) * @param $object * @param $property * @param $value + * @return mixed + * @throws \ReflectionException */ protected function setPropertyValue(&$object, $property, $value) { diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php index 7a81ccae6f0d0..2c930237da831 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php +++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricing/Validator/TierPriceTest.php @@ -346,6 +346,7 @@ public function isValidAddMessagesCallDataProvider() * @param object $object * @param string $property * @return mixed + * @throws \ReflectionException */ protected function getPropertyValue($object, $property) { @@ -363,6 +364,7 @@ protected function getPropertyValue($object, $property) * @param string $property * @param mixed $value * @return object + * @throws \ReflectionException */ protected function setPropertyValue(&$object, $property, $value) { diff --git a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php index 08743b9fa7f2c..340e81746f029 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php +++ b/app/code/Magento/AdvancedPricingImportExport/Test/Unit/Model/Import/AdvancedPricingTest.php @@ -209,6 +209,10 @@ public function testGetEntityTypeCode() * Test method validateRow against its result. * * @dataProvider validateRowResultDataProvider + * @param array $rowData + * @param string|null $behavior + * @param bool $expectedResult + * @throws \ReflectionException */ public function testValidateRowResult($rowData, $behavior, $expectedResult) { @@ -234,6 +238,10 @@ public function testValidateRowResult($rowData, $behavior, $expectedResult) * Test method validateRow whether AddRowError is called. * * @dataProvider validateRowAddRowErrorCallDataProvider + * @param array $rowData + * @param string|null $behavior + * @param string $error + * @throws \ReflectionException */ public function testValidateRowAddRowErrorCall($rowData, $behavior, $error) { @@ -324,6 +332,13 @@ public function testSaveAdvancedPricing() * Take into consideration different data and check relative internal calls. * * @dataProvider saveAndReplaceAdvancedPricesAppendBehaviourDataProvider + * @param array $data + * @param string $tierCustomerGroupId + * @param string $groupCustomerGroupId + * @param string $tierWebsiteId + * @param string $groupWebsiteId + * @param array $expectedTierPrices + * @throws \ReflectionException */ public function testSaveAndReplaceAdvancedPricesAppendBehaviourDataAndCalls( $data, @@ -956,6 +971,7 @@ public function processCountExistingPricesDataProvider() * @param $object * @param $property * @return mixed + * @throws \ReflectionException */ protected function getPropertyValue($object, $property) { @@ -972,6 +988,8 @@ protected function getPropertyValue($object, $property) * @param $object * @param $property * @param $value + * @return mixed + * @throws \ReflectionException */ protected function setPropertyValue(&$object, $property, $value) { @@ -989,8 +1007,8 @@ protected function setPropertyValue(&$object, $property, $value) * @param object $object * @param string $method * @param array $args - * - * @return mixed the method result. + * @return mixed + * @throws \ReflectionException */ private function invokeMethod($object, $method, $args = []) { @@ -1007,6 +1025,7 @@ private function invokeMethod($object, $method, $args = []) * @param array $methods * * @return \PHPUnit_Framework_MockObject_MockObject + * @throws \ReflectionException */ private function getAdvancedPricingMock($methods = []) { diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index f5e05cbc3e212..17ecba545efad 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -534,12 +534,12 @@ public function updateQtyOption($options, \Magento\Framework\DataObject $option, foreach ($selections as $selection) { if ($selection->getProductId() == $optionProduct->getId()) { - foreach ($options as &$option) { - if ($option->getCode() == 'selection_qty_' . $selection->getSelectionId()) { + foreach ($options as $quoteItemOption) { + if ($quoteItemOption->getCode() == 'selection_qty_' . $selection->getSelectionId()) { if ($optionUpdateFlag) { - $option->setValue(intval($option->getValue())); + $quoteItemOption->setValue(intval($quoteItemOption->getValue())); } else { - $option->setValue($value); + $quoteItemOption->setValue($value); } } } diff --git a/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php b/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php index d582005f653ef..181211a0fc4a2 100644 --- a/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php +++ b/app/code/Magento/Catalog/Block/Product/View/Options/AbstractOptions.php @@ -105,9 +105,11 @@ public function getOption() } /** + * Retrieve formatted price + * * @return string */ - public function getFormatedPrice() + public function getFormattedPrice() { if ($option = $this->getOption()) { return $this->_formatPrice( @@ -120,6 +122,17 @@ public function getFormatedPrice() return ''; } + /** + * @return string + * + * @deprecated + * @see getFormattedPrice() + */ + public function getFormatedPrice() + { + return $this->getFormattedPrice(); + } + /** * Return formated price * diff --git a/app/code/Magento/Catalog/Block/Product/View/Price.php b/app/code/Magento/Catalog/Block/Product/View/Price.php index c38625247b533..37598dfb1a8da 100644 --- a/app/code/Magento/Catalog/Block/Product/View/Price.php +++ b/app/code/Magento/Catalog/Block/Product/View/Price.php @@ -9,6 +9,8 @@ */ namespace Magento\Catalog\Block\Product\View; +use Magento\Catalog\Model\Product; + class Price extends \Magento\Framework\View\Element\Template { /** @@ -37,7 +39,8 @@ public function __construct( */ public function getPrice() { + /** @var Product $product */ $product = $this->_coreRegistry->registry('product'); - return $product->getFormatedPrice(); + return $product->getFormattedPrice(); } } diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index f514e5c68769e..90af9bee270bd 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -1124,11 +1124,24 @@ public function getTierPrice($qty = null) /** * Get formatted by currency product price * - * @return array || double + * @return array|double + */ + public function getFormattedPrice() + { + return $this->getPriceModel()->getFormattedPrice($this); + } + + /** + * Get formatted by currency product price + * + * @return array|double + * + * @deprecated + * @see getFormattedPrice() */ public function getFormatedPrice() { - return $this->getPriceModel()->getFormatedPrice($this); + return $this->getFormattedPrice(); } /** diff --git a/app/code/Magento/Catalog/Model/Product/Type/Price.php b/app/code/Magento/Catalog/Model/Product/Type/Price.php index 7eaedf77eb859..f6caa299d66d7 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/Price.php +++ b/app/code/Magento/Catalog/Model/Product/Type/Price.php @@ -474,14 +474,15 @@ public function getTierPriceCount($product) * * @param float $qty * @param Product $product + * * @return array|float */ - public function getFormatedTierPrice($qty, $product) + public function getFormattedTierPrice($qty, $product) { $price = $product->getTierPrice($qty); if (is_array($price)) { foreach (array_keys($price) as $index) { - $price[$index]['formated_price'] = $this->priceCurrency->convertAndFormat( + $price[$index]['formatted_price'] = $this->priceCurrency->convertAndFormat( $price[$index]['website_price'] ); } @@ -492,15 +493,45 @@ public function getFormatedTierPrice($qty, $product) return $price; } + /** + * Get formatted by currency tier price + * + * @param float $qty + * @param Product $product + * + * @return array|float + * + * @deprecated + * @see getFormattedTierPrice() + */ + public function getFormatedTierPrice($qty, $product) + { + return $this->getFormattedTierPrice($qty, $product); + } + + /** + * Get formatted by currency product price + * + * @param Product $product + * @return array|float + */ + public function getFormattedPrice($product) + { + return $this->priceCurrency->format($product->getFinalPrice()); + } + /** * Get formatted by currency product price * * @param Product $product * @return array || float + * + * @deprecated + * @see getFormattedPrice() */ public function getFormatedPrice($product) { - return $this->priceCurrency->format($product->getFinalPrice()); + return $this->getFormattedPrice($product); } /** diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml index 0166d15e226c0..5ed2bd5f75c01 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/SaveProductWithCustomOptionsSecondWebsiteTest.xml @@ -34,6 +34,7 @@ + diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml index 8e5583a6699b7..30c05c2ec689b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/date.phtml @@ -13,7 +13,7 @@
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml index edf4f68afded7..4ad7a95c91980 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/file.phtml @@ -7,6 +7,7 @@ // @codingStandardsIgnoreFile ?> + getOption(); ?> getFileInfo(); ?> hasData() ? true : false; ?> @@ -64,7 +65,7 @@ require(['prototype'], function(){
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/text.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/text.phtml index 14e485c6445e0..11fba22ea8139 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/text.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/composite/fieldset/options/type/text.phtml @@ -12,7 +12,7 @@
getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_FIELD): ?> diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/date.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/date.phtml index 3420512977aad..66895fa1eabf9 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/date.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/date.phtml @@ -7,6 +7,7 @@ // @codingStandardsIgnoreFile ?> + getOption() ?> getId() ?> getIsRequire()) ? ' required' : ''; ?> @@ -15,7 +16,7 @@
escapeHtml($_option->getTitle()) ?> - getFormatedPrice() ?> + getFormattedPrice() ?>
getType() == \Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_TYPE_DATE_TIME diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/file.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/file.phtml index 3ceba2eebd214..adb729c6d86ec 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/file.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/file.phtml @@ -7,6 +7,7 @@ // @codingStandardsIgnoreFile ?> + getOption(); ?> getFileInfo(); ?> hasData(); ?> @@ -19,7 +20,7 @@
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/text.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/text.phtml index 852e0095f2f66..a04e366a43a2d 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/text.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/options/type/text.phtml @@ -7,6 +7,7 @@ // @codingStandardsIgnoreFile ?> + getOption(); $class = ($_option->getIsRequire()) ? ' required' : ''; @@ -17,7 +18,7 @@ $class = ($_option->getIsRequire()) ? ' required' : ''; } ?>">
diff --git a/app/code/Magento/Checkout/i18n/en_US.csv b/app/code/Magento/Checkout/i18n/en_US.csv index 53fdebb8a2995..2dcb611c1fe60 100644 --- a/app/code/Magento/Checkout/i18n/en_US.csv +++ b/app/code/Magento/Checkout/i18n/en_US.csv @@ -177,3 +177,7 @@ Payment,Payment "We received your order!","We received your order!" "Thank you for your purchase!","Thank you for your purchase!" "Password", "Password" +"Something went wrong while saving the page. Please refresh the page and try again.","Something went wrong while saving the page. Please refresh the page and try again." +"Item in Cart","Item in Cart" +"Items in Cart","Items in Cart" +"Close","Close" diff --git a/app/code/Magento/Checkout/view/frontend/web/template/form/element/email.html b/app/code/Magento/Checkout/view/frontend/web/template/form/element/email.html index bb68e24835b67..8d6142e07fcf0 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/form/element/email.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/form/element/email.html @@ -22,7 +22,8 @@ type="email" data-bind=" textInput: email, - hasFocus: emailFocused" + hasFocus: emailFocused, + mageInit: {'mage/trim-input':{}}" name="username" data-validate="{required:true, 'validate-email':true}" id="customer-email" /> diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml new file mode 100644 index 0000000000000..7bb2441a6a529 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/ConfigSalesTaxClassActionGroup.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml b/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml index e517f6ef62c7a..c24e578c9109c 100644 --- a/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml +++ b/app/code/Magento/Config/Test/Mftf/Page/AdminConfigPage.xml @@ -12,4 +12,7 @@
+ +
+ diff --git a/app/code/Magento/Config/Test/Mftf/Section/SalesConfigSection.xml b/app/code/Magento/Config/Test/Mftf/Section/SalesConfigSection.xml new file mode 100644 index 0000000000000..f1520f5813e6d --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Section/SalesConfigSection.xml @@ -0,0 +1,17 @@ + + + + +
+ + + + +
+
\ No newline at end of file diff --git a/app/code/Magento/Customer/view/frontend/templates/form/forgotpassword.phtml b/app/code/Magento/Customer/view/frontend/templates/form/forgotpassword.phtml index 5bc4a929d6d94..f8eb0bd44b681 100644 --- a/app/code/Magento/Customer/view/frontend/templates/form/forgotpassword.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/form/forgotpassword.phtml @@ -20,7 +20,7 @@ getChildHtml('form_additional_info') ?> diff --git a/app/code/Magento/Developer/Model/Di/PluginList.php b/app/code/Magento/Developer/Model/Di/PluginList.php index 0a1df8a974242..fc342b5051000 100644 --- a/app/code/Magento/Developer/Model/Di/PluginList.php +++ b/app/code/Magento/Developer/Model/Di/PluginList.php @@ -145,7 +145,10 @@ private function addPluginToList($pluginInstance, $pluginMethod, $methodTypes, $ if (!array_key_exists($pluginInstance, $this->pluginList[$this->pluginTypeMapping[$typeCode]])) { $this->pluginList[$this->pluginTypeMapping[$typeCode]][$pluginInstance] = []; } - $this->pluginList[$this->pluginTypeMapping[$typeCode]][$pluginInstance][] = $pluginMethod ; + + if (!in_array($pluginMethod, $this->pluginList[$this->pluginTypeMapping[$typeCode]][$pluginInstance])) { + $this->pluginList[$this->pluginTypeMapping[$typeCode]][$pluginInstance][] = $pluginMethod; + } } } } diff --git a/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml b/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml index b633c61d9dc35..b2e0edbf04452 100644 --- a/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml +++ b/app/code/Magento/Newsletter/view/frontend/templates/subscribe.phtml @@ -23,6 +23,7 @@
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Discount.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Discount.php index bb173f4010311..0cc4143e569db 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Discount.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Discount.php @@ -25,7 +25,7 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) * Calculate how much shipping discount should be applied * basing on how much shipping should be refunded. */ - $baseShippingAmount = (float)$creditmemo->getBaseShippingAmount(); + $baseShippingAmount = $this->getBaseShippingAmount($creditmemo); if ($baseShippingAmount) { $baseShippingDiscount = $baseShippingAmount * $order->getBaseShippingDiscountAmount() / @@ -75,4 +75,21 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $creditmemo->setBaseGrandTotal($creditmemo->getBaseGrandTotal() - $baseTotalDiscountAmount); return $this; } + + /** + * Get base shipping amount + * + * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo + * @return float + */ + private function getBaseShippingAmount(\Magento\Sales\Model\Order\Creditmemo $creditmemo): float + { + $baseShippingAmount = (float)$creditmemo->getBaseShippingAmount(); + if (!$baseShippingAmount) { + $baseShippingInclTax = (float)$creditmemo->getBaseShippingInclTax(); + $baseShippingTaxAmount = (float)$creditmemo->getBaseShippingTaxAmount(); + $baseShippingAmount = $baseShippingInclTax - $baseShippingTaxAmount; + } + return $baseShippingAmount; + } } diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php index 92d00d0436634..f06da0de0fd00 100644 --- a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php +++ b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php @@ -138,7 +138,7 @@ protected function prepareTemplate(Order $order) */ $this->eventManager->dispatch( 'email_order_set_template_vars_before', - ['sender' => $this, 'transport' => $transportObject->getData(), 'transportObject' => $transportObject] + ['sender' => $this, 'transport' => $transportObject, 'transportObject' => $transportObject] ); $this->templateContainer->setTemplateVars($transportObject->getData()); diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml new file mode 100644 index 0000000000000..26139f7182bab --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml @@ -0,0 +1,136 @@ + + + + + + + + + <description value="Verify credit memo grand total after shipping discount is applied via Cart Price Rule"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-92924"/> + <group value="sales"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <actionGroup ref="LoginActionGroup" stepKey="loginAsAdmin"/> + <actionGroup ref="SetTaxClassForShipping" stepKey="setShippingTaxClass"/> + </before> + <after> + <actionGroup ref="ResetTaxClassForShipping" stepKey="resetTaxClassForShipping"/> + <actionGroup ref="DeleteCartPriceRuleByName" stepKey="deleteSalesRule"> + <argument name="ruleName" value="{{ApiSalesRule.name}}"/> + </actionGroup> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="createCategory" stepKey="deleteProduct1"/> + <deleteData createDataKey="createProduct" stepKey="deleteCategory1"/> + </after> + + <!-- Create a cart price rule for $10 Fixed amount discount --> + <amOnPage url="{{AdminCartPriceRulesPage.url}}" stepKey="amOnCartPriceList"/> + <waitForPageLoad stepKey="waitForRulesPage"/> + <click selector="{{AdminCartPriceRulesSection.addNewRuleButton}}" stepKey="clickAddNewRule"/> + <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{ApiSalesRule.name}}" stepKey="fillRuleName"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" stepKey="selectWebsite"/> + <actionGroup ref="selectNotLoggedInCustomerGroup" stepKey="chooseNotLoggedInCustomerGroup"/> + <!--<selectOption selector="{{AdminCartPriceRulesFormSection.customerGroups}}" userInput="NOT LOGGED IN" stepKey="selectCustomerGroup"/>--> + + <!-- Open the Actions Tab in the Rules Edit page --> + <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions"/> + <waitForElementVisible selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="waitForElementToBeVisible"/> + <click selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="enableApplyDiscountToShiping"/> + <seeCheckboxIsChecked selector="{{AdminCartPriceRulesFormSection.applyDiscountToShipping}}" stepKey="DiscountIsAppliedToShiping"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Fixed amount discount" stepKey="selectActionType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="10" stepKey="fillDiscountAmount"/> + + <!--<scrollTo selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="scrollToShippingLabel"/>--> + <!--<click selector="{{AdminCartPriceRulesFormSection.applyDiscountToShippingLabel}}" stepKey="enableApplyDiscountToShiping"/>--> + <!--<seeCheckboxIsChecked selector="{{AdminCartPriceRulesFormSection.applyDiscountToShipping}}" stepKey="DiscountIsAppliedToShiping"/>--> + <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> + <see selector="{{AdminCartPriceRulesSection.messages}}" userInput="You saved the rule." stepKey="seeSuccessMessage"/> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + + <!-- Place an order from Storefront as a Guest --> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverOverProduct"/> + <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductToAdd"/> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/> + <click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <!-- fill out customer information --> + <fillField selector="{{CheckoutShippingGuestInfoSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="enterEmail"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.street}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.city}}" userInput="{{CustomerAddressSimple.city}}" stepKey="enterCity"/> + <selectOption selector="{{CheckoutShippingGuestInfoSection.region}}" userInput="{{CustomerAddressSimple.state}}" stepKey="selectRegion"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.postcode}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="enterPostcode"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.telephone}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="enterTelephone"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + + <!-- Choose Shippping - Flat Rate Shipping --> + <click selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask2"/> + <waitForElement selector="{{CheckoutShippingMethodsSection.next}}" time="30" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/> + <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + + <!-- Search for Order in the order grid --> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask3"/> + <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="searchOrderNum"/> + <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearch"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask4"/> + + <!-- Create invoice --> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceButton"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seeNewInvoiceInPageTitle" after="clickInvoiceButton"/> + + <!-- Verify Invoice Totals including subTotal Shipping Discount and GrandTotal --> + <see selector="{{AdminInvoiceTotalSection.total('Subtotal')}}" userInput="${{AdminOrderSimpleProduct.subtotal}}" stepKey="seeInvoiceSubTotal"/> + <comment userInput="Shipping and Handling" stepKey="commentViewShippingAndHandling" after="seeInvoiceSubTotal"/> + <see selector="{{AdminInvoiceTotalSection.total('Shipping')}}" userInput="${{AdminOrderSimpleProduct.shipping}}" stepKey="seeShippingAndHandling"/> + <scrollTo selector="{{AdminInvoiceTotalSection.total('Shipping')}}" stepKey="scrollToInvoiceTotals"/> + <grabTextFrom selector="{{AdminInvoiceTotalSection.total('Shipping')}}" stepKey="grabShippingCost"/> + <assertEquals expected='$5.00' expectedType="string" actual="($grabShippingCost)" message="ExpectedShipping" stepKey="assertShippingAndHandling"/> + + <see selector="{{AdminInvoiceTotalSection.total('Discount')}}" userInput="-$15.00" stepKey="seeShippingAndHandling2"/> + <grabTextFrom selector="{{AdminInvoiceTotalSection.total('Discount')}}" stepKey="grabInvoiceDiscount"/> + <assertEquals expected='-$15.00' expectedType="string" actual="($grabInvoiceDiscount)" message="ExpectedDiscount" stepKey="assertDiscountValue"/> + + <see selector="{{AdminInvoiceTotalSection.grandTotal}}" userInput="$113.00" stepKey="seeCorrectGrandTotal"/> + <grabTextFrom selector="{{AdminInvoiceTotalSection.grandTotal}}" stepKey="grabInvoiceGrandTotal" after="seeCorrectGrandTotal"/> + + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeSuccessMessage1"/> + + <!--Create Credit Memo--> + <comment userInput="Admin creates credit memo" stepKey="createCreditMemoComment"/> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreateCreditMemo" after="createCreditMemoComment"/> + <seeInCurrentUrl url="{{AdminCreditMemoNewPage.url}}" stepKey="seeNewCreditMemoPage" after="clickCreateCreditMemo"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle" after="seeNewCreditMemoPage"/> + + <!-- Verify Refund Totals --> + <see selector="{{AdminCreditMemoTotalSection.total('Subtotal')}}" userInput="${{AdminOrderSimpleProduct.subtotal}}" stepKey="seeRefundSubTotal"/> + <grabTextFrom selector="{{AdminCreditMemoTotalSection.total('Discount')}}" stepKey="grabRefundDiscountValue"/> + <assertEquals expected='-$15.00' expectedType="string" actual="($grabRefundDiscountValue)" message="notExpectedDiscountOnRefundPage" stepKey="assertDiscountValue1"/> + <grabTextFrom selector="{{AdminInvoiceTotalSection.grandTotal}}" stepKey="grabRefundGrandTotal"/> + <assertEquals expected="($grabInvoiceGrandTotal)" actual="($grabRefundGrandTotal)" message="RefundGrandTotalMatchesWithInvoiceGrandTotal" stepKey="compareRefundGrandTotalAndInvoiceGrandTotal"/> + </test> +</tests> + diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/DiscountTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/DiscountTest.php index 2531a26321d67..18efef38b204c 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/DiscountTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/DiscountTest.php @@ -48,7 +48,7 @@ protected function setUp() ]); $this->creditmemoMock = $this->createPartialMock(\Magento\Sales\Model\Order\Creditmemo::class, [ 'setBaseCost', 'getAllItems', 'getOrder', 'getBaseShippingAmount', 'roundPrice', - 'setDiscountAmount', 'setBaseDiscountAmount' + 'setDiscountAmount', 'setBaseDiscountAmount', 'getBaseShippingInclTax', 'getBaseShippingTaxAmount' ]); $this->creditmemoItemMock = $this->createPartialMock(\Magento\Sales\Model\Order\Creditmemo\Item::class, [ 'getHasChildren', 'getBaseCost', 'getQty', 'getOrderItem', 'setDiscountAmount', @@ -127,6 +127,82 @@ public function testCollect() $this->assertEquals($this->total, $this->total->collect($this->creditmemoMock)); } + public function testCollectNoBaseShippingAmount() + { + $this->creditmemoMock->expects($this->exactly(2)) + ->method('setDiscountAmount') + ->willReturnSelf(); + $this->creditmemoMock->expects($this->exactly(2)) + ->method('setBaseDiscountAmount') + ->willReturnSelf(); + $this->creditmemoMock->expects($this->once()) + ->method('getOrder') + ->willReturn($this->orderMock); + $this->creditmemoMock->expects($this->once()) + ->method('getBaseShippingAmount') + ->willReturn(0); + $this->creditmemoMock->expects($this->once()) + ->method('getBaseShippingInclTax') + ->willReturn(1); + $this->creditmemoMock->expects($this->once()) + ->method('getBaseShippingTaxAmount') + ->willReturn(0); + $this->orderMock->expects($this->once()) + ->method('getBaseShippingDiscountAmount') + ->willReturn(1); + $this->orderMock->expects($this->exactly(2)) + ->method('getBaseShippingAmount') + ->willReturn(1); + $this->orderMock->expects($this->once()) + ->method('getShippingAmount') + ->willReturn(1); + $this->creditmemoMock->expects($this->once()) + ->method('getAllItems') + ->willReturn([$this->creditmemoItemMock]); + $this->creditmemoItemMock->expects($this->atLeastOnce()) + ->method('getOrderItem') + ->willReturn($this->orderItemMock); + $this->orderItemMock->expects($this->once()) + ->method('isDummy') + ->willReturn(false); + $this->orderItemMock->expects($this->once()) + ->method('getDiscountInvoiced') + ->willReturn(1); + $this->orderItemMock->expects($this->once()) + ->method('getBaseDiscountInvoiced') + ->willReturn(1); + $this->orderItemMock->expects($this->once()) + ->method('getQtyInvoiced') + ->willReturn(1); + $this->orderItemMock->expects($this->once()) + ->method('getDiscountRefunded') + ->willReturn(1); + $this->orderItemMock->expects($this->once()) + ->method('getQtyRefunded') + ->willReturn(0); + $this->creditmemoItemMock->expects($this->once()) + ->method('isLast') + ->willReturn(false); + $this->creditmemoItemMock->expects($this->atLeastOnce()) + ->method('getQty') + ->willReturn(1); + $this->creditmemoItemMock->expects($this->exactly(1)) + ->method('setDiscountAmount') + ->willReturnSelf(); + $this->creditmemoItemMock->expects($this->exactly(1)) + ->method('setBaseDiscountAmount') + ->willReturnSelf(); + $this->creditmemoMock->expects($this->exactly(2)) + ->method('roundPrice') + ->willReturnMap( + [ + [1, 'regular', true, 1], + [1, 'base', true, 1] + ] + ); + $this->assertEquals($this->total, $this->total->collect($this->creditmemoMock)); + } + public function testCollectZeroShipping() { $this->creditmemoMock->expects($this->exactly(2)) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml b/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml index 87408aac2c0c9..f31ff1a456898 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Section/AdminCartPriceRulesFormSection.xml @@ -25,6 +25,8 @@ <!-- Actions sub-form --> <element name="actionsHeader" type="button" selector="div[data-index='actions']" timeout="30"/> <element name="apply" type="select" selector="select[name='simple_action']"/> + <element name="applyDiscountToShipping" type="checkbox" selector="input[name='apply_to_shipping']"/> + <element name="applyDiscountToShippingLabel" type="checkbox" selector="input[name='apply_to_shipping']+label"/> <element name="discountAmount" type="input" selector="input[name='discount_amount']"/> <element name="discountStep" type="input" selector="input[name='discount_step']"/> diff --git a/app/code/Magento/SendFriend/view/frontend/templates/send.phtml b/app/code/Magento/SendFriend/view/frontend/templates/send.phtml index 7a972cd5f01c5..3342530f01eb5 100644 --- a/app/code/Magento/SendFriend/view/frontend/templates/send.phtml +++ b/app/code/Magento/SendFriend/view/frontend/templates/send.phtml @@ -35,6 +35,7 @@ <div class="control"> <input name="recipients[email][<%- data._index_ %>]" title="<?= $block->escapeHtmlAttr(__('Email')) ?>" id="recipients-email<%- data._index_ %>" type="email" class="input-text" + data-mage-init='{"mage/trim-input":{}}' data-validate="{required:true, 'validate-email':true}"/> </div> </div> @@ -72,7 +73,8 @@ <label for="sender-email" class="label"><span><?= $block->escapeHtml(__('Email')) ?></span></label> <div class="control"> <input name="sender[email]" value="<?= $block->escapeHtmlAttr($block->getEmail()) ?>" - title="<?= $block->escapeHtmlAttr(__('Email')) ?>" id="sender-email" type="text" class="input-text" + title="<?= $block->escapeHtmlAttr(__('Email')) ?>" id="sender-email" type="email" class="input-text" + data-mage-init='{"mage/trim-input":{}}' data-validate="{required:true, 'validate-email':true}"/> </div> </div> diff --git a/app/code/Magento/Theme/view/frontend/web/js/row-builder.js b/app/code/Magento/Theme/view/frontend/web/js/row-builder.js index 62537c8b1b899..7785ced2e4bd5 100644 --- a/app/code/Magento/Theme/view/frontend/web/js/row-builder.js +++ b/app/code/Magento/Theme/view/frontend/web/js/row-builder.js @@ -144,7 +144,7 @@ define([ $(tmpl).appendTo(row); - $(this.options.rowContainer).append(row); + $(this.options.rowContainer).append(row).trigger('contentUpdated'); row.addClass(this.options.additionalRowClass); diff --git a/app/code/Magento/Ui/Model/Export/ConvertToCsv.php b/app/code/Magento/Ui/Model/Export/ConvertToCsv.php index 40b10749db21e..eb811bfae788f 100644 --- a/app/code/Magento/Ui/Model/Export/ConvertToCsv.php +++ b/app/code/Magento/Ui/Model/Export/ConvertToCsv.php @@ -9,7 +9,6 @@ use Magento\Framework\Exception\FileSystemException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem; -use Magento\Framework\Filesystem\Directory\WriteInterface; use Magento\Ui\Component\MassAction\Filter; /** @@ -18,7 +17,7 @@ class ConvertToCsv { /** - * @var WriteInterface + * @var DirectoryList */ protected $directory; diff --git a/app/code/Magento/Ui/Model/Export/ConvertToXml.php b/app/code/Magento/Ui/Model/Export/ConvertToXml.php index 5f6e45a948f24..19eb651113fcf 100644 --- a/app/code/Magento/Ui/Model/Export/ConvertToXml.php +++ b/app/code/Magento/Ui/Model/Export/ConvertToXml.php @@ -13,7 +13,6 @@ use Magento\Framework\Exception\FileSystemException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Filesystem; -use Magento\Framework\Filesystem\Directory\WriteInterface; use Magento\Ui\Component\MassAction\Filter; /** @@ -22,7 +21,7 @@ class ConvertToXml { /** - * @var WriteInterface + * @var DirectoryList */ protected $directory; diff --git a/app/code/Magento/Ui/view/base/web/js/modal/modal.js b/app/code/Magento/Ui/view/base/web/js/modal/modal.js index 6c9b4b89bec7a..147a18c08c54c 100644 --- a/app/code/Magento/Ui/view/base/web/js/modal/modal.js +++ b/app/code/Magento/Ui/view/base/web/js/modal/modal.js @@ -104,11 +104,12 @@ define([ /** * Escape key press handler, * close modal window + * @param {Object} event - event */ - escapeKey: function () { + escapeKey: function (event) { if (this.options.isOpen && this.modal.find(document.activeElement).length || this.options.isOpen && this.modal[0] === document.activeElement) { - this.closeModal(); + this.closeModal(event); } } } diff --git a/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less index d76630b5cea47..5cdb1444094e9 100644 --- a/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less +++ b/app/design/frontend/Magento/blank/web/css/source/components/_modals_extend.less @@ -63,6 +63,8 @@ } .modal-popup { + pointer-events: none; + .modal-title { .lib-css(border-bottom, @modal-title__border); .lib-css(font-weight, @font-weight__light); diff --git a/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less b/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less index e90d312aa7801..ae68fc81acd6e 100644 --- a/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less +++ b/app/design/frontend/Magento/luma/web/css/source/components/_modals_extend.less @@ -63,6 +63,8 @@ } .modal-popup { + pointer-events: none; + .modal-title { .lib-css(border-bottom, @modal-title__border); .lib-css(font-weight, @font-weight__light); diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateOnlineCreditMemoPayflowLinkTest.xml b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateOnlineCreditMemoPayflowLinkTest.xml index f3922aa474735..f212f48237ecb 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateOnlineCreditMemoPayflowLinkTest.xml +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/TestCase/CreateOnlineCreditMemoPayflowLinkTest.xml @@ -6,7 +6,7 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd"> - <testCase name="Magento\Paypal\Test\TestCase\CreateOnlineCreditMemoPayflowLinkTest" summary="Create online credit memo for order placed with with PayPal Payflow Link"> + <testCase name="Magento\Paypal\Test\TestCase\CreateOnlineCreditMemoPayflowLinkTest" summary="Create online credit memo for order placed with PayPal Payflow Link"> <variation name="CreateOnlineCreditMemoPayflowLinkVariation1" summary="Create Refund for Order Paid with PayPal Payflow Link" ticketId="MAGETWO-13061"> <data name="tag" xsi:type="string">test_type:3rd_party_test, severity:S0</data> <data name="products/0" xsi:type="string">catalogProductSimple::product_100_dollar</data> diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml index 10b9d3e80d0c2..521d7d68ac4a6 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml @@ -96,8 +96,8 @@ <field name="stop_rules_processing" xsi:type="string">Yes</field> </dataset> <dataset name="active_sales_rule_with_complex_conditions"> - <field name="name" xsi:type="string">Cart Price Rule with with complex conditions %isolation%</field> - <field name="description" xsi:type="string">Cart Price Rule with with complex conditions</field> + <field name="name" xsi:type="string">Cart Price Rule with complex conditions %isolation%</field> + <field name="description" xsi:type="string">Cart Price Rule with complex conditions</field> <field name="is_active" xsi:type="string">Yes</field> <field name="website_ids" xsi:type="array"> <item name="0" xsi:type="string">Main Website</item> @@ -129,8 +129,8 @@ <field name="stop_rules_processing" xsi:type="string">Yes</field> <field name="simple_free_shipping" xsi:type="string">For matching items only</field> <field name="store_labels" xsi:type="array"> - <item name="0" xsi:type="string">Cart Price Rule with with complex conditions</item> - <item name="1" xsi:type="string">Cart Price Rule with with complex conditions</item> + <item name="0" xsi:type="string">Cart Price Rule with complex conditions</item> + <item name="1" xsi:type="string">Cart Price Rule with complex conditions</item> </field> </dataset> diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml b/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml index fc30822ab8bed..2cebaf93ff2a9 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Fixture/SynonymGroup.xml @@ -13,7 +13,7 @@ collection="Magento\Search\Model\ResourceModel\Block\Grid\Collection" handler_interface="Magento\Search\Test\Handler\SynonymGroup\SynonymGroupInterface" repository_class="Magento\Search\Test\Repository\SynonymGroup" class="Magento\Search\Test\Fixture\SynonymGroup"> - <field name="group_id" is_required="1 "/> + <field name="group_id" is_required="1"/> <field name="synonyms" is_required="0" /> <field name="scope_id" is_required="0" source="Magento\Search\Test\Fixture\SynonymGroup\ScopeId" /> <field name="mergeOnConflict" is_required="0" /> diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.xml b/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.xml index 7f7741d2f1c13..25acb75ee134f 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.xml +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/TestCase/CreateTaxWithFptTest.xml @@ -97,7 +97,7 @@ </variation> <variation name="CreateTaxWithFptTestVariation5" firstConstraint="Magento\Weee\Test\Constraint\AssertFptApplied" method="test"> <data name="tag" xsi:type="string">to_maintain:yes</data> - <data name="description" xsi:type="string">Check taxed FPT display set to Excluding, Description and Including FPT on product with with custom option catalog price Excluding Tax</data> + <data name="description" xsi:type="string">Check taxed FPT display set to Excluding, Description and Including FPT on product with custom option catalog price Excluding Tax</data> <data name="configData" xsi:type="string">shipping_tax_class_taxable_goods,tax_with_fpt_taxed_cat_excl_disc_on_excl</data> <data name="productData" xsi:type="string">with_custom_option_and_fpt</data> <data name="prices/category_price" xsi:type="string">70.00</data> @@ -117,7 +117,7 @@ <constraint name="Magento\Weee\Test\Constraint\AssertFptApplied" /> </variation> <variation name="CreateTaxWithFptTestVariation6" firstConstraint="Magento\Weee\Test\Constraint\AssertFptApplied" method="test"> - <data name="description" xsi:type="string">Check taxed FPT display set to Including FPT and Description on product with with custom option catalog price Excluding Tax</data> + <data name="description" xsi:type="string">Check taxed FPT display set to Including FPT and Description on product with custom option catalog price Excluding Tax</data> <data name="configData" xsi:type="string">shipping_tax_class_taxable_goods,tax_with_fpt_taxed_cat_excl_disc_on_incl, display_including_tax</data> <data name="productData" xsi:type="string">with_custom_option_and_fpt</data> <data name="prices/category_price" xsi:type="string">86.60</data> @@ -173,7 +173,7 @@ <constraint name="Magento\Weee\Test\Constraint\AssertFptApplied" /> </variation> <variation name="CreateTaxWithFptTestVariation9" firstConstraint="Magento\Weee\Test\Constraint\AssertFptApplied" method="test"> - <data name="description" xsi:type="string">Check taxed FPT display set to Excluding, Description and Including FPT on product with with special price and catalog price Including Tax</data> + <data name="description" xsi:type="string">Check taxed FPT display set to Excluding, Description and Including FPT on product with special price and catalog price Including Tax</data> <data name="configData" xsi:type="string">shipping_tax_class_taxable_goods,tax_with_fpt_taxed_cat_incl_disc_on_excl</data> <data name="productData" xsi:type="string">with_special_price_and_fpt</data> <data name="prices/category_price" xsi:type="string">92.38</data> @@ -193,7 +193,7 @@ <constraint name="Magento\Weee\Test\Constraint\AssertFptApplied" /> </variation> <variation name="CreateTaxWithFptTestVariation10" firstConstraint="Magento\Weee\Test\Constraint\AssertFptApplied" method="test"> - <data name="description" xsi:type="string">Check taxed FPT display set to Including FPT and Description on product with with special price and catalog price Including Tax</data> + <data name="description" xsi:type="string">Check taxed FPT display set to Including FPT and Description on product with special price and catalog price Including Tax</data> <data name="configData" xsi:type="string">shipping_tax_class_taxable_goods,tax_with_fpt_taxed_cat_incl_disc_on_incl</data> <data name="productData" xsi:type="string">with_special_price_and_fpt</data> <data name="prices/category_price" xsi:type="string">101.62</data> @@ -210,7 +210,7 @@ </variation> <variation name="CreateTaxWithFptTestVariation11" firstConstraint="Magento\Weee\Test\Constraint\AssertFptApplied" method="test"> <data name="issue" xsi:type="string">MAGETWO-44968: FPT Final price includes tax on custom option, when display is set to excluding tax</data> - <data name="description" xsi:type="string">Check taxed FPT display set to Excluding, Description and Including FPT on product with with custom option and catalog price Including Tax</data> + <data name="description" xsi:type="string">Check taxed FPT display set to Excluding, Description and Including FPT on product with custom option and catalog price Including Tax</data> <data name="configData" xsi:type="string">shipping_tax_class_taxable_goods,tax_with_fpt_taxed_cat_incl_disc_on_excl</data> <data name="productData" xsi:type="string">with_custom_option_and_fpt</data> <data name="prices/category_price" xsi:type="string">64.67</data> diff --git a/dev/tests/integration/testsuite/Magento/Captcha/Observer/ResetAttemptForFrontendAccountEditObserverTest.php b/dev/tests/integration/testsuite/Magento/Captcha/Observer/ResetAttemptForFrontendAccountEditObserverTest.php new file mode 100644 index 0000000000000..c09211b020b30 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Captcha/Observer/ResetAttemptForFrontendAccountEditObserverTest.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Captcha\Observer; + +use Magento\Captcha\Model\ResourceModel\Log as CaptchaLog; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Framework\Event\ManagerInterface; +use Magento\Framework\ObjectManagerInterface; + +/** + * Class ResetAttemptForFrontendAccountEditObserverTest + * + * Test for checking that the customer login attempts are removed after account details edit + */ +class ResetAttemptForFrontendAccountEditObserverTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + public function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoDataFixture Magento/Captcha/_files/failed_logins_frontend.php + */ + public function testAccountEditRemovesFailedAttempts() + { + $customerEmail = 'mageuser@dummy.com'; + $captchaLogFactory = $this->objectManager->get(LogFactory::class); + $eventManager = $this->objectManager->get(ManagerInterface::class); + + $eventManager->dispatch( + 'customer_account_edited', + ['email' => $customerEmail] + ); + + /** + * @var CaptchaLog $captchaLog + */ + $captchaLog = $captchaLogFactory->create(); + + self::assertEquals(0, $captchaLog->countAttemptsByUserLogin($customerEmail)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Captcha/Observer/ResetAttemptForFrontendObserverTest.php b/dev/tests/integration/testsuite/Magento/Captcha/Observer/ResetAttemptForFrontendObserverTest.php new file mode 100644 index 0000000000000..f8dd80595f936 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Captcha/Observer/ResetAttemptForFrontendObserverTest.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Captcha\Observer; + +use Magento\Captcha\Model\ResourceModel\Log as CaptchaLog; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Customer\Model\Customer; +use Magento\Customer\Model\CustomerFactory; +use Magento\Framework\Event\ManagerInterface; +use Magento\Framework\ObjectManagerInterface; + +/** + * Class ResetAttemptForFrontendObserverTest + * + * Test for checking that the customer login attempts are removed after a successful login + */ +class ResetAttemptForFrontendObserverTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + public function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoDataFixture Magento/Captcha/_files/failed_logins_frontend.php + */ + public function testSuccesfulLoginRemovesFailedAttempts() + { + $customerEmail = 'mageuser@dummy.com'; + $customerFactory = $this->objectManager->get(CustomerFactory::class); + $captchaLogFactory = $this->objectManager->get(LogFactory::class); + $eventManager = $this->objectManager->get(ManagerInterface::class); + + /** @var Customer $customer */ + $customer = $customerFactory->create(); + $customer->setEmail($customerEmail); + + $eventManager->dispatch( + 'customer_customer_authenticated', + ['model' => $customer, 'password' => 'some_password'] + ); + + /** + * @var CaptchaLog $captchaLog + */ + $captchaLog = $captchaLogFactory->create(); + + self::assertEquals(0, $captchaLog->countAttemptsByUserLogin($customerEmail)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Captcha/_files/failed_logins_frontend.php b/dev/tests/integration/testsuite/Magento/Captcha/_files/failed_logins_frontend.php new file mode 100644 index 0000000000000..4e0db30fa82c1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Captcha/_files/failed_logins_frontend.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Captcha\Model\ResourceModel\Log; + +$objectManager = Bootstrap::getObjectManager(); +$logFactory = $objectManager->get(LogFactory::class); + +/** @var Log $captchaLog */ +$captchaLog = $logFactory->create(); +$captchaLog->logAttempt('mageuser@dummy.com'); diff --git a/dev/tests/integration/testsuite/Magento/Captcha/_files/failed_logins_frontend_rollback.php b/dev/tests/integration/testsuite/Magento/Captcha/_files/failed_logins_frontend_rollback.php new file mode 100644 index 0000000000000..a01edb6d0a219 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Captcha/_files/failed_logins_frontend_rollback.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Captcha\Model\ResourceModel\LogFactory; +use Magento\Captcha\Model\ResourceModel\Log; + +$objectManager = Bootstrap::getObjectManager(); +$logFactory = $objectManager->get(LogFactory::class); + +/** @var Log $captchaLog */ +$captchaLog = $logFactory->create(); +$captchaLog->deleteUserAttempts('mageuser@dummy.com'); diff --git a/lib/web/css/source/lib/_forms.less b/lib/web/css/source/lib/_forms.less index 800054e58c3dd..b1c7a49da4a7a 100644 --- a/lib/web/css/source/lib/_forms.less +++ b/lib/web/css/source/lib/_forms.less @@ -465,11 +465,9 @@ .lib-css(margin, @_margin); .lib-css(padding, @_padding); letter-spacing: -.31em; - //word-spacing: -.43em; > * { letter-spacing: normal; - //word-spacing: normal; } > .legend { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php index 7759eb51a52ad..d78e259ec06e0 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php @@ -117,7 +117,7 @@ private function extract(\RecursiveIteratorIterator $recursiveIterator) /** * @param array $classNames * @param string $fileItemPath - * @return bool Whether the clas is included or not + * @return bool Whether the class is included or not */ private function includeClasses(array $classNames, $fileItemPath) { diff --git a/setup/src/Magento/Setup/Module/Di/Code/Scanner/ConfigurationScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/ConfigurationScanner.php index fac5b1b4aec98..747865f7cfef9 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Scanner/ConfigurationScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/ConfigurationScanner.php @@ -28,7 +28,7 @@ public function __construct( * * @param string $fileName * - * @return array array of paths to the configuration files + * @return array of paths to the configuration files */ public function scan($fileName) {