diff --git a/app/code/Magento/Backend/Block/Store/Switcher.php b/app/code/Magento/Backend/Block/Store/Switcher.php
index 9c35cfb5df81d..2b9f70844df86 100644
--- a/app/code/Magento/Backend/Block/Store/Switcher.php
+++ b/app/code/Magento/Backend/Block/Store/Switcher.php
@@ -592,7 +592,7 @@ public function getHintHtml()
'What is this?'
) . '"' . ' class="admin__field-tooltip-action action-help">' . __(
'What is this?'
- ) . '' . ' ';
+ ) . '' . ' ';
}
return $html;
}
diff --git a/app/code/Magento/CardinalCommerce/etc/adminhtml/system.xml b/app/code/Magento/CardinalCommerce/etc/adminhtml/system.xml
index 532fcdd0f598f..046475baba676 100644
--- a/app/code/Magento/CardinalCommerce/etc/adminhtml/system.xml
+++ b/app/code/Magento/CardinalCommerce/etc/adminhtml/system.xml
@@ -19,26 +19,41 @@
Magento\CardinalCommerce\Model\Adminhtml\Source\Environment
three_d_secure/cardinal/environment
+
+ 1
+
three_d_secure/cardinal/org_unit_id
Magento\Config\Model\Config\Backend\Encrypted
+
+ 1
+
three_d_secure/cardinal/api_key
Magento\Config\Model\Config\Backend\Encrypted
+
+ 1
+
three_d_secure/cardinal/api_identifier
Magento\Config\Model\Config\Backend\Encrypted
+
+ 1
+
Magento\Config\Model\Config\Source\Yesno
three_d_secure/cardinal/debug
+
+ 1
+
diff --git a/app/code/Magento/Catalog/Model/Product/Option.php b/app/code/Magento/Catalog/Model/Product/Option.php
index 4f730834412e4..3a0920fb1c530 100644
--- a/app/code/Magento/Catalog/Model/Product/Option.php
+++ b/app/code/Magento/Catalog/Model/Product/Option.php
@@ -11,6 +11,11 @@
use Magento\Catalog\Api\Data\ProductCustomOptionValuesInterfaceFactory;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product;
+use Magento\Catalog\Model\Product\Option\Type\Date;
+use Magento\Catalog\Model\Product\Option\Type\DefaultType;
+use Magento\Catalog\Model\Product\Option\Type\File;
+use Magento\Catalog\Model\Product\Option\Type\Select;
+use Magento\Catalog\Model\Product\Option\Type\Text;
use Magento\Catalog\Model\ResourceModel\Product\Option\Value\Collection;
use Magento\Catalog\Pricing\Price\BasePrice;
use Magento\Framework\EntityManager\MetadataPool;
@@ -98,6 +103,16 @@ class Option extends AbstractExtensibleModel implements ProductCustomOptionInter
*/
protected $validatorPool;
+ /**
+ * @var string[]
+ */
+ private $optionGroups;
+
+ /**
+ * @var string[]
+ */
+ private $optionTypesToGroups;
+
/**
* @var MetadataPool
*/
@@ -121,6 +136,8 @@ class Option extends AbstractExtensibleModel implements ProductCustomOptionInter
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
* @param array $data
* @param ProductCustomOptionValuesInterfaceFactory|null $customOptionValuesFactory
+ * @param array $optionGroups
+ * @param array $optionTypesToGroups
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -135,14 +152,34 @@ public function __construct(
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = [],
- ProductCustomOptionValuesInterfaceFactory $customOptionValuesFactory = null
+ ProductCustomOptionValuesInterfaceFactory $customOptionValuesFactory = null,
+ array $optionGroups = [],
+ array $optionTypesToGroups = []
) {
$this->productOptionValue = $productOptionValue;
$this->optionTypeFactory = $optionFactory;
- $this->validatorPool = $validatorPool;
$this->string = $string;
+ $this->validatorPool = $validatorPool;
$this->customOptionValuesFactory = $customOptionValuesFactory ?:
\Magento\Framework\App\ObjectManager::getInstance()->get(ProductCustomOptionValuesInterfaceFactory::class);
+ $this->optionGroups = $optionGroups ?: [
+ self::OPTION_GROUP_DATE => Date::class,
+ self::OPTION_GROUP_FILE => File::class,
+ self::OPTION_GROUP_SELECT => Select::class,
+ self::OPTION_GROUP_TEXT => Text::class,
+ ];
+ $this->optionTypesToGroups = $optionTypesToGroups ?: [
+ self::OPTION_TYPE_FIELD => self::OPTION_GROUP_TEXT,
+ self::OPTION_TYPE_AREA => self::OPTION_GROUP_TEXT,
+ self::OPTION_TYPE_FILE => self::OPTION_GROUP_FILE,
+ self::OPTION_TYPE_DROP_DOWN => self::OPTION_GROUP_SELECT,
+ self::OPTION_TYPE_RADIO => self::OPTION_GROUP_SELECT,
+ self::OPTION_TYPE_CHECKBOX => self::OPTION_GROUP_SELECT,
+ self::OPTION_TYPE_MULTIPLE => self::OPTION_GROUP_SELECT,
+ self::OPTION_TYPE_DATE => self::OPTION_GROUP_DATE,
+ self::OPTION_TYPE_DATE_TIME => self::OPTION_GROUP_DATE,
+ self::OPTION_TYPE_TIME => self::OPTION_GROUP_DATE,
+ ];
parent::__construct(
$context,
@@ -314,36 +351,22 @@ public function getGroupByType($type = null)
if ($type === null) {
$type = $this->getType();
}
- $optionGroupsToTypes = [
- self::OPTION_TYPE_FIELD => self::OPTION_GROUP_TEXT,
- self::OPTION_TYPE_AREA => self::OPTION_GROUP_TEXT,
- self::OPTION_TYPE_FILE => self::OPTION_GROUP_FILE,
- self::OPTION_TYPE_DROP_DOWN => self::OPTION_GROUP_SELECT,
- self::OPTION_TYPE_RADIO => self::OPTION_GROUP_SELECT,
- self::OPTION_TYPE_CHECKBOX => self::OPTION_GROUP_SELECT,
- self::OPTION_TYPE_MULTIPLE => self::OPTION_GROUP_SELECT,
- self::OPTION_TYPE_DATE => self::OPTION_GROUP_DATE,
- self::OPTION_TYPE_DATE_TIME => self::OPTION_GROUP_DATE,
- self::OPTION_TYPE_TIME => self::OPTION_GROUP_DATE,
- ];
- return $optionGroupsToTypes[$type] ?? '';
+ return $this->optionTypesToGroups[$type] ?? '';
}
/**
* Group model factory
*
* @param string $type Option type
- * @return \Magento\Catalog\Model\Product\Option\Type\DefaultType
+ * @return DefaultType
* @throws LocalizedException
*/
public function groupFactory($type)
{
$group = $this->getGroupByType($type);
- if (!empty($group)) {
- return $this->optionTypeFactory->create(
- 'Magento\Catalog\Model\Product\Option\Type\\' . $this->string->upperCaseWords($group)
- );
+ if (!empty($group) && isset($this->optionGroups[$group])) {
+ return $this->optionTypeFactory->create($this->optionGroups[$group]);
}
throw new LocalizedException(__('The option type to get group instance is incorrect.'));
}
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index ff2fab73e0379..e48e9f3b2b717 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -411,6 +411,28 @@
+
+
+
+ - Magento\Catalog\Model\Product\Option\Type\Date
+ - Magento\Catalog\Model\Product\Option\Type\File
+ - Magento\Catalog\Model\Product\Option\Type\Select
+ - Magento\Catalog\Model\Product\Option\Type\Text
+
+
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_TEXT
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_TEXT
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_FILE
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_SELECT
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_DATE
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_DATE
+ - Magento\Catalog\Api\Data\ProductCustomOptionInterface::OPTION_GROUP_DATE
+
+
+
diff --git a/app/code/Magento/CheckoutAgreements/Model/AgreementsConfigProvider.php b/app/code/Magento/CheckoutAgreements/Model/AgreementsConfigProvider.php
index 1217270d780e1..ff77db60a64e6 100644
--- a/app/code/Magento/CheckoutAgreements/Model/AgreementsConfigProvider.php
+++ b/app/code/Magento/CheckoutAgreements/Model/AgreementsConfigProvider.php
@@ -102,7 +102,8 @@ protected function getAgreementsConfig()
: nl2br($this->escaper->escapeHtml($agreement->getContent())),
'checkboxText' => $this->escaper->escapeHtml($agreement->getCheckboxText()),
'mode' => $agreement->getMode(),
- 'agreementId' => $agreement->getAgreementId()
+ 'agreementId' => $agreement->getAgreementId(),
+ 'contentHeight' => $agreement->getContentHeight()
];
}
diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/AgreementsConfigProviderTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/AgreementsConfigProviderTest.php
index c8309bacb0a86..6b8477e0b4919 100644
--- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/AgreementsConfigProviderTest.php
+++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/AgreementsConfigProviderTest.php
@@ -77,6 +77,7 @@ public function testGetConfigIfContentIsHtml()
$escapedCheckboxText = 'escaped_checkbox_text';
$mode = \Magento\CheckoutAgreements\Model\AgreementModeOptions::MODE_AUTO;
$agreementId = 100;
+ $contentHeight = '100px';
$expectedResult = [
'checkoutAgreements' => [
'isEnabled' => 1,
@@ -86,6 +87,7 @@ public function testGetConfigIfContentIsHtml()
'checkboxText' => $escapedCheckboxText,
'mode' => $mode,
'agreementId' => $agreementId,
+ 'contentHeight' => $contentHeight
],
],
],
@@ -116,6 +118,7 @@ public function testGetConfigIfContentIsHtml()
$agreement->expects($this->once())->method('getCheckboxText')->willReturn($checkboxText);
$agreement->expects($this->once())->method('getMode')->willReturn($mode);
$agreement->expects($this->once())->method('getAgreementId')->willReturn($agreementId);
+ $agreement->expects($this->once())->method('getContentHeight')->willReturn($contentHeight);
$this->assertEquals($expectedResult, $this->model->getConfig());
}
@@ -133,6 +136,7 @@ public function testGetConfigIfContentIsNotHtml()
$escapedCheckboxText = 'escaped_checkbox_text';
$mode = \Magento\CheckoutAgreements\Model\AgreementModeOptions::MODE_AUTO;
$agreementId = 100;
+ $contentHeight = '100px';
$expectedResult = [
'checkoutAgreements' => [
'isEnabled' => 1,
@@ -142,6 +146,7 @@ public function testGetConfigIfContentIsNotHtml()
'checkboxText' => $escapedCheckboxText,
'mode' => $mode,
'agreementId' => $agreementId,
+ 'contentHeight' => $contentHeight
],
],
],
@@ -172,6 +177,7 @@ public function testGetConfigIfContentIsNotHtml()
$agreement->expects($this->once())->method('getCheckboxText')->willReturn($checkboxText);
$agreement->expects($this->once())->method('getMode')->willReturn($mode);
$agreement->expects($this->once())->method('getAgreementId')->willReturn($agreementId);
+ $agreement->expects($this->once())->method('getContentHeight')->willReturn($contentHeight);
$this->assertEquals($expectedResult, $this->model->getConfig());
}
diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements.js b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements.js
index 434676fc04116..a189c42918099 100644
--- a/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements.js
+++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/js/view/checkout-agreements.js
@@ -23,6 +23,7 @@ define([
agreements: agreementsConfig.agreements,
modalTitle: ko.observable(null),
modalContent: ko.observable(null),
+ contentHeight: ko.observable(null),
modalWindow: null,
/**
@@ -42,6 +43,7 @@ define([
showContent: function (element) {
this.modalTitle(element.checkboxText);
this.modalContent(element.content);
+ this.contentHeight(element.contentHeight ? element.contentHeight : 'auto');
agreementsModal.showModal();
},
diff --git a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html
index 4b1a68624e547..f1c807fab3d22 100644
--- a/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html
+++ b/app/code/Magento/CheckoutAgreements/view/frontend/web/template/checkout/checkout-agreements.html
@@ -35,7 +35,7 @@
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
index c60953e33e9eb..5b50cc0ebd5e0 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
@@ -9,12 +9,14 @@
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\Data\ProductInterfaceFactory;
+use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\Config;
use Magento\Catalog\Model\Product\Gallery\ReadHandler as GalleryReadHandler;
use Magento\ConfigurableProduct\Model\Product\Type\Collection\SalableProcessor;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\EntityManager\MetadataPool;
+use Magento\Framework\Api\SearchCriteriaBuilder;
/**
* Configurable product type implementation
@@ -194,9 +196,18 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
*/
private $salableProcessor;
+ /**
+ * @var ProductAttributeRepositoryInterface|null
+ */
+ private $productAttributeRepository;
+
+ /**
+ * @var SearchCriteriaBuilder|null
+ */
+ private $searchCriteriaBuilder;
+
/**
* @codingStandardsIgnoreStart/End
- *
* @param \Magento\Catalog\Model\Product\Option $catalogProductOption
* @param \Magento\Eav\Model\Config $eavConfig
* @param \Magento\Catalog\Model\Product\Type $catalogProductType
@@ -214,9 +225,13 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
* @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor
+ * @param \Magento\Framework\Cache\FrontendInterface|null $cache
+ * @param \Magento\Customer\Model\Session|null $customerSession
* @param \Magento\Framework\Serialize\Serializer\Json $serializer
* @param ProductInterfaceFactory $productFactory
* @param SalableProcessor $salableProcessor
+ * @param ProductAttributeRepositoryInterface|null $productAttributeRepository
+ * @param SearchCriteriaBuilder|null $searchCriteriaBuilder
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -241,7 +256,9 @@ public function __construct(
\Magento\Customer\Model\Session $customerSession = null,
\Magento\Framework\Serialize\Serializer\Json $serializer = null,
ProductInterfaceFactory $productFactory = null,
- SalableProcessor $salableProcessor = null
+ SalableProcessor $salableProcessor = null,
+ ProductAttributeRepositoryInterface $productAttributeRepository = null,
+ SearchCriteriaBuilder $searchCriteriaBuilder = null
) {
$this->typeConfigurableFactory = $typeConfigurableFactory;
$this->_eavAttributeFactory = $eavAttributeFactory;
@@ -256,6 +273,10 @@ public function __construct(
$this->productFactory = $productFactory ?: ObjectManager::getInstance()
->get(ProductInterfaceFactory::class);
$this->salableProcessor = $salableProcessor ?: ObjectManager::getInstance()->get(SalableProcessor::class);
+ $this->productAttributeRepository = $productAttributeRepository ?:
+ ObjectManager::getInstance()->get(ProductAttributeRepositoryInterface::class);
+ $this->searchCriteriaBuilder = $searchCriteriaBuilder ?:
+ ObjectManager::getInstance()->get(SearchCriteriaBuilder::class);
parent::__construct(
$catalogProductOption,
$eavConfig,
@@ -1231,19 +1252,16 @@ public function isPossibleBuyFromList($product)
/**
* Returns array of sub-products for specified configurable product
- *
- * $requiredAttributeIds - one dimensional array, if provided
* Result array contains all children for specified configurable product
*
* @param \Magento\Catalog\Model\Product $product
- * @param array $requiredAttributeIds
+ * @param array $requiredAttributeIds Attributes to include in the select; one-dimensional array
* @return ProductInterface[]
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function getUsedProducts($product, $requiredAttributeIds = null)
{
if (!$product->hasData($this->_usedProducts)) {
- $collection = $this->getConfiguredUsedProductCollection($product, false);
+ $collection = $this->getConfiguredUsedProductCollection($product, false, $requiredAttributeIds);
$usedProducts = array_values($collection->getItems());
$product->setData($this->_usedProducts, $usedProducts);
}
@@ -1390,16 +1408,18 @@ private function getUsedProductsCacheKey($keyParts)
/**
* Prepare collection for retrieving sub-products of specified configurable product
- *
* Retrieve related products collection with additional configuration
*
* @param \Magento\Catalog\Model\Product $product
* @param bool $skipStockFilter
+ * @param array $requiredAttributeIds Attributes to include in the select
* @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection
+ * @throws \Magento\Framework\Exception\LocalizedException
*/
private function getConfiguredUsedProductCollection(
\Magento\Catalog\Model\Product $product,
- $skipStockFilter = true
+ $skipStockFilter = true,
+ $requiredAttributeIds = null
) {
$collection = $this->getUsedProductCollection($product);
@@ -1407,8 +1427,19 @@ private function getConfiguredUsedProductCollection(
$collection->setFlag('has_stock_status_filter', true);
}
+ $attributesForSelect = $this->getAttributesForCollection($product);
+ if ($requiredAttributeIds) {
+ $this->searchCriteriaBuilder->addFilter('attribute_id', $requiredAttributeIds, 'in');
+ $requiredAttributes = $this->productAttributeRepository
+ ->getList($this->searchCriteriaBuilder->create())->getItems();
+ $requiredAttributeCodes = [];
+ foreach ($requiredAttributes as $requiredAttribute) {
+ $requiredAttributeCodes[] = $requiredAttribute->getAttributeCode();
+ }
+ $attributesForSelect = array_unique(array_merge($attributesForSelect, $requiredAttributeCodes));
+ }
$collection
- ->addAttributeToSelect($this->getAttributesForCollection($product))
+ ->addAttributeToSelect($attributesForSelect)
->addFilterByRequiredOptions()
->setStoreId($product->getStoreId());
diff --git a/app/code/Magento/Paypal/view/adminhtml/web/styles.css b/app/code/Magento/Paypal/view/adminhtml/web/styles.css
index 9d63dbff5f3f9..ee0bb1d0c420b 100644
--- a/app/code/Magento/Paypal/view/adminhtml/web/styles.css
+++ b/app/code/Magento/Paypal/view/adminhtml/web/styles.css
@@ -28,9 +28,9 @@
.paypal-recommended-header > .admin__collapsible-block > a::before {content: "" !important;}
.paypal-other-header > .admin__collapsible-block > a::before {content: '' !important; width: 0; height: 0; border-color: transparent; border-top-color: #000; border-style: solid; border-width: .8rem .5rem 0 .5rem; margin-top:1px; transition: all .2s linear;}
.paypal-other-header > .admin__collapsible-block > a.open::before {border-color: transparent; border-bottom-color: #000; border-width: 0 .5rem .8rem .5rem;}
-.paypal-other-header > .admin__collapsible-block > a {color: #007bdb !important; text-align: right;}
.payments-other-header > .admin__collapsible-block > a,
-.paypal-recommended-header > .admin__collapsible-block > a {display: inline-block;}
+.paypal-recommended-header > .admin__collapsible-block > a,
+.paypal-other-header > .admin__collapsible-block > a {display: inline-block;}
.payments-other-header > .admin__collapsible-block > a::before,
.paypal-recommended-header > .admin__collapsible-block > a::before {content: '' !important; width: 0; height: 0; border-color: transparent; border-top-color: #000; border-style: solid; border-width: .8rem .5rem 0 .5rem; margin-top:1px; transition: all .2s linear;}
.payments-other-header > .admin__collapsible-block > a.open::before,
diff --git a/app/code/Magento/Quote/Api/CartManagementInterface.php b/app/code/Magento/Quote/Api/CartManagementInterface.php
index 7aa4bc4c7603a..dc8ab7fedc870 100644
--- a/app/code/Magento/Quote/Api/CartManagementInterface.php
+++ b/app/code/Magento/Quote/Api/CartManagementInterface.php
@@ -52,6 +52,9 @@ public function getCartForCustomer($customerId);
* @param int $customerId The customer ID.
* @param int $storeId
* @return boolean
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\StateException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function assignCustomer($cartId, $customerId, $storeId);
diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php
index 84ef699b6209e..3a81341e2b02a 100644
--- a/app/code/Magento/Quote/Model/QuoteManagement.php
+++ b/app/code/Magento/Quote/Model/QuoteManagement.php
@@ -298,22 +298,28 @@ public function assignCustomer($cartId, $customerId, $storeId)
);
}
try {
- $this->quoteRepository->getForCustomer($customerId);
- throw new StateException(
- __("The customer can't be assigned to the cart because the customer already has an active cart.")
- );
+ $customerActiveQuote = $this->quoteRepository->getForCustomer($customerId);
+
+ $quote->merge($customerActiveQuote);
+ $customerActiveQuote->setIsActive(0);
+ $this->quoteRepository->save($customerActiveQuote);
+
// phpcs:ignore Magento2.CodeAnalysis.EmptyBlock
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
}
$quote->setCustomer($customer);
$quote->setCustomerIsGuest(0);
+ $quote->setIsActive(1);
+
/** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */
$quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'quote_id');
if ($quoteIdMask->getId()) {
$quoteIdMask->delete();
}
+
$this->quoteRepository->save($quote);
+
return true;
}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
index cd2afc39733f2..2c61c192ead62 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
@@ -7,11 +7,13 @@
namespace Magento\Quote\Test\Unit\Model;
+use Magento\Customer\Api\Data\CustomerInterface;
+use Magento\Customer\Model\Customer;
use Magento\Framework\App\RequestInterface;
-use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
use Magento\Quote\Model\CustomerManagement;
+use Magento\Quote\Model\Quote;
use Magento\Quote\Model\QuoteIdMaskFactory;
use Magento\Sales\Api\Data\OrderAddressInterface;
@@ -199,7 +201,7 @@ protected function setUp()
);
$this->quoteMock = $this->createPartialMock(
- \Magento\Quote\Model\Quote::class,
+ Quote::class,
[
'assignCustomer',
'collectTotals',
@@ -275,7 +277,7 @@ public function testCreateEmptyCartAnonymous()
$storeId = 345;
$quoteId = 2311;
- $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
+ $quoteMock = $this->createMock(Quote::class);
$quoteAddress = $this->createPartialMock(
\Magento\Quote\Model\Quote\Address::class,
['setCollectShippingRates']
@@ -306,14 +308,14 @@ public function testCreateEmptyCartForCustomer()
$quoteId = 2311;
$userId = 567;
- $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
+ $quoteMock = $this->createMock(Quote::class);
$this->quoteRepositoryMock
->expects($this->once())
->method('getActiveForCustomer')
->with($userId)
- ->willThrowException(new NoSuchEntityException());
- $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)
+ ->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException());
+ $customer = $this->getMockBuilder(CustomerInterface::class)
->setMethods(['getDefaultBilling'])->disableOriginalConstructor()->getMockForAbstractClass();
$quoteAddress = $this->createPartialMock(
\Magento\Quote\Model\Quote\Address::class,
@@ -342,14 +344,14 @@ public function testCreateEmptyCartForCustomerReturnExistsQuote()
$storeId = 345;
$userId = 567;
- $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
+ $quoteMock = $this->createMock(Quote::class);
$this->quoteRepositoryMock
->expects($this->once())
->method('getActiveForCustomer')
->with($userId)->willReturn($quoteMock);
- $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)
+ $customer = $this->getMockBuilder(CustomerInterface::class)
->setMethods(['getDefaultBilling'])->disableOriginalConstructor()->getMockForAbstractClass();
$quoteAddress = $this->createPartialMock(
\Magento\Quote\Model\Quote\Address::class,
@@ -379,8 +381,8 @@ public function testAssignCustomerFromAnotherStore()
$customerId = 455;
$storeId = 5;
- $quoteMock = $this->createMock(\Magento\Quote\Model\Quote::class);
- $customerMock = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class);
+ $quoteMock = $this->createMock(Quote::class);
+ $customerMock = $this->createMock(CustomerInterface::class);
$this->quoteRepositoryMock
->expects($this->once())
@@ -395,7 +397,7 @@ public function testAssignCustomerFromAnotherStore()
->willReturn($customerMock);
$customerModelMock = $this->createPartialMock(
- \Magento\Customer\Model\Customer::class,
+ Customer::class,
['load', 'getSharedStoreIds']
);
$this->customerFactoryMock->expects($this->once())->method('create')->willReturn($customerModelMock);
@@ -424,10 +426,10 @@ public function testAssignCustomerToNonanonymousCart()
$storeId = 5;
$quoteMock = $this->createPartialMock(
- \Magento\Quote\Model\Quote::class,
+ Quote::class,
['getCustomerId', 'setCustomer', 'setCustomerIsGuest']
);
- $customerMock = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class);
+ $customerMock = $this->createMock(CustomerInterface::class);
$this->quoteRepositoryMock
->expects($this->once())
@@ -442,7 +444,7 @@ public function testAssignCustomerToNonanonymousCart()
->willReturn($customerMock);
$customerModelMock = $this->createPartialMock(
- \Magento\Customer\Model\Customer::class,
+ Customer::class,
['load', 'getSharedStoreIds']
);
$this->customerFactoryMock->expects($this->once())->method('create')->willReturn($customerModelMock);
@@ -463,7 +465,7 @@ public function testAssignCustomerToNonanonymousCart()
}
/**
- * @expectedException \Magento\Framework\Exception\StateException
+ * @expectedException \Magento\Framework\Exception\NoSuchEntityException
*/
public function testAssignCustomerNoSuchCustomer()
{
@@ -472,10 +474,51 @@ public function testAssignCustomerNoSuchCustomer()
$storeId = 5;
$quoteMock = $this->createPartialMock(
- \Magento\Quote\Model\Quote::class,
+ Quote::class,
['getCustomerId', 'setCustomer', 'setCustomerIsGuest']
);
- $customerMock = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class);
+
+ $this->quoteRepositoryMock
+ ->expects($this->once())
+ ->method('getActive')
+ ->with($cartId)
+ ->willReturn($quoteMock);
+
+ $this->customerRepositoryMock
+ ->expects($this->once())
+ ->method('getById')
+ ->with($customerId)
+ ->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException());
+
+ $this->expectExceptionMessage(
+ "No such entity."
+ );
+
+ $this->model->assignCustomer($cartId, $customerId, $storeId);
+ }
+
+ public function testAssignCustomerWithActiveCart()
+ {
+ $cartId = 220;
+ $customerId = 455;
+ $storeId = 5;
+
+ $this->getPropertyValue($this->model, 'quoteIdMaskFactory')
+ ->expects($this->once())
+ ->method('create')
+ ->willReturn($this->quoteIdMock);
+
+ $quoteMock = $this->createPartialMock(
+ Quote::class,
+ ['getCustomerId', 'setCustomer', 'setCustomerIsGuest', 'setIsActive', 'getIsActive', 'merge']
+ );
+
+ $activeQuoteMock = $this->createPartialMock(
+ Quote::class,
+ ['getCustomerId', 'setCustomer', 'setCustomerIsGuest', 'setIsActive', 'getIsActive', 'merge']
+ );
+
+ $customerMock = $this->createMock(CustomerInterface::class);
$this->quoteRepositoryMock
->expects($this->once())
@@ -490,7 +533,7 @@ public function testAssignCustomerNoSuchCustomer()
->willReturn($customerMock);
$customerModelMock = $this->createPartialMock(
- \Magento\Customer\Model\Customer::class,
+ Customer::class,
['load', 'getSharedStoreIds']
);
$this->customerFactoryMock->expects($this->once())->method('create')->willReturn($customerModelMock);
@@ -506,17 +549,26 @@ public function testAssignCustomerNoSuchCustomer()
->willReturn([$storeId, 'some store value']);
$quoteMock->expects($this->once())->method('getCustomerId')->willReturn(null);
-
$this->quoteRepositoryMock
->expects($this->once())
->method('getForCustomer')
- ->with($customerId);
+ ->with($customerId)
+ ->willReturn($activeQuoteMock);
- $this->model->assignCustomer($cartId, $customerId, $storeId);
+ $quoteMock->expects($this->once())->method('merge')->with($activeQuoteMock)->willReturnSelf();
+ $activeQuoteMock->expects($this->once())->method('setIsActive')->with(0);
+ $this->quoteRepositoryMock->expects($this->atLeastOnce())->method('save')->with($activeQuoteMock);
- $this->expectExceptionMessage(
- "The customer can't be assigned to the cart because the customer already has an active cart."
- );
+ $quoteMock->expects($this->once())->method('setCustomer')->with($customerMock);
+ $quoteMock->expects($this->once())->method('setCustomerIsGuest')->with(0);
+ $quoteMock->expects($this->once())->method('setIsActive')->with(1);
+
+ $this->quoteIdMock->expects($this->once())->method('load')->with($cartId, 'quote_id')->willReturnSelf();
+ $this->quoteIdMock->expects($this->once())->method('getId')->willReturn(10);
+ $this->quoteIdMock->expects($this->once())->method('delete');
+ $this->quoteRepositoryMock->expects($this->atLeastOnce())->method('save')->with($quoteMock);
+
+ $this->model->assignCustomer($cartId, $customerId, $storeId);
}
public function testAssignCustomer()
@@ -529,15 +581,13 @@ public function testAssignCustomer()
->expects($this->once())
->method('create')
->willReturn($this->quoteIdMock);
- $this->quoteIdMock->expects($this->once())->method('load')->with($cartId, 'quote_id')->willReturnSelf();
- $this->quoteIdMock->expects($this->once())->method('getId')->willReturn(10);
- $this->quoteIdMock->expects($this->once())->method('delete');
+
$quoteMock = $this->createPartialMock(
- \Magento\Quote\Model\Quote::class,
- ['getCustomerId', 'setCustomer', 'setCustomerIsGuest']
+ Quote::class,
+ ['getCustomerId', 'setCustomer', 'setCustomerIsGuest', 'setIsActive', 'getIsActive', 'merge']
);
- $customerMock = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class);
+ $customerMock = $this->createMock(CustomerInterface::class);
$this->quoteRepositoryMock
->expects($this->once())
->method('getActive')
@@ -551,10 +601,12 @@ public function testAssignCustomer()
->willReturn($customerMock);
$customerModelMock = $this->createPartialMock(
- \Magento\Customer\Model\Customer::class,
+ Customer::class,
['load', 'getSharedStoreIds']
);
+
$this->customerFactoryMock->expects($this->once())->method('create')->willReturn($customerModelMock);
+
$customerModelMock
->expects($this->once())
->method('load')
@@ -572,11 +624,17 @@ public function testAssignCustomer()
->expects($this->once())
->method('getForCustomer')
->with($customerId)
- ->willThrowException(new NoSuchEntityException());
+ ->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException());
+
+ $quoteMock->expects($this->never())->method('merge');
$quoteMock->expects($this->once())->method('setCustomer')->with($customerMock);
$quoteMock->expects($this->once())->method('setCustomerIsGuest')->with(0);
+ $quoteMock->expects($this->once())->method('setIsActive')->with(1);
+ $this->quoteIdMock->expects($this->once())->method('load')->with($cartId, 'quote_id')->willReturnSelf();
+ $this->quoteIdMock->expects($this->once())->method('getId')->willReturn(10);
+ $this->quoteIdMock->expects($this->once())->method('delete');
$this->quoteRepositoryMock->expects($this->once())->method('save')->with($quoteMock);
$this->model->assignCustomer($cartId, $customerId, $storeId);
@@ -881,7 +939,7 @@ protected function getQuote(
\Magento\Quote\Model\Quote\Address $shippingAddress = null
) {
$quote = $this->createPartialMock(
- \Magento\Quote\Model\Quote::class,
+ Quote::class,
[
'setIsActive',
'getCustomerEmail',
@@ -928,7 +986,7 @@ protected function getQuote(
->willReturn($payment);
$customer = $this->createPartialMock(
- \Magento\Customer\Model\Customer::class,
+ Customer::class,
['getDefaultBilling', 'getId']
);
$quote->expects($this->any())->method('getCustomerId')->willReturn($customerId);
@@ -1016,12 +1074,12 @@ protected function prepareOrderFactory(
}
/**
- * @throws NoSuchEntityException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
*/
public function testGetCartForCustomer()
{
$customerId = 100;
- $cartMock = $this->createMock(\Magento\Quote\Model\Quote::class);
+ $cartMock = $this->createMock(Quote::class);
$this->quoteRepositoryMock->expects($this->once())
->method('getActiveForCustomer')
->with($customerId)
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/AbstractSidebar.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/AbstractSidebar.php
index 06c6a9eb0652b..737ca446bb8e9 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/AbstractSidebar.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/AbstractSidebar.php
@@ -3,6 +3,9 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
+declare(strict_types=1);
+
namespace Magento\Sales\Block\Adminhtml\Order\Create\Sidebar;
use Magento\Framework\Pricing\PriceCurrencyInterface;
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Cart.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Cart.php
index f2200e1c1a108..a927b7177294a 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Cart.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Sidebar/Cart.php
@@ -9,6 +9,7 @@
use Magento\Catalog\Model\Product;
use Magento\Catalog\Pricing\Price\FinalPrice;
+use Magento\Store\Model\ScopeInterface;
/**
* Adminhtml sales order create sidebar cart block
@@ -146,4 +147,30 @@ private function getCartItemCustomPrice(Product $product): ?float
return null;
}
+
+ /**
+ * @inheritdoc
+ */
+ public function getItemCount()
+ {
+ $count = $this->getData('item_count');
+ if ($count === null) {
+ $useQty = $this->_scopeConfig->getValue(
+ 'checkout/cart_link/use_qty',
+ ScopeInterface::SCOPE_STORE
+ );
+ $allItems = $this->getItems();
+ if ($useQty) {
+ $count = 0;
+ foreach ($allItems as $item) {
+ $count += $item->getQty();
+ }
+ } else {
+ $count = count($allItems);
+ }
+ $this->setData('item_count', $count);
+ }
+
+ return $count;
+ }
}
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php
index 300b7ee37f2ef..6e7c2e5ce5609 100644
--- a/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php
+++ b/app/code/Magento/Sales/Controller/Adminhtml/Invoice/AbstractInvoice/View.php
@@ -1,17 +1,22 @@
registry = $registry;
parent::__construct($context);
+ $this->registry = $registry;
$this->resultForwardFactory = $resultForwardFactory;
+ $this->invoiceRepository = $invoiceRepository ?:
+ ObjectManager::getInstance()->get(InvoiceRepositoryInterface::class);
}
/**
@@ -70,13 +79,14 @@ public function execute()
}
/**
+ * Get invoice using invoice Id from request params
+ *
* @return \Magento\Sales\Model\Order\Invoice|bool
*/
protected function getInvoice()
{
try {
- $invoice = $this->getInvoiceRepository()
- ->get($this->getRequest()->getParam('invoice_id'));
+ $invoice = $this->invoiceRepository->get($this->getRequest()->getParam('invoice_id'));
$this->registry->register('current_invoice', $invoice);
} catch (\Exception $e) {
$this->messageManager->addErrorMessage(__('Invoice capturing error'));
@@ -85,19 +95,4 @@ protected function getInvoice()
return $invoice;
}
-
- /**
- * @return InvoiceRepository
- *
- * @deprecated 100.1.0
- */
- private function getInvoiceRepository()
- {
- if ($this->invoiceRepository === null) {
- $this->invoiceRepository = ObjectManager::getInstance()
- ->get(InvoiceRepositoryInterface::class);
- }
-
- return $this->invoiceRepository;
- }
}
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/AddComment.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/AddComment.php
index 515c0753542a0..23dcae3a858cc 100644
--- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/AddComment.php
+++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/AddComment.php
@@ -1,23 +1,30 @@
invoiceCommentSender = $invoiceCommentSender;
$this->resultJsonFactory = $resultJsonFactory;
$this->resultPageFactory = $resultPageFactory;
$this->resultRawFactory = $resultRawFactory;
- parent::__construct($context, $registry, $resultForwardFactory);
+ $this->invoiceRepository = $invoiceRepository ?:
+ ObjectManager::getInstance()->get(InvoiceRepositoryInterface::class);
+ parent::__construct($context, $registry, $resultForwardFactory, $invoiceRepository);
}
/**
@@ -90,7 +106,7 @@ public function execute()
);
$this->invoiceCommentSender->send($invoice, !empty($data['is_customer_notified']), $data['comment']);
- $invoice->save();
+ $this->invoiceRepository->save($invoice);
/** @var \Magento\Backend\Model\View\Result\Page $resultPage */
$resultPage = $this->resultPageFactory->create();
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml
index 76be3a1094327..589da3e49dc89 100644
--- a/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AddSimpleProductToOrderFromShoppingCartTest.xml
@@ -46,8 +46,9 @@
-
+
+
@@ -64,6 +65,7 @@
+
@@ -75,6 +77,6 @@
-
+
diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/AddCommentTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/AddCommentTest.php
index 053df53949296..9fe3042fa6bdf 100644
--- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/AddCommentTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/AddCommentTest.php
@@ -3,6 +3,9 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
+declare(strict_types=1);
+
namespace Magento\Sales\Test\Unit\Controller\Adminhtml\Order\Invoice;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
@@ -186,7 +189,8 @@ protected function setUp()
'invoiceCommentSender' => $this->commentSenderMock,
'resultPageFactory' => $this->resultPageFactoryMock,
'resultRawFactory' => $this->resultRawFactoryMock,
- 'resultJsonFactory' => $this->resultJsonFactoryMock
+ 'resultJsonFactory' => $this->resultJsonFactoryMock,
+ 'invoiceRepository' => $this->invoiceRepository
]
);
@@ -230,8 +234,9 @@ public function testExecute()
$invoiceMock->expects($this->once())
->method('addComment')
->with($data['comment'], false, false);
- $invoiceMock->expects($this->once())
- ->method('save');
+ $this->invoiceRepository->expects($this->once())
+ ->method('save')
+ ->with($invoiceMock);
$this->invoiceRepository->expects($this->once())
->method('get')
@@ -307,11 +312,11 @@ public function testExecuteModelException()
public function testExecuteException()
{
$response = ['error' => true, 'message' => 'Cannot add new comment.'];
- $e = new \Exception('test');
+ $error = new \Exception('test');
$this->requestMock->expects($this->once())
->method('getParam')
- ->will($this->throwException($e));
+ ->will($this->throwException($error));
$this->resultJsonFactoryMock->expects($this->once())
->method('create')
diff --git a/app/design/adminhtml/Magento/backend/web/css/styles-old.less b/app/design/adminhtml/Magento/backend/web/css/styles-old.less
index b2afde435a627..c9ecf2e6670c1 100644
--- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less
+++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less
@@ -3958,6 +3958,22 @@
.grid tr.headings th > span {
white-space: normal;
}
+
+ .field {
+ &.field-subscription {
+ .admin__field-label {
+ margin-left: 10px;
+ float: none;
+ cursor: pointer;
+ }
+
+ .admin__field-control {
+ float: left;
+ width: auto;
+ margin: 6px 0px 0px 0px;
+ }
+ }
+ }
}
}
diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less
index 65f3eeef63b01..5f69db5acec4b 100644
--- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less
+++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less
@@ -110,7 +110,7 @@
@_dropdown-list-position-right: 0,
@_dropdown-list-pointer-position: right,
@_dropdown-list-pointer-position-left-right: 26px,
- @_dropdown-list-z-index: 101,
+ @_dropdown-list-z-index: 101,
@_dropdown-toggle-icon-content: @icon-cart,
@_dropdown-toggle-active-icon-content: @icon-cart,
@_dropdown-list-item-padding: false,
@@ -304,7 +304,7 @@
.weee[data-label] {
.lib-font-size(11);
-
+
.label {
&:extend(.abs-no-display all);
}
@@ -340,7 +340,6 @@
}
.item-qty {
- margin-right: @indent__s;
text-align: center;
width: 45px;
}
@@ -390,6 +389,16 @@
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__s) {
.minicart-wrapper {
margin-top: @indent__s;
+ .lib-clearfix();
+ .product {
+ .actions {
+ float: left;
+ margin: 10px 0 0 0;
+ }
+ }
+ .update-cart-item {
+ float: right;
+ }
}
}
@@ -400,7 +409,7 @@
.media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) {
.minicart-wrapper {
margin-left: 13px;
-
+
.block-minicart {
right: -15px;
width: 390px;
diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less
index af94dd7b97bbb..d6cc62c2ddef3 100644
--- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less
+++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less
@@ -120,7 +120,7 @@
@_dropdown-list-position-right: -10px,
@_dropdown-list-pointer-position: right,
@_dropdown-list-pointer-position-left-right: 12px,
- @_dropdown-list-z-index: 101,
+ @_dropdown-list-z-index: 101,
@_dropdown-toggle-icon-content: @icon-cart,
@_dropdown-toggle-active-icon-content: @icon-cart,
@_dropdown-list-item-padding: false,
@@ -136,7 +136,7 @@
.block-minicart {
.lib-css(padding, 25px @minicart__padding-horizontal);
-
+
.block-title {
display: none;
}
@@ -233,7 +233,7 @@
.minicart-items {
.lib-list-reset-styles();
-
+
.product-item {
padding: @indent__base 0;
@@ -316,7 +316,7 @@
&:extend(.abs-toggling-title all);
border: 0;
padding: 0 @indent__xl @indent__xs 0;
-
+
&:after {
.lib-css(color, @color-gray56);
margin: 0 0 0 @indent__xs;
@@ -349,7 +349,7 @@
@_icon-font-position: after
);
}
-
+
> span {
&:extend(.abs-visually-hidden-reset all);
}
@@ -369,7 +369,6 @@
}
.item-qty {
- margin-right: @indent__s;
text-align: center;
width: 60px;
}
@@ -419,6 +418,16 @@
.media-width(@extremum, @break) when (@extremum = 'max') and (@break = @screen__m) {
.minicart-wrapper {
margin-top: @indent__s;
+ .lib-clearfix();
+ .product {
+ .actions {
+ float: left;
+ margin: 10px 0 0 0;
+ }
+ }
+ .update-cart-item {
+ float: right;
+ }
}
}
diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartManagementTest.php
index 6d585561ae3a9..08821b08ede5e 100644
--- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartManagementTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartManagementTest.php
@@ -310,21 +310,20 @@ public function testAssignCustomerThrowsExceptionIfCartIsAssignedToDifferentStor
}
/**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
+ * @magentoApiDataFixture Magento/Checkout/_files/quote_with_items_saved.php
* @magentoApiDataFixture Magento/Sales/_files/quote.php
- * @expectedException \Exception
*/
- public function testAssignCustomerThrowsExceptionIfCustomerAlreadyHasActiveCart()
+ public function testAssignCustomerCartMerged()
{
/** @var $customer \Magento\Customer\Model\Customer */
$customer = $this->objectManager->create(\Magento\Customer\Model\Customer::class)->load(1);
// Customer has a quote with reserved order ID test_order_1 (see fixture)
/** @var $customerQuote \Magento\Quote\Model\Quote */
$customerQuote = $this->objectManager->create(\Magento\Quote\Model\Quote::class)
- ->load('test_order_1', 'reserved_order_id');
- $customerQuote->setIsActive(1)->save();
+ ->load('test_order_item_with_items', 'reserved_order_id');
/** @var $quote \Magento\Quote\Model\Quote */
$quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class)->load('test01', 'reserved_order_id');
+ $expectedQuoteItemsQty = $customerQuote->getItemsQty() + $quote->getItemsQty();
$cartId = $quote->getId();
$customerId = $customer->getId();
@@ -346,11 +345,13 @@ public function testAssignCustomerThrowsExceptionIfCustomerAlreadyHasActiveCart(
'customerId' => $customerId,
'storeId' => 1,
];
- $this->_webApiCall($serviceInfo, $requestData);
+ $this->assertTrue($this->_webApiCall($serviceInfo, $requestData));
- $this->expectExceptionMessage(
- "The customer can't be assigned to the cart because the customer already has an active cart."
- );
+ $mergedQuote = $this->objectManager
+ ->create(\Magento\Quote\Model\Quote::class)
+ ->load('test01', 'reserved_order_id');
+
+ $this->assertEquals($expectedQuoteItemsQty, $mergedQuote->getItemsQty());
}
/**
diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartManagementTest.php
index bbd1e59f83f90..120781e674d47 100644
--- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartManagementTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartManagementTest.php
@@ -231,21 +231,20 @@ public function testAssignCustomerThrowsExceptionIfTargetCartIsNotAnonymous()
}
/**
- * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php
+ * @magentoApiDataFixture Magento/Checkout/_files/quote_with_items_saved.php
* @magentoApiDataFixture Magento/Sales/_files/quote.php
- * @expectedException \Exception
*/
- public function testAssignCustomerThrowsExceptionIfCustomerAlreadyHasActiveCart()
+ public function testAssignCustomerCartMerged()
{
/** @var $customer \Magento\Customer\Model\Customer */
$customer = $this->objectManager->create(\Magento\Customer\Model\Customer::class)->load(1);
// Customer has a quote with reserved order ID test_order_1 (see fixture)
/** @var $customerQuote \Magento\Quote\Model\Quote */
$customerQuote = $this->objectManager->create(\Magento\Quote\Model\Quote::class)
- ->load('test_order_1', 'reserved_order_id');
- $customerQuote->setIsActive(1)->save();
+ ->load('test_order_item_with_items', 'reserved_order_id');
/** @var $quote \Magento\Quote\Model\Quote */
$quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class)->load('test01', 'reserved_order_id');
+ $expectedQuoteItemsQty = $customerQuote->getItemsQty() + $quote->getItemsQty();
$cartId = $quote->getId();
@@ -284,11 +283,12 @@ public function testAssignCustomerThrowsExceptionIfCustomerAlreadyHasActiveCart(
'customerId' => $customerId,
'storeId' => 1,
];
- $this->_webApiCall($serviceInfo, $requestData);
+ $this->assertTrue($this->_webApiCall($serviceInfo, $requestData));
+ $mergedQuote = $this->objectManager
+ ->create(\Magento\Quote\Model\Quote::class)
+ ->load('test01', 'reserved_order_id');
- $this->expectExceptionMessage(
- "The customer can't be assigned to the cart because the customer already has an active cart."
- );
+ $this->assertEquals($expectedQuoteItemsQty, $mergedQuote->getItemsQty());
}
/**
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
index 78fa4733a2562..0d2043434d359 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
@@ -254,6 +254,33 @@ public function testGetUsedProducts()
}
}
+ /**
+ * Tests the $requiredAttributes parameter; uses meta_description as an example of an attribute that is not
+ * included in default attribute select.
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable_with_metadescription.php
+ */
+ public function testGetUsedProductsWithRequiredAttributes()
+ {
+ $requiredAttributeIds = [86];
+ $products = $this->model->getUsedProducts($this->product, $requiredAttributeIds);
+ foreach ($products as $product) {
+ self::assertNotNull($product->getData('meta_description'));
+ }
+ }
+
+ /**
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable_with_metadescription.php
+ */
+ public function testGetUsedProductsWithoutRequiredAttributes()
+ {
+ $products = $this->model->getUsedProducts($this->product);
+ foreach ($products as $product) {
+ self::assertNull($product->getData('meta_description'));
+ }
+ }
+
/**
* Test getUsedProducts returns array with same indexes regardless collections was cache or not.
*
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_with_metadescription.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_with_metadescription.php
new file mode 100644
index 0000000000000..d0afeeaf19fe8
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_with_metadescription.php
@@ -0,0 +1,145 @@
+reinitialize();
+
+require __DIR__ . '/configurable_attribute.php';
+
+/** @var ProductRepositoryInterface $productRepository */
+$productRepository = Bootstrap::getObjectManager()
+ ->create(ProductRepositoryInterface::class);
+
+/** @var $installer CategorySetup */
+$installer = Bootstrap::getObjectManager()->create(CategorySetup::class);
+
+/* Create simple products per each option value*/
+/** @var AttributeOptionInterface[] $options */
+$options = $attribute->getOptions();
+
+$attributeValues = [];
+$attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default');
+$associatedProductIds = [];
+$productIds = [10, 20];
+array_shift($options); //remove the first option which is empty
+
+foreach ($options as $option) {
+ /** @var $product Product */
+ $product = Bootstrap::getObjectManager()->create(Product::class);
+ $productId = array_shift($productIds);
+ $product->setTypeId(Type::TYPE_SIMPLE)
+ ->setId($productId)
+ ->setAttributeSetId($attributeSetId)
+ ->setWebsiteIds([1])
+ ->setName('Configurable Option' . $option->getLabel())
+ ->setSku('simple_' . $productId)
+ ->setPrice($productId)
+ ->setTestConfigurable($option->getValue())
+ ->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setMetaDescription('meta_description' . $productId)
+ ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]);
+
+ $product = $productRepository->save($product);
+
+ /** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
+ $stockItem = Bootstrap::getObjectManager()->create(\Magento\CatalogInventory\Model\Stock\Item::class);
+ $stockItem->load($productId, 'product_id');
+
+ if (!$stockItem->getProductId()) {
+ $stockItem->setProductId($productId);
+ }
+ $stockItem->setUseConfigManageStock(1);
+ $stockItem->setQty(1000);
+ $stockItem->setIsQtyDecimal(0);
+ $stockItem->setIsInStock(1);
+ $stockItem->save();
+
+ $attributeValues[] = [
+ 'label' => 'test',
+ 'attribute_id' => $attribute->getId(),
+ 'value_index' => $option->getValue(),
+ ];
+ $associatedProductIds[] = $product->getId();
+}
+
+/** @var $product Product */
+$product = Bootstrap::getObjectManager()->create(Product::class);
+
+/** @var Factory $optionsFactory */
+$optionsFactory = Bootstrap::getObjectManager()->create(Factory::class);
+
+$configurableAttributesData = [
+ [
+ 'attribute_id' => $attribute->getId(),
+ 'code' => $attribute->getAttributeCode(),
+ 'label' => $attribute->getStoreLabel(),
+ 'position' => '0',
+ 'values' => $attributeValues,
+ ],
+];
+
+$configurableOptions = $optionsFactory->create($configurableAttributesData);
+
+$extensionConfigurableAttributes = $product->getExtensionAttributes();
+$extensionConfigurableAttributes->setConfigurableProductOptions($configurableOptions);
+$extensionConfigurableAttributes->setConfigurableProductLinks($associatedProductIds);
+
+$product->setExtensionAttributes($extensionConfigurableAttributes);
+
+// Remove any previously created product with the same id.
+/** @var \Magento\Framework\Registry $registry */
+$registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+try {
+ $productToDelete = $productRepository->getById(1);
+ $productRepository->delete($productToDelete);
+
+ /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource */
+ $itemResource = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\ResourceModel\Quote\Item::class);
+ $itemResource->getConnection()->delete(
+ $itemResource->getMainTable(),
+ 'product_id = ' . $productToDelete->getId()
+ );
+} catch (\Exception $e) {
+ // Nothing to remove
+}
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
+
+$product->setTypeId(Configurable::TYPE_CODE)
+ ->setId(1)
+ ->setAttributeSetId($attributeSetId)
+ ->setWebsiteIds([1])
+ ->setName('Configurable Product')
+ ->setSku('configurable')
+ ->setVisibility(Visibility::VISIBILITY_BOTH)
+ ->setStatus(Status::STATUS_ENABLED)
+ ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]);
+
+$productRepository->save($product);
+
+/** @var \Magento\Catalog\Api\CategoryLinkManagementInterface $categoryLinkManagement */
+$categoryLinkManagement = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->create(\Magento\Catalog\Api\CategoryLinkManagementInterface::class);
+
+$categoryLinkManagement->assignProductToCategories(
+ $product->getSku(),
+ [2]
+);
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_with_metadescription_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_with_metadescription_rollback.php
new file mode 100644
index 0000000000000..21953dea6f587
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_with_metadescription_rollback.php
@@ -0,0 +1,39 @@
+get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+
+foreach (['simple_10', 'simple_20', 'configurable'] as $sku) {
+ try {
+ $product = $productRepository->get($sku, true);
+
+ $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class);
+ $stockStatus->load($product->getEntityId(), 'product_id');
+ $stockStatus->delete();
+
+ if ($product->getId()) {
+ $productRepository->delete($product);
+ }
+ } catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
+ //Product already removed
+ }
+}
+
+require __DIR__ . '/configurable_attribute_rollback.php';
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchApplier.php b/lib/internal/Magento/Framework/Setup/Patch/PatchApplier.php
index bdaca77e5b4eb..e1b0e2842628d 100644
--- a/lib/internal/Magento/Framework/Setup/Patch/PatchApplier.php
+++ b/lib/internal/Magento/Framework/Setup/Patch/PatchApplier.php
@@ -161,6 +161,9 @@ public function applyDataPatch($moduleName = null)
$this->moduleDataSetup->getConnection()->beginTransaction();
$dataPatch->apply();
$this->patchHistory->fixPatch(get_class($dataPatch));
+ foreach ($dataPatch->getAliases() as $patchAlias) {
+ $this->patchHistory->fixPatch($patchAlias);
+ }
$this->moduleDataSetup->getConnection()->commit();
} catch (\Exception $e) {
$this->moduleDataSetup->getConnection()->rollBack();
@@ -237,6 +240,9 @@ public function applySchemaPatch($moduleName = null)
$schemaPatch = $this->patchFactory->create($schemaPatch, ['schemaSetup' => $this->schemaSetup]);
$schemaPatch->apply();
$this->patchHistory->fixPatch(get_class($schemaPatch));
+ foreach ($schemaPatch->getAliases() as $patchAlias) {
+ $this->patchHistory->fixPatch($patchAlias);
+ }
} catch (\Exception $e) {
throw new SetupException(
new Phrase(
diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchApplierTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchApplierTest.php
index cb40845bcc488..b649f6f062e9e 100644
--- a/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchApplierTest.php
+++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchApplierTest.php
@@ -10,8 +10,11 @@
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Module\ModuleResource;
use Magento\Framework\ObjectManagerInterface;
+use Magento\Framework\Setup\Exception;
use Magento\Framework\Setup\ModuleDataSetupInterface;
+use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchBackwardCompatability;
+use Magento\Framework\Setup\Patch\PatchInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Framework\Setup\Patch\PatchApplier;
@@ -169,8 +172,10 @@ public function testApplyDataPatchForNewlyInstalledModule($moduleName, $dataPatc
$patch1 = $this->createMock(\SomeDataPatch::class);
$patch1->expects($this->once())->method('apply');
+ $patch1->expects($this->once())->method('getAliases')->willReturn([]);
$patch2 = $this->createMock(\OtherDataPatch::class);
$patch2->expects($this->once())->method('apply');
+ $patch2->expects($this->once())->method('getAliases')->willReturn([]);
$this->objectManagerMock->expects($this->any())->method('create')->willReturnMap(
[
['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1],
@@ -188,6 +193,60 @@ public function testApplyDataPatchForNewlyInstalledModule($moduleName, $dataPatc
$this->patchApllier->applyDataPatch($moduleName);
}
+ /**
+ * @param $moduleName
+ * @param $dataPatches
+ * @param $moduleVersionInDb
+ *
+ * @dataProvider applyDataPatchDataNewModuleProvider()
+ *
+ * @expectedException Exception
+ * @expectedExceptionMessageRegExp "Unable to apply data patch .+ cannot be applied twice"
+ */
+ public function testApplyDataPatchForAlias($moduleName, $dataPatches, $moduleVersionInDb)
+ {
+ $this->dataPatchReaderMock->expects($this->once())
+ ->method('read')
+ ->with($moduleName)
+ ->willReturn($dataPatches);
+
+ $this->moduleResourceMock->expects($this->any())->method('getDataVersion')->willReturnMap(
+ [
+ [$moduleName, $moduleVersionInDb]
+ ]
+ );
+
+ $patch1 = $this->createMock(DataPatchInterface::class);
+ $patch1->expects($this->once())->method('getAliases')->willReturn(['PatchAlias']);
+ $patchClass = get_class($patch1);
+
+ $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, [$patchClass], ['registerPatch']);
+ $patchRegistryMock->expects($this->any())
+ ->method('registerPatch');
+
+ $this->patchRegistryFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($patchRegistryMock);
+
+ $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap(
+ [
+ ['\\' . $patchClass, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1],
+ ]
+ );
+ $this->connectionMock->expects($this->exactly(1))->method('beginTransaction');
+ $this->connectionMock->expects($this->never())->method('commit');
+ $this->patchHistoryMock->expects($this->any())->method('fixPatch')->will(
+ $this->returnCallback(
+ function ($param1) {
+ if ($param1 == 'PatchAlias') {
+ throw new \LogicException(sprintf("Patch %s cannot be applied twice", $param1));
+ }
+ }
+ )
+ );
+ $this->patchApllier->applyDataPatch($moduleName);
+ }
+
/**
* @return array
*/
@@ -243,8 +302,10 @@ public function testApplyDataPatchForInstalledModule($moduleName, $dataPatches,
$patch1 = $this->createMock(\SomeDataPatch::class);
$patch1->expects(self::never())->method('apply');
+ $patch1->expects(self::any())->method('getAliases')->willReturn([]);
$patch2 = $this->createMock(\OtherDataPatch::class);
$patch2->expects(self::once())->method('apply');
+ $patch2->expects(self::any())->method('getAliases')->willReturn([]);
$this->objectManagerMock->expects(self::any())->method('create')->willReturnMap(
[
['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1],
@@ -279,7 +340,7 @@ public function applyDataPatchDataInstalledModuleProvider()
* @param $dataPatches
* @param $moduleVersionInDb
*
- * @expectedException \Magento\Framework\Setup\Exception
+ * @expectedException Exception
* @expectedExceptionMessage Patch Apply Error
*
* @dataProvider applyDataPatchDataInstalledModuleProvider()
@@ -328,7 +389,7 @@ public function testApplyDataPatchRollback($moduleName, $dataPatches, $moduleVer
}
/**
- * @expectedException \Magento\Framework\Setup\Exception
+ * @expectedException Exception
* @expectedExceptionMessageRegExp "Patch [a-zA-Z0-9\_]+ should implement DataPatchInterface"
*/
public function testNonDataPatchApply()
@@ -434,8 +495,10 @@ public function testSchemaPatchAplly($moduleName, $schemaPatches, $moduleVersion
$patch1 = $this->createMock(\SomeSchemaPatch::class);
$patch1->expects($this->never())->method('apply');
+ $patch1->expects($this->any())->method('getAliases')->willReturn([]);
$patch2 = $this->createMock(\OtherSchemaPatch::class);
$patch2->expects($this->once())->method('apply');
+ $patch2->expects($this->any())->method('getAliases')->willReturn([]);
$this->patchFactoryMock->expects($this->any())->method('create')->willReturnMap(
[
[\SomeSchemaPatch::class, ['schemaSetup' => $this->schemaSetupMock], $patch1],
@@ -448,6 +511,55 @@ public function testSchemaPatchAplly($moduleName, $schemaPatches, $moduleVersion
$this->patchApllier->applySchemaPatch($moduleName);
}
+ /**
+ * @param $moduleName
+ * @param $schemaPatches
+ * @param $moduleVersionInDb
+ *
+ * @dataProvider schemaPatchDataProvider()
+ *
+ * @expectedException Exception
+ * @expectedExceptionMessageRegExp "Unable to apply patch .+ cannot be applied twice"
+ */
+ public function testSchemaPatchApplyForPatchAlias($moduleName, $schemaPatches, $moduleVersionInDb)
+ {
+ $this->schemaPatchReaderMock->expects($this->once())
+ ->method('read')
+ ->with($moduleName)
+ ->willReturn($schemaPatches);
+
+ $this->moduleResourceMock->expects($this->any())->method('getDbVersion')->willReturnMap(
+ [
+ [$moduleName, $moduleVersionInDb]
+ ]
+ );
+
+ $patch1 = $this->createMock(PatchInterface::class);
+ $patch1->expects($this->once())->method('getAliases')->willReturn(['PatchAlias']);
+ $patchClass = get_class($patch1);
+
+ $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, [$patchClass], ['registerPatch']);
+ $patchRegistryMock->expects($this->any())
+ ->method('registerPatch');
+
+ $this->patchRegistryFactoryMock->expects($this->any())
+ ->method('create')
+ ->willReturn($patchRegistryMock);
+
+ $this->patchFactoryMock->expects($this->any())->method('create')->willReturn($patch1);
+ $this->patchHistoryMock->expects($this->any())->method('fixPatch')->will(
+ $this->returnCallback(
+ function ($param1) {
+ if ($param1 == 'PatchAlias') {
+ throw new \LogicException(sprintf("Patch %s cannot be applied twice", $param1));
+ }
+ }
+ )
+ );
+
+ $this->patchApllier->applySchemaPatch($moduleName);
+ }
+
public function testRevertDataPatches()
{
$patches = [\RevertableDataPatch::class];
@@ -534,33 +646,43 @@ private function createAggregateIteratorMock($className, array $items = [], arra
$someIterator->expects($this->any())
->method('rewind')
- ->willReturnCallback(function () use ($iterator) {
- $iterator->rewind();
- });
+ ->willReturnCallback(
+ function () use ($iterator) {
+ $iterator->rewind();
+ }
+ );
$someIterator->expects($this->any())
->method('current')
- ->willReturnCallback(function () use ($iterator) {
- return $iterator->current();
- });
+ ->willReturnCallback(
+ function () use ($iterator) {
+ return $iterator->current();
+ }
+ );
$someIterator->expects($this->any())
->method('key')
- ->willReturnCallback(function () use ($iterator) {
- return $iterator->key();
- });
+ ->willReturnCallback(
+ function () use ($iterator) {
+ return $iterator->key();
+ }
+ );
$someIterator->expects($this->any())
->method('next')
- ->willReturnCallback(function () use ($iterator) {
- $iterator->next();
- });
+ ->willReturnCallback(
+ function () use ($iterator) {
+ $iterator->next();
+ }
+ );
$someIterator->expects($this->any())
->method('valid')
- ->willReturnCallback(function () use ($iterator) {
- return $iterator->valid();
- });
+ ->willReturnCallback(
+ function () use ($iterator) {
+ return $iterator->valid();
+ }
+ );
return $mockIteratorAggregate;
}
diff --git a/lib/web/magnifier/magnify.js b/lib/web/magnifier/magnify.js
index 9d673092b806c..559e7782f2476 100644
--- a/lib/web/magnifier/magnify.js
+++ b/lib/web/magnifier/magnify.js
@@ -680,8 +680,6 @@ define([
$image.removeClass(imageDraggableClass);
}
} else if (gallery.fullScreen && (!transitionEnabled || !transitionActive)) {
- e.preventDefault();
-
imagePosY = getTop($image);
imagePosX = $image.offset().left;