From 26801a18c646b8a389dea9c697acb02fd60259f0 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 10 Aug 2017 15:18:54 -0500 Subject: [PATCH 0001/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix block --- .../product/price/configured_price.phtml | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index 98b713be685d0..ec93fb431ed10 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -12,13 +12,44 @@ $schema = ($block->getZone() == 'item_view') ? true : false; $priceLabel = ($block->getPriceLabel() !== null) ? $block->getPriceLabel() : ''; + +/** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */ +$priceModel = $block->getPriceType('regular_price'); + +$finalPriceModel = $block->getPriceType('final_price'); +$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; ?> -

- renderAmount($configuredPrice->getAmount(), [ - 'display_label' => $priceLabel, - 'price_id' => $block->getPriceId('product-price-'), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ]); ?> -

+ +hasSpecialPrice()) : ?> +

+ + renderAmount($finalPriceModel->getAmount(), [ + 'display_label' => __('Special Price'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ]); ?> + + + renderAmount($priceModel->getAmount(), [ + 'display_label' => __('Regular Price'), + 'price_id' => $block->getPriceId('old-price-' . $idSuffix), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ]); ?> + +

+ +

+ renderAmount($configuredPrice->getAmount(), [ + 'display_label' => $priceLabel, + 'price_id' => $block->getPriceId('product-price-'), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ]); ?> +

+ + From 0dd21c6e8b833e37e80c2eb062f2e9cfd66be19c Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 10 Aug 2017 18:03:49 -0500 Subject: [PATCH 0002/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix block --- .../product/price/configured_price.phtml | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index ec93fb431ed10..5b2b3aefb21bf 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -6,24 +6,20 @@ ?> getPrice(); $schema = ($block->getZone() == 'item_view') ? true : false; -$priceLabel = ($block->getPriceLabel() !== null) - ? $block->getPriceLabel() - : ''; - -/** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */ -$priceModel = $block->getPriceType('regular_price'); - -$finalPriceModel = $block->getPriceType('final_price'); $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; ?> hasSpecialPrice()) : ?> + getPriceType('regular_price'); + + $finalPriceModel = $block->getPriceType('final_price'); + ?>

- renderAmount($finalPriceModel->getAmount(), [ + renderAmount($finalPriceModel->getAmount(), [ 'display_label' => __('Special Price'), 'price_id' => $block->getPriceId('product-price-' . $idSuffix), 'price_type' => 'finalPrice', @@ -32,7 +28,7 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; ]); ?> - renderAmount($priceModel->getAmount(), [ + renderAmount($priceModel->getAmount(), [ 'display_label' => __('Regular Price'), 'price_id' => $block->getPriceId('old-price-' . $idSuffix), 'price_type' => 'oldPrice', @@ -42,14 +38,20 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : '';

+ getPrice(); + $priceLabel = ($block->getPriceLabel() !== null) + ? $block->getPriceLabel() + : ''; + ?>

renderAmount($configuredPrice->getAmount(), [ 'display_label' => $priceLabel, - 'price_id' => $block->getPriceId('product-price-'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), 'price_type' => 'finalPrice', 'include_container' => true, 'schema' => $schema ]); ?>

- From 5d949e9ce10453b8940185682ab71d9d02baa0ed Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 10 Aug 2017 18:21:11 -0500 Subject: [PATCH 0003/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix block --- .../product/price/configured_price.phtml | 60 ++++++++++++------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index 5b2b3aefb21bf..ec3ee5671f82c 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -19,22 +19,34 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; ?>

- renderAmount($finalPriceModel->getAmount(), [ - 'display_label' => __('Special Price'), - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ]); ?> + escapeHtml( + $block->renderAmount( + $finalPriceModel->getAmount(), + [ + 'display_label' => __('Special Price'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] + ); ?> - renderAmount($priceModel->getAmount(), [ - 'display_label' => __('Regular Price'), - 'price_id' => $block->getPriceId('old-price-' . $idSuffix), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ]); ?> + escapeHtml( + $block->renderAmount( + $priceModel->getAmount(), + [ + 'display_label' => __('Regular Price'), + 'price_id' => $block->getPriceId('old-price-' . $idSuffix), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] + ), + ['span'] + ); ?>

@@ -46,12 +58,18 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; : ''; ?>

- renderAmount($configuredPrice->getAmount(), [ - 'display_label' => $priceLabel, - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ]); ?> + escapeHtml( + $block->renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $priceLabel, + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] + ); ?>

From 19356f92a55a8cf8a3681fb24f32a300b283819e Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 11 Aug 2017 12:31:41 -0500 Subject: [PATCH 0004/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix block --- .../product/price/configured_price.phtml | 63 ++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index ec3ee5671f82c..fa4e93f7851a5 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -19,33 +19,27 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; ?>

- escapeHtml( - $block->renderAmount( - $finalPriceModel->getAmount(), - [ - 'display_label' => __('Special Price'), - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $finalPriceModel->getAmount(), + [ + 'display_label' => $block->escapeHtml(__('Special Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?> - escapeHtml( - $block->renderAmount( - $priceModel->getAmount(), - [ - 'display_label' => __('Regular Price'), - 'price_id' => $block->getPriceId('old-price-' . $idSuffix), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ] - ), - ['span'] + renderAmount( + $priceModel->getAmount(), + [ + 'display_label' => $block->escapeHtml(__('Regular Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] ); ?>

@@ -58,18 +52,15 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; : ''; ?>

- escapeHtml( - $block->renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $priceLabel, - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml($priceLabel), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?>

From 892a7db34863ee32e6a3cdc98cc42d331fc26931 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Tue, 22 Aug 2017 12:36:09 -0500 Subject: [PATCH 0005/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix bundle regular price --- .../Block/Catalog/Product/View/Type/Bundle.php | 15 +++++++++------ .../Bundle/Pricing/Price/BundleOptionPrice.php | 8 +++++--- .../Pricing/Price/BundleOptionPriceInterface.php | 3 ++- .../Bundle/Pricing/Price/BundleSelectionPrice.php | 4 ++-- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php index 6cb103fc86789..1b015610f8ad3 100644 --- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php +++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php @@ -227,11 +227,14 @@ private function getSelectionItemData(Product $product, Product $selection) { $qty = ($selection->getSelectionQty() * 1) ?: '1'; - $optionPriceAmount = $product->getPriceInfo() - ->getPrice('bundle_option') - ->getOptionSelectionAmount($selection); - $finalPrice = $optionPriceAmount->getValue(); - $basePrice = $optionPriceAmount->getBaseAmount(); + $bundleOptionPrice = $product->getPriceInfo() + ->getPrice('bundle_option'); + $finalPrice = $bundleOptionPrice->getOptionSelectionAmount($selection)->getValue(); + $basePrice = $bundleOptionPrice->getOptionSelectionAmount($selection)->getBaseAmount(); + + $oldPrice = $bundleOptionPrice + ->getOptionSelectionAmount($selection, true) + ->getValue(); $selection = [ 'qty' => $qty, @@ -239,7 +242,7 @@ private function getSelectionItemData(Product $product, Product $selection) 'optionId' => $selection->getId(), 'prices' => [ 'oldPrice' => [ - 'amount' => $basePrice + 'amount' => $oldPrice ], 'basePrice' => [ 'amount' => $basePrice diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php index 995572636e759..cac169045e007 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php @@ -105,22 +105,24 @@ public function getOptions() * Get selection amount * * @param \Magento\Bundle\Model\Selection $selection + * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getOptionSelectionAmount($selection) + public function getOptionSelectionAmount($selection, $useRegularPrice = false) { $cacheKey = implode( '_', [ $this->product->getId(), $selection->getOptionId(), - $selection->getSelectionId() + $selection->getSelectionId(), + $useRegularPrice ? 1: 0 ] ); if (!isset($this->optionSelecionAmountCache[$cacheKey])) { $selectionPrice = $this->selectionFactory - ->create($this->product, $selection, $selection->getSelectionQty()); + ->create($this->product, $selection, $selection->getSelectionQty(), ['useRegularPrice' => $useRegularPrice ? true: false]); $this->optionSelecionAmountCache[$cacheKey] = $selectionPrice->getAmount(); } diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php index 1fa8a9710beb8..cc0aa01673d6b 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php @@ -21,7 +21,8 @@ public function getOptions(); /** * @param \Magento\Bundle\Model\Selection $selection + * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getOptionSelectionAmount($selection); + public function getOptionSelectionAmount($selection, $useRegularPrice = false); } diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php index 71c1b5c5e98cb..513a1a0adf3b7 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php @@ -103,7 +103,7 @@ public function getValue() return $this->value; } $product = $this->selection; - $bundleSelectionKey = 'bundle-selection-value-' . $product->getSelectionId(); + $bundleSelectionKey = 'bundle-selection-value-' . $product->getSelectionId() . '-' . ($this->useRegularPrice ? 1 : 0); if ($product->hasData($bundleSelectionKey)) { return $product->getData($bundleSelectionKey); } @@ -150,7 +150,7 @@ public function getValue() public function getAmount() { $product = $this->selection; - $bundleSelectionKey = 'bundle-selection-amount-' . $product->getSelectionId(); + $bundleSelectionKey = 'bundle-selection-amount-' . $product->getSelectionId() . '-' . ($this->useRegularPrice ? 1 : 0); if ($product->hasData($bundleSelectionKey)) { return $product->getData($bundleSelectionKey); } From 5428e1524e0a30cc29680e8a9eb0aa15936bd015 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Tue, 22 Aug 2017 16:37:42 -0500 Subject: [PATCH 0006/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix bundle regular price and move code using composition --- .../Catalog/Product/View/Type/Bundle.php | 16 ++- .../Pricing/Price/BundleOptionPrice.php | 70 +++------- .../Price/BundleOptionPriceInterface.php | 3 +- .../Price/BundleOptionRegularPrice.php | 117 +++++++++++++++++ .../Bundle/Pricing/Price/BundleOptions.php | 121 ++++++++++++++++++ app/code/Magento/Bundle/etc/di.xml | 1 + 6 files changed, 270 insertions(+), 58 deletions(-) create mode 100644 app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php create mode 100644 app/code/Magento/Bundle/Pricing/Price/BundleOptions.php diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php index 1b015610f8ad3..3f19e20de8918 100644 --- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php +++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php @@ -227,13 +227,15 @@ private function getSelectionItemData(Product $product, Product $selection) { $qty = ($selection->getSelectionQty() * 1) ?: '1'; - $bundleOptionPrice = $product->getPriceInfo() - ->getPrice('bundle_option'); - $finalPrice = $bundleOptionPrice->getOptionSelectionAmount($selection)->getValue(); - $basePrice = $bundleOptionPrice->getOptionSelectionAmount($selection)->getBaseAmount(); - - $oldPrice = $bundleOptionPrice - ->getOptionSelectionAmount($selection, true) + $optionPriceAmount = $product->getPriceInfo() + ->getPrice(\Magento\Bundle\Pricing\Price\BundleOptionPrice::PRICE_CODE) + ->getOptionSelectionAmount($selection); + $finalPrice = $optionPriceAmount->getValue(); + $basePrice = $optionPriceAmount->getBaseAmount(); + + $oldPrice = $product->getPriceInfo() + ->getPrice(\Magento\Bundle\Pricing\Price\BundleOptionRegularPrice::PRICE_CODE) + ->getOptionSelectionAmount($selection) ->getValue(); $selection = [ diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php index cac169045e007..dd2be8ec0311a 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php @@ -10,7 +10,7 @@ use Magento\Framework\Pricing\Price\AbstractPrice; /** - * Bundle option price model + * Bundle option price model with final price */ class BundleOptionPrice extends AbstractPrice implements BundleOptionPriceInterface { @@ -25,6 +25,7 @@ class BundleOptionPrice extends AbstractPrice implements BundleOptionPriceInterf protected $calculator; /** + * @deprecated * @var BundleSelectionFactory */ protected $selectionFactory; @@ -34,23 +35,32 @@ class BundleOptionPrice extends AbstractPrice implements BundleOptionPriceInterf */ protected $maximalPrice; + /** + * @var \Magento\Bundle\Pricing\Price\BundleOptions + */ + private $bundleOptions; + /** * @param Product $saleableItem * @param float $quantity * @param BundleCalculatorInterface $calculator * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency * @param BundleSelectionFactory $bundleSelectionFactory + * @param BundleOptions $bundleOptions */ public function __construct( Product $saleableItem, $quantity, BundleCalculatorInterface $calculator, \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency, - BundleSelectionFactory $bundleSelectionFactory + BundleSelectionFactory $bundleSelectionFactory, + BundleOptions $bundleOptions ) { $this->selectionFactory = $bundleSelectionFactory; parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency); $this->product->setQty($this->quantity); + $this->bundleOptions = $bundleOptions ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Bundle\Pricing\Price\BundleOptions::class); } /** @@ -59,7 +69,7 @@ public function __construct( public function getValue() { if (null === $this->value) { - $this->value = $this->calculateOptions(); + $this->value = $this->bundleOptions->calculateOptions($this->product); } return $this->value; } @@ -72,7 +82,7 @@ public function getValue() public function getMaxValue() { if (null === $this->maximalPrice) { - $this->maximalPrice = $this->calculateOptions(false); + $this->maximalPrice = $this->bundleOptions->calculateOptions($this->product, false); } return $this->maximalPrice; } @@ -84,49 +94,22 @@ public function getMaxValue() */ public function getOptions() { - $bundleProduct = $this->product; - /** @var \Magento\Bundle\Model\Product\Type $typeInstance */ - $typeInstance = $bundleProduct->getTypeInstance(); - $typeInstance->setStoreFilter($bundleProduct->getStoreId(), $bundleProduct); - - /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionCollection */ - $optionCollection = $typeInstance->getOptionsCollection($bundleProduct); - - $selectionCollection = $typeInstance->getSelectionsCollection( - $typeInstance->getOptionsIds($bundleProduct), - $bundleProduct - ); - - $priceOptions = $optionCollection->appendSelections($selectionCollection, true, false); - return $priceOptions; + return $this->bundleOptions->getOptions($this->product); } /** * Get selection amount * * @param \Magento\Bundle\Model\Selection $selection - * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getOptionSelectionAmount($selection, $useRegularPrice = false) + public function getOptionSelectionAmount($selection) { - $cacheKey = implode( - '_', - [ - $this->product->getId(), - $selection->getOptionId(), - $selection->getSelectionId(), - $useRegularPrice ? 1: 0 - ] + return $this->bundleOptions->getOptionSelectionAmount( + $this->product, + $selection, + false ); - - if (!isset($this->optionSelecionAmountCache[$cacheKey])) { - $selectionPrice = $this->selectionFactory - ->create($this->product, $selection, $selection->getSelectionQty(), ['useRegularPrice' => $useRegularPrice ? true: false]); - $this->optionSelecionAmountCache[$cacheKey] = $selectionPrice->getAmount(); - } - - return $this->optionSelecionAmountCache[$cacheKey]; } /** @@ -137,18 +120,7 @@ public function getOptionSelectionAmount($selection, $useRegularPrice = false) */ protected function calculateOptions($searchMin = true) { - $priceList = []; - /* @var $option \Magento\Bundle\Model\Option */ - foreach ($this->getOptions() as $option) { - if ($searchMin && !$option->getRequired()) { - continue; - } - $selectionPriceList = $this->calculator->createSelectionPriceList($option, $this->product); - $selectionPriceList = $this->calculator->processOptions($option, $selectionPriceList, $searchMin); - $priceList = array_merge($priceList, $selectionPriceList); - } - $amount = $this->calculator->calculateBundleAmount(0., $this->product, $priceList); - return $amount->getValue(); + return $this->bundleOptions->calculateOptions($this->product, $searchMin); } /** diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php index cc0aa01673d6b..1fa8a9710beb8 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPriceInterface.php @@ -21,8 +21,7 @@ public function getOptions(); /** * @param \Magento\Bundle\Model\Selection $selection - * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getOptionSelectionAmount($selection, $useRegularPrice = false); + public function getOptionSelectionAmount($selection); } diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php new file mode 100644 index 0000000000000..2a8ecc892ae88 --- /dev/null +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php @@ -0,0 +1,117 @@ +selectionFactory = $bundleSelectionFactory; + parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency); + $this->product->setQty($this->quantity); + $this->bundleOptions = $bundleOptions; + } + + /** + * {@inheritdoc} + */ + public function getValue() + { + if (null === $this->value) { + $this->value = $this->bundleOptions->calculateOptions($this->product); + } + return $this->value; + } + + /** + * Getter for maximal price of options + * + * @return bool|float + */ + public function getMaxValue() + { + if (null === $this->maximalPrice) { + $this->maximalPrice = $this->bundleOptions->calculateOptions($this->product, false); + } + return $this->maximalPrice; + } + + /** + * Get Options with attached Selections collection + * + * @return \Magento\Bundle\Model\ResourceModel\Option\Collection + */ + public function getOptions() + { + return $this->bundleOptions->getOptions($this->product); + } + + /** + * Get selection amount + * + * @param \Magento\Bundle\Model\Selection $selection + * @return \Magento\Framework\Pricing\Amount\AmountInterface + */ + public function getOptionSelectionAmount($selection) + { + return $this->bundleOptions->getOptionSelectionAmount( + $this->product, + $selection, + true + ); + } + + /** + * Get minimal amount of bundle price with options + * + * @return \Magento\Framework\Pricing\Amount\AmountInterface + */ + public function getAmount() + { + return $this->calculator->getOptionsAmount($this->product); + } +} diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptions.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptions.php new file mode 100644 index 0000000000000..a01143e614926 --- /dev/null +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptions.php @@ -0,0 +1,121 @@ +calculator = $calculator; + $this->selectionFactory = $bundleSelectionFactory; + } + + /** + * Get Options with attached Selections collection + * + * @param \Magento\Framework\Pricing\SaleableInterface $bundleProduct + * @return \Magento\Bundle\Model\ResourceModel\Option\Collection + */ + public function getOptions(\Magento\Framework\Pricing\SaleableInterface $bundleProduct) + { + /** @var \Magento\Bundle\Model\Product\Type $typeInstance */ + $typeInstance = $bundleProduct->getTypeInstance(); + $typeInstance->setStoreFilter($bundleProduct->getStoreId(), $bundleProduct); + + /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionCollection */ + $optionCollection = $typeInstance->getOptionsCollection($bundleProduct); + + $selectionCollection = $typeInstance->getSelectionsCollection( + $typeInstance->getOptionsIds($bundleProduct), + $bundleProduct + ); + + $priceOptions = $optionCollection->appendSelections($selectionCollection, true, false); + return $priceOptions; + } + + + /** + * Calculate maximal or minimal options value + * + * @param \Magento\Framework\Pricing\SaleableInterface $bundleProduct + * @param bool $searchMin + * @return float + */ + public function calculateOptions( + \Magento\Framework\Pricing\SaleableInterface $bundleProduct, + $searchMin = true + ) { + $priceList = []; + /* @var $option \Magento\Bundle\Model\Option */ + foreach ($this->getOptions($bundleProduct) as $option) { + if ($searchMin && !$option->getRequired()) { + continue; + } + $selectionPriceList = $this->calculator->createSelectionPriceList($option, $bundleProduct); + $selectionPriceList = $this->calculator->processOptions($option, $selectionPriceList, $searchMin); + $priceList = array_merge($priceList, $selectionPriceList); + } + $amount = $this->calculator->calculateBundleAmount(0., $bundleProduct, $priceList); + return $amount->getValue(); + } + + /** + * Get selection amount + * + * @param \Magento\Framework\Pricing\SaleableInterface $bundleProduct + * @param \Magento\Bundle\Model\Selection $selection + * @param bool $useRegularPrice + * @return \Magento\Framework\Pricing\Amount\AmountInterface + */ + public function getOptionSelectionAmount( + $bundleProduct, + $selection, + $useRegularPrice = false + ) { + $cacheKey = implode( + '_', + [ + $bundleProduct->getId(), + $selection->getOptionId(), + $selection->getSelectionId(), + $useRegularPrice ? 1 : 0 + ] + ); + + if (!isset($this->optionSelectionAmountCache[$cacheKey])) { + $selectionPrice = $this->selectionFactory + ->create( + $bundleProduct, + $selection, + $selection->getSelectionQty(), + ['useRegularPrice' => $useRegularPrice ? true : false] + ); + $this->optionSelectionAmountCache[$cacheKey] = $selectionPrice->getAmount(); + } + + return $this->optionSelectionAmountCache[$cacheKey]; + } +} diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml index 287a6c8bfdbc0..7de25ce991a35 100644 --- a/app/code/Magento/Bundle/etc/di.xml +++ b/app/code/Magento/Bundle/etc/di.xml @@ -51,6 +51,7 @@ Magento\Catalog\Pricing\Price\BasePrice Magento\Bundle\Pricing\Price\ConfiguredPrice Magento\Bundle\Pricing\Price\BundleOptionPrice + Magento\Bundle\Pricing\Price\BundleOptionRegularPrice Magento\CatalogRule\Pricing\Price\CatalogRulePrice From d751495cf78ae8e3fbee186d65ff3b6bd8802ca1 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 24 Aug 2017 15:53:54 -0500 Subject: [PATCH 0007/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix static --- .../Bundle/Pricing/Price/BundleOptionPrice.php | 6 +++--- .../Pricing/Price/BundleOptionRegularPrice.php | 13 ------------- .../Magento/Bundle/Pricing/Price/BundleOptions.php | 3 +-- .../Bundle/Pricing/Price/BundleSelectionPrice.php | 5 ++++- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php index dd2be8ec0311a..1533a34b29bdb 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php @@ -46,7 +46,7 @@ class BundleOptionPrice extends AbstractPrice implements BundleOptionPriceInterf * @param BundleCalculatorInterface $calculator * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency * @param BundleSelectionFactory $bundleSelectionFactory - * @param BundleOptions $bundleOptions + * @param BundleOptions|null $bundleOptions */ public function __construct( Product $saleableItem, @@ -54,12 +54,12 @@ public function __construct( BundleCalculatorInterface $calculator, \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency, BundleSelectionFactory $bundleSelectionFactory, - BundleOptions $bundleOptions + BundleOptions $bundleOptions = null ) { $this->selectionFactory = $bundleSelectionFactory; parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency); $this->product->setQty($this->quantity); - $this->bundleOptions = $bundleOptions ?: \Magento\Framework\App\ObjectManager::getInstance() + $this->bundleOptions = $bundleOptions ?: \Magento\Framework\App\ObjectManager::getInstance() ->get(\Magento\Bundle\Pricing\Price\BundleOptions::class); } diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php index 2a8ecc892ae88..9ecf63f873c65 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php @@ -67,19 +67,6 @@ public function getValue() return $this->value; } - /** - * Getter for maximal price of options - * - * @return bool|float - */ - public function getMaxValue() - { - if (null === $this->maximalPrice) { - $this->maximalPrice = $this->bundleOptions->calculateOptions($this->product, false); - } - return $this->maximalPrice; - } - /** * Get Options with attached Selections collection * diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptions.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptions.php index a01143e614926..05fe902f730e1 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptions.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptions.php @@ -56,7 +56,6 @@ public function getOptions(\Magento\Framework\Pricing\SaleableInterface $bundleP return $priceOptions; } - /** * Calculate maximal or minimal options value * @@ -111,7 +110,7 @@ public function getOptionSelectionAmount( $bundleProduct, $selection, $selection->getSelectionQty(), - ['useRegularPrice' => $useRegularPrice ? true : false] + ['useRegularPrice' => $useRegularPrice] ); $this->optionSelectionAmountCache[$cacheKey] = $selectionPrice->getAmount(); } diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php index 513a1a0adf3b7..085d7b920118d 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php @@ -150,7 +150,10 @@ public function getValue() public function getAmount() { $product = $this->selection; - $bundleSelectionKey = 'bundle-selection-amount-' . $product->getSelectionId() . '-' . ($this->useRegularPrice ? 1 : 0); + $bundleSelectionKey = 'bundle-selection-amount-' + . $product->getSelectionId() + . '-' + . ($this->useRegularPrice ? '' : 'regular-price'); if ($product->hasData($bundleSelectionKey)) { return $product->getData($bundleSelectionKey); } From 33328e037a527723fc7c7478e9044d6434000116 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 24 Aug 2017 18:13:13 -0500 Subject: [PATCH 0008/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - add unit tests --- .../Pricing/Price/BundleOptionPrice.php | 3 +- .../Pricing/Price/BundleOptionPriceTest.php | 375 ++--------------- .../Price/BundleOptionRegularPriceTest.php | 95 +++++ .../Unit/Pricing/Price/BundleOptionTest.php | 393 ++++++++++++++++++ 4 files changed, 517 insertions(+), 349 deletions(-) create mode 100644 app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php create mode 100644 app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionTest.php diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php index 1533a34b29bdb..241902f6bba61 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionPrice.php @@ -25,8 +25,8 @@ class BundleOptionPrice extends AbstractPrice implements BundleOptionPriceInterf protected $calculator; /** - * @deprecated * @var BundleSelectionFactory + * @deprecated */ protected $selectionFactory; @@ -78,6 +78,7 @@ public function getValue() * Getter for maximal price of options * * @return bool|float + * @deprecated */ public function getMaxValue() { diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php index b6485d0e441e9..fdb37e910d6da 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php @@ -8,95 +8,39 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ class BundleOptionPriceTest extends \PHPUnit\Framework\TestCase { /** * @var \Magento\Bundle\Pricing\Price\BundleOptionPrice */ - protected $bundleOptionPrice; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $baseCalculator; + private $bundleOptionPrice; /** * @var ObjectManagerHelper */ - protected $objectManagerHelper; + private $objectManagerHelper; /** * @var \Magento\Framework\Pricing\SaleableInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $saleableItemMock; + private $saleableItemMock; /** * @var \Magento\Bundle\Pricing\Adjustment\BundleCalculatorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $bundleCalculatorMock; - - /** - * @var \Magento\Bundle\Pricing\Price\BundleSelectionFactory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $selectionFactoryMock; + private $bundleCalculatorMock; /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $amountFactory; - - /** - * @var \Magento\Framework\Pricing\PriceInfo\Base|\PHPUnit_Framework_MockObject_MockObject - */ - protected $priceInfoMock; + private $bundleOptionsMock; protected function setUp() { - $this->priceInfoMock = $this->createMock(\Magento\Framework\Pricing\PriceInfo\Base::class); + $this->bundleOptionsMock = $this->createMock(\Magento\Bundle\Pricing\Price\BundleOptions::class); $this->saleableItemMock = $this->createMock(\Magento\Catalog\Model\Product::class); - $priceCurrency = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class)->getMock(); - $this->saleableItemMock->expects($this->once()) - ->method('getPriceInfo') - ->will($this->returnValue($this->priceInfoMock)); - - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - $priceCurrency->expects($this->any())->method('round')->will($this->returnArgument(0)); - - $this->saleableItemMock->expects($this->once()) - ->method('setQty') - ->will($this->returnSelf()); - - $this->saleableItemMock->expects($this->any()) - ->method('getStore') - ->will($this->returnValue($store)); + $this->bundleCalculatorMock = $this->createMock(\Magento\Bundle\Pricing\Adjustment\Calculator::class); - $this->selectionFactoryMock = $this->getMockBuilder(\Magento\Bundle\Pricing\Price\BundleSelectionFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->amountFactory = $this->createMock(\Magento\Framework\Pricing\Amount\AmountFactory::class); - $factoryCallback = $this->returnCallback( - function ($fullAmount, $adjustments) { - return $this->createAmountMock(['amount' => $fullAmount, 'adjustmentAmounts' => $adjustments]); - } - ); - $this->amountFactory->expects($this->any())->method('create')->will($factoryCallback); - $this->baseCalculator = $this->createMock(\Magento\Framework\Pricing\Adjustment\Calculator::class); - - $taxData = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->bundleCalculatorMock = $this->getMockBuilder(\Magento\Bundle\Pricing\Adjustment\Calculator::class) - ->setConstructorArgs( - [$this->baseCalculator, $this->amountFactory, $this->selectionFactoryMock, $taxData, $priceCurrency] - ) - ->setMethods(['getOptionsAmount']) - ->getMock(); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->bundleOptionPrice = $this->objectManagerHelper->getObject( \Magento\Bundle\Pricing\Price\BundleOptionPrice::class, @@ -104,102 +48,32 @@ function ($fullAmount, $adjustments) { 'saleableItem' => $this->saleableItemMock, 'quantity' => 1., 'calculator' => $this->bundleCalculatorMock, - 'bundleSelectionFactory' => $this->selectionFactoryMock + 'bundleOptions' => $this->bundleOptionsMock ] ); } - /** - * @dataProvider getOptionsDataProvider - */ - public function testGetOptions($selectionCollection) + public function testGetOptions() { - $this->prepareOptionMocks($selectionCollection); - $this->assertSame($selectionCollection, $this->bundleOptionPrice->getOptions()); - $this->assertSame($selectionCollection, $this->bundleOptionPrice->getOptions()); - } - - /** - * @param array $selectionCollection - * @return void - */ - protected function prepareOptionMocks($selectionCollection) - { - $this->saleableItemMock->expects($this->atLeastOnce()) - ->method('getStoreId') - ->will($this->returnValue(1)); - - $priceTypeMock = $this->createMock(\Magento\Bundle\Model\Product\Type::class); - $priceTypeMock->expects($this->atLeastOnce()) - ->method('setStoreFilter') - ->with($this->equalTo(1), $this->equalTo($this->saleableItemMock)) - ->will($this->returnSelf()); - - $optionIds = ['41', '55']; - $priceTypeMock->expects($this->atLeastOnce()) - ->method('getOptionsIds') - ->with($this->equalTo($this->saleableItemMock)) - ->will($this->returnValue($optionIds)); - - $priceTypeMock->expects($this->atLeastOnce()) - ->method('getSelectionsCollection') - ->with($this->equalTo($optionIds), $this->equalTo($this->saleableItemMock)) - ->will($this->returnValue($selectionCollection)); - $collection = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class); - $collection->expects($this->atLeastOnce()) - ->method('appendSelections') - ->with($this->equalTo($selectionCollection), $this->equalTo(true), $this->equalTo(false)) - ->will($this->returnValue($selectionCollection)); - - $priceTypeMock->expects($this->atLeastOnce()) - ->method('getOptionsCollection') - ->with($this->equalTo($this->saleableItemMock)) + $this->bundleOptionsMock->expects($this->any()) + ->method('getOptions') ->will($this->returnValue($collection)); - - $this->saleableItemMock->expects($this->atLeastOnce()) - ->method('getTypeInstance') - ->will($this->returnValue($priceTypeMock)); - } - - public function getOptionsDataProvider() - { - return [ - ['1', '2'] - ]; - } - - /** - * @param float $selectionQty - * @param float|bool $selectionAmount - * @dataProvider selectionAmountDataProvider - */ - public function testGetOptionSelectionAmount($selectionQty, $selectionAmount) - { - $selection = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['getSelectionQty', '__wakeup']); - $selection->expects($this->once()) - ->method('getSelectionQty') - ->will($this->returnValue($selectionQty)); - $priceMock = $this->createMock(\Magento\Bundle\Pricing\Price\BundleSelectionPrice::class); - $priceMock->expects($this->once()) - ->method('getAmount') - ->will($this->returnValue($selectionAmount)); - $this->selectionFactoryMock->expects($this->once()) - ->method('create') - ->with($this->equalTo($this->saleableItemMock), $this->equalTo($selection), $this->equalTo($selectionQty)) - ->will($this->returnValue($priceMock)); - $this->assertSame($selectionAmount, $this->bundleOptionPrice->getOptionSelectionAmount($selection)); + $selection = $this->createMock(\Magento\Catalog\Model\Product::class); + $this->assertEquals($collection, $this->bundleOptionPrice->getOptions($selection)); } - /** - * @return array - */ - public function selectionAmountDataProvider() + public function testGetOptionSelectionAmount() { - return [ - [1., 50.5], - [2.2, false] - ]; + $selectionAmount = $this->createMock(\Magento\Framework\Pricing\Amount\AmountInterface::class); + $product = $this->createMock(\Magento\Catalog\Model\Product::class); + $selection = $this->createMock(\Magento\Bundle\Model\Selection::class); + $this->bundleOptionsMock->expects($this->any()) + ->method('getOptionSelectionAmount') + ->will($this->returnValue($selectionAmount)) + ->with($product, $selection, false); + + $this->assertEquals($selectionAmount, $this->bundleOptionPrice->getOptionSelectionAmount($selection)); } public function testGetAmount() @@ -212,205 +86,10 @@ public function testGetAmount() $this->assertSame($amountMock, $this->bundleOptionPrice->getAmount()); } - /** - * Create amount mock - * - * @param array $amountData - * @return \Magento\Framework\Pricing\Amount\Base|\PHPUnit_Framework_MockObject_MockObject - */ - protected function createAmountMock($amountData) - { - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Pricing\Amount\Base $amount */ - $amount = $this->createMock(\Magento\Framework\Pricing\Amount\Base::class); - $amount->expects($this->any())->method('getAdjustmentAmounts')->will( - $this->returnValue(isset($amountData['adjustmentAmounts']) ? $amountData['adjustmentAmounts'] : []) - ); - $amount->expects($this->any())->method('getValue')->will($this->returnValue($amountData['amount'])); - return $amount; - } - - /** - * Create option mock - * - * @param array $optionData - * @return \Magento\Bundle\Model\Option|\PHPUnit_Framework_MockObject_MockObject - */ - protected function createOptionMock($optionData) - { - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Bundle\Model\Option $option */ - $option = $this->createPartialMock(\Magento\Bundle\Model\Option::class, ['isMultiSelection', '__wakeup']); - $option->expects($this->any())->method('isMultiSelection') - ->will($this->returnValue($optionData['isMultiSelection'])); - $selections = []; - foreach ($optionData['selections'] as $selectionData) { - $selections[] = $this->createSelectionMock($selectionData); - } - foreach ($optionData['data'] as $key => $value) { - $option->setData($key, $value); - } - $option->setData('selections', $selections); - return $option; - } - - /** - * Create selection product mock - * - * @param array $selectionData - * @return \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject - */ - protected function createSelectionMock($selectionData) + public function testGetValue() { - $selection = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) - ->setMethods(['isSalable', 'getAmount', 'getQuantity', 'getProduct', '__wakeup']) - ->disableOriginalConstructor() - ->getMock(); - - // All items are saleable - $selection->expects($this->any())->method('isSalable')->will($this->returnValue(true)); - foreach ($selectionData['data'] as $key => $value) { - $selection->setData($key, $value); - } - $amountMock = $this->createAmountMock($selectionData['amount']); - $selection->expects($this->any())->method('getAmount')->will($this->returnValue($amountMock)); - $selection->expects($this->any())->method('getQuantity')->will($this->returnValue(1)); - - $innerProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) - ->setMethods(['getSelectionCanChangeQty', '__wakeup']) - ->disableOriginalConstructor() - ->getMock(); - $innerProduct->expects($this->any())->method('getSelectionCanChangeQty')->will($this->returnValue(true)); - $selection->expects($this->any())->method('getProduct')->will($this->returnValue($innerProduct)); - - return $selection; - } - - /** - * @dataProvider getTestDataForCalculation - */ - public function testCalculation($optionList, $expected) - { - $storeId = 1; - $this->saleableItemMock->expects($this->any())->method('getStoreId')->will($this->returnValue($storeId)); - $this->selectionFactoryMock->expects($this->any())->method('create')->will($this->returnArgument(1)); - - $this->baseCalculator->expects($this->atLeastOnce())->method('getAmount') - ->will($this->returnValue($this->createAmountMock(['amount' => 0.]))); - - $options = []; - foreach ($optionList as $optionData) { - $options[] = $this->createOptionMock($optionData); - } - /** @var \PHPUnit_Framework_MockObject_MockObject $optionsCollection */ - $optionsCollection = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class); - $optionsCollection->expects($this->atLeastOnce())->method('appendSelections')->will($this->returnSelf()); - $optionsCollection->expects($this->atLeastOnce())->method('getIterator') - ->will($this->returnValue(new \ArrayIterator($options))); - - /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Product\Type\AbstractType $typeMock */ - $typeMock = $this->createMock(\Magento\Bundle\Model\Product\Type::class); - $typeMock->expects($this->any())->method('setStoreFilter')->with($storeId, $this->saleableItemMock); - $typeMock->expects($this->any())->method('getOptionsCollection')->with($this->saleableItemMock) - ->will($this->returnValue($optionsCollection)); - $this->saleableItemMock->expects($this->any())->method('getTypeInstance')->will($this->returnValue($typeMock)); - - $this->assertEquals($expected['min'], $this->bundleOptionPrice->getValue()); - $this->assertEquals($expected['max'], $this->bundleOptionPrice->getMaxValue()); - } - - /** - * @return array - */ - public function getTestDataForCalculation() - { - return [ - 'first case' => [ - 'optionList' => [ - // first option with single choice of product - [ - 'isMultiSelection' => false, - 'data' => [ - 'title' => 'test option 1', - 'default_title' => 'test option 1', - 'type' => 'select', - 'option_id' => '1', - 'position' => '0', - 'required' => '1', - ], - 'selections' => [ - [ - 'data' => ['price' => 70.], - 'amount' => ['amount' => 70], - ], - [ - 'data' => ['price' => 80.], - 'amount' => ['amount' => 80] - ], - [ - 'data' => ['price' => 50.], - 'amount' => ['amount' => 50] - ], - ] - ], - // second not required option - [ - 'isMultiSelection' => false, - 'data' => [ - 'title' => 'test option 2', - 'default_title' => 'test option 2', - 'type' => 'select', - 'option_id' => '2', - 'position' => '1', - 'required' => '0', - ], - 'selections' => [ - [ - 'data' => ['value' => 20.], - 'amount' => ['amount' => 20], - ], - ] - ], - // third with multi-selection - [ - 'isMultiSelection' => true, - 'data' => [ - 'title' => 'test option 3', - 'default_title' => 'test option 3', - 'type' => 'select', - 'option_id' => '3', - 'position' => '2', - 'required' => '1', - ], - 'selections' => [ - [ - 'data' => ['price' => 40.], - 'amount' => ['amount' => 40], - ], - [ - 'data' => ['price' => 20.], - 'amount' => ['amount' => 20] - ], - [ - 'data' => ['price' => 60.], - 'amount' => ['amount' => 60] - ], - ] - ], - // fourth without selections - [ - 'isMultiSelection' => true, - 'data' => [ - 'title' => 'test option 3', - 'default_title' => 'test option 3', - 'type' => 'select', - 'option_id' => '4', - 'position' => '3', - 'required' => '1', - ], - 'selections' => [] - ], - ], - 'expected' => ['min' => 70, 'max' => 220], - ] - ]; + $value = 1; + $this->bundleOptionsMock->expects($this->any())->method('calculateOptions')->will($this->returnValue($value)); + $this->assertEquals($value, $this->bundleOptionPrice->getValue()); } } diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php new file mode 100644 index 0000000000000..d2f4cfc907bb6 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php @@ -0,0 +1,95 @@ +bundleOptionsMock = $this->createMock(\Magento\Bundle\Pricing\Price\BundleOptions::class); + $this->saleableItemMock = $this->createMock(\Magento\Catalog\Model\Product::class); + $this->bundleCalculatorMock = $this->createMock(\Magento\Bundle\Pricing\Adjustment\Calculator::class); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->bundleOptionRegularPrice = $this->objectManagerHelper->getObject( + \Magento\Bundle\Pricing\Price\bundleOptionRegularPrice::class, + [ + 'saleableItem' => $this->saleableItemMock, + 'quantity' => 1., + 'calculator' => $this->bundleCalculatorMock, + 'bundleOptions' => $this->bundleOptionsMock + ] + ); + } + + public function testGetOptions() + { + $collection = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class); + $this->bundleOptionsMock->expects($this->any()) + ->method('getOptions') + ->will($this->returnValue($collection)); + $selection = $this->createMock(\Magento\Catalog\Model\Product::class); + $this->assertEquals($collection, $this->bundleOptionRegularPrice->getOptions($selection)); + } + + public function testGetOptionSelectionAmount() + { + $selectionAmount = $this->createMock(\Magento\Framework\Pricing\Amount\AmountInterface::class); + $product = $this->createMock(\Magento\Catalog\Model\Product::class); + $selection = $this->createMock(\Magento\Bundle\Model\Selection::class); + $this->bundleOptionsMock->expects($this->any()) + ->method('getOptionSelectionAmount') + ->will($this->returnValue($selectionAmount)) + ->with($product, $selection, true); + + $this->assertEquals($selectionAmount, $this->bundleOptionRegularPrice->getOptionSelectionAmount($selection)); + } + + public function testGetAmount() + { + $amountMock = $this->createMock(\Magento\Framework\Pricing\Amount\AmountInterface::class); + $this->bundleCalculatorMock->expects($this->once()) + ->method('getOptionsAmount') + ->with($this->equalTo($this->saleableItemMock)) + ->will($this->returnValue($amountMock)); + $this->assertSame($amountMock, $this->bundleOptionRegularPrice->getAmount()); + } + + public function testGetValue() + { + $value = 1; + $this->bundleOptionsMock->expects($this->any())->method('calculateOptions')->will($this->returnValue($value)); + $this->assertEquals($value, $this->bundleOptionRegularPrice->getValue()); + } +} diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionTest.php new file mode 100644 index 0000000000000..0329047ba48e4 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionTest.php @@ -0,0 +1,393 @@ +priceInfoMock = $this->createMock(\Magento\Framework\Pricing\PriceInfo\Base::class); + $this->saleableItemMock = $this->createMock(\Magento\Catalog\Model\Product::class); + $priceCurrency = $this->getMockBuilder(\Magento\Framework\Pricing\PriceCurrencyInterface::class)->getMock(); + $priceCurrency->expects($this->any())->method('round')->will($this->returnArgument(0)); + $this->selectionFactoryMock = $this->getMockBuilder(\Magento\Bundle\Pricing\Price\BundleSelectionFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->amountFactory = $this->createMock(\Magento\Framework\Pricing\Amount\AmountFactory::class); + $factoryCallback = $this->returnCallback( + function ($fullAmount, $adjustments) { + return $this->createAmountMock(['amount' => $fullAmount, 'adjustmentAmounts' => $adjustments]); + } + ); + $this->amountFactory->expects($this->any())->method('create')->will($factoryCallback); + $this->baseCalculator = $this->createMock(\Magento\Framework\Pricing\Adjustment\Calculator::class); + + $taxData = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->bundleCalculatorMock = $this->getMockBuilder(\Magento\Bundle\Pricing\Adjustment\Calculator::class) + ->setConstructorArgs( + [$this->baseCalculator, $this->amountFactory, $this->selectionFactoryMock, $taxData, $priceCurrency] + ) + ->setMethods(['getOptionsAmount']) + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->bundleOptions = $this->objectManagerHelper->getObject( + \Magento\Bundle\Pricing\Price\BundleOptions::class, + [ + 'calculator' => $this->bundleCalculatorMock, + 'bundleSelectionFactory' => $this->selectionFactoryMock + ] + ); + } + + /** + * @dataProvider getOptionsDataProvider + */ + public function testGetOptions($selectionCollection) + { + $this->prepareOptionMocks($selectionCollection); + $this->bundleOptions->getOptions($this->saleableItemMock); + $this->assertSame($selectionCollection, $this->bundleOptions->getOptions($this->saleableItemMock)); + $this->assertSame($selectionCollection, $this->bundleOptions->getOptions($this->saleableItemMock)); + } + + /** + * @param array $selectionCollection + * @return void + */ + private function prepareOptionMocks($selectionCollection) + { + $this->saleableItemMock->expects($this->atLeastOnce()) + ->method('getStoreId') + ->will($this->returnValue(1)); + + $priceTypeMock = $this->createMock(\Magento\Bundle\Model\Product\Type::class); + $priceTypeMock->expects($this->atLeastOnce()) + ->method('setStoreFilter') + ->with($this->equalTo(1), $this->equalTo($this->saleableItemMock)) + ->will($this->returnSelf()); + + $optionIds = ['41', '55']; + $priceTypeMock->expects($this->atLeastOnce()) + ->method('getOptionsIds') + ->with($this->equalTo($this->saleableItemMock)) + ->will($this->returnValue($optionIds)); + + $priceTypeMock->expects($this->atLeastOnce()) + ->method('getSelectionsCollection') + ->with($this->equalTo($optionIds), $this->equalTo($this->saleableItemMock)) + ->will($this->returnValue($selectionCollection)); + + $collection = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class); + $collection->expects($this->atLeastOnce()) + ->method('appendSelections') + ->with($this->equalTo($selectionCollection), $this->equalTo(true), $this->equalTo(false)) + ->will($this->returnValue($selectionCollection)); + + $priceTypeMock->expects($this->atLeastOnce()) + ->method('getOptionsCollection') + ->with($this->equalTo($this->saleableItemMock)) + ->will($this->returnValue($collection)); + + $this->saleableItemMock->expects($this->atLeastOnce()) + ->method('getTypeInstance') + ->will($this->returnValue($priceTypeMock)); + } + + public function getOptionsDataProvider() + { + return [ + ['1', '2'] + ]; + } + + /** + * @param float $selectionQty + * @param float|bool $selectionAmount + * @param bool $useRegularPrice + * @dataProvider selectionAmountDataProvider + */ + public function testGetOptionSelectionAmount($selectionQty, $selectionAmount, $useRegularPrice) + { + $selection = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['getSelectionQty', '__wakeup']); + $selection->expects($this->once()) + ->method('getSelectionQty') + ->will($this->returnValue($selectionQty)); + $priceMock = $this->createMock(\Magento\Bundle\Pricing\Price\BundleSelectionPrice::class); + $priceMock->expects($this->once()) + ->method('getAmount') + ->will($this->returnValue($selectionAmount)); + $this->selectionFactoryMock->expects($this->once()) + ->method('create') + ->with($this->equalTo($this->saleableItemMock), $this->equalTo($selection), $this->equalTo($selectionQty)) + ->will($this->returnValue($priceMock)); + $this->assertSame( + $selectionAmount, + $this->bundleOptions->getOptionSelectionAmount($this->saleableItemMock, $selection, $useRegularPrice) + ); + } + + /** + * @return array + */ + public function selectionAmountDataProvider() + { + return [ + [1., 50.5, false], + [2.2, false, true] + ]; + } + + /** + * Create amount mock + * + * @param array $amountData + * @return \Magento\Framework\Pricing\Amount\Base|\PHPUnit_Framework_MockObject_MockObject + */ + private function createAmountMock($amountData) + { + /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Pricing\Amount\Base $amount */ + $amount = $this->createMock(\Magento\Framework\Pricing\Amount\Base::class); + $amount->expects($this->any())->method('getAdjustmentAmounts')->will( + $this->returnValue(isset($amountData['adjustmentAmounts']) ? $amountData['adjustmentAmounts'] : []) + ); + $amount->expects($this->any())->method('getValue')->will($this->returnValue($amountData['amount'])); + return $amount; + } + + /** + * Create option mock + * + * @param array $optionData + * @return \Magento\Bundle\Model\Option|\PHPUnit_Framework_MockObject_MockObject + */ + private function createOptionMock($optionData) + { + /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Bundle\Model\Option $option */ + $option = $this->createPartialMock(\Magento\Bundle\Model\Option::class, ['isMultiSelection', '__wakeup']); + $option->expects($this->any())->method('isMultiSelection') + ->will($this->returnValue($optionData['isMultiSelection'])); + $selections = []; + foreach ($optionData['selections'] as $selectionData) { + $selections[] = $this->createSelectionMock($selectionData); + } + foreach ($optionData['data'] as $key => $value) { + $option->setData($key, $value); + } + $option->setData('selections', $selections); + return $option; + } + + /** + * Create selection product mock + * + * @param array $selectionData + * @return \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject + */ + private function createSelectionMock($selectionData) + { + $selection = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->setMethods(['isSalable', 'getAmount', 'getQuantity', 'getProduct', '__wakeup']) + ->disableOriginalConstructor() + ->getMock(); + + // All items are saleable + $selection->expects($this->any())->method('isSalable')->will($this->returnValue(true)); + foreach ($selectionData['data'] as $key => $value) { + $selection->setData($key, $value); + } + $amountMock = $this->createAmountMock($selectionData['amount']); + $selection->expects($this->any())->method('getAmount')->will($this->returnValue($amountMock)); + $selection->expects($this->any())->method('getQuantity')->will($this->returnValue(1)); + + $innerProduct = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) + ->setMethods(['getSelectionCanChangeQty', '__wakeup']) + ->disableOriginalConstructor() + ->getMock(); + $innerProduct->expects($this->any())->method('getSelectionCanChangeQty')->will($this->returnValue(true)); + $selection->expects($this->any())->method('getProduct')->will($this->returnValue($innerProduct)); + + return $selection; + } + + /** + * @dataProvider getTestDataForCalculation + */ + public function testCalculation($optionList, $expected) + { + $storeId = 1; + $this->saleableItemMock->expects($this->any())->method('getStoreId')->will($this->returnValue($storeId)); + $this->selectionFactoryMock->expects($this->any())->method('create')->will($this->returnArgument(1)); + + $this->baseCalculator->expects($this->atLeastOnce())->method('getAmount') + ->will($this->returnValue($this->createAmountMock(['amount' => 0.]))); + + $options = []; + foreach ($optionList as $optionData) { + $options[] = $this->createOptionMock($optionData); + } + /** @var \PHPUnit_Framework_MockObject_MockObject $optionsCollection */ + $optionsCollection = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class); + $optionsCollection->expects($this->atLeastOnce())->method('appendSelections')->will($this->returnSelf()); + $optionsCollection->expects($this->atLeastOnce())->method('getIterator') + ->will($this->returnValue(new \ArrayIterator($options))); + + /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Product\Type\AbstractType $typeMock */ + $typeMock = $this->createMock(\Magento\Bundle\Model\Product\Type::class); + $typeMock->expects($this->any())->method('setStoreFilter')->with($storeId, $this->saleableItemMock); + $typeMock->expects($this->any())->method('getOptionsCollection')->with($this->saleableItemMock) + ->will($this->returnValue($optionsCollection)); + $this->saleableItemMock->expects($this->any())->method('getTypeInstance')->will($this->returnValue($typeMock)); + + $this->assertEquals($expected['min'], $this->bundleOptions->calculateOptions($this->saleableItemMock)); + $this->assertEquals($expected['max'], $this->bundleOptions->calculateOptions($this->saleableItemMock, false)); + } + + /** + * @return array + */ + public function getTestDataForCalculation() + { + return [ + 'first case' => [ + 'optionList' => [ + // first option with single choice of product + [ + 'isMultiSelection' => false, + 'data' => [ + 'title' => 'test option 1', + 'default_title' => 'test option 1', + 'type' => 'select', + 'option_id' => '1', + 'position' => '0', + 'required' => '1', + ], + 'selections' => [ + [ + 'data' => ['price' => 70.], + 'amount' => ['amount' => 70], + ], + [ + 'data' => ['price' => 80.], + 'amount' => ['amount' => 80] + ], + [ + 'data' => ['price' => 50.], + 'amount' => ['amount' => 50] + ], + ] + ], + // second not required option + [ + 'isMultiSelection' => false, + 'data' => [ + 'title' => 'test option 2', + 'default_title' => 'test option 2', + 'type' => 'select', + 'option_id' => '2', + 'position' => '1', + 'required' => '0', + ], + 'selections' => [ + [ + 'data' => ['value' => 20.], + 'amount' => ['amount' => 20], + ], + ] + ], + // third with multi-selection + [ + 'isMultiSelection' => true, + 'data' => [ + 'title' => 'test option 3', + 'default_title' => 'test option 3', + 'type' => 'select', + 'option_id' => '3', + 'position' => '2', + 'required' => '1', + ], + 'selections' => [ + [ + 'data' => ['price' => 40.], + 'amount' => ['amount' => 40], + ], + [ + 'data' => ['price' => 20.], + 'amount' => ['amount' => 20] + ], + [ + 'data' => ['price' => 60.], + 'amount' => ['amount' => 60] + ], + ] + ], + // fourth without selections + [ + 'isMultiSelection' => true, + 'data' => [ + 'title' => 'test option 3', + 'default_title' => 'test option 3', + 'type' => 'select', + 'option_id' => '4', + 'position' => '3', + 'required' => '1', + ], + 'selections' => [] + ], + ], + 'expected' => ['min' => 70, 'max' => 220], + ] + ]; + } +} From dc1efbb9e4f6a3539525c71030452798f13d68d2 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 24 Aug 2017 18:29:35 -0500 Subject: [PATCH 0009/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - refactor --- .../Bundle/Pricing/Price/BundleSelectionPrice.php | 13 ++++++++----- .../Unit/Pricing/Price/BundleOptionPriceTest.php | 1 - .../Pricing/Price/BundleOptionRegularPriceTest.php | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php index 085d7b920118d..12c98992c906c 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php @@ -103,7 +103,10 @@ public function getValue() return $this->value; } $product = $this->selection; - $bundleSelectionKey = 'bundle-selection-value-' . $product->getSelectionId() . '-' . ($this->useRegularPrice ? 1 : 0); + $bundleSelectionKey = 'bundle-selection-' + . ($this->useRegularPrice ? 'regular-' : '') + . 'value-' + . $product->getSelectionId(); if ($product->hasData($bundleSelectionKey)) { return $product->getData($bundleSelectionKey); } @@ -150,10 +153,10 @@ public function getValue() public function getAmount() { $product = $this->selection; - $bundleSelectionKey = 'bundle-selection-amount-' - . $product->getSelectionId() - . '-' - . ($this->useRegularPrice ? '' : 'regular-price'); + $bundleSelectionKey = 'bundle-selection' + . ($this->useRegularPrice ? 'regular-' : '') + . '-amount-' + . $product->getSelectionId(); if ($product->hasData($bundleSelectionKey)) { return $product->getData($bundleSelectionKey); } diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php index fdb37e910d6da..5739595033bdd 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionPriceTest.php @@ -72,7 +72,6 @@ public function testGetOptionSelectionAmount() ->method('getOptionSelectionAmount') ->will($this->returnValue($selectionAmount)) ->with($product, $selection, false); - $this->assertEquals($selectionAmount, $this->bundleOptionPrice->getOptionSelectionAmount($selection)); } diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php index d2f4cfc907bb6..1186369a40e2f 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php @@ -72,7 +72,6 @@ public function testGetOptionSelectionAmount() ->method('getOptionSelectionAmount') ->will($this->returnValue($selectionAmount)) ->with($product, $selection, true); - $this->assertEquals($selectionAmount, $this->bundleOptionRegularPrice->getOptionSelectionAmount($selection)); } From 885b55fc4db5fcff87dea1564a6ef5d1b7aba00f Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 24 Aug 2017 19:19:19 -0500 Subject: [PATCH 0010/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - rename test --- .../Pricing/Price/{BundleOptionTest.php => BundleOptionsTest.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/code/Magento/Bundle/Test/Unit/Pricing/Price/{BundleOptionTest.php => BundleOptionsTest.php} (100%) diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionsTest.php similarity index 100% rename from app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionTest.php rename to app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionsTest.php From 2f99825b945131cfc86c70799dbdf17d37a22e1c Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 24 Aug 2017 22:57:13 -0500 Subject: [PATCH 0011/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - adding integration test for prices --- .../Catalog/Product/View/Type/BundleTest.php | 63 +++++++++++++ .../product_dynamic_price_with_option.php | 94 +++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php new file mode 100644 index 0000000000000..01f3932ab18ca --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php @@ -0,0 +1,63 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $this->product = $this->productRepository->get('bundle-product', false, null, true); + + $this->objectManager->get(\Magento\Framework\Registry::class)->unregister('product'); + $this->objectManager->get(\Magento\Framework\Registry::class)->register('product', $this->product); + + $this->block = $this->objectManager->get( + \Magento\Framework\View\LayoutInterface::class + )->createBlock( + \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class + ); + } + + public function testGetJsonConfig() + { + $option = $this->productRepository->get('simple'); + $option->setSpecialPrice(5) + ->save(); + $config = json_decode($this->block->getJsonConfig(), true); + $options = current($config['options']); + $selection = current($options['selections']); + $this->assertEquals(10, $selection['prices']['oldPrice']['amount']); + $this->assertEquals(5, $selection['prices']['basePrice']['amount']); + $this->assertEquals(5, $selection['prices']['finalPrice']['amount']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php new file mode 100644 index 0000000000000..d492548b10e14 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php @@ -0,0 +1,94 @@ +create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$sampleProduct = $productRepository->get('simple'); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId('bundle') + ->setId(3) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Bundle Product') + ->setSku('bundle-product') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setPriceView(1) + ->setPriceType(1) + ->setPriceType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC) + ->setShipmentType(1) + ->setPrice(10.0) + ->setBundleOptionsData( + [ + [ + 'title' => 'Bundle Product Items', + 'default_title' => 'Bundle Product Items', + 'type' => 'select', 'required' => 1, + 'delete' => '', + ], + ] + ) + ->setBundleSelectionsData( + [ + [ + [ + 'product_id' => $sampleProduct->getId(), + 'selection_qty' => 1, + 'selection_can_change_qty' => 1, + 'delete' => '', + ], + ], + ] + ); + +if ($product->getBundleOptionsData()) { + $options = []; + foreach ($product->getBundleOptionsData() as $key => $optionData) { + if (!(bool)$optionData['delete']) { + $option = $objectManager->create(\Magento\Bundle\Api\Data\OptionInterfaceFactory::class) + ->create(['data' => $optionData]); + $option->setSku($product->getSku()); + $option->setOptionId(null); + + $links = []; + $bundleLinks = $product->getBundleSelectionsData(); + if (!empty($bundleLinks[$key])) { + foreach ($bundleLinks[$key] as $linkData) { + if (!(bool)$linkData['delete']) { + /** @var \Magento\Bundle\Api\Data\LinkInterface$link */ + $link = $objectManager->create(\Magento\Bundle\Api\Data\LinkInterfaceFactory::class) + ->create(['data' => $linkData]); + $linkProduct = $productRepository->getById($linkData['product_id']); + $link->setSku($linkProduct->getSku()); + $link->setQty($linkData['selection_qty']); + if (isset($linkData['selection_can_change_qty'])) { + $link->setCanChangeQuantity($linkData['selection_can_change_qty']); + } + $links[] = $link; + } + } + $option->setProductLinks($links); + $options[] = $option; + } + } + } + $extension = $product->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $product->setExtensionAttributes($extension); +} +$product->save(); From 155835b8b81daf03faa583351b086be5a382dded Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Thu, 24 Aug 2017 23:01:52 -0500 Subject: [PATCH 0012/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix copyright --- .../Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php | 2 +- .../Bundle/Test/Unit/Pricing/Price/BundleOptionsTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php index 1186369a40e2f..7b00b962e389e 100644 --- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleOptionRegularPriceTest.php @@ -1,6 +1,6 @@ Date: Thu, 24 Aug 2017 23:10:11 -0500 Subject: [PATCH 0013/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix namespace --- .../Catalog/Product/View/Type/BundleTest.php | 6 +- .../product_dynamic_price_with_option.php | 94 ------------------- 2 files changed, 3 insertions(+), 97 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php index 01f3932ab18ca..4134d4711741c 100644 --- a/dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php +++ b/dev/tests/integration/testsuite/Magento/Bundle/Block/Catalog/Product/View/Type/BundleTest.php @@ -3,10 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Catalog\Block\Product\View; +namespace Magento\Bundle\Block\Catalog\Product\View\Type; /** - * @magentoDataFixture Magento/Bundle/_files/product_dynamic_price_with_option.php + * @magentoDataFixture Magento/Bundle/_files/product.php * @magentoAppArea frontend */ class BundleTest extends \PHPUnit\Framework\TestCase @@ -37,7 +37,7 @@ protected function setUp() $this->productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); $this->product = $this->productRepository->get('bundle-product', false, null, true); - + $this->product->setPriceType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC)->save(); $this->objectManager->get(\Magento\Framework\Registry::class)->unregister('product'); $this->objectManager->get(\Magento\Framework\Registry::class)->register('product', $this->product); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php deleted file mode 100644 index d492548b10e14..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Bundle/_files/product_dynamic_price_with_option.php +++ /dev/null @@ -1,94 +0,0 @@ -create(\Magento\Catalog\Api\ProductRepositoryInterface::class); -$sampleProduct = $productRepository->get('simple'); - -/** @var $product \Magento\Catalog\Model\Product */ -$product = $objectManager->create(\Magento\Catalog\Model\Product::class); -$product->setTypeId('bundle') - ->setId(3) - ->setAttributeSetId(4) - ->setWebsiteIds([1]) - ->setName('Bundle Product') - ->setSku('bundle-product') - ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) - ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) - ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) - ->setPriceView(1) - ->setPriceType(1) - ->setPriceType(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC) - ->setShipmentType(1) - ->setPrice(10.0) - ->setBundleOptionsData( - [ - [ - 'title' => 'Bundle Product Items', - 'default_title' => 'Bundle Product Items', - 'type' => 'select', 'required' => 1, - 'delete' => '', - ], - ] - ) - ->setBundleSelectionsData( - [ - [ - [ - 'product_id' => $sampleProduct->getId(), - 'selection_qty' => 1, - 'selection_can_change_qty' => 1, - 'delete' => '', - ], - ], - ] - ); - -if ($product->getBundleOptionsData()) { - $options = []; - foreach ($product->getBundleOptionsData() as $key => $optionData) { - if (!(bool)$optionData['delete']) { - $option = $objectManager->create(\Magento\Bundle\Api\Data\OptionInterfaceFactory::class) - ->create(['data' => $optionData]); - $option->setSku($product->getSku()); - $option->setOptionId(null); - - $links = []; - $bundleLinks = $product->getBundleSelectionsData(); - if (!empty($bundleLinks[$key])) { - foreach ($bundleLinks[$key] as $linkData) { - if (!(bool)$linkData['delete']) { - /** @var \Magento\Bundle\Api\Data\LinkInterface$link */ - $link = $objectManager->create(\Magento\Bundle\Api\Data\LinkInterfaceFactory::class) - ->create(['data' => $linkData]); - $linkProduct = $productRepository->getById($linkData['product_id']); - $link->setSku($linkProduct->getSku()); - $link->setQty($linkData['selection_qty']); - if (isset($linkData['selection_can_change_qty'])) { - $link->setCanChangeQuantity($linkData['selection_can_change_qty']); - } - $links[] = $link; - } - } - $option->setProductLinks($links); - $options[] = $option; - } - } - } - $extension = $product->getExtensionAttributes(); - $extension->setBundleProductOptions($options); - $product->setExtensionAttributes($extension); -} -$product->save(); From b070001764f544df80b85b3d07c63662163ea169 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 25 Aug 2017 13:33:17 -0500 Subject: [PATCH 0014/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix unit test --- .../Block/Catalog/Product/View/Type/BundleTest.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php index 97e8098b8181e..2353dc8251b6a 100644 --- a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php @@ -244,12 +244,14 @@ public function testGetJsonConfigFixedPriceBundle() ), ] ); + $bundleOptionPriceMock = $this->getAmountPriceMock( + $baseAmount, + $regularPriceMock, + [['item' => $selections[0], 'value' => $basePriceValue, 'base_amount' => 321321]] + ); $prices = [ - 'bundle_option' => $this->getAmountPriceMock( - $baseAmount, - $regularPriceMock, - [['item' => $selections[0], 'value' => $basePriceValue, 'base_amount' => 321321]] - ), + 'bundle_option' => $bundleOptionPriceMock, + 'bundle_option_regular_price' => $bundleOptionPriceMock, \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE => $finalPriceMock, \Magento\Catalog\Pricing\Price\RegularPrice::PRICE_CODE => $regularPriceMock, ]; From d2221e6f817a9f07a653707c61fffa01a79cb00e Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 1 Sep 2017 01:19:02 -0500 Subject: [PATCH 0015/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix configurable and bundle phtml --- .../Price/BundleOptionRegularPrice.php | 5 -- .../Bundle/Pricing/Price/ConfiguredPrice.php | 5 +- .../product/price/configured_price.phtml | 21 +++--- .../ConfiguredPrice/ConfigurableProduct.php | 24 +++++++ .../base/layout/catalog_product_prices.xml | 14 ++++ .../price/bundle/configured_price.phtml | 69 +++++++++++++++++++ .../price/configurable/configured_price.phtml | 63 +++++++++++++++++ 7 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml create mode 100644 app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php index 9ecf63f873c65..026a3fa7afcc8 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleOptionRegularPrice.php @@ -24,11 +24,6 @@ class BundleOptionRegularPrice extends AbstractPrice implements BundleOptionPric */ protected $calculator; - /** - * @var float|bool|null - */ - private $maximalPrice; - /** * @var \Magento\Bundle\Pricing\Price\BundleOptions */ diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php index 274ea95474120..79b111e32a055 100644 --- a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php @@ -109,15 +109,16 @@ public function getOptions() * Option amount calculation for bundle product * * @param float $baseValue + * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getConfiguredAmount($baseValue = 0.) + public function getConfiguredAmount($baseValue = 0., $useRegularPrice = false) { $selectionPriceList = []; foreach ($this->getOptions() as $option) { $selectionPriceList = array_merge( $selectionPriceList, - $this->calculator->createSelectionPriceList($option, $this->product) + $this->calculator->createSelectionPriceList($option, $this->product, $useRegularPrice) ); } return $this->calculator->calculateBundleAmount( diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index fa4e93f7851a5..bba58df2d099b 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -8,19 +8,18 @@ /** @var \Magento\Catalog\Pricing\Render\FinalPriceBox $block */ $schema = ($block->getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; +/** @var \Magento\Catalog\Pricing\Price\ConfiguredPrice $configuredPrice */ +$configuredPrice = $block->getPrice(); +/** @var \Magento\Framework\Pricing\Price\PriceInterface $regularPriceModel */ +$regularPriceModel = $block->getPriceType('regular_price'); ?> - -hasSpecialPrice()) : ?> - getPriceType('regular_price'); - - $finalPriceModel = $block->getPriceType('final_price'); - ?> + +hasSpecialPrice() + && $configuredPrice->getAmount()->getValue() !== $regularPriceModel->getValue()) : ?>

renderAmount( - $finalPriceModel->getAmount(), + $configuredPrice->getAmount(), [ 'display_label' => $block->escapeHtml(__('Special Price')), 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), @@ -32,7 +31,7 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; renderAmount( - $priceModel->getAmount(), + $regularPriceModel->getAmount(), [ 'display_label' => $block->escapeHtml(__('Regular Price')), 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), @@ -45,8 +44,6 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : '';

getPrice(); $priceLabel = ($block->getPriceLabel() !== null) ? $block->getPriceLabel() : ''; diff --git a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php index 027860fe01ab8..f3e54a2b8ae31 100644 --- a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php +++ b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php @@ -16,6 +16,30 @@ class ConfigurableProduct extends FinalPrice implements ConfiguredPriceInterface */ private $item; + /** + * Get Regular Price Amount object + * + * @return \Magento\Framework\Pricing\Amount\AmountInterface + */ + public function getRegularAmount() + { + /** @var \Magento\Wishlist\Model\Item\Option $customOption */ + $customOption = $this->getProduct()->getCustomOption('simple_product'); + $product = $customOption ? $customOption->getProduct() : $this->getProduct(); + return $product->getPriceInfo()->getPrice('regular_price')->getAmount(); + } + + /** + * Get selected option + * + * @return \Magento\Wishlist\Model\Item\Option + */ + public function getOption() + { + /** @var \Magento\Wishlist\Model\Item\Option $customOption */ + return $this->getProduct()->getCustomOption('simple_product'); + } + /** * @inheritdoc */ diff --git a/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml b/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml index e80ef742079a4..5755b80f1def0 100644 --- a/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml +++ b/app/code/Magento/Wishlist/view/base/layout/catalog_product_prices.xml @@ -16,6 +16,20 @@ + + + + Magento_Wishlist::product/price/configurable/configured_price.phtml + + + + + + + Magento_Wishlist::product/price/bundle/configured_price.phtml + + + diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml new file mode 100644 index 0000000000000..2cf262af5ea9c --- /dev/null +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -0,0 +1,69 @@ + +getZone() == 'item_view') ? true : false; +$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; +/** @var \Magento\Catalog\Pricing\Price\ConfiguredPrice $configuredPrice */ +$configuredPrice = $block->getPrice(); +?> +hasSpecialPrice()) : ?> + getOptions())) { + $finalPriceModelAmount = $configuredPrice->getConfiguredAmount(); + $regularPriceAmount = $configuredPrice->getConfiguredAmount(0, true); + } else { + $finalPriceModelAmount = $block->getPriceType('final_price')->getAmount(); + $regularPriceAmount = $block->getPriceType('regular_price')->getAmount(); + } + ?> +

+ + renderAmount( + $finalPriceModelAmount, + [ + 'display_label' => $block->escapeHtml(__('Special Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ); ?> + + + renderAmount( + $regularPriceAmount, + [ + 'display_label' => $block->escapeHtml(__('Regular Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] + ); ?> + +

+ + getPriceLabel() !== null) + ? $block->getPriceLabel() + : ''; + ?> +

+ renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml($priceLabel), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ); ?> +

+ diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml new file mode 100644 index 0000000000000..4857fc51e73cc --- /dev/null +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -0,0 +1,63 @@ + +getZone() == 'item_view') ? true : false; +$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; +/** @var \Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct $configuredPrice */ +$configuredPrice = $block->getPrice(); +$option = $configuredPrice->getOption(); +?> + +hasSpecialPrice() + && $configuredPrice->getOption() + && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getRegularAmount()->getValue()) : ?> +

+ + renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml(__('Special Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ); ?> + + + renderAmount( + $configuredPrice->getRegularAmount(), + [ + 'display_label' => $block->escapeHtml(__('Regular Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] + ); ?> + +

+ + getPriceLabel() !== null) + ? $block->getPriceLabel() + : ''; + ?> +

+ renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml($priceLabel), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ); ?> +

+ From c21f7f0e4927bc734f6648623dbe53222b320b79 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 1 Sep 2017 10:52:52 -0500 Subject: [PATCH 0016/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix escape --- .../base/templates/product/price/configured_price.phtml | 6 +++--- .../templates/product/price/bundle/configured_price.phtml | 8 ++++---- .../product/price/configurable/configured_price.phtml | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index bba58df2d099b..c1c1a7b6b0420 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -18,7 +18,7 @@ $regularPriceModel = $block->getPriceType('regular_price'); && $configuredPrice->getAmount()->getValue() !== $regularPriceModel->getValue()) : ?>

- renderAmount( + renderAmount( $configuredPrice->getAmount(), [ 'display_label' => $block->escapeHtml(__('Special Price')), @@ -30,7 +30,7 @@ $regularPriceModel = $block->getPriceType('regular_price'); ); ?> - renderAmount( + renderAmount( $regularPriceModel->getAmount(), [ 'display_label' => $block->escapeHtml(__('Regular Price')), @@ -49,7 +49,7 @@ $regularPriceModel = $block->getPriceType('regular_price'); : ''; ?>

- renderAmount( + renderAmount( $configuredPrice->getAmount(), [ 'display_label' => $block->escapeHtml($priceLabel), diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml index 2cf262af5ea9c..a44753312215d 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -1,6 +1,6 @@ @@ -24,7 +24,7 @@ $configuredPrice = $block->getPrice(); ?>

- renderAmount( + renderAmount( $finalPriceModelAmount, [ 'display_label' => $block->escapeHtml(__('Special Price')), @@ -36,7 +36,7 @@ $configuredPrice = $block->getPrice(); ); ?> - renderAmount( + renderAmount( $regularPriceAmount, [ 'display_label' => $block->escapeHtml(__('Regular Price')), @@ -55,7 +55,7 @@ $configuredPrice = $block->getPrice(); : ''; ?>

- renderAmount( + renderAmount( $configuredPrice->getAmount(), [ 'display_label' => $block->escapeHtml($priceLabel), diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml index 4857fc51e73cc..9ef87facb7fd9 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -1,6 +1,6 @@ @@ -18,7 +18,7 @@ $option = $configuredPrice->getOption(); && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getRegularAmount()->getValue()) : ?>

- renderAmount( + renderAmount( $configuredPrice->getAmount(), [ 'display_label' => $block->escapeHtml(__('Special Price')), @@ -30,7 +30,7 @@ $option = $configuredPrice->getOption(); ); ?> - renderAmount( + renderAmount( $configuredPrice->getRegularAmount(), [ 'display_label' => $block->escapeHtml(__('Regular Price')), @@ -49,7 +49,7 @@ $option = $configuredPrice->getOption(); : ''; ?>

- renderAmount( + renderAmount( $configuredPrice->getAmount(), [ 'display_label' => $block->escapeHtml($priceLabel), From f7bc93a565bc3f26f0da347e38d369da4b49da4e Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 1 Sep 2017 11:25:48 -0500 Subject: [PATCH 0017/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix static --- .../base/templates/product/price/bundle/configured_price.phtml | 2 +- .../templates/product/price/configurable/configured_price.phtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml index a44753312215d..03434e484dedc 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -1,6 +1,6 @@ diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml index 9ef87facb7fd9..845ee3cf342a8 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -1,6 +1,6 @@ From 715d05f83d48d5b6f2155c2b15d24f9f4a1d50fa Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 1 Sep 2017 11:57:23 -0500 Subject: [PATCH 0018/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - refactor --- .../Pricing/ConfiguredPrice/ConfigurableProduct.php | 7 ++++--- .../product/price/configurable/configured_price.phtml | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php index f3e54a2b8ae31..d23118c018d28 100644 --- a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php +++ b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php @@ -17,16 +17,17 @@ class ConfigurableProduct extends FinalPrice implements ConfiguredPriceInterface private $item; /** - * Get Regular Price Amount object + * Get Configured Price Amount object by price type * + * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getRegularAmount() + public function getConfiguredAmount($useRegularPrice = false) { /** @var \Magento\Wishlist\Model\Item\Option $customOption */ $customOption = $this->getProduct()->getCustomOption('simple_product'); $product = $customOption ? $customOption->getProduct() : $this->getProduct(); - return $product->getPriceInfo()->getPrice('regular_price')->getAmount(); + return $product->getPriceInfo()->getPrice($useRegularPrice ? 'regular_price' : self::PRICE_CODE)->getAmount(); } /** diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml index 845ee3cf342a8..f55677440a9b1 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -15,7 +15,7 @@ $option = $configuredPrice->getOption(); hasSpecialPrice() && $configuredPrice->getOption() - && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getRegularAmount()->getValue()) : ?> + && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getConfiguredAmount(true)->getValue()) : ?>

renderAmount( @@ -31,7 +31,7 @@ $option = $configuredPrice->getOption(); renderAmount( - $configuredPrice->getRegularAmount(), + $configuredPrice->getConfiguredAmount(true), [ 'display_label' => $block->escapeHtml(__('Regular Price')), 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), From 1a8bc121aaf74ba7f6397da6df0c3a16a330502a Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 7 Sep 2017 23:01:14 -0500 Subject: [PATCH 0019/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist --- .../product/price/configured_price.phtml | 64 ++++++++++-------- .../price/bundle/configured_price.phtml | 65 +++++++++++-------- .../price/configurable/configured_price.phtml | 64 ++++++++++-------- 3 files changed, 109 insertions(+), 84 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index c1c1a7b6b0420..2fa8737b2b000 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -13,32 +13,37 @@ $configuredPrice = $block->getPrice(); /** @var \Magento\Framework\Pricing\Price\PriceInterface $regularPriceModel */ $regularPriceModel = $block->getPriceType('regular_price'); ?> - hasSpecialPrice() && $configuredPrice->getAmount()->getValue() !== $regularPriceModel->getValue()) : ?>

- renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $block->escapeHtml(__('Special Price')), - 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] + escapeHtml( + $block->renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => __('Special Price'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] ); ?> - renderAmount( - $regularPriceModel->getAmount(), - [ - 'display_label' => $block->escapeHtml(__('Regular Price')), - 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ] + escapeHtml( + $block->renderAmount( + $regularPriceModel->getAmount(), + [ + 'display_label' => __('Regular Price'), + 'price_id' => $block->getPriceId('old-price-' . $idSuffix), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] + ), + ['span'] ); ?>

@@ -49,15 +54,18 @@ $regularPriceModel = $block->getPriceType('regular_price'); : ''; ?>

- renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $block->escapeHtml($priceLabel), - 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] + escapeHtml( + $block->renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $priceLabel, + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] ); ?>

diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml index 03434e484dedc..244ee1af74436 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -8,7 +8,7 @@ /** @var \Magento\Catalog\Pricing\Render\FinalPriceBox $block */ $schema = ($block->getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; -/** @var \Magento\Catalog\Pricing\Price\ConfiguredPrice $configuredPrice */ +/** @var \Magento\Bundle\Pricing\Price\ConfiguredPrice $configuredPrice */ $configuredPrice = $block->getPrice(); ?> hasSpecialPrice()) : ?> @@ -24,27 +24,33 @@ $configuredPrice = $block->getPrice(); ?>

- renderAmount( - $finalPriceModelAmount, - [ - 'display_label' => $block->escapeHtml(__('Special Price')), - 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] + escapeHtml( + $block->renderAmount( + $finalPriceModelAmount, + [ + 'display_label' => __('Special Price'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] ); ?> - renderAmount( - $regularPriceAmount, - [ - 'display_label' => $block->escapeHtml(__('Regular Price')), - 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ] + escapeHtml( + $block->renderAmount( + $regularPriceAmount, + [ + 'display_label' => __('Regular Price'), + 'price_id' => $block->getPriceId('old-price-' . $idSuffix), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] + ), + ['span'] ); ?>

@@ -55,15 +61,18 @@ $configuredPrice = $block->getPrice(); : ''; ?>

- renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $block->escapeHtml($priceLabel), - 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] + escapeHtml( + $block->renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml($priceLabel), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] ); ?>

diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml index f55677440a9b1..c61ae51f15b4e 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -12,33 +12,38 @@ $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; $configuredPrice = $block->getPrice(); $option = $configuredPrice->getOption(); ?> - hasSpecialPrice() && $configuredPrice->getOption() && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getConfiguredAmount(true)->getValue()) : ?>

- renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $block->escapeHtml(__('Special Price')), - 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] + escapeHtml( + $block->renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => __('Special Price'), + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] ); ?> - renderAmount( - $configuredPrice->getConfiguredAmount(true), - [ - 'display_label' => $block->escapeHtml(__('Regular Price')), - 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ] + escapeHtml( + $block->renderAmount( + $configuredPrice->getConfiguredAmount(true), + [ + 'display_label' => __('Regular Price'), + 'price_id' => $block->getPriceId('old-price-' . $idSuffix), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] + ), + ['span'] ); ?>

@@ -49,15 +54,18 @@ $option = $configuredPrice->getOption(); : ''; ?>

- renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $block->escapeHtml($priceLabel), - 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] + escapeHtml( + $block->renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $priceLabel, + 'price_id' => $block->getPriceId('product-price-' . $idSuffix), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] + ), + ['span'] ); ?>

From d60de62d47a9e0f809a9b2b1e14303c185e1b02e Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 7 Sep 2017 23:27:34 -0500 Subject: [PATCH 0020/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist --- .../Bundle/Pricing/Price/ConfiguredPrice.php | 16 ++++++++-- .../Pricing/Price/ConfiguredRegularPrice.php | 31 +++++++++++++++++++ app/code/Magento/Bundle/etc/di.xml | 1 + 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php index 79b111e32a055..7b5abbdfa31e5 100644 --- a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php @@ -109,16 +109,15 @@ public function getOptions() * Option amount calculation for bundle product * * @param float $baseValue - * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getConfiguredAmount($baseValue = 0., $useRegularPrice = false) + public function getConfiguredAmount($baseValue = 0.) { $selectionPriceList = []; foreach ($this->getOptions() as $option) { $selectionPriceList = array_merge( $selectionPriceList, - $this->calculator->createSelectionPriceList($option, $this->product, $useRegularPrice) + $this->createSelectionPriceList($option) ); } return $this->calculator->calculateBundleAmount( @@ -155,4 +154,15 @@ public function getAmount() { return $this->item ? $this->getConfiguredAmount($this->getBasePrice()->getValue()) : parent::getAmount(); } + + /** + * Create Selection Price List + * + * @param \Magento\Bundle\Model\Option $option + * @return BundleSelectionPrice[] + */ + protected function createSelectionPriceList($option) + { + return $this->calculator->createSelectionPriceList($option, $this->product); + } } diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php new file mode 100644 index 0000000000000..02fdcb0d705bb --- /dev/null +++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php @@ -0,0 +1,31 @@ +calculator->createSelectionPriceList($option, $this->product, true); + } +} diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml index 7de25ce991a35..faae53a4c7c6f 100644 --- a/app/code/Magento/Bundle/etc/di.xml +++ b/app/code/Magento/Bundle/etc/di.xml @@ -50,6 +50,7 @@ Magento\Catalog\Pricing\Price\CustomOptionPrice Magento\Catalog\Pricing\Price\BasePrice Magento\Bundle\Pricing\Price\ConfiguredPrice + Magento\Bundle\Pricing\Price\ConfiguredRegularPrice Magento\Bundle\Pricing\Price\BundleOptionPrice Magento\Bundle\Pricing\Price\BundleOptionRegularPrice Magento\CatalogRule\Pricing\Price\CatalogRulePrice From 415214cf99335a3c5f0332fba5e41d9a805042cf Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 7 Sep 2017 23:47:37 -0500 Subject: [PATCH 0021/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist --- .../templates/product/price/bundle/configured_price.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml index 244ee1af74436..3785505d51f35 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -15,8 +15,8 @@ $configuredPrice = $block->getPrice(); getOptions())) { - $finalPriceModelAmount = $configuredPrice->getConfiguredAmount(); - $regularPriceAmount = $configuredPrice->getConfiguredAmount(0, true); + $finalPriceModelAmount = $block->getPriceType('configured_price')->getConfiguredAmount(); + $regularPriceAmount = $block->getPriceType('configured_regular_price')->getConfiguredAmount(); } else { $finalPriceModelAmount = $block->getPriceType('final_price')->getAmount(); $regularPriceAmount = $block->getPriceType('regular_price')->getAmount(); From 7ac4782d6685bd6ec6700b5f200480de4eb07dd8 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 11 Sep 2017 17:54:57 -0500 Subject: [PATCH 0022/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fixed function tests failures: Magento\Bundle\Test\TestCase\BundleOptionsSummaryTest Magento\Bundle\Test\TestCase\CreateBundleDynamicProductEntityTest --- .../product/price/configured_price.phtml | 63 ++++++++----------- .../price/bundle/configured_price.phtml | 63 ++++++++----------- .../price/configurable/configured_price.phtml | 63 ++++++++----------- 3 files changed, 81 insertions(+), 108 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index 2fa8737b2b000..3705a74f11e34 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -17,33 +17,27 @@ $regularPriceModel = $block->getPriceType('regular_price'); && $configuredPrice->getAmount()->getValue() !== $regularPriceModel->getValue()) : ?>

- escapeHtml( - $block->renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => __('Special Price'), - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml(__('Special Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?> - escapeHtml( - $block->renderAmount( - $regularPriceModel->getAmount(), - [ - 'display_label' => __('Regular Price'), - 'price_id' => $block->getPriceId('old-price-' . $idSuffix), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ] - ), - ['span'] + renderAmount( + $regularPriceModel->getAmount(), + [ + 'display_label' => $block->escapeHtml(__('Regular Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] ); ?>

@@ -54,18 +48,15 @@ $regularPriceModel = $block->getPriceType('regular_price'); : ''; ?>

- escapeHtml( - $block->renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $priceLabel, - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml($priceLabel), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?>

diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml index 3785505d51f35..0096d24dd02be 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -24,33 +24,27 @@ $configuredPrice = $block->getPrice(); ?>

- escapeHtml( - $block->renderAmount( - $finalPriceModelAmount, - [ - 'display_label' => __('Special Price'), - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $finalPriceModelAmount, + [ + 'display_label' => $block->escapeHtml(__('Special Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?> - escapeHtml( - $block->renderAmount( - $regularPriceAmount, - [ - 'display_label' => __('Regular Price'), - 'price_id' => $block->getPriceId('old-price-' . $idSuffix), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ] - ), - ['span'] + renderAmount( + $regularPriceAmount, + [ + 'display_label' => $block->escapeHtml(__('Regular Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] ); ?>

@@ -61,18 +55,15 @@ $configuredPrice = $block->getPrice(); : ''; ?>

- escapeHtml( - $block->renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $block->escapeHtml($priceLabel), - 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml($priceLabel), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?>

diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml index c61ae51f15b4e..c2890766c0517 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -17,33 +17,27 @@ $option = $configuredPrice->getOption(); && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getConfiguredAmount(true)->getValue()) : ?>

- escapeHtml( - $block->renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => __('Special Price'), - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml(__('Special Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?> - escapeHtml( - $block->renderAmount( - $configuredPrice->getConfiguredAmount(true), - [ - 'display_label' => __('Regular Price'), - 'price_id' => $block->getPriceId('old-price-' . $idSuffix), - 'price_type' => 'oldPrice', - 'include_container' => true, - 'skip_adjustments' => true - ] - ), - ['span'] + renderAmount( + $configuredPrice->getConfiguredAmount(true), + [ + 'display_label' => $block->escapeHtml(__('Regular Price')), + 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), + 'price_type' => 'oldPrice', + 'include_container' => true, + 'skip_adjustments' => true + ] ); ?>

@@ -54,18 +48,15 @@ $option = $configuredPrice->getOption(); : ''; ?>

- escapeHtml( - $block->renderAmount( - $configuredPrice->getAmount(), - [ - 'display_label' => $priceLabel, - 'price_id' => $block->getPriceId('product-price-' . $idSuffix), - 'price_type' => 'finalPrice', - 'include_container' => true, - 'schema' => $schema - ] - ), - ['span'] + renderAmount( + $configuredPrice->getAmount(), + [ + 'display_label' => $block->escapeHtml($priceLabel), + 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), + 'price_type' => 'finalPrice', + 'include_container' => true, + 'schema' => $schema + ] ); ?>

From 8698e73ffb1eead58bf9de87ef2837516aeb3408 Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 13 Sep 2017 10:41:47 -0500 Subject: [PATCH 0023/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fixed issue with price of bundle product (without special price) displayed $0 on wishlist --- .../base/templates/product/price/bundle/configured_price.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml index 0096d24dd02be..04766a4943dbc 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -56,7 +56,7 @@ $configuredPrice = $block->getPrice(); ?>

renderAmount( - $configuredPrice->getAmount(), + $block->getPriceType('configured_price')->getAmount(), [ 'display_label' => $block->escapeHtml($priceLabel), 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), From 92f24eccffdab3beafc0957a14f2603a5a0d0669 Mon Sep 17 00:00:00 2001 From: Elze Kool Date: Tue, 26 Sep 2017 14:47:19 +0200 Subject: [PATCH 0024/1464] Handle transparncy correctly for watermark The watermark functionality uses imagecopymerge for copying the watermark into the image, this function loses the alpha information. Therefor use imagecopy for 100% opacity and use imagefilter in other cases. Resolves: #10661 --- .../Magento/Framework/Image/Adapter/Gd2.php | 80 +++++++++++++++++-- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php index 444ab7113d429..de48e234a58d2 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php @@ -404,7 +404,7 @@ public function rotate($angle) */ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = 30, $tile = false) { - list($watermarkSrcWidth, $watermarkSrcHeight, $watermarkFileType, ) = $this->_getImageOptions($imagePath); + list($watermarkSrcWidth, $watermarkSrcHeight, $watermarkFileType,) = $this->_getImageOptions($imagePath); $this->_getFileAttributes(); $watermark = call_user_func( $this->_getCallback('create', $watermarkFileType, 'Unsupported watermark image format.'), @@ -465,7 +465,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = } elseif ($this->getWatermarkPosition() == self::POSITION_CENTER) { $positionX = $this->_imageSrcWidth / 2 - imagesx($watermark) / 2; $positionY = $this->_imageSrcHeight / 2 - imagesy($watermark) / 2; - imagecopymerge( + $this->imagecopymergeWithAlphaFix( $this->_imageHandler, $watermark, $positionX, @@ -478,7 +478,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = ); } elseif ($this->getWatermarkPosition() == self::POSITION_TOP_RIGHT) { $positionX = $this->_imageSrcWidth - imagesx($watermark); - imagecopymerge( + $this->imagecopymergeWithAlphaFix( $this->_imageHandler, $watermark, $positionX, @@ -490,7 +490,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = $this->getWatermarkImageOpacity() ); } elseif ($this->getWatermarkPosition() == self::POSITION_TOP_LEFT) { - imagecopymerge( + $this->imagecopymergeWithAlphaFix( $this->_imageHandler, $watermark, $positionX, @@ -504,7 +504,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = } elseif ($this->getWatermarkPosition() == self::POSITION_BOTTOM_RIGHT) { $positionX = $this->_imageSrcWidth - imagesx($watermark); $positionY = $this->_imageSrcHeight - imagesy($watermark); - imagecopymerge( + $this->imagecopymergeWithAlphaFix( $this->_imageHandler, $watermark, $positionX, @@ -517,7 +517,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = ); } elseif ($this->getWatermarkPosition() == self::POSITION_BOTTOM_LEFT) { $positionY = $this->_imageSrcHeight - imagesy($watermark); - imagecopymerge( + $this->imagecopymergeWithAlphaFix( $this->_imageHandler, $watermark, $positionX, @@ -531,7 +531,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = } if ($tile === false && $merged === false) { - imagecopymerge( + $this->imagecopymergeWithAlphaFix( $this->_imageHandler, $watermark, $positionX, @@ -547,7 +547,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = $offsetY = $positionY; while ($offsetY <= $this->_imageSrcHeight + imagesy($watermark)) { while ($offsetX <= $this->_imageSrcWidth + imagesx($watermark)) { - imagecopymerge( + $this->imagecopymergeWithAlphaFix( $this->_imageHandler, $watermark, $offsetX, @@ -778,4 +778,68 @@ protected function _createEmptyImage($width, $height) $this->imageDestroy(); $this->_imageHandler = $image; } + + /** + * Fix an issue with the usage of imagecopymerge where the alpha channel is lost + * + * @param resource $dst_im + * @param resource $src_im + * @param int $dst_x + * @param int $dst_y + * @param int $src_x + * @param int $src_y + * @param int $src_w + * @param int $src_h + * @param int $pct + * + * @return bool + */ + private function imagecopymergeWithAlphaFix( + $dst_im, + $src_im, + $dst_x, + $dst_y, + $src_x, + $src_y, + $src_w, + $src_h, + $pct + ) { + if ($pct >= 100) { + return imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); + } + + if ($pct < 0) { + return false; + } + + $sizeX = imagesx($src_im); + $sizeY = imagesy($src_im); + if (false === $sizeX || false === $sizeY) { + return false; + } + + $tmpImg = imagecreatetruecolor($src_w, $src_h); + if (false === $tmpImg) { + return false; + } + + if (false === imagealphablending($tmpImg, false)) { + return false; + } + + if (false === imagecopy($tmpImg, $src_im, 0, 0, 0, 0, $sizeX, $sizeY)) { + return false; + } + + $transparancy = 127 - (($pct*127)/100); + if (false === imagefilter($tmpImg, IMG_FILTER_COLORIZE, 0, 0, 0, $transparancy)) { + return false; + } + + $result = imagecopy($dst_im, $tmpImg, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); + imagedestroy($tmpImg); + + return $result; + } } From 1e6097dc236543e9ed0f3040eab3338f95a5308c Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 6 Oct 2017 15:43:53 -0500 Subject: [PATCH 0025/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix configurable regular price amount --- .../Bundle/Pricing/Price/ConfiguredPrice.php | 33 ++++++---- .../Pricing/Render/ConfiguredPriceBox.php | 60 +++++++++++++++++++ .../product/price/configured_price.phtml | 9 ++- .../price/bundle/configured_price.phtml | 20 ++----- 4 files changed, 92 insertions(+), 30 deletions(-) diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php index 7b5abbdfa31e5..28f55cd679ed0 100644 --- a/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredPrice.php @@ -84,13 +84,12 @@ public function getOptions() $bundleOptions = []; /** @var \Magento\Bundle\Model\Product\Type $typeInstance */ $typeInstance = $bundleProduct->getTypeInstance(); - - // get bundle options - $optionsQuoteItemOption = $this->item->getOptionByCode('bundle_option_ids'); - $bundleOptionsIds = $optionsQuoteItemOption - ? $this->serializer->unserialize($optionsQuoteItemOption->getValue()) - : []; - + $bundleOptionsIds = []; + if ($this->item) { + // get bundle options + $optionsQuoteItemOption = $this->item->getOptionByCode('bundle_option_ids'); + $bundleOptionsIds = $this->serializer->unserialize($optionsQuoteItemOption->getValue()); + } if ($bundleOptionsIds) { /** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */ $optionsCollection = $typeInstance->getOptionsByIds($bundleOptionsIds, $bundleProduct); @@ -106,12 +105,10 @@ public function getOptions() } /** - * Option amount calculation for bundle product - * - * @param float $baseValue - * @return \Magento\Framework\Pricing\Amount\AmountInterface + * Get Selection pricing list + * @return \Magento\Bundle\Pricing\Price\BundleSelectionPrice[] */ - public function getConfiguredAmount($baseValue = 0.) + public function getSelectionPriceList() { $selectionPriceList = []; foreach ($this->getOptions() as $option) { @@ -120,6 +117,18 @@ public function getConfiguredAmount($baseValue = 0.) $this->createSelectionPriceList($option) ); } + return $selectionPriceList; + } + + /** + * Option amount calculation for bundle product + * + * @param float $baseValue + * @return \Magento\Framework\Pricing\Amount\AmountInterface + */ + public function getConfiguredAmount($baseValue = 0.) + { + $selectionPriceList = $this->getSelectionPriceList(); return $this->calculator->calculateBundleAmount( $baseValue, $this->product, diff --git a/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php b/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php index 0722f018ae4eb..18587e49de799 100644 --- a/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php +++ b/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php @@ -7,6 +7,7 @@ namespace Magento\Catalog\Pricing\Render; use Magento\Catalog\Model\Product\Configuration\Item\ItemInterface; +use Magento\Framework\Pricing\Price\PriceInterface; /** * Class for configured_price rendering @@ -34,4 +35,63 @@ protected function _prepareLayout() } return parent::_prepareLayout(); } + + /** + * {@inheritdoc} + */ + public function getPriceType($priceCode) + { + $price = $this->saleableItem->getPriceInfo()->getPrice($priceCode); + $item = $this->getData('item'); + if ($price instanceof \Magento\Catalog\Pricing\Price\ConfiguredPriceInterface + && $item instanceof \Magento\Catalog\Model\Product\Configuration\Item\ItemInterface) { + $price->setItem($item); + } + return $price; + } + + /** + * @return PriceInterface + */ + public function getConfiguredPrice() + { + /** @var \Magento\Bundle\Pricing\Price\ConfiguredPrice $configuredPrice */ + $configuredPrice = $this->getPrice(); + if (empty($configuredPrice->getSelectionPriceList())) { + // If there was no selection we must show minimal regular price + return $this->getSaleableItem()->getPriceInfo()->getPrice('final_price'); + } + + return $configuredPrice; + } + + /** + * @return PriceInterface + */ + public function getConfiguredRegularPrice() + { + /** @var \Magento\Bundle\Pricing\Price\ConfiguredPrice $configuredPrice */ + $configuredPrice = $this->getPriceType('configured_regular_price'); + if (empty($configuredPrice->getSelectionPriceList())) { + // If there was no selection we must show minimal regular price + return $this->getSaleableItem()->getPriceInfo()->getPrice('regular_price'); + } + + return $configuredPrice; + } + + /** + * Define if the special price should be shown + * + * @return bool + */ + public function hasSpecialPrice() + { + if ($this->price->getPriceCode() == 'configured_price') { + $displayRegularPrice = $this->getConfiguredRegularPrice()->getAmount()->getValue(); + $displayFinalPrice = $this->getConfiguredPrice()->getAmount()->getValue(); + return $displayFinalPrice < $displayRegularPrice; + } + return parent::hasSpecialPrice(); + } } diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index 3705a74f11e34..f6b23b6de95f1 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -10,11 +10,16 @@ $schema = ($block->getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; /** @var \Magento\Catalog\Pricing\Price\ConfiguredPrice $configuredPrice */ $configuredPrice = $block->getPrice(); +/** @var \Magento\Bundle\Pricing\Price\FinalPrice $finalPriceModel */ +$finalPriceModel = $block->getPriceType('final_price'); +$minimalPrice = $configuredPrice->getMinimalPrice(); +$maximalPrice = $finalPriceModel->getMaximalPrice(); /** @var \Magento\Framework\Pricing\Price\PriceInterface $regularPriceModel */ $regularPriceModel = $block->getPriceType('regular_price'); +$maximalRegularPrice = $regularPriceModel->getMaximalPrice(); +$minimalRegularPrice = $regularPriceModel->getMinimalPrice(); ?> -hasSpecialPrice() - && $configuredPrice->getAmount()->getValue() !== $regularPriceModel->getValue()) : ?> +

renderAmount( diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml index 04766a4943dbc..3afb1752e1b71 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/bundle/configured_price.phtml @@ -5,27 +5,15 @@ */ ?> getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; -/** @var \Magento\Bundle\Pricing\Price\ConfiguredPrice $configuredPrice */ -$configuredPrice = $block->getPrice(); ?> hasSpecialPrice()) : ?> - getOptions())) { - $finalPriceModelAmount = $block->getPriceType('configured_price')->getConfiguredAmount(); - $regularPriceAmount = $block->getPriceType('configured_regular_price')->getConfiguredAmount(); - } else { - $finalPriceModelAmount = $block->getPriceType('final_price')->getAmount(); - $regularPriceAmount = $block->getPriceType('regular_price')->getAmount(); - } - ?>

renderAmount( - $finalPriceModelAmount, + $block->getConfiguredPrice()->getAmount(), [ 'display_label' => $block->escapeHtml(__('Special Price')), 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), @@ -37,7 +25,7 @@ $configuredPrice = $block->getPrice(); renderAmount( - $regularPriceAmount, + $block->getConfiguredRegularPrice()->getAmount(), [ 'display_label' => $block->escapeHtml(__('Regular Price')), 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), @@ -56,7 +44,7 @@ $configuredPrice = $block->getPrice(); ?>

renderAmount( - $block->getPriceType('configured_price')->getAmount(), + $this->getConfiguredPrice()->getAmount(), [ 'display_label' => $block->escapeHtml($priceLabel), 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), From a2d30ffc8805d72653e6b8a02f312e8e2632eeb7 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Fri, 6 Oct 2017 16:01:33 -0500 Subject: [PATCH 0026/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix configurable regular price amount --- .../Pricing/ConfiguredPrice/ConfigurableProduct.php | 11 ----------- .../product/price/configurable/configured_price.phtml | 2 -- 2 files changed, 13 deletions(-) diff --git a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php index d23118c018d28..043b291bea908 100644 --- a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php +++ b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php @@ -30,17 +30,6 @@ public function getConfiguredAmount($useRegularPrice = false) return $product->getPriceInfo()->getPrice($useRegularPrice ? 'regular_price' : self::PRICE_CODE)->getAmount(); } - /** - * Get selected option - * - * @return \Magento\Wishlist\Model\Item\Option - */ - public function getOption() - { - /** @var \Magento\Wishlist\Model\Item\Option $customOption */ - return $this->getProduct()->getCustomOption('simple_product'); - } - /** * @inheritdoc */ diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml index c2890766c0517..47006fefbe8e7 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -10,10 +10,8 @@ $schema = ($block->getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; /** @var \Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct $configuredPrice */ $configuredPrice = $block->getPrice(); -$option = $configuredPrice->getOption(); ?> hasSpecialPrice() - && $configuredPrice->getOption() && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getConfiguredAmount(true)->getValue()) : ?>

From f0fe02297949f72cf68e7394d509462b509579b3 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Mon, 9 Oct 2017 09:48:59 -0500 Subject: [PATCH 0027/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist --- .../templates/product/price/configured_price.phtml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index f6b23b6de95f1..689a77007e432 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -10,16 +10,10 @@ $schema = ($block->getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; /** @var \Magento\Catalog\Pricing\Price\ConfiguredPrice $configuredPrice */ $configuredPrice = $block->getPrice(); -/** @var \Magento\Bundle\Pricing\Price\FinalPrice $finalPriceModel */ -$finalPriceModel = $block->getPriceType('final_price'); -$minimalPrice = $configuredPrice->getMinimalPrice(); -$maximalPrice = $finalPriceModel->getMaximalPrice(); -/** @var \Magento\Framework\Pricing\Price\PriceInterface $regularPriceModel */ -$regularPriceModel = $block->getPriceType('regular_price'); -$maximalRegularPrice = $regularPriceModel->getMaximalPrice(); -$minimalRegularPrice = $regularPriceModel->getMinimalPrice(); +/** @var \Magento\Catalog\Pricing\Price\RegularPrice $regularPrice */ +$regularPrice = $block->getPriceType('regular_price'); ?> - +getAmount()->getValue() < $regularPrice->getAmount()->getValue()) : ?>

renderAmount( @@ -35,7 +29,7 @@ $minimalRegularPrice = $regularPriceModel->getMinimalPrice(); renderAmount( - $regularPriceModel->getAmount(), + $regularPrice->getAmount(), [ 'display_label' => $block->escapeHtml(__('Regular Price')), 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), From 32558577099d2cdc3dd56cf5d84f814ab3184987 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Wed, 11 Oct 2017 13:07:34 +0200 Subject: [PATCH 0028/1464] Database backup doesn't include triggers #9036 ADDED getTableTriggersSql() and now it returns valid SQL with drop & create queries for triggers --- app/code/Magento/Backup/Model/Db.php | 1 + .../Magento/Backup/Model/ResourceModel/Db.php | 25 +++++++++++++ .../Backup/Model/ResourceModel/Helper.php | 37 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/app/code/Magento/Backup/Model/Db.php b/app/code/Magento/Backup/Model/Db.php index 776141249f92b..98b04149cc7ea 100644 --- a/app/code/Magento/Backup/Model/Db.php +++ b/app/code/Magento/Backup/Model/Db.php @@ -173,6 +173,7 @@ public function createBackup(\Magento\Framework\Backup\Db\BackupInterface $backu } } $backup->write($this->getResource()->getTableForeignKeysSql()); + $backup->write($this->getResource()->getTableTriggersSql()); $backup->write($this->getResource()->getFooter()); $this->getResource()->commitTransaction(); diff --git a/app/code/Magento/Backup/Model/ResourceModel/Db.php b/app/code/Magento/Backup/Model/ResourceModel/Db.php index 3fbaf44ebb063..5ba3230e8c463 100644 --- a/app/code/Magento/Backup/Model/ResourceModel/Db.php +++ b/app/code/Magento/Backup/Model/ResourceModel/Db.php @@ -114,6 +114,31 @@ public function getTableForeignKeysSql($tableName = null) return $fkScript; } + /** + * Return triggers fro table(s) + * + * @param string|null $tableName + * @param bool $addDropIfExists + * @return string + */ + public function getTableTriggersSql($tableName = null, $addDropIfExists = true) + { + $triggerScript = ''; + if (!$tableName) { + $tables = $this->getTables(); + foreach ($tables as $table) { + $tableTriggerScript = $this->_resourceHelper->getTableTriggersSql($table, $addDropIfExists); + if (!empty($tableTriggerScript)) { + $triggerScript .= "\n" . $tableTriggerScript; + } + } + } else { + $triggerScript = $this->getTableTriggersSql($tableName, $addDropIfExists); + } + return $triggerScript; + + } + /** * Retrieve table status * diff --git a/app/code/Magento/Backup/Model/ResourceModel/Helper.php b/app/code/Magento/Backup/Model/ResourceModel/Helper.php index b5418865339c3..5f1db6ae7ca60 100644 --- a/app/code/Magento/Backup/Model/ResourceModel/Helper.php +++ b/app/code/Magento/Backup/Model/ResourceModel/Helper.php @@ -337,4 +337,41 @@ public function restoreTransactionIsolationLevel() { $this->getConnection()->query('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'); } + + /** + * Get create script for triggers + * + * @param string $tableName + * @param boolean $addDropIfExists + * @param boolean $stripDefiner + * @return string + */ + public function getTableTriggersSql($tableName, $addDropIfExists = false, $stripDefiner = true) + { + $script = "--\n-- Triggers structure for table `{$tableName}`\n--\n"; + $triggers = $this->getConnection()->query('SHOW TRIGGERS LIKE \''. $tableName . '\'')->fetchAll(); + + if (!$triggers) { + return ''; + } + foreach ($triggers as $trigger) { + if ($addDropIfExists) { + $script .= 'DROP TRIGGER IF EXISTS ' . $trigger['Trigger'] . ";\n"; + } + $script .= "delimiter ;;\n"; + + $triggerData = $this->getConnection()->query('SHOW CREATE TRIGGER '. $trigger['Trigger'])->fetch(); + if ($stripDefiner) { + $cleanedScript = preg_replace('/DEFINER=[^\s]*/', '', $triggerData['SQL Original Statement']); + $script .= $cleanedScript . "\n"; + } else { + $script .= $triggerData['SQL Original Statement'] . "\n"; + } + $script .= ";;\n"; + $script .= "delimiter ;\n"; + } + + return $script; + + } } From f1bcf38e7ce0202bde7be843ba1c46d20687ab43 Mon Sep 17 00:00:00 2001 From: Denis Ristic Date: Thu, 12 Oct 2017 10:13:13 +0200 Subject: [PATCH 0029/1464] FIXED PhpCS violations --- app/code/Magento/Backup/Model/ResourceModel/Db.php | 1 - app/code/Magento/Backup/Model/ResourceModel/Helper.php | 1 - 2 files changed, 2 deletions(-) diff --git a/app/code/Magento/Backup/Model/ResourceModel/Db.php b/app/code/Magento/Backup/Model/ResourceModel/Db.php index 5ba3230e8c463..f50a3c5b091ad 100644 --- a/app/code/Magento/Backup/Model/ResourceModel/Db.php +++ b/app/code/Magento/Backup/Model/ResourceModel/Db.php @@ -136,7 +136,6 @@ public function getTableTriggersSql($tableName = null, $addDropIfExists = true) $triggerScript = $this->getTableTriggersSql($tableName, $addDropIfExists); } return $triggerScript; - } /** diff --git a/app/code/Magento/Backup/Model/ResourceModel/Helper.php b/app/code/Magento/Backup/Model/ResourceModel/Helper.php index 5f1db6ae7ca60..6d7084a87546c 100644 --- a/app/code/Magento/Backup/Model/ResourceModel/Helper.php +++ b/app/code/Magento/Backup/Model/ResourceModel/Helper.php @@ -372,6 +372,5 @@ public function getTableTriggersSql($tableName, $addDropIfExists = false, $strip } return $script; - } } From 86a9bcc7f2e672a33d856466a2f1db86c37c44af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Mart=C3=ADnez?= Date: Fri, 13 Oct 2017 04:37:07 +0200 Subject: [PATCH 0030/1464] Ability to use whitelist for testing code style, based on const defined in phpunit xml config file --- dev/tests/static/phpunit-all.xml.dist | 2 ++ dev/tests/static/phpunit.xml.dist | 2 ++ dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dev/tests/static/phpunit-all.xml.dist b/dev/tests/static/phpunit-all.xml.dist index a77f536980c59..131cfa6a5ff60 100644 --- a/dev/tests/static/phpunit-all.xml.dist +++ b/dev/tests/static/phpunit-all.xml.dist @@ -19,5 +19,7 @@ + + diff --git a/dev/tests/static/phpunit.xml.dist b/dev/tests/static/phpunit.xml.dist index 6ccb9603000a0..1ae9342598e4b 100644 --- a/dev/tests/static/phpunit.xml.dist +++ b/dev/tests/static/phpunit.xml.dist @@ -29,6 +29,8 @@ + + diff --git a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php index f3dc7841d2df8..5058ef402cbd2 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php @@ -201,11 +201,14 @@ private function getFullWhitelist() public function testCodeStyle() { + $whiteList = defined('TESTCODESTYLE_IS_FULL_SCAN') && TESTCODESTYLE_IS_FULL_SCAN === '1' + ? $this->getFullWhitelist() : self::getWhitelist(['php', 'phtml']); + $reportFile = self::$reportDir . '/phpcs_report.txt'; $codeSniffer = new CodeSniffer('Magento', $reportFile, new Wrapper()); $this->assertEquals( 0, - $result = $codeSniffer->run($this->getFullWhitelist()), + $result = $codeSniffer->run($whiteList), "PHP Code Sniffer detected {$result} violation(s): " . PHP_EOL . file_get_contents($reportFile) ); } From d89cf0bc8a9e8e2fbdf615fe6d1deddb7a027647 Mon Sep 17 00:00:00 2001 From: Wesley Date: Mon, 16 Oct 2017 18:14:58 -0400 Subject: [PATCH 0031/1464] Add MagentoStyle as Console nput/output helper object to allow easier acces to io helpers in symfony/console --- .../Console/InputValidationException.php | 14 + .../Setup/Console/Style/MagentoStyle.php | 508 ++++++++++++++++++ .../Console/Style/MagentoStyleInterface.php | 15 + .../Unit/Console/Style/MagentoStyleTest.php | 62 +++ 4 files changed, 599 insertions(+) create mode 100755 setup/src/Magento/Setup/Console/InputValidationException.php create mode 100755 setup/src/Magento/Setup/Console/Style/MagentoStyle.php create mode 100755 setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php create mode 100755 setup/src/Magento/Setup/Test/Unit/Console/Style/MagentoStyleTest.php diff --git a/setup/src/Magento/Setup/Console/InputValidationException.php b/setup/src/Magento/Setup/Console/InputValidationException.php new file mode 100755 index 0000000000000..5d78bdabf3c8f --- /dev/null +++ b/setup/src/Magento/Setup/Console/InputValidationException.php @@ -0,0 +1,14 @@ +input = $input; + $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); + // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. + $currentLength = $this->getTerminalWidth() - (int) (DIRECTORY_SEPARATOR === '\\'); + $this->lineLength = min($currentLength, self::MAX_LINE_LENGTH); + + parent::__construct($output); + } + + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + * @param string|null $type The block type (added in [] on first line) + * @param string|null $style The style to apply to the whole block + * @param string $prefix The prefix for the block + * @param bool $padding Whether to add vertical padding + */ + public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = false) + { + $messages = is_array($messages) ? array_values($messages) : array($messages); + + $this->autoPrependBlock(); + $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, true)); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function title($message) + { + $this->autoPrependBlock(); + $bar = str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message)); + $this->writeln(array( + sprintf(' %s', OutputFormatter::escapeTrailingBackslash($message)), + sprintf(' %s', $bar), + )); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function section($message) + { + $this->autoPrependBlock(); + $bar = str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message)); + $this->writeln(array( + sprintf(' %s', OutputFormatter::escapeTrailingBackslash($message)), + sprintf(' %s', $bar), + )); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function listing(array $elements) + { + $this->autoPrependText(); + $elements = array_map(function ($element) { + return sprintf(' * %s', $element); + }, $elements); + + $this->writeln($elements); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function text($message) + { + $this->autoPrependText(); + + $messages = is_array($message) ? array_values($message) : array($message); + foreach ($messages as $message) { + $this->writeln(sprintf(' %s', $message)); + } + } + + /** + * Formats a command comment. + * + * @param string|array $message + */ + public function comment($message, $padding = false) + { + $this->block($message, null, 'comment', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function success($message, $padding = true) + { + $this->block($message, 'SUCCESS', 'fg=black;bg=green', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function error($message, $padding = true) + { + $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function warning($message, $padding = true) + { + $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function note($message, $padding = false) + { + $this->block($message, 'NOTE', 'fg=yellow', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function caution($message, $padding = true) + { + $this->block($message, 'CAUTION', 'fg=black;bg=yellow', ' ! ', $padding); + } + + /** + * {@inheritdoc} + */ + public function table(array $headers, array $rows) + { + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('%s'); + + $table = new Table($this); + $table->setHeaders($headers); + $table->setRows($rows); + $table->setStyle($style); + + $table->render(); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function ask($question, $default = null, $validator = null, $maxAttempts = null) + { + $question = new Question($question, $default); + $question->setValidator($validator); + $question->setMaxAttempts($maxAttempts); + + return $this->askQuestion($question); + } + + /** + * {@inheritdoc} + */ + public function askHidden($question, $validator = null) + { + $question = new Question($question); + + $question->setHidden(true); + $question->setValidator($validator); + + return $this->askQuestion($question); + } + + /** + * {@inheritdoc} + */ + public function confirm($question, $default = true) + { + return $this->askQuestion(new ConfirmationQuestion($question, $default)); + } + + /** + * {@inheritdoc} + */ + public function choice($question, array $choices, $default = null) + { + if (null !== $default) { + $values = array_flip($choices); + $default = $values[$default]; + } + + return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); + } + + /** + * {@inheritdoc} + */ + public function progressStart($max = 0) + { + $this->progressBar = $this->createProgressBar($max); + $this->progressBar->start(); + } + + /** + * {@inheritdoc} + */ + public function progressAdvance($step = 1) + { + $this->getProgressBar()->advance($step); + } + + /** + * {@inheritdoc} + */ + public function progressFinish() + { + $this->getProgressBar()->finish(); + $this->newLine(2); + $this->progressBar = null; + } + + /** + * {@inheritdoc} + */ + public function createProgressBar($max = 0) + { + $progressBar = parent::createProgressBar($max); + $progressBar->setEmptyBarCharacter(' '); + $progressBar->setProgressCharacter('>'); + $progressBar->setBarCharacter('='); + + return $progressBar; + } + + /** + * @param Question $question + * + * @return string + */ + public function askQuestion(Question $question) + { + if ($this->input->isInteractive()) { + $this->autoPrependBlock(); + } + + if (!$this->questionHelper) { + $this->questionHelper = new SymfonyQuestionHelper(); + } + + $answer = $this->questionHelper->ask($this->input, $this, $question); + + if ($this->input->isInteractive()) { + $this->newLine(); + $this->bufferedOutput->write("\n"); + } + + return $answer; + } + + /** + * Ask for an missing argument. + * + * @param string $argument + * @param string $question + * @param string|null $default + * @param callable|null $validator + * @param int|null $maxAttempts + * @param bool $comment + * @param string $commentFormat + */ + public function askForMissingArgument( + $argument, + $question, + $default = null, + $validator = null, + $maxAttempts = null, + $comment = null, + $commentFormat = "Argument [%s] set to: %s" + ) { + try { + if( is_null($this->input->getArgument($argument)) ) { + $this->input->setArgument($argument, $this->ask($question, $default, $validator, $maxAttempts) ); + } + $argumentValue = $this->input->getArgument($argument); + $validated = ( is_callable($validator) ? $validator($argumentValue) : $argumentValue ); + if( (bool) ( is_null($comment) ? $this->isDebug() : $comment ) ) + { + $this->comment( sprintf($commentFormat, $argument, $validated) ); + } + } catch( InputValidationException $e ) { + $this->error("Validation Error: ".$e->getMessage()); + $this->askForMissingArgument($argument, $question, $default, $validator, + $maxAttempts, $comment, $commentFormat); + } + } + + /** + * Ask for an missing option. + * + * @param string $option + * @param string $question + * @param string|null $default + * @param callable|null $validator + * @param int|null $maxAttempts + * @param bool $comment + * @param string $commentFormat + */ + public function askForMissingOption( + $option, + $question, + $default = null, + $validator = null, + $maxAttempts = null, + $comment = null, + $commentFormat = "Option [%s] set to: %s" + ) { + try { + if( is_null($this->input->getOption($option)) ) { + $this->input->setOption($option, $this->ask($question, $default, $validator, $maxAttempts) ); + } + $optionValue = $this->input->getOption($option); + $validated = ( is_callable($validator) ? $validator($optionValue) : $optionValue ); + if( (bool) ( is_null($comment) ? $this->isDebug() : $comment ) ) + { + $this->comment( sprintf($commentFormat, $option, $validated) ); + } + } catch( InputValidationException $e ) { + $this->error("Validation Error: ".$e->getMessage()); + $this->askForMissingOption($option, $question, $default, $validator, + $maxAttempts, $comment, $commentFormat); + } + } + + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + parent::writeln($messages, $type); + $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type); + } + + /** + * {@inheritdoc} + */ + public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) + { + parent::write($messages, $newline, $type); + $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type); + } + + /** + * {@inheritdoc} + */ + public function newLine($count = 1) + { + parent::newLine($count); + $this->bufferedOutput->write(str_repeat("\n", $count)); + } + + /** + * @return ProgressBar + */ + private function getProgressBar() + { + if (!$this->progressBar) { + throw new RuntimeException('The ProgressBar is not started.'); + } + + return $this->progressBar; + } + + private function getTerminalWidth() + { + $application = new Application(); + $dimensions = $application->getTerminalDimensions(); + + return $dimensions[0] ?: self::MAX_LINE_LENGTH; + } + + private function autoPrependBlock() + { + $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); + + if (!isset($chars[0])) { + return $this->newLine(); //empty history, so we should start with a new line. + } + //Prepend new line for each non LF chars (This means no blank line was output before) + $this->newLine(2 - substr_count($chars, "\n")); + } + + private function autoPrependText() + { + $fetched = $this->bufferedOutput->fetch(); + //Prepend new line if last char isn't EOL: + if ("\n" !== substr($fetched, -1)) { + $this->newLine(); + } + } + + private function reduceBuffer($messages) + { + // We need to know if the two last chars are PHP_EOL + // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer + return array_map(function ($value) { + return substr($value, -4); + }, array_merge(array($this->bufferedOutput->fetch()), (array) $messages)); + } + + private function createBlock( + $messages, + $type = null, + $style = null, + $prefix = ' ', + $padding = false, + $escape = false + ) { + $indentLength = 0; + $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix); + $lines = array(); + + if (null !== $type) { + $type = sprintf('[%s] ', $type); + $indentLength = strlen($type); + $lineIndentation = str_repeat(' ', $indentLength); + } + + // wrap and add newlines for each element + foreach ($messages as $key => $message) { + if ($escape) { + $message = OutputFormatter::escape($message); + } + + $wordwrap = wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true); + $lines = array_merge($lines, explode(PHP_EOL, $wordwrap)); + + if (count($messages) > 1 && $key < count($messages) - 1) { + $lines[] = ''; + } + } + + $firstLineIndex = 0; + if ($padding && $this->isDecorated()) { + $firstLineIndex = 1; + array_unshift($lines, ''); + $lines[] = ''; + } + + foreach ($lines as $i => &$line) { + if (null !== $type) { + $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line; + } + + $line = $prefix.$line; + $multiplier = $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line); + $line .= str_repeat(' ', $multiplier); + + if ($style) { + $line = sprintf('<%s>%s', $style, $line); + } + } + + return $lines; + } + +} \ No newline at end of file diff --git a/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php b/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php new file mode 100755 index 0000000000000..7760480623006 --- /dev/null +++ b/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php @@ -0,0 +1,15 @@ + 'foo'), new InputDefinition(array(new InputArgument('name')))); + $output = new TestOutput(); + + $io = new MagentoStyle($input,$output); + + $io->title("My Title"); + + $expected = "\r\n My Title\n ========\n\r\n"; + + $this->assertEquals($expected,$output->output,"Title does not match output"); + } + + public function testSectionStyle() + { + $input = new ArrayInput(array('name' => 'foo'), new InputDefinition(array(new InputArgument('name')))); + $output = new TestOutput(); + + $io = new MagentoStyle($input,$output); + + $io->section("My Section"); + + $expected = "\r\n My Section\n ----------\n\r\n"; + + $this->assertEquals($expected,$output->output,"Section does not match output"); + } + +} + +class TestOutput extends Output +{ + public $output = ''; + + public function clear() + { + $this->output = ''; + } + + protected function doWrite($message, $newline) + { + $this->output .= $message.($newline ? "\n" : ''); + } +} \ No newline at end of file From b4bfe4b142a6c279dffda59eb345d77b37fd20fd Mon Sep 17 00:00:00 2001 From: Andrew Howden Date: Tue, 17 Oct 2017 12:44:36 +0200 Subject: [PATCH 0032/1464] Modify Report processor to return 500 The report processor is currently returning a HTTP 503 status code; generally used for temporarily failures to connect to a service such as when that service is in maintenance mode, when an upstream proxy is unavailable etc. This commit modifies the report HTTP code to be a 500. The author believes this to be a better reflection that the error is miscellaneous in nature, and that action is required in order to change it (i.e. it is not a temporary condition) --- pub/errors/processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pub/errors/processor.php b/pub/errors/processor.php index 5ca9d826e2e03..de719d6a22ef2 100644 --- a/pub/errors/processor.php +++ b/pub/errors/processor.php @@ -215,7 +215,7 @@ public function process503() public function processReport() { $this->pageTitle = 'There has been an error processing your request'; - $this->_response->setHttpResponseCode(503); + $this->_response->setHttpResponseCode(500); $this->showErrorMsg = false; $this->showSentMsg = false; From 18d3296acf94470319e747122b7e94d5434f3fa3 Mon Sep 17 00:00:00 2001 From: Gil Greenberg Date: Fri, 20 Oct 2017 15:24:51 -0400 Subject: [PATCH 0033/1464] Add support for fotorama 'thumbmargin' setting within a theme's view.xml 16 --- .../Catalog/view/frontend/templates/product/view/gallery.phtml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml index 5a064b33355a4..2bfe986b6dec2 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/gallery.phtml @@ -68,6 +68,9 @@ "thumbheight": getImageAttribute('product_page_image_small', 'height') ?: $block->getImageAttribute('product_page_image_small', 'width'); ?>, + getVar("gallery/thumbmargin"))): ?> + "thumbmargin": getVar("gallery/thumbmargin"); ?>, + getImageAttribute('product_page_image_medium', 'height') || $block->getImageAttribute('product_page_image_medium', 'width')): ?> "height": getImageAttribute('product_page_image_medium', 'height') ?: $block->getImageAttribute('product_page_image_medium', 'width'); ?>, From 129034d44c497ae81f95c0315b56a1c09cef33ed Mon Sep 17 00:00:00 2001 From: gwharton Date: Tue, 24 Oct 2017 22:55:15 +0100 Subject: [PATCH 0034/1464] UPS Option to include TAX in rate The current UPS Module uses the UPS Rate excluding TAX to use as the rate charged to the customer during checkout. This modification adds an additional config option so you can choose whether to request and include TAX information from UPS in the rate or not. This modification is especially useful for businesses who are not TAX registered and cannot claim back the TAX charged by UPS. This allows them to pass on the TAX costs to the customer as part of the overall shipping rate. --- app/code/Magento/Ups/Model/Carrier.php | 25 +++++++++++++++++-- app/code/Magento/Ups/etc/adminhtml/system.xml | 4 +++ app/code/Magento/Ups/etc/config.xml | 1 + app/code/Magento/Ups/i18n/en_US.csv | 1 + .../system/shipping/carrier_config.phtml | 2 +- 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php index 095f4b9a5e0df..8ede1ca0bdf53 100644 --- a/app/code/Magento/Ups/Model/Carrier.php +++ b/app/code/Magento/Ups/Model/Carrier.php @@ -718,6 +718,9 @@ protected function _getXmlQuotes() if ($this->getConfigFlag('negotiated_active')) { $xmlParams .= ""; } + if ($this->getConfigFlag('include_taxes')) { + $xmlParams .= ""; + } $xmlParams .= << @@ -819,10 +822,28 @@ protected function _parseXmlResponse($xmlResponse) foreach ($arr as $shipElement) { $code = (string)$shipElement->Service->Code; if (in_array($code, $allowedMethods)) { + + //The location of tax information is in a different place depending on whether we are using negotiated rates or not if ($negotiatedActive) { - $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue; + $includeTaxesArr = $xml->getXpath("//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates/TaxCharges"); + $includeTaxesActive = $this->getConfigFlag( + 'include_taxes' + ) && !empty($includeTaxesArr); + $cost = (double)$shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue; + if ($includeTaxesActive) { + $taxes = (double)$shipElement->NegotiatedRates->TaxCharges->MonetaryValue; + $cost += $taxes; + } } else { - $cost = $shipElement->TotalCharges->MonetaryValue; + $includeTaxesArr = $xml->getXpath("//RatingServiceSelectionResponse/RatedShipment/TaxCharges"); + $includeTaxesActive = $this->getConfigFlag( + 'include_taxes' + ) && !empty($includeTaxesArr); + $cost = (double)$shipElement->TotalCharges->MonetaryValue; + if ($includeTaxesActive) { + $taxes = (double)$shipElement->TaxCharges->MonetaryValue; + $cost += $taxes; + } } //convert price with Origin country currency code to base currency code diff --git a/app/code/Magento/Ups/etc/adminhtml/system.xml b/app/code/Magento/Ups/etc/adminhtml/system.xml index 255039e6499cc..57a0097075c7d 100644 --- a/app/code/Magento/Ups/etc/adminhtml/system.xml +++ b/app/code/Magento/Ups/etc/adminhtml/system.xml @@ -118,6 +118,10 @@ Magento\Config\Model\Config\Source\Yesno + + + Magento\Config\Model\Config\Source\Yesno + Required for negotiated rates; 6-character UPS diff --git a/app/code/Magento/Ups/etc/config.xml b/app/code/Magento/Ups/etc/config.xml index 7dd47b6bf673b..0f92ae4dad195 100644 --- a/app/code/Magento/Ups/etc/config.xml +++ b/app/code/Magento/Ups/etc/config.xml @@ -35,6 +35,7 @@ F O 0 + 0 1 UPS 0 diff --git a/app/code/Magento/Ups/i18n/en_US.csv b/app/code/Magento/Ups/i18n/en_US.csv index 0412a993b00ef..adc784b512bfd 100644 --- a/app/code/Magento/Ups/i18n/en_US.csv +++ b/app/code/Magento/Ups/i18n/en_US.csv @@ -103,6 +103,7 @@ Title,Title "Weight Unit","Weight Unit" "User ID","User ID" "Enable Negotiated Rates","Enable Negotiated Rates" +"Include TAX in Rate","Include TAX in Rate" "Shipper Number","Shipper Number" "Required for negotiated rates; 6-character UPS","Required for negotiated rates; 6-character UPS" "Ship to Applicable Countries","Ship to Applicable Countries" diff --git a/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml b/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml index 388727f1e0d65..411bec20cde57 100644 --- a/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml +++ b/app/code/Magento/Ups/view/adminhtml/templates/system/shipping/carrier_config.phtml @@ -81,7 +81,7 @@ require(["prototype"], function(){ this.onlyUpsXmlElements = ['carriers_ups_gateway_xml_url','carriers_ups_tracking_xml_url', 'carriers_ups_username','carriers_ups_password','carriers_ups_access_license_number', 'carriers_ups_origin_shipment','carriers_ups_negotiated_active','carriers_ups_shipper_number', - 'carriers_ups_mode_xml']; + 'carriers_ups_mode_xml','carriers_ups_include_taxes']; this.onlyUpsElements = ['carriers_ups_gateway_url']; this.storedOriginShipment = ''; From 6f4aed443d8d4631a1d6a8bce590f94a53606ac4 Mon Sep 17 00:00:00 2001 From: gwharton Date: Tue, 24 Oct 2017 23:17:06 +0100 Subject: [PATCH 0035/1464] Remove blank line Remove blank line that was added by mistake --- app/code/Magento/Ups/Model/Carrier.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php index 8ede1ca0bdf53..218bd258d6903 100644 --- a/app/code/Magento/Ups/Model/Carrier.php +++ b/app/code/Magento/Ups/Model/Carrier.php @@ -822,7 +822,6 @@ protected function _parseXmlResponse($xmlResponse) foreach ($arr as $shipElement) { $code = (string)$shipElement->Service->Code; if (in_array($code, $allowedMethods)) { - //The location of tax information is in a different place depending on whether we are using negotiated rates or not if ($negotiatedActive) { $includeTaxesArr = $xml->getXpath("//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates/TaxCharges"); From fa647d7bc1bcc11900715db620b53976d26e4fa9 Mon Sep 17 00:00:00 2001 From: Cristian Partica Date: Wed, 25 Oct 2017 16:17:08 -0500 Subject: [PATCH 0036/1464] MAGETWO-69634: Product with a special price must be showed with this price in the wishlist - fix configurable regular price amount and grouped --- .../Pricing/Price/ConfiguredRegularPrice.php | 1 - .../Price/ConfiguredPriceInterface.php | 6 ++ .../Pricing/Price/ConfiguredRegularPrice.php | 93 +++++++++++++++++++ .../Pricing/Render/ConfiguredPriceBox.php | 11 ++- app/code/Magento/Catalog/etc/di.xml | 2 +- .../product/price/configured_price.phtml | 10 +- .../Pricing/Price/ConfiguredRegularPrice.php | 75 +++++++++++++++ app/code/Magento/GroupedProduct/etc/di.xml | 1 + .../ConfiguredPrice/ConfigurableProduct.php | 18 +++- .../price/configurable/configured_price.phtml | 9 +- 10 files changed, 209 insertions(+), 17 deletions(-) create mode 100644 app/code/Magento/Catalog/Pricing/Price/ConfiguredRegularPrice.php create mode 100644 app/code/Magento/GroupedProduct/Pricing/Price/ConfiguredRegularPrice.php diff --git a/app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php b/app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php index 02fdcb0d705bb..830f7c7407a87 100644 --- a/app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/ConfiguredRegularPrice.php @@ -21,7 +21,6 @@ class ConfiguredRegularPrice extends ConfiguredPrice * Create Selection Price List * * @param \Magento\Bundle\Model\Option $option - * @param bool $useRegularPrice * @return BundleSelectionPrice[] */ protected function createSelectionPriceList($option) diff --git a/app/code/Magento/Catalog/Pricing/Price/ConfiguredPriceInterface.php b/app/code/Magento/Catalog/Pricing/Price/ConfiguredPriceInterface.php index e6d35a0f5239a..c0e07aff41069 100644 --- a/app/code/Magento/Catalog/Pricing/Price/ConfiguredPriceInterface.php +++ b/app/code/Magento/Catalog/Pricing/Price/ConfiguredPriceInterface.php @@ -18,6 +18,12 @@ interface ConfiguredPriceInterface */ const CONFIGURED_PRICE_CODE = 'configured_price'; + /** + * Price type configured + */ + const CONFIGURED_REGULAR_PRICE_CODE = 'configured_regular_price'; + + /** * @param ItemInterface $item * @return $this diff --git a/app/code/Magento/Catalog/Pricing/Price/ConfiguredRegularPrice.php b/app/code/Magento/Catalog/Pricing/Price/ConfiguredRegularPrice.php new file mode 100644 index 0000000000000..422482f30b7ec --- /dev/null +++ b/app/code/Magento/Catalog/Pricing/Price/ConfiguredRegularPrice.php @@ -0,0 +1,93 @@ +item = $item; + parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency); + } + + /** + * @param ItemInterface $item + * @return $this + */ + public function setItem(ItemInterface $item) + { + $this->item = $item; + return $this; + } + + /** + * Get value of configured options + * + * @return array + */ + protected function getOptionsValue() + { + $product = $this->item->getProduct(); + $value = 0.; + $basePrice = parent::getValue(); + $optionIds = $this->item->getOptionByCode('option_ids'); + if ($optionIds) { + foreach (explode(',', $optionIds->getValue()) as $optionId) { + $option = $product->getOptionById($optionId); + if ($option) { + $itemOption = $this->item->getOptionByCode('option_' . $option->getId()); + /** @var $group \Magento\Catalog\Model\Product\Option\Type\DefaultType */ + $group = $option->groupFactory($option->getType()) + ->setOption($option) + ->setConfigurationItem($this->item) + ->setConfigurationItemOption($itemOption); + $value += $group->getOptionPrice($itemOption->getValue(), $basePrice); + } + } + } + return $value; + } + + /** + * Price value of product with configured options + * + * @return bool|float + */ + public function getValue() + { + return $this->item ? parent::getValue() + $this->getOptionsValue() : parent::getValue(); + } +} diff --git a/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php b/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php index 18587e49de799..d6d8a35a75588 100644 --- a/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php +++ b/app/code/Magento/Catalog/Pricing/Render/ConfiguredPriceBox.php @@ -8,6 +8,9 @@ use Magento\Catalog\Model\Product\Configuration\Item\ItemInterface; use Magento\Framework\Pricing\Price\PriceInterface; +use Magento\Catalog\Pricing\Price\ConfiguredPriceInterface; +use Magento\Catalog\Pricing\Price\FinalPrice; +use Magento\Catalog\Pricing\Price\RegularPrice; /** * Class for configured_price rendering @@ -59,7 +62,7 @@ public function getConfiguredPrice() $configuredPrice = $this->getPrice(); if (empty($configuredPrice->getSelectionPriceList())) { // If there was no selection we must show minimal regular price - return $this->getSaleableItem()->getPriceInfo()->getPrice('final_price'); + return $this->getSaleableItem()->getPriceInfo()->getPrice(FinalPrice::PRICE_CODE); } return $configuredPrice; @@ -71,10 +74,10 @@ public function getConfiguredPrice() public function getConfiguredRegularPrice() { /** @var \Magento\Bundle\Pricing\Price\ConfiguredPrice $configuredPrice */ - $configuredPrice = $this->getPriceType('configured_regular_price'); + $configuredPrice = $this->getPriceType(ConfiguredPriceInterface::CONFIGURED_REGULAR_PRICE_CODE); if (empty($configuredPrice->getSelectionPriceList())) { // If there was no selection we must show minimal regular price - return $this->getSaleableItem()->getPriceInfo()->getPrice('regular_price'); + return $this->getSaleableItem()->getPriceInfo()->getPrice(RegularPrice::PRICE_CODE); } return $configuredPrice; @@ -87,7 +90,7 @@ public function getConfiguredRegularPrice() */ public function hasSpecialPrice() { - if ($this->price->getPriceCode() == 'configured_price') { + if ($this->price->getPriceCode() == ConfiguredPriceInterface::CONFIGURED_PRICE_CODE) { $displayRegularPrice = $this->getConfiguredRegularPrice()->getAmount()->getValue(); $displayFinalPrice = $this->getConfiguredPrice()->getAmount()->getValue(); return $displayFinalPrice < $displayRegularPrice; diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 114d46f63fdd3..21956d0c2c924 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -356,7 +356,7 @@ Magento\Catalog\Pricing\Price\BasePrice Magento\Catalog\Pricing\Price\CustomOptionPrice Magento\Catalog\Pricing\Price\ConfiguredPrice - + Magento\Catalog\Pricing\Price\ConfiguredRegularPrice diff --git a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml index 689a77007e432..5bb14f6e7d309 100644 --- a/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml +++ b/app/code/Magento/Catalog/view/base/templates/product/price/configured_price.phtml @@ -10,10 +10,12 @@ $schema = ($block->getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; /** @var \Magento\Catalog\Pricing\Price\ConfiguredPrice $configuredPrice */ $configuredPrice = $block->getPrice(); -/** @var \Magento\Catalog\Pricing\Price\RegularPrice $regularPrice */ -$regularPrice = $block->getPriceType('regular_price'); +/** @var \Magento\Catalog\Pricing\Price\ConfiguredRegularPrice $configuredRegularPrice */ +$configuredRegularPrice = $block->getPriceType( + \Magento\Catalog\Pricing\Price\ConfiguredPriceInterface::CONFIGURED_REGULAR_PRICE_CODE +); ?> -getAmount()->getValue() < $regularPrice->getAmount()->getValue()) : ?> +getAmount()->getValue() < $configuredRegularPrice->getAmount()->getValue()) : ?>

renderAmount( @@ -29,7 +31,7 @@ $regularPrice = $block->getPriceType('regular_price'); renderAmount( - $regularPrice->getAmount(), + $configuredRegularPrice->getAmount(), [ 'display_label' => $block->escapeHtml(__('Regular Price')), 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), diff --git a/app/code/Magento/GroupedProduct/Pricing/Price/ConfiguredRegularPrice.php b/app/code/Magento/GroupedProduct/Pricing/Price/ConfiguredRegularPrice.php new file mode 100644 index 0000000000000..4ca5b63219c2a --- /dev/null +++ b/app/code/Magento/GroupedProduct/Pricing/Price/ConfiguredRegularPrice.php @@ -0,0 +1,75 @@ +item = $item; + return $this; + } + + /** + * Calculate configured price + * + * @return float + */ + protected function calculatePrice() + { + $value = 0.; + /** @var \Magento\GroupedProduct\Model\Product\Type\Grouped $typeInstance */ + $typeInstance = $this->getProduct()->getTypeInstance(); + $associatedProducts = $typeInstance + ->setStoreFilter($this->getProduct()->getStore(), $this->getProduct()) + ->getAssociatedProducts($this->getProduct()); + + foreach ($associatedProducts as $product) { + /** @var Product $product */ + /** @var \Magento\Wishlist\Model\Item\Option $customOption */ + $customOption = $this->getProduct() + ->getCustomOption('associated_product_' . $product->getId()); + if (!$customOption) { + continue; + } + $finalPrice = $product->getPriceInfo() + ->getPrice(RegularPrice::PRICE_CODE) + ->getValue(); + $value += $finalPrice * ($customOption->getValue() ? $customOption->getValue() : 1); + } + return $value; + } + + /** + * Price value of product with configured options + * + * @return bool|float + */ + public function getValue() + { + return $this->item ? $this->calculatePrice() : parent::getValue(); + } +} diff --git a/app/code/Magento/GroupedProduct/etc/di.xml b/app/code/Magento/GroupedProduct/etc/di.xml index f39bcfa01453c..8f688e3d06b00 100644 --- a/app/code/Magento/GroupedProduct/etc/di.xml +++ b/app/code/Magento/GroupedProduct/etc/di.xml @@ -48,6 +48,7 @@ Magento\GroupedProduct\Pricing\Price\FinalPrice Magento\GroupedProduct\Pricing\Price\ConfiguredPrice + Magento\GroupedProduct\Pricing\Price\ConfiguredRegularPrice Magento\Catalog\Pricing\Price\Pool diff --git a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php index 043b291bea908..6b06bf3b9de7f 100644 --- a/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php +++ b/app/code/Magento/Wishlist/Pricing/ConfiguredPrice/ConfigurableProduct.php @@ -19,15 +19,27 @@ class ConfigurableProduct extends FinalPrice implements ConfiguredPriceInterface /** * Get Configured Price Amount object by price type * - * @param bool $useRegularPrice * @return \Magento\Framework\Pricing\Amount\AmountInterface */ - public function getConfiguredAmount($useRegularPrice = false) + public function getConfiguredAmount() { /** @var \Magento\Wishlist\Model\Item\Option $customOption */ $customOption = $this->getProduct()->getCustomOption('simple_product'); $product = $customOption ? $customOption->getProduct() : $this->getProduct(); - return $product->getPriceInfo()->getPrice($useRegularPrice ? 'regular_price' : self::PRICE_CODE)->getAmount(); + return $product->getPriceInfo()->getPrice(self::CONFIGURED_PRICE_CODE)->getAmount(); + } + + /** + * Get Configured Regular Price Amount object by price type + * + * @return \Magento\Framework\Pricing\Amount\AmountInterface + */ + public function getConfiguredRegularAmount() + { + /** @var \Magento\Wishlist\Model\Item\Option $customOption */ + $customOption = $this->getProduct()->getCustomOption('simple_product'); + $product = $customOption ? $customOption->getProduct() : $this->getProduct(); + return $product->getPriceInfo()->getPrice(self::CONFIGURED_REGULAR_PRICE_CODE)->getAmount(); } /** diff --git a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml index 47006fefbe8e7..6467cd619a176 100644 --- a/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml +++ b/app/code/Magento/Wishlist/view/base/templates/product/price/configurable/configured_price.phtml @@ -5,18 +5,19 @@ */ ?> getZone() == 'item_view') ? true : false; $idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : ''; /** @var \Magento\Wishlist\Pricing\ConfiguredPrice\ConfigurableProduct $configuredPrice */ $configuredPrice = $block->getPrice(); ?> hasSpecialPrice() - && $configuredPrice->getAmount()->getValue() !== $configuredPrice->getConfiguredAmount(true)->getValue()) : ?> + && $configuredPrice->getConfiguredAmount()->getValue() !== $configuredPrice->getConfiguredRegularAmount()->getValue() + && $configuredPrice->getConfiguredRegularAmount()->getValue()) : ?>

renderAmount( - $configuredPrice->getAmount(), + $configuredPrice->getConfiguredAmount(), [ 'display_label' => $block->escapeHtml(__('Special Price')), 'price_id' => $block->escapeHtml($block->getPriceId('product-price-' . $idSuffix)), @@ -28,7 +29,7 @@ $configuredPrice = $block->getPrice(); renderAmount( - $configuredPrice->getConfiguredAmount(true), + $configuredPrice->getConfiguredRegularAmount(), [ 'display_label' => $block->escapeHtml(__('Regular Price')), 'price_id' => $block->escapeHtml($block->getPriceId('old-price-' . $idSuffix)), From 3b72839e482dde668c8451f922b9924ec1dd76fb Mon Sep 17 00:00:00 2001 From: gwharton Date: Thu, 26 Oct 2017 10:40:40 +0100 Subject: [PATCH 0037/1464] Suppressed Excessive Method Length checks This pull request adds enough lines of code to the function to trigger the excessive method length check in PHPMD. The majority of the code in the function is not mine and I do not want to change stuff for the sake of passing this check. My goal was to make the changes with as little impact on the existing code base as possible. --- app/code/Magento/Ups/Model/Carrier.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php index 218bd258d6903..263fa20cb7c6b 100644 --- a/app/code/Magento/Ups/Model/Carrier.php +++ b/app/code/Magento/Ups/Model/Carrier.php @@ -796,6 +796,7 @@ private function mapCurrencyCode($code) * @param mixed $xmlResponse * @return Result * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function _parseXmlResponse($xmlResponse) { From e6aea374904b2c4a4deed537beca3cf7ea3a7733 Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Wed, 8 Nov 2017 13:10:34 +0100 Subject: [PATCH 0038/1464] Add option "share" for shell command "config:set" This is similar to the "lock" switch which writes configuration values to app/etc/env.php. The "share" switch writes it to app/etc/config.php instead which can be shared between environments. --- .../ConfigSet/ConfigSetProcessorFactory.php | 1 + .../Command/ConfigSet/LockProcessor.php | 3 +- .../Command/ConfigSet/ProcessorFacade.php | 28 +++-- .../Command/ConfigSet/ShareProcessor.php | 109 ++++++++++++++++++ .../Console/Command/ConfigSetCommand.php | 12 +- app/code/Magento/Config/etc/di.xml | 1 + 6 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php index e005747ea5ed5..2fc3374859ba6 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php @@ -28,6 +28,7 @@ class ConfigSetProcessorFactory */ const TYPE_DEFAULT = 'default'; const TYPE_LOCK = 'lock'; + const TYPE_SHARE = 'share'; /**#@-*/ /**#@-*/ diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php index 0bd28f0f78d96..9e39b7bf7bf40 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php @@ -16,7 +16,8 @@ /** * Processes file lock flow of config:set command. - * This processor saves the value of configuration and lock it for editing in Admin interface. + * This processor saves the value of configuration into app/etc/env.php + * and locks it for editing in Admin interface. * * {@inheritdoc} */ diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php b/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php index 06a01c6686bfd..4b202538b3701 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php @@ -96,13 +96,14 @@ public function __construct( * @param string $scope The configuration scope (default, website, or store) * @param string $scopeCode The scope code * @param boolean $lock The lock flag + * @param boolean $share The share flag * @return string Processor response message * @throws ValidatorException If some validation is wrong * @throws CouldNotSaveException If cannot save config value * @throws ConfigurationMismatchException If processor can not be instantiated * @since 100.2.0 */ - public function process($path, $value, $scope, $scopeCode, $lock) + public function process($path, $value, $scope, $scopeCode, $lock, $share = false) { try { $this->scopeValidator->isValid($scope, $scopeCode); @@ -111,14 +112,25 @@ public function process($path, $value, $scope, $scopeCode, $lock) throw new ValidatorException(__($exception->getMessage()), $exception); } - $processor = $lock - ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK) - : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT); - $message = $lock - ? 'Value was saved and locked.' - : 'Value was saved.'; + $processor = + $share + ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_SHARE) + : ( + $lock + ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK) + : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT) + ); - // The processing flow depends on --lock option. + $message = + $share + ? 'Value was saved in app/etc/config.php and locked.' + : ( + $lock + ? 'Value was saved in app/etc/env.php and locked.' + : 'Value was saved.' + ); + + // The processing flow depends on --lock and --share options. $processor->process($path, $value, $scope, $scopeCode); $this->hash->regenerate(System::CONFIG_TYPE); diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php new file mode 100644 index 0000000000000..c1b004a62a730 --- /dev/null +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php @@ -0,0 +1,109 @@ +preparedValueFactory = $preparedValueFactory; + $this->deploymentConfigWriter = $writer; + $this->arrayManager = $arrayManager; + $this->configPathResolver = $configPathResolver; + } + + /** + * Processes lock flow of config:set command. + * Requires read access to filesystem. + * + * {@inheritdoc} + */ + public function process($path, $value, $scope, $scopeCode) + { + try { + $configPath = $this->configPathResolver->resolve($path, $scope, $scopeCode, System::CONFIG_TYPE); + $backendModel = $this->preparedValueFactory->create($path, $value, $scope, $scopeCode); + + if ($backendModel instanceof Value) { + /** + * Temporary solution until Magento introduce unified interface + * for storing system configuration into database and configuration files. + */ + $backendModel->validateBeforeSave(); + $backendModel->beforeSave(); + + $value = $backendModel->getValue(); + + $backendModel->afterSave(); + + /** + * Because FS does not support transactions, + * we'll write value just after all validations are triggered. + */ + $this->deploymentConfigWriter->saveConfig( + [ConfigFilePool::APP_CONFIG => $this->arrayManager->set($configPath, [], $value)], + false + ); + } + } catch (\Exception $exception) { + throw new CouldNotSaveException(__('%1', $exception->getMessage()), $exception); + } + } +} diff --git a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php index 1df1b3c4bed14..2b96164b1a766 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php +++ b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php @@ -34,6 +34,7 @@ class ConfigSetCommand extends Command const OPTION_SCOPE = 'scope'; const OPTION_SCOPE_CODE = 'scope-code'; const OPTION_LOCK = 'lock'; + const OPTION_SHARE = 'share'; /**#@-*/ /**#@-*/ @@ -112,7 +113,13 @@ protected function configure() static::OPTION_LOCK, 'l', InputOption::VALUE_NONE, - 'Lock value which prevents modification in the Admin' + 'Lock value which prevents modification in the Admin (will be saved in app/etc/env.php)' + ), + new InputOption( + static::OPTION_SHARE, + 's', + InputOption::VALUE_NONE, + 'Lock and share value with other installations, prevents modification in the Admin (will be saved in app/etc/config.php)' ), ]); @@ -151,7 +158,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $input->getArgument(static::ARG_VALUE), $input->getOption(static::OPTION_SCOPE), $input->getOption(static::OPTION_SCOPE_CODE), - $input->getOption(static::OPTION_LOCK) + $input->getOption(static::OPTION_LOCK), + $input->getOption(static::OPTION_SHARE) ); }); diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml index bcddd8ceaf27a..dcd2b255ba338 100644 --- a/app/code/Magento/Config/etc/di.xml +++ b/app/code/Magento/Config/etc/di.xml @@ -297,6 +297,7 @@ Magento\Config\Console\Command\ConfigSet\DefaultProcessor Magento\Config\Console\Command\ConfigSet\LockProcessor + Magento\Config\Console\Command\ConfigSet\ShareProcessor From e60d7bc39f5dc79886ec1224342aa359840a8f79 Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Wed, 8 Nov 2017 13:20:44 +0100 Subject: [PATCH 0039/1464] Add unit tests for option "share" of shell command "config:set" --- .../Command/ConfigSet/ShareProcessorTest.php | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ShareProcessorTest.php diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ShareProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ShareProcessorTest.php new file mode 100644 index 0000000000000..8a93ce5cf4940 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ShareProcessorTest.php @@ -0,0 +1,219 @@ +preparedValueFactory = $this->getMockBuilder(PreparedValueFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->deploymentConfigWriterMock = $this->getMockBuilder(DeploymentConfig\Writer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configPathResolver = $this->getMockBuilder(ConfigPathResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->valueMock = $this->getMockBuilder(Value::class) + ->setMethods(['validateBeforeSave', 'beforeSave', 'setValue', 'getValue', 'afterSave']) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new ShareProcessor( + $this->preparedValueFactory, + $this->deploymentConfigWriterMock, + $this->arrayManagerMock, + $this->configPathResolver + ); + } + + /** + * Tests process of share flow. + * + * @param string $path + * @param string $value + * @param string $scope + * @param string|null $scopeCode + * @dataProvider processDataProvider + */ + public function testProcess($path, $value, $scope, $scopeCode) + { + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->with($path, $value, $scope, $scopeCode) + ->willReturn($this->valueMock); + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->arrayManagerMock->expects($this->once()) + ->method('set') + ->with('system/default/test/test/test', [], $value) + ->willReturn([ + 'system' => [ + 'default' => [ + 'test' => [ + 'test' => [ + 'test' => $value + ] + ] + ] + ] + ]); + $this->valueMock->expects($this->once()) + ->method('getValue') + ->willReturn($value); + $this->deploymentConfigWriterMock->expects($this->once()) + ->method('saveConfig') + ->with( + [ + ConfigFilePool::APP_CONFIG => [ + 'system' => [ + 'default' => [ + 'test' => [ + 'test' => [ + 'test' => $value + ] + ] + ] + ] + ] + ], + false + ); + $this->valueMock->expects($this->once()) + ->method('validateBeforeSave'); + $this->valueMock->expects($this->once()) + ->method('beforeSave'); + $this->valueMock->expects($this->once()) + ->method('afterSave'); + + $this->model->process($path, $value, $scope, $scopeCode); + } + + /** + * @return array + */ + public function processDataProvider() + { + return [ + ['test/test/test', 'value', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null], + ['test/test/test', 'value', ScopeInterface::SCOPE_WEBSITE, 'base'], + ['test/test/test', 'value', ScopeInterface::SCOPE_STORE, 'test'], + ]; + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Filesystem is not writable. + */ + public function testProcessNotReadableFs() + { + $path = 'test/test/test'; + $value = 'value'; + + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->willReturn($this->valueMock); + $this->valueMock->expects($this->once()) + ->method('getValue') + ->willReturn($value); + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->arrayManagerMock->expects($this->once()) + ->method('set') + ->with('system/default/test/test/test', [], $value) + ->willReturn(null); + $this->deploymentConfigWriterMock->expects($this->once()) + ->method('saveConfig') + ->willThrowException(new FileSystemException(__('Filesystem is not writable.'))); + + $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid values + */ + public function testCustomException() + { + $path = 'test/test/test'; + $value = 'value'; + + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->willReturn($this->valueMock); + $this->arrayManagerMock->expects($this->never()) + ->method('set'); + $this->valueMock->expects($this->once()) + ->method('getValue'); + $this->valueMock->expects($this->once()) + ->method('afterSave') + ->willThrowException(new \Exception('Invalid values')); + $this->deploymentConfigWriterMock->expects($this->never()) + ->method('saveConfig'); + + $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + } +} From 78d1d8555c25dc1526a17d7bf6751827a5c641fd Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Fri, 10 Nov 2017 18:29:50 +0100 Subject: [PATCH 0040/1464] Fix unit tests for option "share" of shell command "config:set" --- .../Command/ConfigSet/ProcessorFacadeTest.php | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php index 4e65ab3f4cc21..51318a8e303ca 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php @@ -217,8 +217,29 @@ public function testExecuteLock() ->method('clean'); $this->assertSame( - 'Value was saved and locked.', + 'Value was saved in app/etc/env.php and locked.', $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, true) ); } + + public function testExecuteShare() + { + $this->scopeValidatorMock->expects($this->once()) + ->method('isValid') + ->willReturn(true); + $this->configSetProcessorFactoryMock->expects($this->once()) + ->method('create') + ->with(ConfigSetProcessorFactory::TYPE_SHARE) + ->willReturn($this->processorMock); + $this->processorMock->expects($this->once()) + ->method('process') + ->with('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + $this->configMock->expects($this->once()) + ->method('clean'); + + $this->assertSame( + 'Value was saved in app/etc/config.php and locked.', + $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, false, true) + ); + } } From f792ba75046e9f76eb7c27d5c3c4da88511b2feb Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi Date: Wed, 15 Nov 2017 15:57:56 +0200 Subject: [PATCH 0041/1464] MAGETWO-77754: [2.2.x] - Rules builder improvement --- .../Rule/Model/Condition/Sql/Builder.php | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index 41a55f4c25166..320df8fdf1504 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -6,9 +6,14 @@ namespace Magento\Rule\Model\Condition\Sql; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Select; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Rule\Model\Condition\AbstractCondition; use Magento\Rule\Model\Condition\Combine; +use Magento\Eav\Api\AttributeRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Eav\Model\Entity\Collection\AbstractCollection; /** * Class SQL Builder @@ -41,12 +46,27 @@ class Builder */ protected $_expressionFactory; + /** + * @var AttributeRepositoryInterface + */ + private $attributeRepository; + + /** + * @var AbstractCollection EAV collection + */ + private $eavCollection; + /** * @param ExpressionFactory $expressionFactory + * @param AttributeRepositoryInterface|null $attributeRepository */ - public function __construct(ExpressionFactory $expressionFactory) - { + public function __construct( + ExpressionFactory $expressionFactory, + AttributeRepositoryInterface $attributeRepository = null + ) { $this->_expressionFactory = $expressionFactory; + $this->attributeRepository = $attributeRepository ?: + ObjectManager::getInstance()->get(AttributeRepositoryInterface::class); } /** @@ -130,9 +150,16 @@ protected function _getMappedSqlCondition(AbstractCondition $condition, $value = throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator')); } + $defaultValue = 0; + // Check if attribute has a table with default value and add it to the query + if ($this->canAttributeHaveDefaultValue($condition->getAttribute())) { + $defaultField = 'at_' . $condition->getAttribute() . '_default.value'; + $defaultValue = $this->_connection->quoteIdentifier($defaultField); + } + $sql = str_replace( ':field', - $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), 0), + $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), $defaultValue), $this->_conditionOperatorMap[$conditionOperator] ); @@ -180,11 +207,34 @@ public function attachConditionToCollection( Combine $combine ) { $this->_connection = $collection->getResource()->getConnection(); + $this->eavCollection = $collection; $this->_joinTablesToCollection($collection, $combine); $whereExpression = (string)$this->_getMappedSqlCombination($combine); if (!empty($whereExpression)) { // Select ::where method adds braces even on empty expression $collection->getSelect()->where($whereExpression); } + $this->eavCollection = null; + } + + /** + * Check if attribute can have default value + * + * @param string $attributeCode + * @return bool + */ + private function canAttributeHaveDefaultValue($attributeCode) + { + try { + $attribute = $this->attributeRepository->get(Product::ENTITY, $attributeCode); + } catch (NoSuchEntityException $e) { + // It's not exceptional case as we want to check if we have such attribute or not + $attribute = null; + } + $isNotDefaultStoreUsed = $this->eavCollection !== null + ? (int)$this->eavCollection->getStoreId() !== (int) $this->eavCollection->getDefaultStoreId() + : false; + + return $isNotDefaultStoreUsed && $attribute !== null && !$attribute->isScopeGlobal(); } } From 9182ca9991a5c9d2fc1ccce89cc5729450dc9594 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Mon, 25 Sep 2017 13:09:03 +0300 Subject: [PATCH 0042/1464] MAGETWO-72597: [2.2.x] - Impossible to perform mass update on product with 60+ attributes in system --- .../Entity/Attribute/Collection.php | 24 +-- .../Entity/Attribute/CollectionTest.php | 159 ++++++++++++++++++ 2 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php diff --git a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php index 872a9b79c9ba6..c1f693b92d2a1 100644 --- a/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php +++ b/app/code/Magento/Eav/Model/ResourceModel/Entity/Attribute/Collection.php @@ -210,17 +210,19 @@ public function setAttributeSetsFilter(array $setIds) */ public function setInAllAttributeSetsFilter(array $setIds) { - foreach ($setIds as $setId) { - $setId = (int)$setId; - if (!$setId) { - continue; - } - $alias = sprintf('entity_attribute_%d', $setId); - $joinCondition = $this->getConnection()->quoteInto( - "{$alias}.attribute_id = main_table.attribute_id AND {$alias}.attribute_set_id =?", - $setId - ); - $this->join([$alias => 'eav_entity_attribute'], $joinCondition, 'attribute_id'); + if (!empty($setIds)) { + $this->getSelect() + ->join( + ['entity_attribute' => $this->getTable('eav_entity_attribute')], + 'entity_attribute.attribute_id = main_table.attribute_id', + ['count' => new \Zend_Db_Expr('COUNT(*)')] + ) + ->where( + 'entity_attribute.attribute_set_id IN (?)', + $setIds + ) + ->group('entity_attribute.attribute_id') + ->having('count = ' . count($setIds)); } //$this->getSelect()->distinct(true); diff --git a/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php new file mode 100644 index 0000000000000..c1a94a7ca4a50 --- /dev/null +++ b/app/code/Magento/Eav/Test/Unit/Model/ResourceModel/Entity/Attribute/CollectionTest.php @@ -0,0 +1,159 @@ +entityFactoryMock = $this->getMockBuilder(\Magento\Framework\Data\Collection\EntityFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fetchStrategyMock = $this->getMockBuilder(FetchStrategyInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->eventManagerMock = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->eavConfigMock = $this->getMockBuilder(\Magento\Eav\Model\Config::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock = $this->getMockBuilder(\Magento\Framework\DB\Adapter\Pdo\Mysql::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeManagerMock = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->resourceMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) + ->setMethods(['__wakeup', 'getConnection', 'getMainTable', 'getTable']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->resourceMock->expects($this->any())->method('getConnection')->willReturn($this->connectionMock); + $this->resourceMock->expects($this->any())->method('getMainTable')->willReturn('eav_entity_attribute'); + + $this->selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->connectionMock->expects($this->any())->method('select')->willReturn($this->selectMock); + + $objectManager = new ObjectManager($this); + $this->model = $objectManager->getObject( + \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection::class, + [ + 'entityFactory' => $this->entityFactoryMock, + 'logger' => $this->loggerMock, + 'fetchStrategy' => $this->fetchStrategyMock, + 'eventManager' => $this->eventManagerMock, + 'eavConfig' => $this->eavConfigMock, + 'connection' => $this->connectionMock, + 'resource' => $this->resourceMock, + ] + ); + } + + /** + * Test method \Magento\Eav\Model\ResourceModel\Entity\Attribute\Collection::setInAllAttributeSetsFilter + * + * @return void + */ + public function testSetInAllAttributeSetsFilter() + { + $setIds = [1, 2, 3]; + + $this->selectMock->expects($this->atLeastOnce()) + ->method('where') + ->with('entity_attribute.attribute_set_id IN (?)', $setIds) + ->willReturnSelf(); + $this->selectMock->expects($this->atLeastOnce())->method('join')->with( + ['entity_attribute' => $this->model->getTable('eav_entity_attribute')], + 'entity_attribute.attribute_id = main_table.attribute_id', + ['count' => new \Zend_Db_Expr('COUNT(*)')] + )->willReturnSelf(); + + $this->selectMock->expects($this->atLeastOnce())->method('group')->with('entity_attribute.attribute_id') + ->willReturnSelf(); + + $this->selectMock->expects($this->atLeastOnce())->method('having')->with('count = ' . count($setIds)) + ->willReturnSelf(); + + $this->model->setInAllAttributeSetsFilter($setIds); + } +} From 04a81b79aa79ffd60f9cd0e1f6432d0a9298aa6f Mon Sep 17 00:00:00 2001 From: Michail Slabko Date: Fri, 17 Nov 2017 15:28:38 +0200 Subject: [PATCH 0043/1464] MAGETWO-73696: Sorting by price column in admin doesn't count disabled products --- .../Product/ProductCollection.php | 28 +++++++++++++++++++ app/code/Magento/Catalog/etc/adminhtml/di.xml | 6 ++++ 2 files changed, 34 insertions(+) create mode 100644 app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php new file mode 100644 index 0000000000000..ca6855af9e7f1 --- /dev/null +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php @@ -0,0 +1,28 @@ +_productLimitationFilters->setUsePriceIndex(false); + return $this->_productLimitationPrice(true); + } +} diff --git a/app/code/Magento/Catalog/etc/adminhtml/di.xml b/app/code/Magento/Catalog/etc/adminhtml/di.xml index 790bd163a6f17..570b6b21d5b2c 100644 --- a/app/code/Magento/Catalog/etc/adminhtml/di.xml +++ b/app/code/Magento/Catalog/etc/adminhtml/di.xml @@ -78,6 +78,11 @@ + + + \Magento\Catalog\Ui\DataProvider\Product\ProductCollection + + @@ -86,6 +91,7 @@ Magento\Catalog\Ui\DataProvider\Product\AddStoreFieldToCollection + \Magento\Catalog\Ui\DataProvider\Product\ProductCollectionFactory From f2446b637679ed7d39dd73b54c13f2bd0d3e45a6 Mon Sep 17 00:00:00 2001 From: Elze Kool Date: Sun, 19 Nov 2017 10:52:08 +0100 Subject: [PATCH 0044/1464] Fix handling of watermark with alpha for Imagick When adding a watermark that already has an alpha channel this was reset because the overal opacity was set for the image. Instead we should multiply the original alpha with the requested opacity --- .../Framework/Image/Adapter/ImageMagick.php | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php index 50b9a5a013273..29f3c85dc1205 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php +++ b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php @@ -269,15 +269,17 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = ); } - if (method_exists($watermark, 'setImageOpacity')) { - // available from imagick 6.3.1 - $watermark->setImageOpacity($opacity); - } else { - // go to each pixel and make it transparent - $watermark->paintTransparentImage($watermark->getImagePixelColor(0, 0), 1, 65530); - $watermark->evaluateImage(\Imagick::EVALUATE_SUBTRACT, 1 - $opacity, \Imagick::CHANNEL_ALPHA); + if (method_exists($watermark, 'getImageAlphaChannel')) { + // available from imagick 6.4.0 + if ($watermark->getImageAlphaChannel() == 0) { + $watermark->setImageAlphaChannel(\Imagick::ALPHACHANNEL_OPAQUE); + } } + $compositeChannels = \Imagick::CHANNEL_ALL; + $watermark->evaluateImage(\Imagick::EVALUATE_MULTIPLY, $opacity, \Imagick::CHANNEL_OPACITY); + $compositeChannels &= ~(\Imagick::CHANNEL_OPACITY); + switch ($this->getWatermarkPosition()) { case self::POSITION_STRETCH: $watermark->sampleImage($this->_imageSrcWidth, $this->_imageSrcHeight); @@ -309,14 +311,14 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = $offsetY = $positionY; while ($offsetY <= $this->_imageSrcHeight + $watermark->getImageHeight()) { while ($offsetX <= $this->_imageSrcWidth + $watermark->getImageWidth()) { - $this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $offsetX, $offsetY); + $this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $offsetX, $offsetY, $compositeChannels); $offsetX += $watermark->getImageWidth(); } $offsetX = $positionX; $offsetY += $watermark->getImageHeight(); } } else { - $this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $positionX, $positionY); + $this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $positionX, $positionY, $compositeChannels); } } catch (\ImagickException $e) { throw new \Exception('Unable to create watermark.', $e->getCode(), $e); From 519f3e1c608e0ee0105f8cec0244b822c3d17cee Mon Sep 17 00:00:00 2001 From: Elze Kool Date: Sun, 19 Nov 2017 10:54:57 +0100 Subject: [PATCH 0045/1464] Handle non true color images with GD2 --- .../Magento/Framework/Image/Adapter/Gd2.php | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php index de48e234a58d2..6817c01b19cbf 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php @@ -465,7 +465,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = } elseif ($this->getWatermarkPosition() == self::POSITION_CENTER) { $positionX = $this->_imageSrcWidth / 2 - imagesx($watermark) / 2; $positionY = $this->_imageSrcHeight / 2 - imagesy($watermark) / 2; - $this->imagecopymergeWithAlphaFix( + $this->copyImageWithAlphaPercentage( $this->_imageHandler, $watermark, $positionX, @@ -478,7 +478,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = ); } elseif ($this->getWatermarkPosition() == self::POSITION_TOP_RIGHT) { $positionX = $this->_imageSrcWidth - imagesx($watermark); - $this->imagecopymergeWithAlphaFix( + $this->copyImageWithAlphaPercentage( $this->_imageHandler, $watermark, $positionX, @@ -490,7 +490,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = $this->getWatermarkImageOpacity() ); } elseif ($this->getWatermarkPosition() == self::POSITION_TOP_LEFT) { - $this->imagecopymergeWithAlphaFix( + $this->copyImageWithAlphaPercentage( $this->_imageHandler, $watermark, $positionX, @@ -504,7 +504,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = } elseif ($this->getWatermarkPosition() == self::POSITION_BOTTOM_RIGHT) { $positionX = $this->_imageSrcWidth - imagesx($watermark); $positionY = $this->_imageSrcHeight - imagesy($watermark); - $this->imagecopymergeWithAlphaFix( + $this->copyImageWithAlphaPercentage( $this->_imageHandler, $watermark, $positionX, @@ -517,7 +517,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = ); } elseif ($this->getWatermarkPosition() == self::POSITION_BOTTOM_LEFT) { $positionY = $this->_imageSrcHeight - imagesy($watermark); - $this->imagecopymergeWithAlphaFix( + $this->copyImageWithAlphaPercentage( $this->_imageHandler, $watermark, $positionX, @@ -531,7 +531,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = } if ($tile === false && $merged === false) { - $this->imagecopymergeWithAlphaFix( + $this->copyImageWithAlphaPercentage( $this->_imageHandler, $watermark, $positionX, @@ -547,7 +547,7 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = $offsetY = $positionY; while ($offsetY <= $this->_imageSrcHeight + imagesy($watermark)) { while ($offsetX <= $this->_imageSrcWidth + imagesx($watermark)) { - $this->imagecopymergeWithAlphaFix( + $this->copyImageWithAlphaPercentage( $this->_imageHandler, $watermark, $offsetX, @@ -780,64 +780,71 @@ protected function _createEmptyImage($width, $height) } /** - * Fix an issue with the usage of imagecopymerge where the alpha channel is lost + * Copy source image onto destination image with given alpha percentage * - * @param resource $dst_im - * @param resource $src_im - * @param int $dst_x - * @param int $dst_y - * @param int $src_x - * @param int $src_y - * @param int $src_w - * @param int $src_h - * @param int $pct + * @internal The arguments and functionality is the same as imagecopymerge + * but with proper handling of alpha transparency + * + * @param resource $destinationImage + * @param resource $sourceImage + * @param int $destinationX + * @param int $destinationY + * @param int $sourceX + * @param int $sourceY + * @param int $sourceWidth + * @param int $sourceHeight + * @param int $alphaPercentage * * @return bool */ - private function imagecopymergeWithAlphaFix( - $dst_im, - $src_im, - $dst_x, - $dst_y, - $src_x, - $src_y, - $src_w, - $src_h, - $pct + private function copyImageWithAlphaPercentage( + $destinationImage, + $sourceImage, + $destinationX, + $destinationY, + $sourceX, + $sourceY, + $sourceWidth, + $sourceHeight, + $alphaPercentage ) { - if ($pct >= 100) { - return imagecopy($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); + if (imageistruecolor($destinationImage) === false || imageistruecolor($sourceImage) === false) { + return imagecopymerge($destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $sourceWidth, $sourceHeight, $alphaPercentage); + } + + if ($alphaPercentage >= 100) { + return imagecopy($destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $sourceWidth, $sourceHeight); } - if ($pct < 0) { + if ($alphaPercentage < 0) { return false; } - $sizeX = imagesx($src_im); - $sizeY = imagesy($src_im); - if (false === $sizeX || false === $sizeY) { + $sizeX = imagesx($sourceImage); + $sizeY = imagesy($sourceImage); + if ($sizeX === false || $sizeY === false || $sizeX === 0 || $sizeY === 0) { return false; } - $tmpImg = imagecreatetruecolor($src_w, $src_h); - if (false === $tmpImg) { + $tmpImg = imagecreatetruecolor($sourceWidth, $sourceHeight); + if ($tmpImg === false) { return false; } - if (false === imagealphablending($tmpImg, false)) { + if (imagealphablending($tmpImg, false) === false) { return false; } - if (false === imagecopy($tmpImg, $src_im, 0, 0, 0, 0, $sizeX, $sizeY)) { + if (imagecopy($tmpImg, $sourceImage, 0, 0, 0, 0, $sizeX, $sizeY) === false) { return false; } - $transparancy = 127 - (($pct*127)/100); - if (false === imagefilter($tmpImg, IMG_FILTER_COLORIZE, 0, 0, 0, $transparancy)) { + $transparency = 127 - (($alphaPercentage*127)/100); + if (imagefilter($tmpImg, IMG_FILTER_COLORIZE, 0, 0, 0, $transparency) === false) { return false; } - $result = imagecopy($dst_im, $tmpImg, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); + $result = imagecopy($destinationImage, $tmpImg, $destinationX, $destinationY, $sourceX, $sourceY, $sourceWidth, $sourceHeight); imagedestroy($tmpImg); return $result; From 00a5c3a2f53c5c880210157fa44648688c212070 Mon Sep 17 00:00:00 2001 From: Elze Kool Date: Sun, 19 Nov 2017 11:03:45 +0100 Subject: [PATCH 0046/1464] Add integration test for watermark with alpha Added integration tests for handling alpha transparency in watermarks. Renamed the current test for watermarks as it only tests if the watermark is correctly places --- .../Framework/Image/Adapter/InterfaceTest.php | 97 +++++++++++++++++- .../Image/_files/watermark_alpha.png | Bin 0 -> 202 bytes .../_files/watermark_alpha_base_image.jpg | Bin 0 -> 1252 bytes 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Image/_files/watermark_alpha.png create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Image/_files/watermark_alpha_base_image.jpg diff --git a/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php b/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php index 420803d9530bd..bc8281d55ac4f 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php @@ -337,6 +337,97 @@ public function rotateDataProvider() ); } + /** + * Test if alpha transparency is correctly handled + * + * @param string $image + * @param string $watermark + * @param int $alphaPercentage + * @param array $comparePoint1 + * @param array $comparePoint2 + * @param string $adapterType + * + * @dataProvider imageWatermarkWithAlphaTransparencyDataProvider + * @depends testOpen + * @depends testImageSize + */ + public function testWatermarkWithAlphaTransparency( + $image, + $watermark, + $alphaPercentage, + $comparePoint1, + $comparePoint2, + $adapterType + ) { + $imageAdapter = $this->_getAdapter($adapterType); + $imageAdapter->open($image); + + $watermarkAdapter = $this->_getAdapter($adapterType); + $watermarkAdapter->open($watermark); + + list($comparePoint1X, $comparePoint1Y) = $comparePoint1; + list($comparePoint2X, $comparePoint2Y) = $comparePoint2; + + $imageAdapter + ->setWatermarkImageOpacity($alphaPercentage) + ->setWatermarkPosition(\Magento\Framework\Image\Adapter\AbstractAdapter::POSITION_TOP_LEFT) + ->watermark($watermark); + + $comparePoint1Color = $imageAdapter->getColorAt($comparePoint1X, $comparePoint1Y); + unset($comparePoint1Color['alpha']); + + $comparePoint2Color = $imageAdapter->getColorAt($comparePoint2X, $comparePoint2Y); + unset($comparePoint2Color['alpha']); + + $result = $this->_compareColors($comparePoint1Color, $comparePoint2Color); + $message = sprintf( + '%s should be different to %s due to alpha transparency', + join(',', $comparePoint1Color), + join(',', $comparePoint2Color) + ); + $this->assertFalse($result, $message); + } + + public function imageWatermarkWithAlphaTransparencyDataProvider() + { + return $this->_prepareData( + [ + // Watermark with alpha channel, 25% + [ + $this->_getFixture('watermark_alpha_base_image.jpg'), + $this->_getFixture('watermark_alpha.png'), + 25, + [ 23, 3 ], + [ 23, 30 ] + ], + // Watermark with alpha channel, 50% + [ + $this->_getFixture('watermark_alpha_base_image.jpg'), + $this->_getFixture('watermark_alpha.png'), + 50, + [ 23, 3 ], + [ 23, 30 ] + ], + // Watermark with no alpha channel, 50% + [ + $this->_getFixture('watermark_alpha_base_image.jpg'), + $this->_getFixture('watermark.png'), + 50, + [ 3, 3 ], + [ 23,3 ] + ], + // Watermark with no alpha channel, 100% + [ + $this->_getFixture('watermark_alpha_base_image.jpg'), + $this->_getFixture('watermark.png'), + 100, + [ 3, 3 ], + [ 3, 60 ] + ], + ] + ); + } + /** * Checks if watermark exists on the right position * @@ -350,10 +441,10 @@ public function rotateDataProvider() * @param int $colorY * @param string $adapterType * - * @dataProvider imageWatermarkDataProvider + * @dataProvider imageWatermarkPositionDataProvider * @depends testOpen */ - public function testWatermark( + public function testWatermarkPosition( $image, $watermark, $width, @@ -387,7 +478,7 @@ public function testWatermark( $this->assertFalse($result, $message); } - public function imageWatermarkDataProvider() + public function imageWatermarkPositionDataProvider() { return $this->_prepareData( [ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Image/_files/watermark_alpha.png b/dev/tests/integration/testsuite/Magento/Framework/Image/_files/watermark_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..af05a14a99fdd34e8f5edb8740fec06d5d3ccd8e GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^ra-L5!3HE#mRxoPQk(@Ik;M!Qd`Cc-ajG_-G*Ga{ z)5S3)qV??+N8W}29+r!mD>>IZ;B(A)*dwZU)WvhN{cn*sD!z*o(hYBaX|T8OYF!)x zC0v<~f9c2zEb#4rG3|h{?V@O=_dve49hdvcf+;{E!bpqj-Alo{ixw<%FNyy2M`r1v jKrJYt)L2~QvYr23A7_64ts-NfI~Y7&{an^LB{Ts5PkTog literal 0 HcmV?d00001 diff --git a/dev/tests/integration/testsuite/Magento/Framework/Image/_files/watermark_alpha_base_image.jpg b/dev/tests/integration/testsuite/Magento/Framework/Image/_files/watermark_alpha_base_image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..361ff523d2130ccfccd86a935f2f72053420e766 GIT binary patch literal 1252 zcmex=5A1R0qH8UG()kY`|EWCgkw?FU=d^$QZ#gA6AnydS1J@SYMi)`L)mHLLD8U# zA5@H!ikdjN#Ka{erBv0_H8izMOwG(KEUlbfT;1F~JiUTLLc_u%BBPR1Qq$5iGP89XZ3R<7E#dCS&q+js2Tb?ESsqsNY) zIC<*Qo&Gyn;}30F zQ~&r*t#8`A{jHf1{~3<&_%&;lyyWMS{r&ngle#q4UEZRxsEdJA{Ny^wlCZ4555KO} zda$DEYZc?`A7NAb|5W#{Tyy#Qhqc=BKfcQchdMvD%bWi3>1UllSJ7K#ts;RAtR!NY zSztTP#_zG)x->?VKW@E)Z9UhejsF??3%{Dqs`@9oH2FV++~ZeSD{9iuUixRVFSSc! z(QdyBi@G!zNW{#O!L~%M{@#9V%j%|uudlvfU;i*F%>Ls$yJegG;ei>--}7@<{PF2$ zHoA(0XWkMCbY&nF7iEL(Fs=LW>)O=&iL=m&O7n5;31I*bWi&6d@8C@Z=nEn4v08E$z Aw*UYD literal 0 HcmV?d00001 From 503204c04627454ebe7e59e076089de640b8fe8b Mon Sep 17 00:00:00 2001 From: Elze Kool Date: Sun, 19 Nov 2017 21:20:44 +0100 Subject: [PATCH 0047/1464] Fix issues with static tests --- .../Magento/Framework/Image/Adapter/Gd2.php | 40 +++++++++++++++++-- .../Framework/Image/Adapter/ImageMagick.php | 16 +++++++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php index 6817c01b19cbf..a36e41a526466 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php @@ -5,6 +5,9 @@ */ namespace Magento\Framework\Image\Adapter; +/** + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + */ class Gd2 extends \Magento\Framework\Image\Adapter\AbstractAdapter { /** @@ -796,6 +799,9 @@ protected function _createEmptyImage($width, $height) * @param int $alphaPercentage * * @return bool + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ private function copyImageWithAlphaPercentage( $destinationImage, @@ -809,11 +815,30 @@ private function copyImageWithAlphaPercentage( $alphaPercentage ) { if (imageistruecolor($destinationImage) === false || imageistruecolor($sourceImage) === false) { - return imagecopymerge($destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $sourceWidth, $sourceHeight, $alphaPercentage); + return imagecopymerge( + $destinationImage, + $sourceImage, + $destinationX, + $destinationY, + $sourceX, + $sourceY, + $sourceWidth, + $sourceHeight, + $alphaPercentage + ); } if ($alphaPercentage >= 100) { - return imagecopy($destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $sourceWidth, $sourceHeight); + return imagecopy( + $destinationImage, + $sourceImage, + $destinationX, + $destinationY, + $sourceX, + $sourceY, + $sourceWidth, + $sourceHeight + ); } if ($alphaPercentage < 0) { @@ -844,7 +869,16 @@ private function copyImageWithAlphaPercentage( return false; } - $result = imagecopy($destinationImage, $tmpImg, $destinationX, $destinationY, $sourceX, $sourceY, $sourceWidth, $sourceHeight); + $result = imagecopy( + $destinationImage, + $tmpImg, + $destinationX, + $destinationY, + $sourceX, + $sourceY, + $sourceWidth, + $sourceHeight + ); imagedestroy($tmpImg); return $result; diff --git a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php index 29f3c85dc1205..5d9ef49c7d285 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php +++ b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php @@ -311,14 +311,26 @@ public function watermark($imagePath, $positionX = 0, $positionY = 0, $opacity = $offsetY = $positionY; while ($offsetY <= $this->_imageSrcHeight + $watermark->getImageHeight()) { while ($offsetX <= $this->_imageSrcWidth + $watermark->getImageWidth()) { - $this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $offsetX, $offsetY, $compositeChannels); + $this->_imageHandler->compositeImage( + $watermark, + \Imagick::COMPOSITE_OVER, + $offsetX, + $offsetY, + $compositeChannels + ); $offsetX += $watermark->getImageWidth(); } $offsetX = $positionX; $offsetY += $watermark->getImageHeight(); } } else { - $this->_imageHandler->compositeImage($watermark, \Imagick::COMPOSITE_OVER, $positionX, $positionY, $compositeChannels); + $this->_imageHandler->compositeImage( + $watermark, + \Imagick::COMPOSITE_OVER, + $positionX, + $positionY, + $compositeChannels + ); } } catch (\ImagickException $e) { throw new \Exception('Unable to create watermark.', $e->getCode(), $e); From 1eb1dfaf8d8498d5638d6ff83a82628010d090af Mon Sep 17 00:00:00 2001 From: Dmytro Vilchynskyi Date: Mon, 20 Nov 2017 14:19:52 +0200 Subject: [PATCH 0048/1464] MAGETWO-84074: Automate "Update Configurable Product (based on Swatch Attribute) from Shopping Cart" FT - FAT is created --- .../view/adminhtml/web/css/swatches.css | 2 +- .../Catalog/Test/Block/Product/View.php | 21 +- .../Checkout/Test/Block/Cart/CartItem.php | 12 ++ .../Constraint/AssertCartItemsOptions.php | 2 +- .../RemoveProductsFromTheCartStep.php | 2 +- .../Attribute/Edit/SwatchAttributeForm.php | 104 +++++++++ .../Product/Attribute/FormPageActions.php | 20 ++ .../Block/Product/ProductList/ProductItem.php | 2 +- .../Test/Block/Product/ViewWithSwatches.php | 56 ++++- .../CatalogProductSwatchAttributeEdit.xml | 15 ++ .../Test/Repository/ConfigurableProduct.xml | 35 +++ .../ConfigurableProduct/CheckoutData.xml | 40 ++++ .../ConfigurableAttributesData.xml | 78 +++++++ .../Repository/SwatchProductAttribute.xml | 45 +++- ...bleProductWithSwatchToShoppingCartTest.php | 6 +- ...bleProductWithSwatchToShoppingCartTest.xml | 3 +- ...eProductWithSwatchFromShoppingCartTest.php | 202 ++++++++++++++++++ ...eProductWithSwatchFromShoppingCartTest.xml | 48 +++++ ...oductToCartFromCatalogCategoryPageStep.php | 2 + 19 files changed, 671 insertions(+), 24 deletions(-) create mode 100644 dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/Edit/SwatchAttributeForm.php create mode 100644 dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/FormPageActions.php create mode 100644 dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Adminhtml/CatalogProductSwatchAttributeEdit.xml create mode 100644 dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.xml diff --git a/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css b/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css index d170ed0345a03..415d24c8c25ac 100644 --- a/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css +++ b/app/code/Magento/Swatches/view/adminhtml/web/css/swatches.css @@ -150,7 +150,7 @@ } .swatches-visual-col.unavailable:after { - content: ''; + /*content: '';*/ position: absolute; width: 35px; height: 2px; diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php index 92f3a2102e85e..a2596a203ad8d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/View.php @@ -42,6 +42,13 @@ class View extends AbstractConfigureBlock */ protected $addToCart = '.tocart'; + /** + * Locator for "Update Cart" button. + * + * @var string + */ + protected $updateCart = '#product-updatecart-button'; + /** * Quantity input id. * @@ -302,13 +309,23 @@ private function getMiniCartBlock() } /** - * Click link. + * Click "Add to Cart" button. * * @return void */ public function clickAddToCart() { - $this->_rootElement->find($this->addToCart, Locator::SELECTOR_CSS)->click(); + $this->_rootElement->find($this->addToCart)->click(); + } + + /** + * Click "Update Cart" button. + * + * @return void + */ + public function clickUpdateCart() + { + $this->_rootElement->find($this->updateCart)->click(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/CartItem.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/CartItem.php index 44068c21418c4..5171116a89bac 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/CartItem.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/CartItem.php @@ -286,4 +286,16 @@ public function isEditButtonVisible() { return $this->_rootElement->find($this->edit)->isVisible(); } + + /** + * Remove all items from Shopping Cart. + * + * @return void + */ + public function clearShoppingCart() + { + while ($this->_rootElement->find($this->removeItem)->isVisible()) { + $this->removeItem(); + } + } } diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php index 9f680eb5fc0ea..a4da0c0ce604d 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php @@ -34,7 +34,7 @@ class AssertCartItemsOptions extends AbstractAssertForm protected $skippedFields = ['sku']; /** - * Assert that cart item options for product(s) display with correct information block + * Assert that cart item options for product(s) are displayed with correct information block * (custom options, variations, links, samples, bundle items etc) according to passed from dataset. * * @param CheckoutCart $checkoutCart diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/RemoveProductsFromTheCartStep.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/RemoveProductsFromTheCartStep.php index b4ea9ba26b0c2..6e1042eed5d83 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/RemoveProductsFromTheCartStep.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestStep/RemoveProductsFromTheCartStep.php @@ -30,7 +30,7 @@ class RemoveProductsFromTheCartStep implements TestStepInterface private $cartPage; /** - * Quantity of items that should be removed from shoping cart. + * Quantity of items that should be removed from shopping cart. * * @var int|null */ diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/Edit/SwatchAttributeForm.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/Edit/SwatchAttributeForm.php new file mode 100644 index 0000000000000..a07f18f40ac98 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/Edit/SwatchAttributeForm.php @@ -0,0 +1,104 @@ +colorPickerOpenLocator, $optionKey); + $this->waitForElementVisible($currentOptionPickerLocator, Locator::SELECTOR_XPATH); + $this->browser->find($currentOptionPickerLocator, Locator::SELECTOR_XPATH)->click(); + + $chooseColorButtonLocator = $currentOptionPickerLocator . $this->chooseColorButtonLocator; + $this->waitForElementVisible($chooseColorButtonLocator, Locator::SELECTOR_XPATH); + $this->browser->find($chooseColorButtonLocator, Locator::SELECTOR_XPATH)->click(); + +// $this->specifyHex($optionKey, $color); + + $this->waitForElementVisible($this->submitColorLocator); + $this->browser->find($this->submitColorLocator)->click(); + } + + /** + * Clear "Hex" input inside Color Picker & specify new Color. + * + * @param int $optionKey + * @param string $color + * @return void + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) + */ + private function specifyHex($optionKey, $color) + { + $currentHexInputLocator = sprintf($this->hexInputLocator, $optionKey); + $this->waitForElementVisible($currentHexInputLocator, Locator::SELECTOR_XPATH); + $hexInput = $this->browser->find($currentHexInputLocator, Locator::SELECTOR_XPATH); + $hexInput->keys( + [ + self::END_KEY, + self::BACKSPACE_KEY, + self::BACKSPACE_KEY, + self::BACKSPACE_KEY, + self::BACKSPACE_KEY, + self::BACKSPACE_KEY, + self::BACKSPACE_KEY + ] + ); + $hexInput->setValue($color); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/FormPageActions.php new file mode 100644 index 0000000000000..89e8ec35697d2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Adminhtml/Product/Attribute/FormPageActions.php @@ -0,0 +1,20 @@ +swatchSelector, $optionId); - $this->_rootElement->find($selector, Locator::SELECTOR_CSS)->click(); + $this->_rootElement->find($selector)->click(); } /** diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php index d30aabd7ff370..f23527d93d59e 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Block/Product/ViewWithSwatches.php @@ -8,6 +8,7 @@ use Magento\Catalog\Test\Block\Product\View; use Magento\Mtf\Client\ElementInterface; +use Magento\Mtf\Client\Locator; use Magento\Mtf\Fixture\InjectableFixture; /** @@ -15,6 +16,20 @@ */ class ViewWithSwatches extends View { + /** + * Locator for "Swatch Attribute" block on "Product" Storefront page. + * + * @var string + */ + protected $swatchBlockSelector = '//*[@attribute-code="%s"]'; + + /** + * Locator for concrete Swatch Option to select. + * + * @var string + */ + protected $swatchOptionSelector = '//div[@option-label="%s"]'; + /** * Selector for all swatch attributes * @@ -23,7 +38,7 @@ class ViewWithSwatches extends View private $swatchAttributesSelector = '.swatch-attribute'; /** - * Selector for swatch attribute label + * Locator for Swatch Attribute label. * * @var string */ @@ -110,4 +125,43 @@ public function getSelectedSwatchOptions(InjectableFixture $product) return $formData; } + + /** + * Customer configures Swatches on "Product" Storefront page. + * + * @param \Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct $product + * @return void + */ + public function fillData(\Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct $product) + { + $attributesSource = $product->getDataFieldConfig('configurable_attributes_data')['source']; + $attributes = $attributesSource->getData()['attributes_data']; + + $checkoutData = $product->getCheckoutData(); + $options = $checkoutData['options']['configurable_options']; + + foreach ($attributes as $attributeKey => $attribute) { + foreach ($options as $option) { + if ($option['title'] === $attributeKey) { + $optionLabel = $attribute['options'][$option['value']]['label']; + $this->clickOnSwatch($attribute['attribute_code'], $optionLabel); + } + } + } + } + + /** + * Customer specifies concrete Option inside concrete Swatch Attribute. + * + * @param string $attributeCode + * @param string $optionLabel + * @return void + */ + private function clickOnSwatch($attributeCode, $optionLabel) + { + $swatchBlockSelector = sprintf($this->swatchBlockSelector, $attributeCode); + $swatchOptionSelector = sprintf($this->swatchOptionSelector, $optionLabel); + + $this->_rootElement->find($swatchBlockSelector . $swatchOptionSelector, Locator::SELECTOR_XPATH)->click(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Adminhtml/CatalogProductSwatchAttributeEdit.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Adminhtml/CatalogProductSwatchAttributeEdit.xml new file mode 100644 index 0000000000000..a933d04f175f1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Page/Adminhtml/CatalogProductSwatchAttributeEdit.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml index 83912c794cea3..91ea8ceea7334 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct.xml @@ -43,6 +43,41 @@ two_text_swatches + + Test configurable product with color %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + visual_swatch + + + In Stock + + + default_subcategory + + + + default + + + + custom_attribute_set + + + 55.55 + + + two_visual_swatches + + Test configurable product with color and size %isolation% sku_test_configurable_product_%isolation% diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml index c67d5b1c1729a..7a0ce226466fd 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/CheckoutData.xml @@ -27,6 +27,46 @@ 48 + + + + + attribute_key_0 + option_key_0 + + + attribute_key_1 + option_key_1 + + + + 1 + + 55.55 + 1 + 55.55 + + + + + + + attribute_key_0 + option_key_1 + + + attribute_key_1 + option_key_2 + + + + 1 + + 66.66 + 1 + 66.66 + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml index 90f783088adfe..866f58c10b143 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -85,6 +85,84 @@ + + + + + + 11.11 + Yes + + + 22.22 + Yes + + + 33.33 + Yes + + + + + + + 44.44 + Yes + + + 55.55 + Yes + + + 66.66 + Yes + + + + + + swatchesProductAttribute::attribute_type_visual_swatch + swatchesProductAttribute::attribute_type_visual_swatch + + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + 10 + 1 + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml index 7b4da9ea28066..df711d4e30355 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Repository/SwatchProductAttribute.xml @@ -5,27 +5,52 @@ * See COPYING.txt for license details. */ --> - + - sw_color%isolation% - Text Swatch - Text Swatch + sw_color_%isolation% + Text Swatch + Text Swatch %isolation% No - R - R + Red + Red No - G - G + Green + Green No - B - B + Blue + Blue + + + Global + Yes + + + sw_color_%isolation% + Visual Swatch + Visual Swatch %isolation% + + + No + Red + Red + + + No + Green + Green + + + No + Blue + Blue Global diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.php index eb188148d532d..4e27f14cfa194 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.php @@ -62,10 +62,9 @@ public function __inject( * Runs add configurable product with swatches attributes test. * * @param ConfigurableProduct $product - * @param bool $addToCart * @return array */ - public function test(ConfigurableProduct $product, $addToCart) + public function test(ConfigurableProduct $product) { $product->persist(); $cart = $this->testStepFactory->create( @@ -74,9 +73,6 @@ public function test(ConfigurableProduct $product, $addToCart) 'product' => $product ] )->run()['cart']; - if ($addToCart) { - $this->categoryView->getMessagesBlock()->waitSuccessMessage(); - } return ['cart' => $cart]; } diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.xml index bbe873e91e36a..22f66d0a0a1f2 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.xml +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/AddConfigurableProductWithSwatchToShoppingCartTest.xml @@ -7,10 +7,9 @@ --> - + addOptions product_with_text_swatch - true diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.php new file mode 100644 index 0000000000000..addc37b2a6028 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.php @@ -0,0 +1,202 @@ +testStep = $testStepFactory; + $this->fixture = $fixtureFactory; + $this->browser = $browser; + $this->cachePage = $adminCache; + $this->categoryPage = $categoryPage; + $this->productPage = $catalogProductView; + $this->cartPage = $checkoutCart; + } + + /** + * Run the Test. + * + * @param ConfigurableProduct $product + * @param array $colors + * @param array $attributesToChange + * @param AssertCartItemsOptions $assertCartItemsOptions + * @param AssertSelectedSwatchOptionsOnProductPage $assertSelectedSwatchOptionsOnProductPage + * @param CatalogProductAttributeIndex $attributeIndex + * @param CatalogProductSwatchAttributeEdit $attribute + * @return array + */ + public function test( + ConfigurableProduct $product, + array $colors, + array $attributesToChange, + AssertCartItemsOptions $assertCartItemsOptions, + AssertSelectedSwatchOptionsOnProductPage $assertSelectedSwatchOptionsOnProductPage, + CatalogProductAttributeIndex $attributeIndex, + CatalogProductSwatchAttributeEdit $attribute + ) { + // Preconditions go on (workaround until MAGETWO-83522 is fixed & backported) + /** @var ConfigurableProduct $product */ + $product->persist(); + $this->updateSwatchAttributes($product, $attributeIndex, $attribute, $colors); + + $this->flushCache(); + $this->cartPage->open()->getCartItemBlock()->clearShoppingCart(); + + // Steps + $cart = $this->testStep->create(AddToCart::class, ['product' => $product])->run()['cart']; + $assertCartItemsOptions->processAssert($this->cartPage, $cart); + + $this->cartPage->getCartItemBlock()->edit(); + $assertSelectedSwatchOptionsOnProductPage->processAssert($this->browser, $this->productPage, $product); + + $productToChange = $product->getData(); + $productToChange['checkout_data'] = $attributesToChange; + $productToChange['price'] = $attributesToChange['cartItem']['price']; + $product = $this->fixture->createByCode('configurableProduct', ['data' => $productToChange]); + + $this->productPage->getProductViewWithSwatchesBlock()->fillData($product); + $this->productPage->getViewBlock()->clickUpdateCart(); + $this->cartPage->getMessagesBlock()->waitSuccessMessage(); + + $cart = $this->fixture->createByCode( + 'cart', + [ + 'data' => [ + 'items' => [ + 'products' => [$product] + ] + ] + ] + ); + return [ + 'cart' => $cart + ]; + } + + /** + * Update (already used in Product) Swatch Attributes' Options with colors. + * + * @param ConfigurableProduct $productBeforeUpdate + * @param CatalogProductAttributeIndex $attributeIndex + * @param CatalogProductSwatchAttributeEdit $attribute + * @param array $colors + * @return void + */ + private function updateSwatchAttributes($productBeforeUpdate, $attributeIndex, $attribute, $colors) + { + foreach ($productBeforeUpdate->getConfigurableAttributesData()['attributes_data'] as $key => $attributeData) { + $attributeIndex->open(); + $filter = ['attribute_code' => $attributeData['attribute_code']]; + $attributeIndex->getGrid()->searchAndOpen($filter); + foreach ($colors as $optionKey => $color) { + $attribute->getVisualSwatches()->applyOptionColor($optionKey, $color); + $attribute->getPageActions()->saveAndContinue(); + } + } + } + + /** + * Flush Magento Cache in Admin panel. + * + * @return void + */ + private function flushCache() + { + $this->cachePage->open(); + $this->cachePage->getActionsBlock()->flushMagentoCache(); + $this->cachePage->getMessagesBlock()->waitSuccessMessage(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.xml new file mode 100644 index 0000000000000..fb55174e8cb77 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestCase/UpdateConfigurableProductWithSwatchFromShoppingCartTest.xml @@ -0,0 +1,48 @@ + + + + + + product_with_visual_swatch + + ff0000 + 00ff00 + 0000ff + + + + + + attribute_key_0 + option_key_1 + + + attribute_key_1 + option_key_2 + + + + 1 + + 66.66 + 1 + 66.66 + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php index 2671e3d920430..925257e393d64 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/TestStep/AddProductToCartFromCatalogCategoryPageStep.php @@ -81,6 +81,8 @@ public function run() $productItemBlock = $productsList->getProductItem($this->product); $productItemBlock->fillData($this->product); $productItemBlock->clickAddToCart(); + $this->categoryView->getMessagesBlock()->waitSuccessMessage(); + $cart = [ 'data' => [ 'items' => [ From 2abaf8c50a8a8b72b5c9045fb816dd5c3ec59ea5 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Tue, 21 Nov 2017 17:36:16 +0100 Subject: [PATCH 0049/1464] Added translate.test.js for Jasmine compatibility unit testing. Removed transtale-test.js from jsTestDriver suite. --- .../mage/translate/translate-test.js | 47 ------------------- .../jasmine/tests/lib/mage/translate.test.js | 45 ++++++++++++++++++ 2 files changed, 45 insertions(+), 47 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js create mode 100644 dev/tests/js/jasmine/tests/lib/mage/translate.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js deleted file mode 100644 index a9bbc7fb10d2d..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -TranslateTest = TestCase('TranslateTest'); -TranslateTest.prototype.testTranslateExist = function() { - assertNotUndefined(jQuery.mage.translate); -}; -TranslateTest.prototype.testTranslationParametersOneArgument = function() { - jQuery.mage.translate.add('Hello World!'); - assertEquals( - 'Hello World!', - jQuery.mage.translate.translate('Hello World!')); -}; -TranslateTest.prototype.testTranslationParametersArray = function() { - jQuery.mage.translate.add(['Hello World!', 'Bonjour tout le monde!']); - assertEquals( - 'Hello World!', - jQuery.mage.translate.translate('Hello World!')); -}; -TranslateTest.prototype.testTranslationParametersObject = function() { - var translation = {'Hello World!': 'Bonjour tout le monde!'}; - jQuery.mage.translate.add(translation); - assertEquals( - translation['Hello World!'], - jQuery.mage.translate.translate('Hello World!')); - - translation = { - 'Hello World!': 'Hallo Welt!', - 'Some text with symbols!-+"%#*': 'Ein Text mit Symbolen!-+"%#*' - }; - jQuery.mage.translate.add(translation); - jQuery.each(translation, function(key) { - assertEquals(translation[key], jQuery.mage.translate.translate(key)); - }); -}; -TranslateTest.prototype.testTranslationParametersTwoArguments = function() { - jQuery.mage.translate.add('Hello World!', 'Bonjour tout le monde!'); - assertEquals( - 'Bonjour tout le monde!', - jQuery.mage.translate.translate('Hello World!')); -}; -TranslateTest.prototype.testTranslationAlias = function() { - var translation = {'Hello World!': 'Bonjour tout le monde!'}; - jQuery.mage.translate.add(translation); - assertEquals(translation['Hello World!'], jQuery.mage.__('Hello World!')); -}; diff --git a/dev/tests/js/jasmine/tests/lib/mage/translate.test.js b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js new file mode 100644 index 0000000000000..10b4e77f3e315 --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js @@ -0,0 +1,45 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'mage/translate' +], function ($) { + 'use strict'; + + describe('Test for mage/translate jQuery plugin', function () { + it('works with one string as parameter', function () { + $.mage.translate.add('Hello World!'); + expect('Hello World!').toEqual($.mage.translate.translate('Hello World!')); + }); + it('works with one array as parameter', function () { + $.mage.translate.add(['Hello World!', 'Bonjour tout le monde!']); + expect('Hello World!').toEqual($.mage.translate.translate('Hello World!')); + }); + it('works with one object as parameter', function () { + var translation = {'Hello World!': 'Bonjour tout le monde!'}; + $.mage.translate.add(translation); + expect(translation['Hello World!']).toEqual($.mage.translate.translate('Hello World!')); + + translation = { + 'Hello World!': 'Hallo Welt!', + 'Some text with symbols!-+"%#*': 'Ein Text mit Symbolen!-+"%#*' + }; + + $.mage.translate.add(translation); + $.each(translation, function (key) { + expect(translation[key]).toEqual($.mage.translate.translate(key)); + }); + }); + it('works with two string as parameter', function () { + $.mage.translate.add('Hello World!', 'Bonjour tout le monde!'); + expect('Bonjour tout le monde!').toEqual($.mage.translate.translate('Hello World!')); + }); + it('works with translation alias __', function () { + $.mage.translate.add('Hello World!'); + expect('Hello World!').toEqual($.mage.__('Hello World!')); + }); + }); + +}); \ No newline at end of file From ba0472f27f53a51ba532ec33fb017663902f34ab Mon Sep 17 00:00:00 2001 From: Ricards Z Date: Wed, 22 Nov 2017 14:58:03 +0200 Subject: [PATCH 0050/1464] Correctly set payment information when using paypal --- app/code/Magento/Paypal/Model/Express.php | 7 +++- .../Paypal/Test/Unit/Model/ExpressTest.php | 11 ++++- .../web/js/action/set-payment-method.js | 40 +++---------------- 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Express.php b/app/code/Magento/Paypal/Model/Express.php index 8ba8adcede511..accb22b265335 100644 --- a/app/code/Magento/Paypal/Model/Express.php +++ b/app/code/Magento/Paypal/Model/Express.php @@ -669,7 +669,7 @@ public function getApi() public function assignData(\Magento\Framework\DataObject $data) { parent::assignData($data); - + $additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA); if (!is_array($additionalData)) { @@ -677,6 +677,11 @@ public function assignData(\Magento\Framework\DataObject $data) } foreach ($additionalData as $key => $value) { + // Skip extension attributes + if ($key === \Magento\Framework\Api\ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY) { + continue; + } + $this->getInfoInstance()->setAdditionalInformation($key, $value); } return $this; diff --git a/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php b/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php index 6a2d33d010190..3d224262c99f1 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php @@ -161,12 +161,21 @@ public function testAssignData() { $transportValue = 'something'; + $extensionAttributeMock = $this->getMockForAbstractClass( + \Magento\Quote\Api\Data\PaymentExtensionInterface::class, + [], + '', + false, + false + ); + $data = new DataObject( [ PaymentInterface::KEY_ADDITIONAL_DATA => [ Express\Checkout::PAYMENT_INFO_TRANSPORT_BILLING_AGREEMENT => $transportValue, Express\Checkout::PAYMENT_INFO_TRANSPORT_PAYER_ID => $transportValue, - Express\Checkout::PAYMENT_INFO_TRANSPORT_TOKEN => $transportValue + Express\Checkout::PAYMENT_INFO_TRANSPORT_TOKEN => $transportValue, + \Magento\Framework\Api\ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY => $extensionAttributeMock ] ] ); diff --git a/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js b/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js index a994f9defd583..650d5794a2445 100644 --- a/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js +++ b/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js @@ -10,42 +10,12 @@ define([ 'mage/storage', 'Magento_Checkout/js/model/error-processor', 'Magento_Customer/js/model/customer', - 'Magento_Checkout/js/model/full-screen-loader' -], function ($, quote, urlBuilder, storage, errorProcessor, customer, fullScreenLoader) { + 'Magento_Checkout/js/model/full-screen-loader', + 'Magento_Checkout/js/action/set-payment-information' +], function ($, quote, urlBuilder, storage, errorProcessor, customer, fullScreenLoader, setPaymentInformation) { 'use strict'; return function (messageContainer) { - var serviceUrl, - payload, - paymentData = quote.paymentMethod(); - - /** - * Checkout for guest and registered customer. - */ - if (!customer.isLoggedIn()) { - serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/set-payment-information', { - cartId: quote.getQuoteId() - }); - payload = { - cartId: quote.getQuoteId(), - email: quote.guestEmail, - paymentMethod: paymentData - }; - } else { - serviceUrl = urlBuilder.createUrl('/carts/mine/set-payment-information', {}); - payload = { - cartId: quote.getQuoteId(), - paymentMethod: paymentData - }; - } - fullScreenLoader.startLoader(); - - return storage.post( - serviceUrl, JSON.stringify(payload) - ).fail(function (response) { - errorProcessor.process(response, messageContainer); - }).always(function () { - fullScreenLoader.stopLoader(); - }); + return setPaymentInformation(messageContainer, quote.paymentMethod()); }; -}); +}); \ No newline at end of file From 48923e1c95a235b490d3a119139bb762e947c68f Mon Sep 17 00:00:00 2001 From: Ricards Z Date: Wed, 22 Nov 2017 15:18:16 +0200 Subject: [PATCH 0051/1464] Added missing new line at the end of the file --- .../Paypal/view/frontend/web/js/action/set-payment-method.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js b/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js index 650d5794a2445..feb2538b0517e 100644 --- a/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js +++ b/app/code/Magento/Paypal/view/frontend/web/js/action/set-payment-method.js @@ -18,4 +18,4 @@ define([ return function (messageContainer) { return setPaymentInformation(messageContainer, quote.paymentMethod()); }; -}); \ No newline at end of file +}); From 16916212d3815d33dcd601eb72d8408099a8c287 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 16:59:22 +0100 Subject: [PATCH 0052/1464] Fix translate.test to be eslint friendly --- dev/tests/js/jasmine/tests/lib/mage/translate.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/translate.test.js b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js index 10b4e77f3e315..c87cfa227c1aa 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/translate.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js @@ -2,6 +2,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +/* eslint-disable max-nested-callbacks */ define([ 'jquery', 'mage/translate' @@ -18,7 +19,10 @@ define([ expect('Hello World!').toEqual($.mage.translate.translate('Hello World!')); }); it('works with one object as parameter', function () { - var translation = {'Hello World!': 'Bonjour tout le monde!'}; + var translation = { + 'Hello World!': 'Bonjour tout le monde!' + }; + $.mage.translate.add(translation); expect(translation['Hello World!']).toEqual($.mage.translate.translate('Hello World!')); @@ -42,4 +46,4 @@ define([ }); }); -}); \ No newline at end of file +}); From 5c17a62b3e4c7144d8deb469e8afb22a50ac772a Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Wed, 22 Nov 2017 18:19:28 +0200 Subject: [PATCH 0053/1464] MAGETWO-83343 Customer shopping cart not accessible in admin order --- .../Magento/Sales/Model/AdminOrder/Create.php | 3 ++- .../Test/Unit/Model/AdminOrder/CreateTest.php | 25 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 69f4d19e4dd63..c111a050ac3db 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -715,9 +715,10 @@ public function getCustomerCart() $this->_cart = $this->quoteFactory->create(); $customerId = (int)$this->getSession()->getCustomerId(); + $storeId = (int)$this->getSession()->getStoreId(); if ($customerId) { try { - $this->_cart = $this->quoteRepository->getForCustomer($customerId); + $this->_cart = $this->quoteRepository->getForCustomer($customerId, [$storeId]); } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { $this->_cart->setStore($this->getSession()->getStore()); $customerData = $this->customerRepository->getById($customerId); diff --git a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php index b284a529d2a15..9ea148649f51b 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php @@ -41,6 +41,11 @@ class CreateTest extends \PHPUnit\Framework\TestCase */ private $adminOrderCreate; + /** + * @var \Magento\Quote\Api\CartRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $quoteRepository; + /** * @var SessionQuote|MockObject */ @@ -78,12 +83,21 @@ class CreateTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->sessionQuote = $this->createMock(SessionQuote::class); $this->formFactory = $this->createPartialMock(FormFactory::class, ['create']); $this->customerFactory = $this->createPartialMock(CustomerInterfaceFactory::class, ['create']); $this->itemUpdater = $this->createMock(Updater::class); + $this->quoteRepository = $this->getMockBuilder(\Magento\Quote\Api\CartRepositoryInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getForCustomer']) + ->getMockForAbstractClass(); + + $this->sessionQuote = $this->getMockBuilder(\Magento\Backend\Model\Session\Quote::class) + ->disableOriginalConstructor() + ->setMethods(['getQuote', 'getStoreId', 'getCustomerId']) + ->getMock(); + $this->customerMapper = $this->getMockBuilder(Mapper::class) ->setMethods(['toFlatArray']) ->disableOriginalConstructor() @@ -105,6 +119,7 @@ protected function setUp() 'quoteItemUpdater' => $this->itemUpdater, 'customerMapper' => $this->customerMapper, 'dataObjectHelper' => $this->dataObjectHelper, + 'quoteRepository' => $this->quoteRepository, ] ); } @@ -266,4 +281,12 @@ public function testApplyCoupon() $object = $this->adminOrderCreate->applyCoupon($couponCode); self::assertEquals($this->adminOrderCreate, $object); } + + public function testGetCustomerCart() + { + $this->sessionQuote->expects($this->once())->method('getStoreId')->willReturn(2); + $this->sessionQuote->expects($this->once())->method('getCustomerId')->willReturn(2); + $this->quoteRepository->expects($this->once())->method('getForCustomer')->with(2, [2]); + $this->adminOrderCreate->getCustomerCart(); + } } From ea56695cb6b5e39f9dfd86302a4daa41f5dd31da Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 17:50:00 +0100 Subject: [PATCH 0054/1464] Added accordion.test.js for Jasmine testing. Removed accordion.js and index.html for jsTestDriver test. --- .../testsuite/mage/accordion/accordion.js | 57 ------------- .../testsuite/mage/accordion/index.html | 31 ------- .../jasmine/tests/lib/mage/accordion.test.js | 81 +++++++++++++++++++ 3 files changed, 81 insertions(+), 88 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html create mode 100644 dev/tests/js/jasmine/tests/lib/mage/accordion.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js deleted file mode 100644 index 562c5c096b654..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @category mage.js - * @package test - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -/* - - */ -test( "Initialization", function() { - expect(2); - var accordion = $("

"); - accordion.accordion(); - ok( accordion.is(':mage-accordion'), "widget instantiated" ); - accordion.accordion('destroy'); - ok( !accordion.is(':mage-accordion'), "widget destroyed" ); -}); - - - -test( "One-collapsible element", function() { - expect(4); - var accordion = $('
'); - var title1 = $('
').appendTo(accordion); - var content1 = $('
').appendTo(accordion); - var title2 = $('
').appendTo(accordion); - var content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); - - accordion.accordion(); - ok( content1.is(':visible'), "content visible" ); - ok( content2.is(':hidden'), "content hidden" ); - title2.trigger('click'); - ok( content1.is(':hidden'), "content hidden" ); - ok( content2.is(':visible'), "content visible" ); - accordion.accordion('destroy'); - -}); - -test( "Multi-collapsible elements", function() { - expect(4); - var accordion = $('
'); - var title1 = $('
').appendTo(accordion); - var content1 = $('
').appendTo(accordion); - var title2 = $('
').appendTo(accordion); - var content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); - - accordion.accordion({multipleCollapsible:true}); - ok( content1.is(':visible'), "content visible" ); - ok( content2.is(':hidden'), "content hidden" ); - title2.trigger('click'); - ok( content1.is(':visible'), "content visible" ); - ok( content2.is(':visible'), "content visible" ); - accordion.accordion('destroy'); -}); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html deleted file mode 100644 index 093284c6f4fa8..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - Accordion Widget: QUnit Tests - - - - - - - - - - - - -
-
-
- - diff --git a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js new file mode 100644 index 0000000000000..a35367946349a --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js @@ -0,0 +1,81 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'mage/accordion' +], function ($) { + 'use strict'; + + describe('Test for mage/accordion jQuery plugin', function () { + it('check if accordion can be initialized', function () { + var accordion = $("
"); + + accordion.accordion(); + expect(accordion.is(':mage-accordion')).toBeTruthy(); + + accordion.accordion('destroy'); + expect(accordion.is(':mage-accordion')).toBeFalsy(); + }); + it('check one-collapsible element accordion', function () { + var accordion = $('
'), + title1 = $('
').appendTo(accordion), + content1 = $('
').appendTo(accordion), + title2 = $('
').appendTo(accordion), + content2 = $('
').appendTo(accordion); + + accordion.appendTo("body"); + + accordion.accordion(); + + expect(accordion.is(':mage-accordion')).toBeTruthy(); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + + title2.trigger('click'); + + expect(content1.is(':hidden')).toBeTruthy(); + expect(content2.is(':visible')).toBeTruthy(); + + title1.trigger('click'); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + + accordion.accordion('destroy'); + + expect(accordion.is(':mage-accordion')).toBeFalsy(); + }); + it('check multi-collapsible element accordion', function () { + var accordion = $('
'); + + $('
').appendTo(accordion); + + var content1 = $('
').appendTo(accordion), + title2 = $('
').appendTo(accordion), + content2 = $('
').appendTo(accordion); + + accordion.appendTo("body"); + + accordion.accordion({ + multipleCollapsible: true + }); + + expect(accordion.is(':mage-accordion')).toBeTruthy(); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + + title2.trigger('click'); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':visible')).toBeTruthy(); + + accordion.accordion('destroy'); + + expect(accordion.is(':mage-accordion')).toBeFalsy(); + }); + }); +}); From 126a1e30be2b23a03063935d9199725d770d84c2 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 18:20:36 +0100 Subject: [PATCH 0055/1464] Eslint upgrades. --- .../js/jasmine/tests/lib/mage/accordion.test.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js index a35367946349a..12ca91a4ae002 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js @@ -25,7 +25,7 @@ define([ title2 = $('
').appendTo(accordion), content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); + accordion.appendTo('body'); accordion.accordion(); @@ -49,15 +49,14 @@ define([ expect(accordion.is(':mage-accordion')).toBeFalsy(); }); it('check multi-collapsible element accordion', function () { - var accordion = $('
'); - - $('
').appendTo(accordion); - - var content1 = $('
').appendTo(accordion), + var accordion = $('
'), + content1 = $('
').appendTo(accordion), title2 = $('
').appendTo(accordion), content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); + $('
').appendTo(accordion); + + accordion.appendTo('body'); accordion.accordion({ multipleCollapsible: true From b3fedbc6ed90ef99f1be17c6d77d2cb0ea50fa74 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko Date: Wed, 22 Nov 2017 19:53:45 +0200 Subject: [PATCH 0056/1464] Added decorate.test.js for Jasmine testing. Removed decorate-test.js --- .../testsuite/mage/decorate-test.js | 141 ------------ .../jasmine/tests/lib/mage/decorate.test.js | 202 ++++++++++++++++++ 2 files changed, 202 insertions(+), 141 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js create mode 100644 dev/tests/js/jasmine/tests/lib/mage/decorate.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js deleted file mode 100644 index 96bad35a17e2e..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -DecoratorTest = TestCase('DecoratorTest'); -DecoratorTest.prototype.testDecoratorList = function () { - /*:DOC +=
    -
  • item1
  • -
  • item2
  • -
  • item3
  • -
  • item4
  • -
- */ - var list = $('#list'); - list.decorate('list'); - assertTrue($(list.find('li')[0]).hasClass('odd')); - assertFalse($(list.find('li')[0]).hasClass('even')); - assertTrue($(list.find('li')[1]).hasClass('even')); - assertFalse($(list.find('li')[1]).hasClass('odd')); - assertTrue($(list.find('li')[2]).hasClass('odd')); - assertFalse($(list.find('li')[2]).hasClass('even')); - assertTrue($(list.find('li')[3]).hasClass('even')); - assertFalse($(list.find('li')[3]).hasClass('odd')); - assertTrue($(list.find('li')[3]).hasClass('last')); -}; - -DecoratorTest.prototype.testDecoratorGeneral = function () { - /*:DOC +=
-
item1
-
item2
-
item3
-
item4
-
- */ - var itemClass = '.item'; - $(itemClass).decorate('generic'); - assertTrue($($(itemClass)[0]).hasClass('odd')); - assertFalse($($(itemClass)[0]).hasClass('even')); - assertTrue($($(itemClass)[0]).hasClass('first')); - assertFalse($($(itemClass)[0]).hasClass('last')); - - assertFalse($($(itemClass)[1]).hasClass('odd')); - assertTrue($($(itemClass)[1]).hasClass('even')); - assertFalse($($(itemClass)[1]).hasClass('first')); - assertFalse($($(itemClass)[1]).hasClass('last')); - - assertTrue($($(itemClass)[2]).hasClass('odd')); - assertFalse($($(itemClass)[2]).hasClass('even')); - assertFalse($($(itemClass)[2]).hasClass('first')); - assertFalse($($(itemClass)[2]).hasClass('last')); - - assertFalse($($(itemClass)[3]).hasClass('odd')); - assertTrue($($(itemClass)[3]).hasClass('even')); - assertFalse($($(itemClass)[3]).hasClass('first')); - assertTrue($($(itemClass)[3]).hasClass('last')); -}; - -DecoratorTest.prototype.testDecoratorTable = function (){ - /*:DOC += - - - - - - - - - - - - - - - - - - - - - - -
MonthSavings
Sum$180
January$100
February$80
- */ - var tableId = '#foo'; - $(tableId).decorate('table'); - assertTrue($(tableId).find('thead tr').hasClass('first')); - assertTrue($(tableId).find('thead tr').hasClass('last')); - assertFalse($(tableId).find('thead tr').hasClass('odd')); - assertFalse($(tableId).find('thead tr').hasClass('even')); - - assertTrue($(tableId).find('tfoot tr').hasClass('first')); - assertTrue($(tableId).find('tfoot tr').hasClass('last')); - assertFalse($(tableId).find('tfoot tr').hasClass('odd')); - assertFalse($(tableId).find('tfoot tr').hasClass('even')); - - assertFalse($(tableId).find('tfoot tr td').last().hasClass('first')); - assertTrue($(tableId).find('tfoot tr td').last().hasClass('last')); - assertFalse($(tableId).find('tfoot tr td').last().hasClass('odd')); - assertFalse($(tableId).find('tfoot tr td').last().hasClass('even')); - - assertTrue($(tableId).find('tbody tr').first().hasClass('first')); - assertTrue($(tableId).find('tbody tr').first().hasClass('odd')); - assertFalse($(tableId).find('tbody tr').first().hasClass('last')); - assertFalse($(tableId).find('tbody tr').first().hasClass('even')); - assertFalse($(tableId).find('tbody tr').last().hasClass('first')); - assertFalse($(tableId).find('tbody tr').last().hasClass('odd')); - assertTrue($(tableId).find('tbody tr').last().hasClass('last')); - assertTrue($(tableId).find('tbody tr').last().hasClass('even')); - - assertFalse($(tableId).find('tbody tr td').last().hasClass('first')); - assertFalse($(tableId).find('tbody tr td').last().hasClass('odd')); - assertTrue($(tableId).find('tbody tr td').last().hasClass('last')); - assertFalse($(tableId).find('tbody tr td').last().hasClass('even')); -}; - -DecoratorTest.prototype.testDecoratorDataList = function () { - /*:DOC +=
-
item
-
item
-
item
-
item
-
- */ - var listId = '#data-list'; - $(listId).decorate('dataList'); - assertTrue($(listId).find('dt').first().hasClass('odd')); - assertFalse($(listId).find('dt').first().hasClass('even')); - assertFalse($(listId).find('dt').first().hasClass('last')); - - assertTrue($(listId).find('dt').last().hasClass('even')); - assertFalse($(listId).find('dt').last().hasClass('odd')); - assertTrue($(listId).find('dt').last().hasClass('last')); - - assertTrue($(listId).find('dd').first().hasClass('odd')); - assertFalse($(listId).find('dd').first().hasClass('even')); - assertFalse($(listId).find('dd').first().hasClass('last')); - - assertTrue($(listId).find('dd').last().hasClass('even')); - assertFalse($(listId).find('dd').last().hasClass('odd')); - assertTrue($(listId).find('dd').last().hasClass('last')); -}; diff --git a/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js b/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js new file mode 100644 index 0000000000000..9b488c417674d --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js @@ -0,0 +1,202 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint-disable max-nested-callbacks */ +define([ + 'mage/decorate', + 'jquery' +], function (decorate, $) { + 'use strict'; + + describe('mage/decorate', function () { + describe('"list" method', function () { + var listId = 'testList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check correct class decoration', function () { + var $list = $('#' + listId); + + $list.decorate('list'); + expect($list.find('li:first').hasClass('first')).toBe(false); + expect($list.find('li:first').hasClass('odd')).toBe(true); + expect($list.find('li:last').hasClass('last')).toBe(true); + expect($list.find('li:odd').hasClass('even')).toBe(true); + expect($list.find('li:even').hasClass('odd')).toBe(true); + }); + }); + + describe('"generic" method', function () { + var listId = 'testList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check correct class decoration with default params', function () { + var $list = $('#' + listId); + + $list.find('li').decorate('generic'); + expect($list.find('li:first').hasClass('first')).toBe(true); + expect($list.find('li:first').hasClass('odd')).toBe(true); + expect($list.find('li:last').hasClass('last')).toBe(true); + expect($list.find('li:odd').hasClass('even')).toBe(true); + expect($list.find('li:even').hasClass('odd')).toBe(true); + }); + + it('Check correct class decoration with custom params', function () { + var $list = $('#' + listId); + + $list.find('li').decorate('generic', ['last', 'first']); + expect($list.find('li:first').hasClass('first')).toBe(true); + expect($list.find('li:first').hasClass('odd')).toBe(false); + expect($list.find('li:last').hasClass('last')).toBe(true); + expect($list.find('li:odd').hasClass('even')).toBe(false); + expect($list.find('li:even').hasClass('odd')).toBe(false); + }); + + it('Check correct class decoration with empty items', function () { + var $list = $('#' + listId); + + $list.find('span').decorate('generic', ['last', 'first']); + expect($list.find('li:first').hasClass('first')).toBe(false); + expect($list.find('li:first').hasClass('odd')).toBe(false); + expect($list.find('li:last').hasClass('last')).toBe(false); + expect($list.find('li:odd').hasClass('even')).toBe(false); + expect($list.find('li:even').hasClass('odd')).toBe(false); + }); + }); + + describe('"table" method', function () { + var tableId = 'testTable'; + + beforeEach(function () { + var table = $('' + + '' + + '' + + '' + + '' + + '' + + '>' + + '' + + '
'); + + $('body').append(table); + }); + + afterEach(function () { + $('#' + tableId).remove(); + }); + + it('Check correct class decoration with default params', function () { + var $table = $('#' + tableId); + + $table.decorate('table'); + expect($table.find('tbody tr:first').hasClass('first')).toBe(true); + expect($table.find('tbody tr:first').hasClass('odd')).toBe(true); + expect($table.find('tbody tr:odd').hasClass('even')).toBe(true); + expect($table.find('tbody tr:even').hasClass('odd')).toBe(true); + expect($table.find('tbody tr:last').hasClass('last')).toBe(true); + expect($table.find('thead tr:first').hasClass('first')).toBe(true); + expect($table.find('thead tr:last').hasClass('last')).toBe(true); + expect($table.find('tfoot tr:first').hasClass('first')).toBe(true); + expect($table.find('tfoot tr:last').hasClass('last')).toBe(true); + expect($table.find('tr td:last').hasClass('last')).toBe(true); + expect($table.find('tr td:first').hasClass('first')).toBe(false); + }); + + it('Check correct class decoration with custom params', function () { + var $table = $('#' + tableId); + + $table.decorate('table', { + 'tbody': ['first'], + 'tbody tr': ['first'], + 'thead tr': ['first'], + 'tfoot tr': ['last'], + 'tr td': ['first'] + }); + expect($table.find('tbody:first').hasClass('first')).toBe(true); + expect($table.find('tbody tr:first').hasClass('first')).toBe(true); + expect($table.find('tbody tr:first').hasClass('odd')).toBe(false); + expect($table.find('tbody tr:odd').hasClass('even')).toBe(false); + expect($table.find('tbody tr:even').hasClass('odd')).toBe(false); + expect($table.find('tbody tr:last').hasClass('last')).toBe(false); + expect($table.find('thead tr:first').hasClass('first')).toBe(true); + expect($table.find('thead tr:last').hasClass('last')).toBe(false); + expect($table.find('tfoot tr:first').hasClass('first')).toBe(false); + expect($table.find('tfoot tr:last').hasClass('last')).toBe(true); + expect($table.find('tr td:last').hasClass('last')).toBe(false); + expect($table.find('tr td:first').hasClass('first')).toBe(true); + }); + }); + + describe('"dataList" method', function () { + var listId = 'testDataList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check correct class decoration', function () { + var $list = $('#' + listId); + + $list.decorate('dataList'); + expect($list.find('dt:first').hasClass('first')).toBe(false); + expect($list.find('dt:first').hasClass('odd')).toBe(true); + expect($list.find('dt:odd').hasClass('even')).toBe(true); + expect($list.find('dt:even').hasClass('odd')).toBe(true); + expect($list.find('dt:last').hasClass('last')).toBe(true); + expect($list.find('dd:first').hasClass('first')).toBe(false); + expect($list.find('dd:first').hasClass('odd')).toBe(true); + expect($list.find('dd:odd').hasClass('even')).toBe(true); + expect($list.find('dd:even').hasClass('odd')).toBe(true); + expect($list.find('dd:last').hasClass('last')).toBe(true); + }); + }); + + describe('Call decorate with fake method', function () { + var listId = 'testDataList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check error message', function () { + var $list = $('#' + listId); + + spyOn(jQuery, 'error'); + $list.decorate('customMethod'); + + expect(jQuery.error).toHaveBeenCalledWith('Method customMethod does not exist on jQuery.decorate'); + }); + }); + }); +}); From 0117f8648080ea88848e1614ffbc62cd38cb2f38 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Tue, 21 Nov 2017 17:36:16 +0100 Subject: [PATCH 0057/1464] Added translate.test.js for Jasmine compatibility unit testing. Removed transtale-test.js from jsTestDriver suite. --- .../mage/translate/translate-test.js | 47 ------------------- .../jasmine/tests/lib/mage/translate.test.js | 45 ++++++++++++++++++ 2 files changed, 45 insertions(+), 47 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js create mode 100644 dev/tests/js/jasmine/tests/lib/mage/translate.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js deleted file mode 100644 index a9bbc7fb10d2d..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/translate/translate-test.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -TranslateTest = TestCase('TranslateTest'); -TranslateTest.prototype.testTranslateExist = function() { - assertNotUndefined(jQuery.mage.translate); -}; -TranslateTest.prototype.testTranslationParametersOneArgument = function() { - jQuery.mage.translate.add('Hello World!'); - assertEquals( - 'Hello World!', - jQuery.mage.translate.translate('Hello World!')); -}; -TranslateTest.prototype.testTranslationParametersArray = function() { - jQuery.mage.translate.add(['Hello World!', 'Bonjour tout le monde!']); - assertEquals( - 'Hello World!', - jQuery.mage.translate.translate('Hello World!')); -}; -TranslateTest.prototype.testTranslationParametersObject = function() { - var translation = {'Hello World!': 'Bonjour tout le monde!'}; - jQuery.mage.translate.add(translation); - assertEquals( - translation['Hello World!'], - jQuery.mage.translate.translate('Hello World!')); - - translation = { - 'Hello World!': 'Hallo Welt!', - 'Some text with symbols!-+"%#*': 'Ein Text mit Symbolen!-+"%#*' - }; - jQuery.mage.translate.add(translation); - jQuery.each(translation, function(key) { - assertEquals(translation[key], jQuery.mage.translate.translate(key)); - }); -}; -TranslateTest.prototype.testTranslationParametersTwoArguments = function() { - jQuery.mage.translate.add('Hello World!', 'Bonjour tout le monde!'); - assertEquals( - 'Bonjour tout le monde!', - jQuery.mage.translate.translate('Hello World!')); -}; -TranslateTest.prototype.testTranslationAlias = function() { - var translation = {'Hello World!': 'Bonjour tout le monde!'}; - jQuery.mage.translate.add(translation); - assertEquals(translation['Hello World!'], jQuery.mage.__('Hello World!')); -}; diff --git a/dev/tests/js/jasmine/tests/lib/mage/translate.test.js b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js new file mode 100644 index 0000000000000..10b4e77f3e315 --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js @@ -0,0 +1,45 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'mage/translate' +], function ($) { + 'use strict'; + + describe('Test for mage/translate jQuery plugin', function () { + it('works with one string as parameter', function () { + $.mage.translate.add('Hello World!'); + expect('Hello World!').toEqual($.mage.translate.translate('Hello World!')); + }); + it('works with one array as parameter', function () { + $.mage.translate.add(['Hello World!', 'Bonjour tout le monde!']); + expect('Hello World!').toEqual($.mage.translate.translate('Hello World!')); + }); + it('works with one object as parameter', function () { + var translation = {'Hello World!': 'Bonjour tout le monde!'}; + $.mage.translate.add(translation); + expect(translation['Hello World!']).toEqual($.mage.translate.translate('Hello World!')); + + translation = { + 'Hello World!': 'Hallo Welt!', + 'Some text with symbols!-+"%#*': 'Ein Text mit Symbolen!-+"%#*' + }; + + $.mage.translate.add(translation); + $.each(translation, function (key) { + expect(translation[key]).toEqual($.mage.translate.translate(key)); + }); + }); + it('works with two string as parameter', function () { + $.mage.translate.add('Hello World!', 'Bonjour tout le monde!'); + expect('Bonjour tout le monde!').toEqual($.mage.translate.translate('Hello World!')); + }); + it('works with translation alias __', function () { + $.mage.translate.add('Hello World!'); + expect('Hello World!').toEqual($.mage.__('Hello World!')); + }); + }); + +}); \ No newline at end of file From 3a907c2be5becbf42ae7cc14cc4d431f7e6a14e4 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 16:59:22 +0100 Subject: [PATCH 0058/1464] Fix translate.test to be eslint friendly --- dev/tests/js/jasmine/tests/lib/mage/translate.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/translate.test.js b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js index 10b4e77f3e315..c87cfa227c1aa 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/translate.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/translate.test.js @@ -2,6 +2,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +/* eslint-disable max-nested-callbacks */ define([ 'jquery', 'mage/translate' @@ -18,7 +19,10 @@ define([ expect('Hello World!').toEqual($.mage.translate.translate('Hello World!')); }); it('works with one object as parameter', function () { - var translation = {'Hello World!': 'Bonjour tout le monde!'}; + var translation = { + 'Hello World!': 'Bonjour tout le monde!' + }; + $.mage.translate.add(translation); expect(translation['Hello World!']).toEqual($.mage.translate.translate('Hello World!')); @@ -42,4 +46,4 @@ define([ }); }); -}); \ No newline at end of file +}); From 821bdaaba4923fa4e6fdc4749ea5c625dcfd0fe0 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 17:50:00 +0100 Subject: [PATCH 0059/1464] Added accordion.test.js for Jasmine testing. Removed accordion.js and index.html for jsTestDriver test. --- .../testsuite/mage/accordion/accordion.js | 57 ------------- .../testsuite/mage/accordion/index.html | 31 ------- .../jasmine/tests/lib/mage/accordion.test.js | 81 +++++++++++++++++++ 3 files changed, 81 insertions(+), 88 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html create mode 100644 dev/tests/js/jasmine/tests/lib/mage/accordion.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js deleted file mode 100644 index 562c5c096b654..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/accordion.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @category mage.js - * @package test - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -/* - - */ -test( "Initialization", function() { - expect(2); - var accordion = $("
"); - accordion.accordion(); - ok( accordion.is(':mage-accordion'), "widget instantiated" ); - accordion.accordion('destroy'); - ok( !accordion.is(':mage-accordion'), "widget destroyed" ); -}); - - - -test( "One-collapsible element", function() { - expect(4); - var accordion = $('
'); - var title1 = $('
').appendTo(accordion); - var content1 = $('
').appendTo(accordion); - var title2 = $('
').appendTo(accordion); - var content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); - - accordion.accordion(); - ok( content1.is(':visible'), "content visible" ); - ok( content2.is(':hidden'), "content hidden" ); - title2.trigger('click'); - ok( content1.is(':hidden'), "content hidden" ); - ok( content2.is(':visible'), "content visible" ); - accordion.accordion('destroy'); - -}); - -test( "Multi-collapsible elements", function() { - expect(4); - var accordion = $('
'); - var title1 = $('
').appendTo(accordion); - var content1 = $('
').appendTo(accordion); - var title2 = $('
').appendTo(accordion); - var content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); - - accordion.accordion({multipleCollapsible:true}); - ok( content1.is(':visible'), "content visible" ); - ok( content2.is(':hidden'), "content hidden" ); - title2.trigger('click'); - ok( content1.is(':visible'), "content visible" ); - ok( content2.is(':visible'), "content visible" ); - accordion.accordion('destroy'); -}); diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html deleted file mode 100644 index 093284c6f4fa8..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/accordion/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - Accordion Widget: QUnit Tests - - - - - - - - - - - - -
-
-
- - diff --git a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js new file mode 100644 index 0000000000000..a35367946349a --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js @@ -0,0 +1,81 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'mage/accordion' +], function ($) { + 'use strict'; + + describe('Test for mage/accordion jQuery plugin', function () { + it('check if accordion can be initialized', function () { + var accordion = $("
"); + + accordion.accordion(); + expect(accordion.is(':mage-accordion')).toBeTruthy(); + + accordion.accordion('destroy'); + expect(accordion.is(':mage-accordion')).toBeFalsy(); + }); + it('check one-collapsible element accordion', function () { + var accordion = $('
'), + title1 = $('
').appendTo(accordion), + content1 = $('
').appendTo(accordion), + title2 = $('
').appendTo(accordion), + content2 = $('
').appendTo(accordion); + + accordion.appendTo("body"); + + accordion.accordion(); + + expect(accordion.is(':mage-accordion')).toBeTruthy(); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + + title2.trigger('click'); + + expect(content1.is(':hidden')).toBeTruthy(); + expect(content2.is(':visible')).toBeTruthy(); + + title1.trigger('click'); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + + accordion.accordion('destroy'); + + expect(accordion.is(':mage-accordion')).toBeFalsy(); + }); + it('check multi-collapsible element accordion', function () { + var accordion = $('
'); + + $('
').appendTo(accordion); + + var content1 = $('
').appendTo(accordion), + title2 = $('
').appendTo(accordion), + content2 = $('
').appendTo(accordion); + + accordion.appendTo("body"); + + accordion.accordion({ + multipleCollapsible: true + }); + + expect(accordion.is(':mage-accordion')).toBeTruthy(); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + + title2.trigger('click'); + + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':visible')).toBeTruthy(); + + accordion.accordion('destroy'); + + expect(accordion.is(':mage-accordion')).toBeFalsy(); + }); + }); +}); From 2846c785b9b9962dfaafd8fdbb81f9d2fe4851a5 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 18:20:36 +0100 Subject: [PATCH 0060/1464] Eslint upgrades. --- .../js/jasmine/tests/lib/mage/accordion.test.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js index a35367946349a..12ca91a4ae002 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js @@ -25,7 +25,7 @@ define([ title2 = $('
').appendTo(accordion), content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); + accordion.appendTo('body'); accordion.accordion(); @@ -49,15 +49,14 @@ define([ expect(accordion.is(':mage-accordion')).toBeFalsy(); }); it('check multi-collapsible element accordion', function () { - var accordion = $('
'); - - $('
').appendTo(accordion); - - var content1 = $('
').appendTo(accordion), + var accordion = $('
'), + content1 = $('
').appendTo(accordion), title2 = $('
').appendTo(accordion), content2 = $('
').appendTo(accordion); - accordion.appendTo("body"); + $('
').appendTo(accordion); + + accordion.appendTo('body'); accordion.accordion({ multipleCollapsible: true From f4712cdda55a88ebd2c455cdb7840dae31a3334a Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 19:09:46 +0100 Subject: [PATCH 0061/1464] Eslint improvements and logical fixes for unit testing. --- .../js/jasmine/tests/lib/mage/accordion.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js index 12ca91a4ae002..19a54d95cf704 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js @@ -10,7 +10,7 @@ define([ describe('Test for mage/accordion jQuery plugin', function () { it('check if accordion can be initialized', function () { - var accordion = $("
"); + var accordion = $('
'); accordion.accordion(); expect(accordion.is(':mage-accordion')).toBeTruthy(); @@ -50,12 +50,11 @@ define([ }); it('check multi-collapsible element accordion', function () { var accordion = $('
'), + title1 = $('
').appendTo(accordion), content1 = $('
').appendTo(accordion), title2 = $('
').appendTo(accordion), content2 = $('
').appendTo(accordion); - $('
').appendTo(accordion); - accordion.appendTo('body'); accordion.accordion({ @@ -63,17 +62,18 @@ define([ }); expect(accordion.is(':mage-accordion')).toBeTruthy(); - expect(content1.is(':visible')).toBeTruthy(); expect(content2.is(':hidden')).toBeTruthy(); - title2.trigger('click'); + $(title1).trigger('click'); + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + $(title2).trigger('click'); expect(content1.is(':visible')).toBeTruthy(); expect(content2.is(':visible')).toBeTruthy(); accordion.accordion('destroy'); - expect(accordion.is(':mage-accordion')).toBeFalsy(); }); }); From f0a18772bae4a7197fcce729ed33dfa168301731 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko Date: Wed, 22 Nov 2017 18:53:45 +0100 Subject: [PATCH 0062/1464] Added decorate.test.js for Jasmine testing. Removed decorate-test.js (cherry picked from commit b3fedbc) --- .../testsuite/mage/decorate-test.js | 141 ------------ .../jasmine/tests/lib/mage/decorate.test.js | 202 ++++++++++++++++++ 2 files changed, 202 insertions(+), 141 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js create mode 100644 dev/tests/js/jasmine/tests/lib/mage/decorate.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js b/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js deleted file mode 100644 index 96bad35a17e2e..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/decorate-test.js +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -DecoratorTest = TestCase('DecoratorTest'); -DecoratorTest.prototype.testDecoratorList = function () { - /*:DOC +=
    -
  • item1
  • -
  • item2
  • -
  • item3
  • -
  • item4
  • -
- */ - var list = $('#list'); - list.decorate('list'); - assertTrue($(list.find('li')[0]).hasClass('odd')); - assertFalse($(list.find('li')[0]).hasClass('even')); - assertTrue($(list.find('li')[1]).hasClass('even')); - assertFalse($(list.find('li')[1]).hasClass('odd')); - assertTrue($(list.find('li')[2]).hasClass('odd')); - assertFalse($(list.find('li')[2]).hasClass('even')); - assertTrue($(list.find('li')[3]).hasClass('even')); - assertFalse($(list.find('li')[3]).hasClass('odd')); - assertTrue($(list.find('li')[3]).hasClass('last')); -}; - -DecoratorTest.prototype.testDecoratorGeneral = function () { - /*:DOC +=
-
item1
-
item2
-
item3
-
item4
-
- */ - var itemClass = '.item'; - $(itemClass).decorate('generic'); - assertTrue($($(itemClass)[0]).hasClass('odd')); - assertFalse($($(itemClass)[0]).hasClass('even')); - assertTrue($($(itemClass)[0]).hasClass('first')); - assertFalse($($(itemClass)[0]).hasClass('last')); - - assertFalse($($(itemClass)[1]).hasClass('odd')); - assertTrue($($(itemClass)[1]).hasClass('even')); - assertFalse($($(itemClass)[1]).hasClass('first')); - assertFalse($($(itemClass)[1]).hasClass('last')); - - assertTrue($($(itemClass)[2]).hasClass('odd')); - assertFalse($($(itemClass)[2]).hasClass('even')); - assertFalse($($(itemClass)[2]).hasClass('first')); - assertFalse($($(itemClass)[2]).hasClass('last')); - - assertFalse($($(itemClass)[3]).hasClass('odd')); - assertTrue($($(itemClass)[3]).hasClass('even')); - assertFalse($($(itemClass)[3]).hasClass('first')); - assertTrue($($(itemClass)[3]).hasClass('last')); -}; - -DecoratorTest.prototype.testDecoratorTable = function (){ - /*:DOC += - - - - - - - - - - - - - - - - - - - - - - -
MonthSavings
Sum$180
January$100
February$80
- */ - var tableId = '#foo'; - $(tableId).decorate('table'); - assertTrue($(tableId).find('thead tr').hasClass('first')); - assertTrue($(tableId).find('thead tr').hasClass('last')); - assertFalse($(tableId).find('thead tr').hasClass('odd')); - assertFalse($(tableId).find('thead tr').hasClass('even')); - - assertTrue($(tableId).find('tfoot tr').hasClass('first')); - assertTrue($(tableId).find('tfoot tr').hasClass('last')); - assertFalse($(tableId).find('tfoot tr').hasClass('odd')); - assertFalse($(tableId).find('tfoot tr').hasClass('even')); - - assertFalse($(tableId).find('tfoot tr td').last().hasClass('first')); - assertTrue($(tableId).find('tfoot tr td').last().hasClass('last')); - assertFalse($(tableId).find('tfoot tr td').last().hasClass('odd')); - assertFalse($(tableId).find('tfoot tr td').last().hasClass('even')); - - assertTrue($(tableId).find('tbody tr').first().hasClass('first')); - assertTrue($(tableId).find('tbody tr').first().hasClass('odd')); - assertFalse($(tableId).find('tbody tr').first().hasClass('last')); - assertFalse($(tableId).find('tbody tr').first().hasClass('even')); - assertFalse($(tableId).find('tbody tr').last().hasClass('first')); - assertFalse($(tableId).find('tbody tr').last().hasClass('odd')); - assertTrue($(tableId).find('tbody tr').last().hasClass('last')); - assertTrue($(tableId).find('tbody tr').last().hasClass('even')); - - assertFalse($(tableId).find('tbody tr td').last().hasClass('first')); - assertFalse($(tableId).find('tbody tr td').last().hasClass('odd')); - assertTrue($(tableId).find('tbody tr td').last().hasClass('last')); - assertFalse($(tableId).find('tbody tr td').last().hasClass('even')); -}; - -DecoratorTest.prototype.testDecoratorDataList = function () { - /*:DOC +=
-
item
-
item
-
item
-
item
-
- */ - var listId = '#data-list'; - $(listId).decorate('dataList'); - assertTrue($(listId).find('dt').first().hasClass('odd')); - assertFalse($(listId).find('dt').first().hasClass('even')); - assertFalse($(listId).find('dt').first().hasClass('last')); - - assertTrue($(listId).find('dt').last().hasClass('even')); - assertFalse($(listId).find('dt').last().hasClass('odd')); - assertTrue($(listId).find('dt').last().hasClass('last')); - - assertTrue($(listId).find('dd').first().hasClass('odd')); - assertFalse($(listId).find('dd').first().hasClass('even')); - assertFalse($(listId).find('dd').first().hasClass('last')); - - assertTrue($(listId).find('dd').last().hasClass('even')); - assertFalse($(listId).find('dd').last().hasClass('odd')); - assertTrue($(listId).find('dd').last().hasClass('last')); -}; diff --git a/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js b/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js new file mode 100644 index 0000000000000..9b488c417674d --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js @@ -0,0 +1,202 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* eslint-disable max-nested-callbacks */ +define([ + 'mage/decorate', + 'jquery' +], function (decorate, $) { + 'use strict'; + + describe('mage/decorate', function () { + describe('"list" method', function () { + var listId = 'testList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check correct class decoration', function () { + var $list = $('#' + listId); + + $list.decorate('list'); + expect($list.find('li:first').hasClass('first')).toBe(false); + expect($list.find('li:first').hasClass('odd')).toBe(true); + expect($list.find('li:last').hasClass('last')).toBe(true); + expect($list.find('li:odd').hasClass('even')).toBe(true); + expect($list.find('li:even').hasClass('odd')).toBe(true); + }); + }); + + describe('"generic" method', function () { + var listId = 'testList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check correct class decoration with default params', function () { + var $list = $('#' + listId); + + $list.find('li').decorate('generic'); + expect($list.find('li:first').hasClass('first')).toBe(true); + expect($list.find('li:first').hasClass('odd')).toBe(true); + expect($list.find('li:last').hasClass('last')).toBe(true); + expect($list.find('li:odd').hasClass('even')).toBe(true); + expect($list.find('li:even').hasClass('odd')).toBe(true); + }); + + it('Check correct class decoration with custom params', function () { + var $list = $('#' + listId); + + $list.find('li').decorate('generic', ['last', 'first']); + expect($list.find('li:first').hasClass('first')).toBe(true); + expect($list.find('li:first').hasClass('odd')).toBe(false); + expect($list.find('li:last').hasClass('last')).toBe(true); + expect($list.find('li:odd').hasClass('even')).toBe(false); + expect($list.find('li:even').hasClass('odd')).toBe(false); + }); + + it('Check correct class decoration with empty items', function () { + var $list = $('#' + listId); + + $list.find('span').decorate('generic', ['last', 'first']); + expect($list.find('li:first').hasClass('first')).toBe(false); + expect($list.find('li:first').hasClass('odd')).toBe(false); + expect($list.find('li:last').hasClass('last')).toBe(false); + expect($list.find('li:odd').hasClass('even')).toBe(false); + expect($list.find('li:even').hasClass('odd')).toBe(false); + }); + }); + + describe('"table" method', function () { + var tableId = 'testTable'; + + beforeEach(function () { + var table = $('' + + '' + + '' + + '' + + '' + + '' + + '>' + + '' + + '
'); + + $('body').append(table); + }); + + afterEach(function () { + $('#' + tableId).remove(); + }); + + it('Check correct class decoration with default params', function () { + var $table = $('#' + tableId); + + $table.decorate('table'); + expect($table.find('tbody tr:first').hasClass('first')).toBe(true); + expect($table.find('tbody tr:first').hasClass('odd')).toBe(true); + expect($table.find('tbody tr:odd').hasClass('even')).toBe(true); + expect($table.find('tbody tr:even').hasClass('odd')).toBe(true); + expect($table.find('tbody tr:last').hasClass('last')).toBe(true); + expect($table.find('thead tr:first').hasClass('first')).toBe(true); + expect($table.find('thead tr:last').hasClass('last')).toBe(true); + expect($table.find('tfoot tr:first').hasClass('first')).toBe(true); + expect($table.find('tfoot tr:last').hasClass('last')).toBe(true); + expect($table.find('tr td:last').hasClass('last')).toBe(true); + expect($table.find('tr td:first').hasClass('first')).toBe(false); + }); + + it('Check correct class decoration with custom params', function () { + var $table = $('#' + tableId); + + $table.decorate('table', { + 'tbody': ['first'], + 'tbody tr': ['first'], + 'thead tr': ['first'], + 'tfoot tr': ['last'], + 'tr td': ['first'] + }); + expect($table.find('tbody:first').hasClass('first')).toBe(true); + expect($table.find('tbody tr:first').hasClass('first')).toBe(true); + expect($table.find('tbody tr:first').hasClass('odd')).toBe(false); + expect($table.find('tbody tr:odd').hasClass('even')).toBe(false); + expect($table.find('tbody tr:even').hasClass('odd')).toBe(false); + expect($table.find('tbody tr:last').hasClass('last')).toBe(false); + expect($table.find('thead tr:first').hasClass('first')).toBe(true); + expect($table.find('thead tr:last').hasClass('last')).toBe(false); + expect($table.find('tfoot tr:first').hasClass('first')).toBe(false); + expect($table.find('tfoot tr:last').hasClass('last')).toBe(true); + expect($table.find('tr td:last').hasClass('last')).toBe(false); + expect($table.find('tr td:first').hasClass('first')).toBe(true); + }); + }); + + describe('"dataList" method', function () { + var listId = 'testDataList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check correct class decoration', function () { + var $list = $('#' + listId); + + $list.decorate('dataList'); + expect($list.find('dt:first').hasClass('first')).toBe(false); + expect($list.find('dt:first').hasClass('odd')).toBe(true); + expect($list.find('dt:odd').hasClass('even')).toBe(true); + expect($list.find('dt:even').hasClass('odd')).toBe(true); + expect($list.find('dt:last').hasClass('last')).toBe(true); + expect($list.find('dd:first').hasClass('first')).toBe(false); + expect($list.find('dd:first').hasClass('odd')).toBe(true); + expect($list.find('dd:odd').hasClass('even')).toBe(true); + expect($list.find('dd:even').hasClass('odd')).toBe(true); + expect($list.find('dd:last').hasClass('last')).toBe(true); + }); + }); + + describe('Call decorate with fake method', function () { + var listId = 'testDataList'; + + beforeEach(function () { + var list = $('
'); + + $('body').append(list); + }); + + afterEach(function () { + $('#' + listId).remove(); + }); + + it('Check error message', function () { + var $list = $('#' + listId); + + spyOn(jQuery, 'error'); + $list.decorate('customMethod'); + + expect(jQuery.error).toHaveBeenCalledWith('Method customMethod does not exist on jQuery.decorate'); + }); + }); + }); +}); From 64bf208aea55998942fe2035a9679e1f470bed8d Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Wed, 22 Nov 2017 19:26:54 +0100 Subject: [PATCH 0063/1464] Eslint improvements and logical fixes for unit testing. --- .../js/jasmine/tests/lib/mage/accordion.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js index 12ca91a4ae002..19a54d95cf704 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/accordion.test.js @@ -10,7 +10,7 @@ define([ describe('Test for mage/accordion jQuery plugin', function () { it('check if accordion can be initialized', function () { - var accordion = $("
"); + var accordion = $('
'); accordion.accordion(); expect(accordion.is(':mage-accordion')).toBeTruthy(); @@ -50,12 +50,11 @@ define([ }); it('check multi-collapsible element accordion', function () { var accordion = $('
'), + title1 = $('
').appendTo(accordion), content1 = $('
').appendTo(accordion), title2 = $('
').appendTo(accordion), content2 = $('
').appendTo(accordion); - $('
').appendTo(accordion); - accordion.appendTo('body'); accordion.accordion({ @@ -63,17 +62,18 @@ define([ }); expect(accordion.is(':mage-accordion')).toBeTruthy(); - expect(content1.is(':visible')).toBeTruthy(); expect(content2.is(':hidden')).toBeTruthy(); - title2.trigger('click'); + $(title1).trigger('click'); + expect(content1.is(':visible')).toBeTruthy(); + expect(content2.is(':hidden')).toBeTruthy(); + $(title2).trigger('click'); expect(content1.is(':visible')).toBeTruthy(); expect(content2.is(':visible')).toBeTruthy(); accordion.accordion('destroy'); - expect(accordion.is(':mage-accordion')).toBeFalsy(); }); }); From 8595da68070577bea09a342f68711f90e059fe6a Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko Date: Wed, 22 Nov 2017 21:02:10 +0200 Subject: [PATCH 0064/1464] Fix decorate.test.js --- dev/tests/js/jasmine/tests/lib/mage/decorate.test.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js b/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js index 9b488c417674d..898bcf8b51128 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/decorate.test.js @@ -192,10 +192,9 @@ define([ it('Check error message', function () { var $list = $('#' + listId); - spyOn(jQuery, 'error'); + spyOn($, 'error'); $list.decorate('customMethod'); - - expect(jQuery.error).toHaveBeenCalledWith('Method customMethod does not exist on jQuery.decorate'); + expect($.error).toHaveBeenCalledWith('Method customMethod does not exist on jQuery.decorate'); }); }); }); From b860e02a353974274663de380322ebf24a506f76 Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Thu, 23 Nov 2017 11:19:36 +0200 Subject: [PATCH 0065/1464] MAGETWO-83343 Customer shopping cart not accessible in admin order --- .../Test/Unit/Model/AdminOrder/CreateTest.php | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php index 9ea148649f51b..22ed48aacfd2a 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php @@ -26,6 +26,7 @@ use Magento\Quote\Model\Quote\Item\Updater; use Magento\Sales\Model\AdminOrder\Create; use Magento\Sales\Model\AdminOrder\Product; +use Magento\Quote\Model\QuoteFactory; use PHPUnit_Framework_MockObject_MockObject as MockObject; /** @@ -46,6 +47,11 @@ class CreateTest extends \PHPUnit\Framework\TestCase */ private $quoteRepository; + /** + * @var \Magento\Quote\Model\QuoteFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $quoteFactory; + /** * @var SessionQuote|MockObject */ @@ -84,6 +90,7 @@ class CreateTest extends \PHPUnit\Framework\TestCase protected function setUp() { $this->formFactory = $this->createPartialMock(FormFactory::class, ['create']); + $this->quoteFactory = $this->createPartialMock(QuoteFactory::class, ['create']); $this->customerFactory = $this->createPartialMock(CustomerInterfaceFactory::class, ['create']); $this->itemUpdater = $this->createMock(Updater::class); @@ -120,6 +127,7 @@ protected function setUp() 'customerMapper' => $this->customerMapper, 'dataObjectHelper' => $this->dataObjectHelper, 'quoteRepository' => $this->quoteRepository, + 'quoteFactory' => $this->quoteFactory, ] ); } @@ -284,9 +292,29 @@ public function testApplyCoupon() public function testGetCustomerCart() { - $this->sessionQuote->expects($this->once())->method('getStoreId')->willReturn(2); - $this->sessionQuote->expects($this->once())->method('getCustomerId')->willReturn(2); - $this->quoteRepository->expects($this->once())->method('getForCustomer')->with(2, [2]); - $this->adminOrderCreate->getCustomerCart(); + $storeId = 2; + $customerId = 2; + $cartResult = [ + 'cart' => true + ]; + + $this->quoteFactory->expects($this->once()) + ->method('create'); + + $this->sessionQuote->expects($this->once()) + ->method('getStoreId') + ->willReturn($storeId); + + $this->sessionQuote->expects($this->once()) + ->method('getCustomerId') + ->willReturn($customerId); + + $this->quoteRepository->expects($this->once()) + ->method('getForCustomer') + ->with($customerId, [$storeId]) + ->willReturn($cartResult); + + $cart = $this->adminOrderCreate->getCustomerCart(); + $this->assertEquals($cart, $cartResult); } } From 420f8389dfc217abf7b295566b2797c34198d8da Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Thu, 23 Nov 2017 11:41:48 +0200 Subject: [PATCH 0066/1464] MAGETWO-83343 Customer shopping cart not accessible in admin order --- .../Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php index 22ed48aacfd2a..fc2341b02e94a 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/AdminOrder/CreateTest.php @@ -314,7 +314,6 @@ public function testGetCustomerCart() ->with($customerId, [$storeId]) ->willReturn($cartResult); - $cart = $this->adminOrderCreate->getCustomerCart(); - $this->assertEquals($cart, $cartResult); + $this->assertEquals($cartResult, $this->adminOrderCreate->getCustomerCart()); } } From 3202e941adcde6cc3aadd4494cc680210c47aa64 Mon Sep 17 00:00:00 2001 From: alojua Date: Thu, 23 Nov 2017 11:13:42 +0100 Subject: [PATCH 0067/1464] Add argument on app:config:dump to specify which types to dump. That allows to dump only scope and theme while skipping system for easier maintainability. --- .../Command/App/ApplicationDumpCommand.php | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php index 9d13c97790fa4..c3492019455f2 100644 --- a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php +++ b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php @@ -12,6 +12,7 @@ use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Console\Cli; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -20,6 +21,18 @@ */ class ApplicationDumpCommand extends Command { + const INPUT_CONFIG_TYPES = 'config-types'; + + /** + * @var array + */ + private $configTypes = [ + \Magento\Store\App\Config\Type\Scopes::CONFIG_TYPE, + \Magento\Deploy\Source\Themes::TYPE, + \Magento\Translation\App\Config\Type\Translation::CONFIG_TYPE, + \Magento\Config\App\Config\Type\System::CONFIG_TYPE, + ]; + /** * @var Writer */ @@ -60,6 +73,12 @@ protected function configure() { $this->setName('app:config:dump'); $this->setDescription('Create dump of application'); + $this->addArgument( + self::INPUT_CONFIG_TYPES, + InputArgument::OPTIONAL | InputArgument::IS_ARRAY, + sprintf('Space-separated list of config types or omit to dump all [%s]', + implode(', ', $this->configTypes)) + ); parent::configure(); } @@ -74,11 +93,14 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { $this->groupSourcesByPool(); - + $dumpedTypes = []; foreach ($this->sources as $pool => $sources) { $dump = []; $comments = []; foreach ($sources as $sourceData) { + if ($this->skipDump($input, $sourceData)) { + continue; + } /** @var ConfigSourceInterface $source */ $source = $sourceData['source']; $namespace = $sourceData['namespace']; @@ -95,15 +117,21 @@ protected function execute(InputInterface $input, OutputInterface $output) null, $comments ); + $dumpedTypes = array_unique($dumpedTypes + array_keys($dump)); if (!empty($comments)) { $output->writeln($comments); } } + if (!$dumpedTypes) { + $output->writeln('Nothing dumped. Check the config types specified and try again'); + return Cli::RETURN_FAILURE; + } + // Generate and save new hash of deployment configuration. $this->configHash->regenerate(); - $output->writeln('Done.'); + $output->writeln(sprintf('Done. Config types dumped: %s', implode(', ', $dumpedTypes))); return Cli::RETURN_SUCCESS; } @@ -127,4 +155,20 @@ private function groupSourcesByPool() $this->sources = $sources; } + + /** + * Check whether the dump source should be skipped + * + * @param InputInterface $input + * @param array $sourceData + * @return bool + */ + private function skipDump(InputInterface $input, array $sourceData): bool + { + $allowedTypes = $input->getArgument(self::INPUT_CONFIG_TYPES); + if ($allowedTypes && !in_array($sourceData['namespace'], $allowedTypes)) { + return true; + } + return false; + } } From 2adf9e8634b4336002d2bcc39e22ffe0387239d4 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Thu, 23 Nov 2017 17:19:58 +0100 Subject: [PATCH 0068/1464] Fixed unsafe comparison with a literal. No need to eslint eqeqeq. Fixed enable method. It was not enabling and activating the collapsible. This was detected on Jasmine unit testing. Minor repositioning to this.options.disabled on disable method for consistency purposes with enable method. --- lib/web/mage/collapsible.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/web/mage/collapsible.js b/lib/web/mage/collapsible.js index 0d8cf836c198e..49624fbeb159a 100644 --- a/lib/web/mage/collapsible.js +++ b/lib/web/mage/collapsible.js @@ -243,7 +243,7 @@ define([ }); // For collapsible widget only (not tabs or accordion) - if (this.header.parent().attr('role') != 'presentation') { //eslint-disable-line eqeqeq + if (this.header.parent().attr('role') !== 'presentation') { this.header .parent() .attr('role', 'tablist'); @@ -316,9 +316,9 @@ define([ * Disable. */ disable: function () { + this.options.disabled = true; this._off(this.trigger); this.forceDeactivate(); - this.options.disabled = true; if (this.options.disabledState) { this.element.addClass(this.options.disabledState); @@ -330,12 +330,14 @@ define([ * Enable. */ enable: function () { - this._on(this.trigger, this.events); this.options.disabled = false; + this._on(this.trigger, this.events); + this.forceActivate(); if (this.options.disabledState) { this.element.removeClass(this.options.disabledState); } + this.trigger.attr('tabIndex', 0); }, /** From 9b28fe25ec7da23e5c1e75499e2984e3019289f2 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Thu, 23 Nov 2017 18:13:38 +0100 Subject: [PATCH 0069/1464] that - this consistency and splat complete function to be Jasmine friendly. --- lib/web/mage/collapsible.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/web/mage/collapsible.js b/lib/web/mage/collapsible.js index 49624fbeb159a..267734605f141 100644 --- a/lib/web/mage/collapsible.js +++ b/lib/web/mage/collapsible.js @@ -519,7 +519,7 @@ define([ that = this; if (url) { - this.xhr = $.get({ + that.xhr = $.get({ url: url, dataType: 'html' }, function () { @@ -535,7 +535,8 @@ define([ setTimeout(function () { that.content.html(response); }, 1); - }).complete(function (jqXHR, status) { + }); + that.xhr.complete(function (jqXHR, status) { setTimeout(function () { if (status === 'abort') { that.content.stop(false, true); From 4127a8c6bc8b0a7fd4e071ea4f2ea42ee92d5622 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Thu, 23 Nov 2017 18:14:49 +0100 Subject: [PATCH 0070/1464] Added collapsible.test.js and removed JsTestDriver equivalent. --- .../testsuite/mage/collapsible/content.html | 14 - .../testsuite/mage/collapsible/index.html | 31 --- .../mage/collapsible/test-collapsible.js | 180 ------------- .../tests/lib/mage/collapsible.test.js | 247 ++++++++++++++++++ 4 files changed, 247 insertions(+), 225 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js create mode 100644 dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html deleted file mode 100644 index e81938dfbeaba..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/content.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - -

Test text

- - diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html deleted file mode 100644 index ccfd4d97f0331..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - Unit test - - - - - - - - - - - -
-
-
- - - diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js b/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js deleted file mode 100644 index 1a22e5a79eb1d..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/collapsible/test-collapsible.js +++ /dev/null @@ -1,180 +0,0 @@ -/** - * @category mage.collapsible - * @package test - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -/* - Test if the collapsible widget gets initialized when is called and destroy function works - */ -test('initialization & destroy', function() { - expect(2); - var group = $('
'); - group.collapsible(); - ok( group.is(':mage-collapsible'), "widget instantiated" ); - group.collapsible('destroy'); - ok( !group.is(':mage-collapsible'), "widget destroyed" ); -}); - -/* - Test enable, disable, activate, deactivate functions - */ -test('Enable, disable, activate, deactivate methods', function() { - expect(5); - var group = $('
'); - var title = $('
'); - var content = $('
'); - title.appendTo(group); - content.appendTo(group); - group.appendTo("body"); - group.collapsible(); - group.collapsible("deactivate"); - ok(content.is(':hidden'), "Content is collapsed"); - group.collapsible("activate"); - ok(content.is(':visible'), "Content is expanded"); - group.collapsible("disable"); - ok(content.is(':hidden'), "Content is collapsed"); - group.collapsible("activate"); - ok(content.is(':hidden'), "Content is collapsed"); - group.collapsible("enable"); - group.collapsible("activate"); - ok(content.is(':visible'), "Content is expanded"); - group.collapsible('destroy'); -}); - -/* - Test if the widget gets expanded/collapsed when the title is clicked - */ -test('Collapse and expand', function() { - expect(3); - var group = $('
'); - var title = $('
'); - var content = $('
'); - title.appendTo(group); - content.appendTo(group); - group.appendTo("body"); - group.collapsible(); - group.collapsible("deactivate"); - ok(content.is(':hidden'), "Content is collapsed"); - title.trigger("click"); - ok(content.is(':visible'), "Content gets expanded on click title"); - title.trigger("click"); - ok(content.is(':hidden'), "Content gets collapsed on click again"); - group.collapsible('destroy'); -}); - - -/* - Test state Classes - */ -test('State classes', function() { - expect(3); - var group = $('
'); - var title = $('
'); - var content = $('
'); - title.appendTo(group); - content.appendTo(group); - group.collapsible({openedState:"opened", closedState:"closed", disabledState:"disabled"}); - ok( group.hasClass("closed")); - title.trigger("click"); - ok( group.hasClass("opened")); - group.collapsible("disable"); - ok( group.hasClass("disabled")); - group.collapsible('destroy'); -}); - -/* - Test if icons are added to title when widget gets initialized and are removed when gets destroyed - */ -test('Create & destroy icons', function() { - expect(2); - var group = $('
'); - var title = $('
'); - var content = $('
'); - title.appendTo(group); - content.appendTo(group); - group.collapsible({icons: {header:"minus",activeHeader:"plus"}}); - ok(title.children("[data-role=icons]").length, "Icons added to title" ); - group.collapsible('destroy'); - ok(!title.children("[data-role=icons]").length, "Icons removed from title" ); -}); - -/* - Test if icon classes are changed when content gets expanded/collapsed - */ -test('Change icons when content gets expanded/collapsed', function() { - expect(2); - var group = $('
'); - var title = $('
'); - var content = $('
'); - title.appendTo(group); - content.appendTo(group); - group.collapsible({icons: {header:"minus",activeHeader:"plus"}}); - group.collapsible("deactivate"); - var icons = group.collapsible("option","icons"); - ok(title.children("[data-role=icons]").hasClass(icons.header), "When content is collapsed,header has the right class for icons" ); - title.trigger("click"); - ok(title.children("[data-role=icons]").hasClass(icons.activeHeader), "When content is expanded,header has the right class for icons" ); - group.collapsible('destroy'); -}); - - -/* - Test if content gets expanded/collapsed when certain keys are pressed - */ -asyncTest( "keyboard support", function() { - - expect( 5 ); - var group = $('
'); - var title = $('
'); - var content = $('
'); - title.appendTo(group); - content.appendTo(group); - group.appendTo("body"); - group.collapsible(); - group.collapsible("deactivate"); - - title.on("focus",function(ev){ - ok(content.is(':hidden'), "Content is collapsed"); - title.trigger($.Event( 'keydown', { keyCode: $.ui.keyCode.ENTER } )); - ok(content.is(':visible'), "Content is expanded"); - title.trigger($.Event( 'keydown', { keyCode: $.ui.keyCode.ENTER } )); - ok(content.is(':hidden'), "Content is collapsed"); - title.trigger($.Event( 'keydown', { keyCode: $.ui.keyCode.SPACE } )); - ok(content.is(':visible'), "Content is expanded"); - title.trigger($.Event( 'keydown', { keyCode: $.ui.keyCode.SPACE } )); - ok(content.is(':hidden'), "Content is collapsed"); - group.collapsible('destroy'); - start(); - } ); - - setTimeout(function(){ - title.focus(); - },10); - -}); - -/* - Test if content gets updated via Ajax when title is clicked - */ -test('Update content via ajax', function() { - expect(2); - var group = $('
'); - var title = $('
'); - var content = $('
'); - var ajax = $(''); - title.appendTo(group); - content.appendTo(group); - ajax.appendTo(content); - group.appendTo("body"); - group.collapsible({ajaxContent : true}); - group.collapsible("deactivate"); - ok(!content.children("p").length, "Content has no data"); - title.trigger("click"); - ok(content.children("p"), "Content gets data from content.html"); - group.collapsible('destroy'); -}); - - - diff --git a/dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js b/dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js new file mode 100644 index 0000000000000..8bb8cd1cafe78 --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js @@ -0,0 +1,247 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/* eslint-disable max-nested-callbacks */ + +define([ + 'jquery', + 'jquery/ui', + 'mage/collapsible' +], function ($) { + 'use strict'; + + describe('Test for mage/collapsible jQuery plugin', function () { + it('check if collapsible can be initialized and destroyed', function () { + var group = $('
'); + + group.collapsible(); + expect(group.is(':mage-collapsible')).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + + describe('Test enable, disable, activate and deactivate methods', function () { + var group = $('
'), + content = $('
').appendTo(group); + + $('
').prependTo(group); + + beforeEach(function () { + group.appendTo('body'); + }); + + afterEach(function () { + group.remove(); + }); + + it('check enable and disable methods', function () { + group.collapsible(); + expect(group.is(':mage-collapsible')).toBeTruthy(); + + group.collapsible('disable'); + expect(content.is(':hidden')).toBeTruthy(); + + group.collapsible('enable'); + expect(content.is(':visible')).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + + it('check activate and deactivate methods', function () { + group.collapsible(); + expect(group.is(':mage-collapsible')).toBeTruthy(); + + group.collapsible('deactivate'); + expect(content.is(':hidden')).toBeTruthy(); + + group.collapsible('activate'); + expect(content.is(':visible')).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + }); + + it('check if the widget gets expanded/collapsed when the title is clicked', function () { + var group = $('
'), + title = $('
').appendTo(group), + content = $('
').appendTo(group); + + group.appendTo('body'); + + group.collapsible(); + expect(group.is(':mage-collapsible')).toBeTruthy(); + + group.collapsible('deactivate'); + expect(content.is(':hidden')).toBeTruthy(); + + title.trigger('click'); + expect(content.is(':visible')).toBeTruthy(); + + title.trigger('click'); + expect(content.is(':hidden')).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + + it('check state classes', function () { + var group = $('
'), + title = $('
').appendTo(group); + + $('
').appendTo(group); + + group.appendTo('body'); + + group.collapsible({ + openedState: 'opened', + closedState: 'closed', + disabledState: 'disabled' + }); + expect(group.is(':mage-collapsible')).toBeTruthy(); + expect(group.hasClass('closed')).toBeTruthy(); + + title.trigger('click'); + expect(group.hasClass('opened')).toBeTruthy(); + + group.collapsible('disable'); + expect(group.hasClass('disabled')).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + + it('check if icons are added to title when initialized and removed when destroyed', function () { + var group = $('
'), + title = $('
').appendTo(group); + + $('
').appendTo(group); + + group.appendTo('body'); + + group.collapsible({ + icons: { + header: 'minus', + activeHeader: 'plus' + } + }); + expect(group.is(':mage-collapsible')).toBeTruthy(); + expect(title.children('[data-role=icons]').length).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + expect(title.children('[data-role=icons]').length).toBeFalsy(); + }); + + it('check if icon classes are changed when content gets expanded/collapsed', function () { + var group = $('
'), + title = $('
').appendTo(group), + content = $('
').appendTo(group), + icons; + + group.appendTo('body'); + + group.collapsible({ + icons: { + header: 'minus', + activeHeader: 'plus' + } + }); + expect(group.is(':mage-collapsible')).toBeTruthy(); + + icons = group.collapsible('option', 'icons'); + group.collapsible('deactivate'); + expect(content.is(':hidden')).toBeTruthy(); + expect(title.children('[data-role=icons]').hasClass(icons.header)).toBeTruthy(); + + title.trigger('click'); + expect(title.children('[data-role=icons]').hasClass(icons.activeHeader)).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + + it('check keyboard support', function () { + var group = $('
'), + title = $('
').appendTo(group), + content = $('
').appendTo(group); + + group.appendTo('body'); + + group.collapsible(); + expect(group.is(':mage-collapsible')).toBeTruthy(); + + group.collapsible('deactivate'); + expect(content.is(':hidden')).toBeTruthy(); + + title.on('focus', function () { + title.trigger($.Event('keydown', { + keyCode: $.ui.keyCode.ENTER + })); + expect(content.is(':visible')).toBeTruthy(); + + title.trigger($.Event('keydown', { + keyCode: $.ui.keyCode.ENTER + })); + expect(content.is(':hidden')).toBeTruthy(); + + title.trigger($.Event('keydown', { + keyCode: $.ui.keyCode.SPACE + })); + expect(content.is(':visible')).toBeTruthy(); + + title.trigger($.Event('keydown', { + keyCode: $.ui.keyCode.SPACE + })); + expect(content.is(':hidden')).toBeTruthy(); + }); + + setTimeout(function () { + title.focus(); + }, 10); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + + it('check if content gets updated via Ajax when title is clicked', function () { + var group = $('
'), + title = $('
').appendTo(group), + content = $('
').appendTo(group); + + $('').appendTo(group); + + $.get = jasmine.createSpy().and.callFake(function () { + var d = $.Deferred(); + + d.promise().success = function () { + }; + + d.promise().complete = function () { + }; + + return d.promise(); + }); + + group.appendTo('body'); + + group.collapsible({ + ajaxContent: true + }); + expect(group.is(':mage-collapsible')).toBeTruthy(); + + group.collapsible('deactivate'); + expect(content.is(':hidden')).toBeTruthy(); + expect(content.children('p').length).toBeFalsy(); + + title.trigger('click'); + expect(content.children('p')).toBeTruthy(); + + group.collapsible('destroy'); + expect(group.is(':mage-collapsible')).toBeFalsy(); + }); + }); +}); From 6366f83500d2a3645d0bc0577201fc655c952abd Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Thu, 23 Nov 2017 20:49:36 +0100 Subject: [PATCH 0071/1464] jscs:disable jsDoc --- dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js b/dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js index 8bb8cd1cafe78..fb1518442c87d 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/collapsible.test.js @@ -3,6 +3,7 @@ * See COPYING.txt for license details. */ /* eslint-disable max-nested-callbacks */ +/* jscs:disable jsDoc */ define([ 'jquery', From ddf07f27309260c7d0b32843513c282a852b95dc Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Fri, 24 Nov 2017 09:15:23 +0100 Subject: [PATCH 0072/1464] 12178 Refactor config:set command to use --lock-config instead of --share option We are using Virtual Classes now as we have almost the same Processor twice and we can avoid having duplicate code this way. --- .../ConfigSet/ConfigSetProcessorFactory.php | 4 +- .../Command/ConfigSet/DefaultProcessor.php | 2 +- .../Command/ConfigSet/LockProcessor.php | 11 +- .../Command/ConfigSet/ProcessorFacade.php | 33 +++--- .../Command/ConfigSet/ShareProcessor.php | 109 ------------------ .../Console/Command/ConfigSetCommand.php | 32 +++-- app/code/Magento/Config/etc/di.xml | 14 ++- 7 files changed, 65 insertions(+), 140 deletions(-) delete mode 100644 app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php index 2fc3374859ba6..a9618f93afc73 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php @@ -27,8 +27,8 @@ class ConfigSetProcessorFactory * lock - save and lock configuration */ const TYPE_DEFAULT = 'default'; - const TYPE_LOCK = 'lock'; - const TYPE_SHARE = 'share'; + const TYPE_LOCK_ENV = 'lock-env'; + const TYPE_LOCK_CONFIG = 'lock-config'; /**#@-*/ /**#@-*/ diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php index 2f5c10037ef06..d7d513bfad423 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php @@ -72,7 +72,7 @@ public function process($path, $value, $scope, $scopeCode) throw new CouldNotSaveException( __( 'The value you set has already been locked. To change the value, use the --%1 option.', - ConfigSetCommand::OPTION_LOCK + ConfigSetCommand::OPTION_LOCK_ENV ) ); } diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php index 9e39b7bf7bf40..6fe2adde3c41e 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php @@ -50,23 +50,30 @@ class LockProcessor implements ConfigSetProcessorInterface * @var ConfigPathResolver */ private $configPathResolver; + /** + * @var string + */ + private $target; /** * @param PreparedValueFactory $preparedValueFactory The factory for prepared value * @param DeploymentConfig\Writer $writer The deployment configuration writer * @param ArrayManager $arrayManager An array manager for different manipulations with arrays * @param ConfigPathResolver $configPathResolver The resolver for configuration paths according to source type + * @param string $target */ public function __construct( PreparedValueFactory $preparedValueFactory, DeploymentConfig\Writer $writer, ArrayManager $arrayManager, - ConfigPathResolver $configPathResolver + ConfigPathResolver $configPathResolver, + $target = ConfigFilePool::APP_ENV ) { $this->preparedValueFactory = $preparedValueFactory; $this->deploymentConfigWriter = $writer; $this->arrayManager = $arrayManager; $this->configPathResolver = $configPathResolver; + $this->target = $target; } /** @@ -98,7 +105,7 @@ public function process($path, $value, $scope, $scopeCode) * we'll write value just after all validations are triggered. */ $this->deploymentConfigWriter->saveConfig( - [ConfigFilePool::APP_ENV => $this->arrayManager->set($configPath, [], $value)], + [$this->target => $this->arrayManager->set($configPath, [], $value)], false ); } diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php b/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php index 4b202538b3701..b2076396d7487 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php @@ -9,6 +9,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Scope\ValidatorInterface; use Magento\Config\Model\Config\PathValidator; +use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\ConfigurationMismatchException; use Magento\Framework\Exception\CouldNotSaveException; @@ -96,14 +97,13 @@ public function __construct( * @param string $scope The configuration scope (default, website, or store) * @param string $scopeCode The scope code * @param boolean $lock The lock flag - * @param boolean $share The share flag + * @param string $lockTarget * @return string Processor response message * @throws ValidatorException If some validation is wrong - * @throws CouldNotSaveException If cannot save config value - * @throws ConfigurationMismatchException If processor can not be instantiated + * @internal param bool $share The share flag * @since 100.2.0 */ - public function process($path, $value, $scope, $scopeCode, $lock, $share = false) + public function process($path, $value, $scope, $scopeCode, $lock, $lockTarget = ConfigFilePool::APP_ENV) { try { $this->scopeValidator->isValid($scope, $scopeCode); @@ -113,22 +113,21 @@ public function process($path, $value, $scope, $scopeCode, $lock, $share = false } $processor = - $share - ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_SHARE) - : ( - $lock - ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK) + $lock + ? ( $lockTarget == ConfigFilePool::APP_ENV + ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK_ENV) + : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK_CONFIG) + ) : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT) - ); + ; $message = - $share - ? 'Value was saved in app/etc/config.php and locked.' - : ( - $lock - ? 'Value was saved in app/etc/env.php and locked.' - : 'Value was saved.' - ); + $lock + ? ( $lockTarget == ConfigFilePool::APP_ENV + ? 'Value was saved in app/etc/env.php and locked.' + : 'Value was saved in app/etc/config.php and locked.' + ) + : 'Value was saved.'; // The processing flow depends on --lock and --share options. $processor->process($path, $value, $scope, $scopeCode); diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php deleted file mode 100644 index c1b004a62a730..0000000000000 --- a/app/code/Magento/Config/Console/Command/ConfigSet/ShareProcessor.php +++ /dev/null @@ -1,109 +0,0 @@ -preparedValueFactory = $preparedValueFactory; - $this->deploymentConfigWriter = $writer; - $this->arrayManager = $arrayManager; - $this->configPathResolver = $configPathResolver; - } - - /** - * Processes lock flow of config:set command. - * Requires read access to filesystem. - * - * {@inheritdoc} - */ - public function process($path, $value, $scope, $scopeCode) - { - try { - $configPath = $this->configPathResolver->resolve($path, $scope, $scopeCode, System::CONFIG_TYPE); - $backendModel = $this->preparedValueFactory->create($path, $value, $scope, $scopeCode); - - if ($backendModel instanceof Value) { - /** - * Temporary solution until Magento introduce unified interface - * for storing system configuration into database and configuration files. - */ - $backendModel->validateBeforeSave(); - $backendModel->beforeSave(); - - $value = $backendModel->getValue(); - - $backendModel->afterSave(); - - /** - * Because FS does not support transactions, - * we'll write value just after all validations are triggered. - */ - $this->deploymentConfigWriter->saveConfig( - [ConfigFilePool::APP_CONFIG => $this->arrayManager->set($configPath, [], $value)], - false - ); - } - } catch (\Exception $exception) { - throw new CouldNotSaveException(__('%1', $exception->getMessage()), $exception); - } - } -} diff --git a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php index 2b96164b1a766..b257041ac8259 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php +++ b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php @@ -10,6 +10,7 @@ use Magento\Deploy\Model\DeploymentConfig\ChangeDetector; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Console\Cli; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -34,7 +35,8 @@ class ConfigSetCommand extends Command const OPTION_SCOPE = 'scope'; const OPTION_SCOPE_CODE = 'scope-code'; const OPTION_LOCK = 'lock'; - const OPTION_SHARE = 'share'; + const OPTION_LOCK_ENV = 'lock-env'; + const OPTION_LOCK_CONFIG = 'lock-config'; /**#@-*/ /**#@-*/ @@ -110,17 +112,23 @@ protected function configure() 'Scope code (required only if scope is not \'default\')' ), new InputOption( - static::OPTION_LOCK, - 'l', + static::OPTION_LOCK_ENV, + 'le', InputOption::VALUE_NONE, 'Lock value which prevents modification in the Admin (will be saved in app/etc/env.php)' ), new InputOption( - static::OPTION_SHARE, - 's', + static::OPTION_LOCK_CONFIG, + 'lc', InputOption::VALUE_NONE, 'Lock and share value with other installations, prevents modification in the Admin (will be saved in app/etc/config.php)' ), + new InputOption( + static::OPTION_LOCK, + 'l', + InputOption::VALUE_NONE, + 'Deprecated, use the --' . static::OPTION_LOCK_ENV . ' option instead.' + ), ]); parent::configure(); @@ -153,13 +161,23 @@ protected function execute(InputInterface $input, OutputInterface $output) try { $message = $this->emulatedAreaProcessor->process(function () use ($input) { + + $lock = $input->getOption(static::OPTION_LOCK_ENV) + || $input->getOption(static::OPTION_LOCK_CONFIG) + || $input->getOption(static::OPTION_LOCK); + + $lockTargetPath = ConfigFilePool::APP_ENV; + if ($input->getOption(static::OPTION_LOCK_CONFIG)) { + $lockTargetPath = ConfigFilePool::APP_CONFIG; + } + return $this->processorFacadeFactory->create()->process( $input->getArgument(static::ARG_PATH), $input->getArgument(static::ARG_VALUE), $input->getOption(static::OPTION_SCOPE), $input->getOption(static::OPTION_SCOPE_CODE), - $input->getOption(static::OPTION_LOCK), - $input->getOption(static::OPTION_SHARE) + $lock, + $lockTargetPath ); }); diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml index dcd2b255ba338..a5dd18097fb47 100644 --- a/app/code/Magento/Config/etc/di.xml +++ b/app/code/Magento/Config/etc/di.xml @@ -296,11 +296,21 @@ Magento\Config\Console\Command\ConfigSet\DefaultProcessor - Magento\Config\Console\Command\ConfigSet\LockProcessor - Magento\Config\Console\Command\ConfigSet\ShareProcessor + Magento\Config\Console\Command\ConfigSet\VirtualLockEnvProcessor + Magento\Config\Console\Command\ConfigSet\VirtualLockConfigProcessor + + + app_env + + + + + app_config + + From f583c875ae2a3e26e0654d780629749e35b04a7c Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Fri, 24 Nov 2017 09:31:18 +0100 Subject: [PATCH 0073/1464] 12178 Adjust unit tests --- .../ConfigSet/ConfigSetProcessorFactoryTest.php | 4 ++-- .../Command/ConfigSet/DefaultProcessorTest.php | 2 +- ...eProcessorTest.php => LockConfigProcessorTest.php} | 11 ++++++----- ...LockProcessorTest.php => LockEnvProcessorTest.php} | 5 +++-- .../Console/Command/ConfigSet/ProcessorFacadeTest.php | 11 ++++++----- 5 files changed, 18 insertions(+), 15 deletions(-) rename app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/{ShareProcessorTest.php => LockConfigProcessorTest.php} (96%) rename app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/{LockProcessorTest.php => LockEnvProcessorTest.php} (98%) diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php index 1fa0310ca62eb..a8f40106eb564 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php @@ -40,7 +40,7 @@ protected function setUp() $this->model = new ConfigSetProcessorFactory( $this->objectManagerMock, [ - ConfigSetProcessorFactory::TYPE_LOCK => LockProcessor::class, + ConfigSetProcessorFactory::TYPE_LOCK_ENV => LockProcessor::class, ConfigSetProcessorFactory::TYPE_DEFAULT => DefaultProcessor::class, 'wrongType' => \stdClass::class, ] @@ -58,7 +58,7 @@ public function testCreate() $this->assertInstanceOf( ConfigSetProcessorInterface::class, - $this->model->create(ConfigSetProcessorFactory::TYPE_LOCK) + $this->model->create(ConfigSetProcessorFactory::TYPE_LOCK_ENV) ); } diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php index 066b0fbe84b50..c4550a4e5ad3c 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php @@ -166,7 +166,7 @@ private function configMockForProcessTest($path, $scope, $scopeCode) /** * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage The value you set has already been locked. To change the value, use the --lock option. + * @expectedExceptionMessage The value you set has already been locked. To change the value, use the --lock-env option. */ public function testProcessLockedValue() { diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ShareProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockConfigProcessorTest.php similarity index 96% rename from app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ShareProcessorTest.php rename to app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockConfigProcessorTest.php index 8a93ce5cf4940..c727184efb4fc 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ShareProcessorTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockConfigProcessorTest.php @@ -5,7 +5,7 @@ */ namespace Magento\Config\Test\Unit\Console\Command\ConfigSet; -use Magento\Config\Console\Command\ConfigSet\ShareProcessor; +use Magento\Config\Console\Command\ConfigSet\LockProcessor; use Magento\Config\Model\PreparedValueFactory; use Magento\Framework\App\Config\ConfigPathResolver; use Magento\Framework\App\Config\ScopeConfigInterface; @@ -23,10 +23,10 @@ * @see ShareProcessor * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ShareProcessorTest extends \PHPUnit\Framework\TestCase +class LockConfigProcessorTest extends \PHPUnit\Framework\TestCase { /** - * @var ShareProcessor + * @var LockProcessor */ private $model; @@ -77,11 +77,12 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->model = new ShareProcessor( + $this->model = new LockProcessor( $this->preparedValueFactory, $this->deploymentConfigWriterMock, $this->arrayManagerMock, - $this->configPathResolver + $this->configPathResolver, + ConfigFilePool::APP_CONFIG ); } diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockEnvProcessorTest.php similarity index 98% rename from app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php rename to app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockEnvProcessorTest.php index 4535e9ad888c2..4e0248f886028 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockEnvProcessorTest.php @@ -23,7 +23,7 @@ * @see LockProcessor * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class LockProcessorTest extends \PHPUnit\Framework\TestCase +class LockEnvProcessorTest extends \PHPUnit\Framework\TestCase { /** * @var LockProcessor @@ -81,7 +81,8 @@ protected function setUp() $this->preparedValueFactory, $this->deploymentConfigWriterMock, $this->arrayManagerMock, - $this->configPathResolver + $this->configPathResolver, + ConfigFilePool::APP_ENV ); } diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php index 51318a8e303ca..6f7cbbef2ce18 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php @@ -11,6 +11,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Scope\ValidatorInterface; use Magento\Config\Model\Config\PathValidator; +use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\ValidatorException; use Magento\Framework\Exception\CouldNotSaveException; @@ -201,14 +202,14 @@ public function testProcessWithCouldNotSaveException() $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, false); } - public function testExecuteLock() + public function testExecuteLockEnv() { $this->scopeValidatorMock->expects($this->once()) ->method('isValid') ->willReturn(true); $this->configSetProcessorFactoryMock->expects($this->once()) ->method('create') - ->with(ConfigSetProcessorFactory::TYPE_LOCK) + ->with(ConfigSetProcessorFactory::TYPE_LOCK_ENV) ->willReturn($this->processorMock); $this->processorMock->expects($this->once()) ->method('process') @@ -222,14 +223,14 @@ public function testExecuteLock() ); } - public function testExecuteShare() + public function testExecuteLockConfig() { $this->scopeValidatorMock->expects($this->once()) ->method('isValid') ->willReturn(true); $this->configSetProcessorFactoryMock->expects($this->once()) ->method('create') - ->with(ConfigSetProcessorFactory::TYPE_SHARE) + ->with(ConfigSetProcessorFactory::TYPE_LOCK_CONFIG) ->willReturn($this->processorMock); $this->processorMock->expects($this->once()) ->method('process') @@ -239,7 +240,7 @@ public function testExecuteShare() $this->assertSame( 'Value was saved in app/etc/config.php and locked.', - $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, false, true) + $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, true, ConfigFilePool::APP_CONFIG) ); } } From 2fabcaf397fdf250d9f9bfd530117225ce81c8c9 Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Fri, 24 Nov 2017 09:42:41 +0100 Subject: [PATCH 0074/1464] 12178 Adjust integration tests --- .../Console/Command/ConfigSetCommandTest.php | 14 +++++++------- .../Developer/Model/Logger/Handler/DebugTest.php | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php index 91e8cbe1cad73..3f333a36c9c93 100644 --- a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php @@ -141,7 +141,7 @@ private function loadConfig() * @magentoDbIsolation enabled * @dataProvider runLockDataProvider */ - public function testRunLock($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + public function testRunLockEnv($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) { $this->inputMock->expects($this->any()) ->method('getArgument') @@ -152,15 +152,15 @@ public function testRunLock($path, $value, $scope = ScopeConfigInterface::SCOPE_ $this->inputMock->expects($this->any()) ->method('getOption') ->willReturnMap([ - [ConfigSetCommand::OPTION_LOCK, true], + [ConfigSetCommand::OPTION_LOCK_ENV, true], [ConfigSetCommand::OPTION_SCOPE, $scope], [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode] ]); $this->outputMock->expects($this->exactly(2)) ->method('writeln') ->withConsecutive( - ['Value was saved and locked.'], - ['Value was saved and locked.'] + ['Value was saved in app/etc/env.php and locked.'], + ['Value was saved in app/etc/env.php and locked.'] ); /** @var ConfigSetCommand $command */ @@ -217,7 +217,7 @@ public function testRunExtended( [ConfigSetCommand::OPTION_SCOPE, $scope], [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode] ]; - $optionsLock = array_merge($options, [[ConfigSetCommand::OPTION_LOCK, true]]); + $optionsLock = array_merge($options, [[ConfigSetCommand::OPTION_LOCK_ENV, true]]); /** @var ConfigPathResolver $resolver */ $resolver = $this->objectManager->get(ConfigPathResolver::class); @@ -233,8 +233,8 @@ public function testRunExtended( ); $this->assertSame(null, $this->arrayManager->get($configPath, $this->loadConfig())); - $this->runCommand($arguments, $optionsLock, 'Value was saved and locked.'); - $this->runCommand($arguments, $optionsLock, 'Value was saved and locked.'); + $this->runCommand($arguments, $optionsLock, 'Value was saved in app/etc/env.php and locked.'); + $this->runCommand($arguments, $optionsLock, 'Value was saved in app/etc/env.php and locked.'); $this->assertSame($value, $this->arrayManager->get($configPath, $this->loadConfig())); } diff --git a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php index 71e61162d29c9..ab893d583dfa3 100644 --- a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php +++ b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php @@ -122,7 +122,7 @@ private function enableDebugging() ->withConsecutive( [ConfigSetCommand::OPTION_SCOPE], [ConfigSetCommand::OPTION_SCOPE_CODE], - [ConfigSetCommand::OPTION_LOCK] + [ConfigSetCommand::OPTION_LOCK_ENV] ) ->willReturnOnConsecutiveCalls( ScopeConfigInterface::SCOPE_TYPE_DEFAULT, From c117468554b0667ef04244460966f8f2e2ffb9b4 Mon Sep 17 00:00:00 2001 From: Andreas von Studnitz Date: Fri, 24 Nov 2017 12:50:20 +0100 Subject: [PATCH 0075/1464] 12178 Fix integration tests --- .../Magento/Developer/Model/Logger/Handler/DebugTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php index ab893d583dfa3..4291ac18e1b10 100644 --- a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php +++ b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php @@ -131,7 +131,7 @@ private function enableDebugging() ); $this->outputMock->expects($this->once()) ->method('writeln') - ->with('Value was saved and locked.'); + ->with('Value was saved in app/etc/env.php and locked.'); $this->assertFalse((bool)$this->configSetCommand->run($this->inputMock, $this->outputMock)); } From c98720f551534b53f2e8f7b475aaac0473a43750 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Fri, 24 Nov 2017 15:12:05 +0100 Subject: [PATCH 0076/1464] Added dropdown.test.js and removed JsTestDriver equivalent. --- .../testsuite/mage/dropdown/index.html | 30 -- .../testsuite/mage/dropdown/test-dropdown.js | 270 -------------- .../jasmine/tests/lib/mage/dropdown.test.js | 351 ++++++++++++++++++ 3 files changed, 351 insertions(+), 300 deletions(-) delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html delete mode 100644 dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js create mode 100644 dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html b/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html deleted file mode 100644 index 3d6ed5a7c1d28..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/index.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - Unit test - - - - - - - - - - - - -
-
-
- - diff --git a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js b/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js deleted file mode 100644 index e67c92b3d4018..0000000000000 --- a/dev/tests/js/JsTestDriver/testsuite/mage/dropdown/test-dropdown.js +++ /dev/null @@ -1,270 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -/* - testing if dialog opens when the triggerEvent is triggered - */ -test( "triggerEvent", function() { - expect(2); - var opener = $('
'); - var dialog = $('
'); - dialog.dropdownDialog({"triggerEvent":"click", "triggerTarget":opener}); - opener.trigger("click"); - equal(dialog.dropdownDialog("isOpen"), true, "Dropdown opens when click opener"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"triggerEvent":null, "triggerTarget":opener}); - opener.trigger("click"); - equal(dialog.dropdownDialog("isOpen"), false, "Dropdown doesn't open when click opener"); - dialog.dropdownDialog( "destroy" ); - -}); - -/* - testing if a specified class is added to the trigger - */ -test( "triggerClass", function() { - expect(2); - var opener = $('
'); - var dialog = $('
'); - dialog.dropdownDialog({"triggerTarget":opener,"triggerClass":"active"}); - dialog.dropdownDialog("open"); - ok( opener.hasClass("active"), "Class added to opener when dialog opens" ); - dialog.dropdownDialog("close"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"triggerEvent":opener, "triggerClass":null}); - dialog.dropdownDialog("open"); - ok( !opener.hasClass("active"), "Class added to opener when dialog opens" ); - dialog.dropdownDialog("close"); - dialog.dropdownDialog( "destroy" ); - -}); - -/* - testing if a specified class is added to the element which the dialog appends to - */ -test( "parentClass", function() { - expect(2); - var parent = $('
'); - var dialog = $('
'); - - dialog.dropdownDialog({"parentClass":"active","appendTo":parent}); - dialog.dropdownDialog("open"); - ok( parent.hasClass("active"), "Class is added to parent when dialog opens" ); - dialog.dropdownDialog("close"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"parentClass":null,"appendTo":parent}); - dialog.dropdownDialog("open"); - ok( !parent.hasClass("active"), "No class is added to parent when dialog opens" ); - dialog.dropdownDialog("close"); - dialog.dropdownDialog( "destroy" ); - -}); - -/* - testing if a specified class is added to the element that becomes dialog - */ -test( "dialogContentClass", function() { - expect(2); - var dialog = $('
'); - - dialog.dropdownDialog({"dialogContentClass":"active"}); - dialog.dropdownDialog("open"); - ok( $('.ui-dialog-content').hasClass("active"), "Class is added to dialog content when dialog opens" ); - dialog.dropdownDialog("close"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"dialogContentClass": null}); - dialog.dropdownDialog("open"); - ok( !$('.ui-dialog-content').hasClass("active"), "No class is added to dialog content" ); - dialog.dropdownDialog("close"); - dialog.dropdownDialog( "destroy" ); -}); - -/* - testing if a specified class is added to dialog - */ -test( "defaultDialogClass", function() { - expect(3); - var dialog = $('
'); - - dialog.dropdownDialog({"defaultDialogClass":"custom"}); - ok( $('.ui-dialog').hasClass("custom"), "Class is added to dialog" ); - ok( !$('.ui-dialog').hasClass("mage-dropdown-dialog"), "Default class has been overwritten" ); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({}); - ok( $('.ui-dialog').hasClass("mage-dropdown-dialog"), "Default class hasn't been overwritten" ); - dialog.dropdownDialog( "destroy" ); -}); - -/* - testing if the specified trigger actually opens the dialog - */ -test( "triggerTarget", function() { - expect(2); - var opener = $('
'); - var dialog = $('
'); - - dialog.dropdownDialog({"triggerTarget":opener}); - opener.trigger("click"); - equal(dialog.dropdownDialog("isOpen"), true, "Dropdown opens when click opener"); - dialog.dropdownDialog("close"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"triggerTarget":null}); - opener.trigger("click"); - equal(dialog.dropdownDialog("isOpen"), false, "Dropdown doesn't open when click opener"); - dialog.dropdownDialog( "destroy" ); -}); - -/* - testing if the dialog gets closed when clicking outside of it - */ -test( "closeOnClickOutside", function() { - expect(2); - var outside = $('
').attr({"id":"outside"}); - var dialog = $('
').attr({"id":"dialog"}); - outside.appendTo("#qunit-fixture"); - dialog.appendTo("#qunit-fixture"); - - dialog.dropdownDialog({"closeOnClickOutside":true}); - dialog.dropdownDialog("open"); - outside.trigger("click"); - equal(dialog.dropdownDialog("isOpen"), false, "Dropdown closes when click outside dropdown"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"closeOnClickOutside":false}); - dialog.dropdownDialog("open"); - outside.trigger("click"); - equal(dialog.dropdownDialog("isOpen"), true, "Dropdown doesn't close when click outside dropdown"); - dialog.dropdownDialog( "destroy" ); -}); - -/* - testing if the dialog gets closed when mouse leaves the dialog area - */ -asyncTest( "closeOnMouseLeave true", function() { - expect(1); - var outside = $('
').attr({"id":"outside"}); - var dialog = $('
').attr({"id":"dialog"}); - var opener = $('
').attr({"id":"opener"}); - outside.appendTo("#qunit-fixture"); - dialog.appendTo("#qunit-fixture"); - opener.appendTo("#qunit-fixture"); - - dialog.dropdownDialog({"closeOnMouseLeave":true}); - dialog.dropdownDialog("open"); - dialog.trigger("mouseenter"); - dialog.trigger("mouseleave"); - - setTimeout(function() { - equal(dialog.dropdownDialog("isOpen"), false, "Dropdown closes when mouseleave the dropdown area"); - dialog.dropdownDialog( "destroy" ); - start(); - }, 3000); - -}); - -/* - testing if the dialog gets closed when mouse leaves the dialog area - */ -asyncTest( "closeOnMouseLeave false", function() { - expect(1); - var outside = $('
').attr({"id":"outside"}); - var dialog = $('
').attr({"id":"dialog"}); - var opener = $('
').attr({"id":"opener"}); - outside.appendTo("#qunit-fixture"); - dialog.appendTo("#qunit-fixture"); - opener.appendTo("#qunit-fixture"); - - dialog.dropdownDialog({"closeOnMouseLeave":false}); - dialog.dropdownDialog("open"); - dialog.trigger("mouseenter"); - dialog.trigger("mouseleave"); - - setTimeout(function() { - equal(dialog.dropdownDialog("isOpen"), true, "Dropdown doesn't close when mouseleave the dropdown area"); - dialog.dropdownDialog( "destroy" ); - start(); - }, 3000); - -}); - -/* - testing if the dialog gets closed with the specified delay - */ -asyncTest( "timeout", function() { - expect(2); - var outside = $('
').attr({"id":"outside"}); - var dialog = $('
').attr({"id":"dialog"}); - var opener = $('
').attr({"id":"opener"}); - outside.appendTo("#qunit-fixture"); - dialog.appendTo("#qunit-fixture"); - opener.appendTo("#qunit-fixture"); - - dialog.dropdownDialog({"timeout":2000}); - dialog.dropdownDialog("open"); - dialog.trigger("mouseenter"); - dialog.trigger("mouseleave"); - equal(dialog.dropdownDialog("isOpen"), true, "Dropdown doesn't close when mouseleave the dropdown area"); - setTimeout(function() { - equal(dialog.dropdownDialog("isOpen"), false, "Dropdown closes when mouseleave the dropdown area, after timeout passed"); - dialog.dropdownDialog( "destroy" ); - start(); - }, 3000); - -}); - -/* - testing if the title bar is prevented from being created - */ -test( "createTitileBar", function() { - expect(2); - var dialog = $('
'); - dialog.dropdownDialog({"createTitleBar":true}); - ok(($(".ui-dialog").find(".ui-dialog-titlebar").length > 0), "Title bar is created"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"createTitleBar":false}); - ok($(".ui-dialog").find(".ui-dialog-titlebar").length <= 0, "Title bar isn't created"); - dialog.dropdownDialog( "destroy" ); -}); - -/* - testing if the position function gets disabled - */ -test( "autoPosition", function() { - expect(2); - var dialog = $('
'); - dialog.dropdownDialog({"autoPosition":false}); - dialog.dropdownDialog("open"); - ok(($(".ui-dialog").css("top") === 'auto'), "_position function disabled"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"autoPosition":true}); - dialog.dropdownDialog("open"); - ok(($(".ui-dialog").css("top") !== '0px'), "_position function enabled"); - dialog.dropdownDialog( "destroy" ); -}); - -/* - testing if the size function gets disabled - */ -test( "autoSize", function() { - expect(2); - var dialog = $('
'); - dialog.dropdownDialog({"autoSize":true, width:"300"}); - dialog.dropdownDialog("open"); - ok(($(".ui-dialog").css("width") === '300px'), "_size function enabled"); - dialog.dropdownDialog( "destroy" ); - - dialog.dropdownDialog({"autoSize":false, width:"300"}); - dialog.dropdownDialog("open"); - ok($(".ui-dialog").css("width") !== '300px', "_size function disabled"); - dialog.dropdownDialog( "destroy" ); -}); diff --git a/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js b/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js new file mode 100644 index 0000000000000..70e608d5bfefd --- /dev/null +++ b/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js @@ -0,0 +1,351 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +/* eslint-disable max-nested-callbacks */ + +define([ + 'jquery', + 'mage/dropdown' +], function ($) { + 'use strict'; + + describe('Test for mage/dropdown jQuery plugin', function () { + it('check if dialog opens when the triggerEvent is triggered', function () { + var opener = $('
'), + dialog = $('
'); + + dialog.dropdownDialog({ + 'triggerEvent': 'click', + 'triggerTarget': opener + }); + + opener.trigger('click'); + expect(dialog.dropdownDialog('isOpen')).toBeTruthy(); + + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'triggerEvent': null, + 'triggerTarget': opener + }); + + opener.trigger('click'); + expect(dialog.dropdownDialog('isOpen')).toBeFalsy(); + dialog.dropdownDialog('destroy'); + }); + + it('check if a specified class is added to the trigger', function () { + var opener = $('
'), + dialog = $('
'); + + dialog.dropdownDialog({ + 'triggerClass': 'active', + 'triggerTarget': opener + }); + + dialog.dropdownDialog('open'); + expect(opener.hasClass('active')).toBeTruthy(); + + dialog.dropdownDialog('close'); + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'triggerClass': null, + 'triggerTarget': opener + }); + + dialog.dropdownDialog('open'); + expect(opener.hasClass('active')).toBeFalsy(); + + dialog.dropdownDialog('close'); + dialog.dropdownDialog('destroy'); + }); + + it('check if a specified class is added to the element which the dialog appends to', function () { + var parent = $('
'), + dialog = $('
'); + + dialog.dropdownDialog({ + 'parentClass': 'active', + 'appendTo': parent + }); + + dialog.dropdownDialog('open'); + expect(parent.hasClass('active')).toBeTruthy(); + + dialog.dropdownDialog('close'); + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'parentClass': null, + 'appendTo': parent + }); + + dialog.dropdownDialog('open'); + expect(parent.hasClass('active')).toBeFalsy(); + + dialog.dropdownDialog('close'); + dialog.dropdownDialog('destroy'); + }); + + it('check if a specified class is added to the element that becomes dialog', function () { + var dialog = $('
'), + content; + + dialog.dropdownDialog({ + 'dialogContentClass': 'active' + }); + + content = $('.ui-dialog-content'); + dialog.dropdownDialog('open'); + expect(content.hasClass('active')).toBeTruthy(); + + dialog.dropdownDialog('close'); + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'dialogContentClass': null + }); + + dialog.dropdownDialog('open'); + expect(content.hasClass('active')).toBeFalsy(); + + dialog.dropdownDialog('close'); + dialog.dropdownDialog('destroy'); + }); + + it('check if a specified class is added to dialog', function () { + var dialog = $('
'), + uiClass = '.ui-dialog', + ui; + + dialog.dropdownDialog({ + 'defaultDialogClass': 'custom' + }); + + ui = $(uiClass); + expect(ui.hasClass('custom')).toBeTruthy(); + expect(ui.hasClass('mage-dropdown-dialog')).toBeFalsy(); + + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({}); + ui = $(uiClass); + expect(ui.hasClass('mage-dropdown-dialog')).toBeTruthy(); + + dialog.dropdownDialog('destroy'); + }); + + it('check if the specified trigger actually opens the dialog', function () { + var opener = $('
'), + dialog = $('
'); + + dialog.dropdownDialog({ + 'triggerTarget': opener + }); + + opener.trigger('click'); + expect(dialog.dropdownDialog('isOpen')).toBeTruthy(); + + dialog.dropdownDialog('close'); + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'triggerTarget': null + }); + + opener.trigger('click'); + expect(dialog.dropdownDialog('isOpen')).toBeFalsy(); + + dialog.dropdownDialog('destroy'); + }); + + it('check if the dialog gets closed when clicking outside of it', function () { + var container = $('
'), + outside = $('
').attr('id', 'outside').appendTo(container), + dialog = $('
').attr('id', 'dialog').appendTo(container); + + container.appendTo('body'); + + dialog.dropdownDialog({ + 'closeOnClickOutside': true + }); + + dialog.dropdownDialog('open'); + outside.trigger('click'); + expect(dialog.dropdownDialog('isOpen')).toBeFalsy(); + + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'closeOnClickOutside': false + }); + + dialog.dropdownDialog('open'); + outside.trigger('click'); + expect(dialog.dropdownDialog('isOpen')).toBeTruthy(); + + dialog.dropdownDialog('destroy'); + }); + + it('check if the dialog gets closed when mouse leaves the dialog area', function () { + var container = $('
'), + dialog = $('
').attr('id', 'dialog').appendTo(container); + + $('
').attr('id', 'outside').appendTo(container); + $('
').attr('id', 'opener').appendTo(container); + + container.appendTo('body'); + + jasmine.clock().install(); + + dialog.dropdownDialog({ + 'closeOnMouseLeave': true + }); + + dialog.dropdownDialog('open'); + dialog.trigger('mouseenter'); + expect(dialog.dropdownDialog('isOpen')).toBeTruthy(); + + dialog.trigger('mouseleave'); + + jasmine.clock().tick(10); + + expect(dialog.dropdownDialog('isOpen')).toBeFalsy(); + dialog.dropdownDialog('destroy'); + + jasmine.clock().uninstall(); + }); + + it('check if the dialog does not close when mouse leaves the dialog area', function () { + var container = $('
'), + dialog = $('
').attr('id', 'dialog').appendTo(container); + + $('
').attr('id', 'outside').appendTo(container); + $('
').attr('id', 'opener').appendTo(container); + + container.appendTo('body'); + + jasmine.clock().install(); + + dialog.dropdownDialog({ + 'closeOnMouseLeave': false + }); + + dialog.dropdownDialog('open'); + dialog.trigger('mouseenter'); + dialog.trigger('mouseleave'); + jasmine.clock().tick(10); + expect(dialog.dropdownDialog('isOpen')).toBeTruthy(); + dialog.dropdownDialog('destroy'); + + jasmine.clock().uninstall(); + }); + + it('check if the dialog gets closed with the specified delay', function () { + var container = $('
'), + dialog = $('
').attr('id', 'dialog').appendTo(container); + + $('
').attr('id', 'outside').appendTo(container); + $('
').attr('id', 'opener').appendTo(container); + + container.appendTo('body'); + + jasmine.clock().install(); + + dialog.dropdownDialog({ + 'timeout': 5 + }); + + dialog.dropdownDialog('open'); + dialog.trigger('mouseenter'); + dialog.trigger('mouseleave'); + expect(dialog.dropdownDialog('isOpen')).toBeTruthy(); + + jasmine.clock().tick(10); + expect(dialog.dropdownDialog('isOpen')).toBeFalsy(); + dialog.dropdownDialog('destroy'); + + jasmine.clock().uninstall(); + }); + + it('check if the title bar is prevented from being created', function () { + var dialog = $('
'), + uiClass = '.ui-dialog', + ui; + + dialog.dropdownDialog({ + 'createTitleBar': true + }); + + ui = $(uiClass); + expect(ui.find('.ui-dialog-titlebar').length > 0).toBeTruthy(); + + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'createTitleBar': false + }); + + ui = $(uiClass); + expect(ui.find('.ui-dialog-titlebar').length <= 0).toBeTruthy(); + + dialog.dropdownDialog('destroy'); + }); + + it('check if the position function gets disabled', function () { + var dialog = $('
'), + uiClass = '.ui-dialog', + ui; + + dialog.dropdownDialog({ + 'autoPosition': false + }); + + ui = $(uiClass); + dialog.dropdownDialog('open'); + expect(ui.css('top') === 'auto').toBeTruthy(); + + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'autoPosition': true + }); + + ui = $(uiClass); + dialog.dropdownDialog('open'); + expect(ui.css('top') !== '0px').toBeTruthy(); + + dialog.dropdownDialog('destroy'); + }); + + it('check if the size function gets disabled', function () { + var dialog = $('
'), + uiClass = '.ui-dialog', + ui; + + dialog.dropdownDialog({ + 'autoSize': true, + 'width': '300' + }); + + ui = $(uiClass); + dialog.dropdownDialog('open'); + expect(ui.css('width') === '300px').toBeTruthy(); + + dialog.dropdownDialog('destroy'); + + dialog.dropdownDialog({ + 'autoSize': false, + 'width': '300' + }); + + ui = $(uiClass); + dialog.dropdownDialog('open'); + expect(ui.css('width') === '300px').toBeFalsy(); + + dialog.dropdownDialog('destroy'); + }); + }); +}); From de225a907f56477b767eae81134154e0398a3bf0 Mon Sep 17 00:00:00 2001 From: Carlos Lizaga Date: Fri, 24 Nov 2017 17:24:15 +0100 Subject: [PATCH 0077/1464] Backend jquery-ui version has a diferent behavior on create that will add ui-dialog-titlebar anyway. This test is only valid with frontend's version @TODO: Re-design Jasmine settings to match a selective architecture for testing in order to split them. --- .../jasmine/tests/lib/mage/dropdown.test.js | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js b/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js index 70e608d5bfefd..1034ad263d9fe 100644 --- a/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js +++ b/dev/tests/js/jasmine/tests/lib/mage/dropdown.test.js @@ -270,29 +270,34 @@ define([ jasmine.clock().uninstall(); }); - it('check if the title bar is prevented from being created', function () { - var dialog = $('
'), - uiClass = '.ui-dialog', - ui; + // Backend jquery-ui version has a diferent behavior on create that will add ui-dialog-titlebar anyway. + // This test is only valid with frontend's version + // @TODO: Re-design Jasmine settings to match a selective architecture for testing in order to split them. + if ($.ui.version !== '1.9.2') { + it('check if the title bar is prevented from being created', function () { + var dialog = $('
'), + uiClass = '.ui-dialog', + ui; - dialog.dropdownDialog({ - 'createTitleBar': true - }); + dialog.dropdownDialog({ + 'createTitleBar': true + }); - ui = $(uiClass); - expect(ui.find('.ui-dialog-titlebar').length > 0).toBeTruthy(); + ui = $(uiClass); + expect(ui.find('.ui-dialog-titlebar').length > 0).toBeTruthy(); - dialog.dropdownDialog('destroy'); + dialog.dropdownDialog('destroy'); - dialog.dropdownDialog({ - 'createTitleBar': false - }); + dialog.dropdownDialog({ + 'createTitleBar': false + }); - ui = $(uiClass); - expect(ui.find('.ui-dialog-titlebar').length <= 0).toBeTruthy(); + ui = $(uiClass); + expect(ui.find('.ui-dialog-titlebar').length <= 0).toBeTruthy(); - dialog.dropdownDialog('destroy'); - }); + dialog.dropdownDialog('destroy'); + }); + } it('check if the position function gets disabled', function () { var dialog = $('
'), From 0812ba807e605343d397768199d67a0ecd811482 Mon Sep 17 00:00:00 2001 From: alojua Date: Sat, 25 Nov 2017 11:18:17 +0100 Subject: [PATCH 0078/1464] Fix failing tests --- .../Deploy/Console/Command/App/ApplicationDumpCommand.php | 3 +-- .../Test/Unit/Console/Command/ApplicationDumpCommandTest.php | 2 +- .../Deploy/Console/Command/App/ApplicationDumpCommandTest.php | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php index c3492019455f2..e47f534a40793 100644 --- a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php +++ b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php @@ -76,8 +76,7 @@ protected function configure() $this->addArgument( self::INPUT_CONFIG_TYPES, InputArgument::OPTIONAL | InputArgument::IS_ARRAY, - sprintf('Space-separated list of config types or omit to dump all [%s]', - implode(', ', $this->configTypes)) + sprintf('Space-separated list of config types or omit to dump all [%s]', implode(', ', $this->configTypes)) ); parent::configure(); } diff --git a/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php b/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php index 67c3796e7c6b9..85cae275932fa 100644 --- a/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php +++ b/app/code/Magento/Deploy/Test/Unit/Console/Command/ApplicationDumpCommandTest.php @@ -130,7 +130,7 @@ public function testExport() ->method('writeln') ->withConsecutive( [['system' => 'Some comment message']], - ['Done.'] + ['Done. Config types dumped: system'] ); $method = new \ReflectionMethod(ApplicationDumpCommand::class, 'execute'); diff --git a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php index cb40b110f5fc6..5602e77eb702c 100644 --- a/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Deploy/Console/Command/App/ApplicationDumpCommandTest.php @@ -176,7 +176,7 @@ public function testExecute() ->with(['system' => $comment]); $outputMock->expects($this->at(1)) ->method('writeln') - ->with('Done.'); + ->with('Done. Config types dumped: scopes, themes, system, i18n'); /** @var ApplicationDumpCommand command */ $command = $this->objectManager->create(ApplicationDumpCommand::class); From afd6a6c0937bda1f50777511c65f3f8adc734fbe Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi Date: Mon, 27 Nov 2017 13:02:39 +0200 Subject: [PATCH 0079/1464] MAGETWO-77754: [2.2.x] - Rules builder improvement --- .../Rule/Model/Condition/Sql/BuilderTest.php | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php index c9640ceba87d2..fbeb3512eab86 100644 --- a/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php +++ b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php @@ -7,49 +7,49 @@ namespace Magento\Rule\Model\Condition\Sql; use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory; +use Magento\CatalogWidget\Model\RuleFactory; +use Magento\CatalogWidget\Model\Rule\Condition\Combine as CombineCondition; +use Magento\CatalogWidget\Model\Rule\Condition\Product as ProductCondition; class BuilderTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Rule\Model\Condition\Sql\Builder + * @var Builder */ private $model; protected function setUp() { - $this->model = Bootstrap::getObjectManager()->create(\Magento\Rule\Model\Condition\Sql\Builder::class); + $this->model = Bootstrap::getObjectManager()->create(Builder::class); } public function testAttachConditionToCollection() { - /** @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory */ - $collectionFactory = Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class - ); - /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ + /** @var ProductCollectionFactory $collectionFactory */ + $collectionFactory = Bootstrap::getObjectManager()->create(ProductCollectionFactory::class); $collection = $collectionFactory->create(); - /** @var \Magento\CatalogWidget\Model\RuleFactory $ruleFactory */ - $ruleFactory = Bootstrap::getObjectManager()->create(\Magento\CatalogWidget\Model\RuleFactory::class); - /** @var \Magento\CatalogWidget\Model\Rule $rule */ + /** @var RuleFactory $ruleFactory */ + $ruleFactory = Bootstrap::getObjectManager()->create(RuleFactory::class); $rule = $ruleFactory->create(); $ruleConditionArray = [ 'conditions' => [ '1' => [ - 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Combine::class, + 'type' => CombineCondition::class, 'aggregator' => 'all', 'value' => '1', 'new_child' => '' ], '1--1' => [ - 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class, + 'type' => ProductCondition::class, 'attribute' => 'category_ids', 'operator' => '==', 'value' => '3' ], '1--2' => [ - 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class, + 'type' => ProductCondition::class, 'attribute' => 'special_to_date', 'operator' => '==', 'value' => '2017-09-15' @@ -60,7 +60,7 @@ public function testAttachConditionToCollection() $rule->loadPost($ruleConditionArray); $this->model->attachConditionToCollection($collection, $rule->getConditions()); - $whereString = 'WHERE (category_id IN (\'3\')))) AND(IFNULL(`e`.`entity_id`, 0) = \'2017-09-15\') ))'; - $this->assertNotFalse(strpos($collection->getSelectSql(true), $whereString)); + $whereString = "/\(category_id IN \('3'\).+\(IFNULL\(`e`\.`entity_id`,.+\) = '2017-09-15'\)/"; + $this->assertNotFalse(preg_match($whereString, $collection->getSelectSql(true))); } } From 6751504cd9f8f2dc7290d802132bffab98a7d745 Mon Sep 17 00:00:00 2001 From: alojua Date: Tue, 28 Nov 2017 09:30:39 +0100 Subject: [PATCH 0080/1464] Remove hard dependencies to set configTypes and get them dynamically instead --- .../Command/App/ApplicationDumpCommand.php | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php index e47f534a40793..4eb965b21d53a 100644 --- a/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php +++ b/app/code/Magento/Deploy/Console/Command/App/ApplicationDumpCommand.php @@ -23,16 +23,6 @@ class ApplicationDumpCommand extends Command { const INPUT_CONFIG_TYPES = 'config-types'; - /** - * @var array - */ - private $configTypes = [ - \Magento\Store\App\Config\Type\Scopes::CONFIG_TYPE, - \Magento\Deploy\Source\Themes::TYPE, - \Magento\Translation\App\Config\Type\Translation::CONFIG_TYPE, - \Magento\Config\App\Config\Type\System::CONFIG_TYPE, - ]; - /** * @var Writer */ @@ -60,10 +50,10 @@ public function __construct( array $sources, Hash $configHash = null ) { - parent::__construct(); $this->writer = $writer; $this->sources = $sources; $this->configHash = $configHash ?: ObjectManager::getInstance()->get(Hash::class); + parent::__construct(); } /** @@ -73,10 +63,12 @@ protected function configure() { $this->setName('app:config:dump'); $this->setDescription('Create dump of application'); + + $configTypes = array_unique(array_column($this->sources, 'namespace')); $this->addArgument( self::INPUT_CONFIG_TYPES, InputArgument::OPTIONAL | InputArgument::IS_ARRAY, - sprintf('Space-separated list of config types or omit to dump all [%s]', implode(', ', $this->configTypes)) + sprintf('Space-separated list of config types or omit to dump all [%s]', implode(', ', $configTypes)) ); parent::configure(); } From 0a6a2d9b80859261afc01c3027f06babdec878aa Mon Sep 17 00:00:00 2001 From: RomanKis Date: Tue, 28 Nov 2017 12:26:42 +0200 Subject: [PATCH 0081/1464] 8830: Can`t delete row in dynamicRows component --- .../view/adminhtml/web/template/form/element/action-delete.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html index d4cfb02611416..9a52dcefa3042 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/form/element/action-delete.html @@ -7,7 +7,7 @@ +
diff --git a/app/code/Magento/Multishipping/view/frontend/web/js/payment.js b/app/code/Magento/Multishipping/view/frontend/web/js/payment.js index 94987328bb278..da24b99597d42 100644 --- a/app/code/Magento/Multishipping/view/frontend/web/js/payment.js +++ b/app/code/Magento/Multishipping/view/frontend/web/js/payment.js @@ -63,9 +63,12 @@ define([ parentsDl = element.closest('dl'); parentsDl.find('dt input:radio').prop('checked', false); - parentsDl.find('.items').hide().find('[name^="payment["]').prop('disabled', true); + parentsDl.find('dd').addClass('no-display').end() + .find('.items').hide() + .find('[name^="payment["]').prop('disabled', true); element.prop('checked', true).parent() - .nextUntil('dt').find('.items').show().find('[name^="payment["]').prop('disabled', false); + .next('dd').removeClass('no-display') + .find('.items').show().find('[name^="payment["]').prop('disabled', false); }, /** @@ -122,16 +125,35 @@ define([ this.element.find(this.options.methodsContainer).show(); }, + /** + * Returns checked payment method. + * + * @private + */ + _getSelectedPaymentMethod: function () { + return this.element.find('input[name=\'payment[method]\']:checked'); + }, + /** * Validate before form submit * @private * @param {EventObject} e */ _submitHandler: function (e) { + var currentMethod, + submitButton; + e.preventDefault(); if (this._validatePaymentMethod()) { - this.element.submit(); + currentMethod = this._getSelectedPaymentMethod(); + submitButton = currentMethod.parent().next('dd').find('button[type=submit]'); + + if (submitButton.length) { + submitButton.first().trigger('click'); + } else { + this.element.submit(); + } } } }); diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml index cb28c0ed69bbb..ff1234cfecc2b 100644 --- a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml +++ b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml @@ -44,6 +44,18 @@ $params = $block->getParams(); }); } ); + + var require = window.top.require; + require( + [ + 'jquery' + ], + function($) { + var parent = window.top; + $(parent).trigger('clearTimeout'); + $(parent.document).find('#multishipping-billing-form').submit(); + } + ); window.top.location = "escapeUrl($params['order_success']) ?>"; From f5788b272a61db42ebcb1fc5fd565ded8b4f8c2c Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov Date: Tue, 19 Dec 2017 13:57:42 +0200 Subject: [PATCH 0190/1464] MAGETWO-84448: Product Import does not allow store-specific Custom Option labels --- .../Model/Export/RowCustomizer.php | 41 +++++++++++-------- .../Model/Import/Product/Type/Bundle.php | 5 ++- .../Model/Export/Product.php | 5 ++- .../Model/Import/Product/Option.php | 4 +- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php index 376de359f2530..24ccbbee23649 100644 --- a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php +++ b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php @@ -109,7 +109,7 @@ class RowCustomizer implements RowCustomizerInterface /** * @var \Magento\Bundle\Model\ResourceModel\Option\Collection[] */ - private $optionsCollection = []; + private $optionCollections = []; /** * @var array @@ -130,9 +130,9 @@ class RowCustomizer implements RowCustomizerInterface * @param StoreManagerInterface $storeManager * @throws \RuntimeException */ - public function __construct(StoreManagerInterface $storeManager = null) + public function __construct(StoreManagerInterface $storeManager) { - $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); + $this->storeManager = $storeManager; } /** @@ -237,10 +237,10 @@ protected function populateBundleData($collection) */ protected function getFormattedBundleOptionValues($product) { - $optionsCollection = $this->getProductOptionsCollection($product); + $optionCollections = $this->getProductOptionCollections($product); $bundleData = ''; $optionTitles = $this->getBundleOptionTitles($product); - foreach ($optionsCollection->getItems() as $option) { + foreach ($optionCollections->getItems() as $option) { $optionValues = $this->getFormattedOptionValues($option, $optionTitles); $bundleData .= $this->getFormattedBundleSelections( $optionValues, @@ -418,6 +418,7 @@ private function parseAdditionalAttributes($additionalAttributes) /** * Get product options titles. + * * Values for all store views (default) should be specified with 'name' key. * If user want to specify value or change existing for non default store views it should be specified with * 'name_' prefix and needed store view suffix. @@ -429,20 +430,20 @@ private function parseAdditionalAttributes($additionalAttributes) * @param \Magento\Catalog\Model\Product $product $product * @return array */ - private function getBundleOptionTitles($product) + private function getBundleOptionTitles($product): array { - $optionsCollection = $this->getProductOptionsCollection($product); + $optionCollections = $this->getProductOptionCollections($product); $optionsTitles = []; /** @var \Magento\Bundle\Model\Option $option */ - foreach ($optionsCollection->getItems() as $option) { + foreach ($optionCollections->getItems() as $option) { $optionsTitles[$option->getId()]['name'] = $option->getTitle(); } $storeIds = $product->getStoreIds(); if (array_count_values($storeIds) > 1) { foreach ($storeIds as $storeId) { - $optionsCollection = $this->getProductOptionsCollection($product, $storeId); + $optionCollections = $this->getProductOptionCollections($product, $storeId); /** @var \Magento\Bundle\Model\Option $option */ - foreach ($optionsCollection->getItems() as $option) { + foreach ($optionCollections->getItems() as $option) { $optionTitle = $option->getTitle(); if ($optionsTitles[$option->getId()]['name'] != $optionTitle) { $optionsTitles[$option->getId()]['name_' . $this->getStoreCodeById($storeId)] = $optionTitle; @@ -455,33 +456,37 @@ private function getBundleOptionTitles($product) /** * Get product options collection by provided product model. + * * Set given store id to the product if it was defined (default store id will be set if was not). * * @param \Magento\Catalog\Model\Product $product $product * @param integer $storeId * @return \Magento\Bundle\Model\ResourceModel\Option\Collection */ - private function getProductOptionsCollection($product, $storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID) - { + private function getProductOptionCollections( + $product, + $storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID + ): \Magento\Bundle\Model\ResourceModel\Option\Collection { $productSku = $product->getSku(); - if (!isset($this->optionsCollection[$productSku][$storeId])) { + if (!isset($this->optionCollections[$productSku][$storeId])) { $product->unsetData($this->optionCollectionCacheKey); $product->setStoreId($storeId); - $this->optionsCollection[$productSku][$storeId] = $product->getTypeInstance() - ->getOptionsCollection($product) + $this->optionCollections[$productSku][$storeId] = $product->getTypeInstance() + ->getOptionCollections($product) ->setOrder('position', Collection::SORT_ORDER_ASC); } - return $this->optionsCollection[$productSku][$storeId]; + return $this->optionCollections[$productSku][$storeId]; } /** * Retrieve store code by it's ID. + * * Collect store id in $storeIdToCode[] private variable if it was not initialized earlier. * * @param $storeId - * @return mixed + * @return string */ - private function getStoreCodeById($storeId) + private function getStoreCodeById($storeId): string { if (!isset($this->storeIdToCode[$storeId])) { $this->storeIdToCode[$storeId] = $this->storeManager->getStore($storeId)->getCode(); diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php index c0e17433e4333..b7f70d18f5c85 100644 --- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php +++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php @@ -155,6 +155,7 @@ class Bundle extends \Magento\CatalogImportExport\Model\Import\Product\Type\Abst * @param \Magento\Framework\EntityManager\MetadataPool|null $metadataPool * @param Bundle\RelationsDataSaver|null $relationsDataSaver * @param StoreManagerInterface $storeManager + * @throws \Magento\Framework\Exception\LocalizedException * @throws \RuntimeException */ public function __construct( @@ -288,7 +289,7 @@ protected function populateOptionValueTemplate($option, $optionId, $storeId = 0) foreach ($optionNames as $optionName) { preg_match($pattern, $optionName, $storeCodes); $storeCode = array_pop($storeCodes); - $storeId = !$storeCode ? $storeId : $this->getStoreIdByCode($storeCode); + $storeId = $storeCode ? $this->getStoreIdByCode($storeCode) : $storeId; $optionValues[] = [ 'option_id' => $optionId, 'parent_product_id' => $option['parent_id'], @@ -728,7 +729,7 @@ protected function clear() * @param string|null $storeCode * @return int */ - private function getStoreIdByCode($storeCode) + private function getStoreIdByCode($storeCode): int { if (!isset($this->storeIdToCode[$storeCode])) { /** @var $store \Magento\Store\Model\Store */ diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php index cead77d7f7134..af14ef0bf6e8e 100644 --- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php @@ -1347,6 +1347,7 @@ protected function optionRowToCellString($option) /** * Collect custom options data for products that will be exported. + * * Option name and type will be collected for all store views, all other data (which can't be changed on store view * level will be collected for DEFAULT_STORE_ID only. * Store view specified data will be saved to the additional store view row. @@ -1381,7 +1382,7 @@ protected function getCustomOptionsData($productIds) $productId = $option['product_id']; $row['name'] = $option['title']; $row['type'] = $option['type']; - if (Store::DEFAULT_STORE_ID == $storeId) { + if (Store::DEFAULT_STORE_ID === $storeId) { $row['required'] = $option['is_require']; $row['price'] = $option['price']; $row['price_type'] = ($option['price_type'] == 'percent') ? $option['price_type'] : 'fixed'; @@ -1403,7 +1404,7 @@ protected function getCustomOptionsData($productIds) if ($values) { foreach ($values as $value) { $row['option_title'] = $value['title']; - if (Store::DEFAULT_STORE_ID == $storeId) { + if (Store::DEFAULT_STORE_ID === $storeId) { $row['option_title'] = $value['title']; $valuePriceType = ($value['price_type'] == 'percent') ? $value['price_type'] : 'fixed'; $row['price'] = $value['price']; diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php index 345c4c634df36..75391e7d4a66a 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Option.php @@ -1197,6 +1197,8 @@ protected function _importData() $this->_tables['catalog_product_option_type_value'] ); $prevOptionId = 0; + $optionId = null; + $valueId = null; while ($bunch = $this->_dataSourceModel->getNextBunch()) { $products = []; $options = []; @@ -1209,7 +1211,7 @@ protected function _importData() $childCount = []; foreach ($bunch as $rowNumber => $rowData) { - if (empty($rowData[PRODUCT::COL_STORE_VIEW_CODE]) && isset($optionId) && isset($valueId)) { + if (isset($optionId, $valueId) && empty($rowData[PRODUCT::COL_STORE_VIEW_CODE])) { $nextOptionId = $optionId; $nextValueId = $valueId; } From 20d7afbe75fed9b8f45e3231848aae40b1c06a3a Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Tue, 19 Dec 2017 14:46:13 +0200 Subject: [PATCH 0191/1464] magento/magento2#12205: Stock inventory reindex bug. --- .../Model/ResourceModel/Indexer/Stock/DefaultStock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php index 366cb1c3902a3..317d055d3e481 100644 --- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php +++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php @@ -288,6 +288,7 @@ protected function _prepareIndexTable($entityIds = null) */ protected function _updateIndex($entityIds) { + $this->deleteOldRecords($entityIds); $connection = $this->getConnection(); $select = $this->_getStockStatusSelect($entityIds, true); $select = $this->getQueryProcessorComposite()->processQuery($select, $entityIds, true); @@ -310,7 +311,6 @@ protected function _updateIndex($entityIds) } } - $this->deleteOldRecords($entityIds); $this->_updateIndexTable($data); return $this; From 2f5b1cc1c788d4e89960a45e296a79f70ab1c07a Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov Date: Tue, 19 Dec 2017 15:31:54 +0200 Subject: [PATCH 0192/1464] MAGETWO-84448: Product Import does not allow store-specific Custom Option labels --- .../BundleImportExport/Model/Export/RowCustomizer.php | 4 ++-- .../BundleImportExport/Model/Import/Product/Type/Bundle.php | 4 ++-- .../Magento/CatalogImportExport/Model/Export/Product.php | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php index 24ccbbee23649..840accf098c4d 100644 --- a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php +++ b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php @@ -294,7 +294,7 @@ function ($value, $key) { * Retrieve option value of bundle product * * @param \Magento\Bundle\Model\Option $option - * @param array $optionTitles + * @param string[] $optionTitles * @return string */ protected function getFormattedOptionValues($option, $optionTitles = []) @@ -464,7 +464,7 @@ private function getBundleOptionTitles($product): array * @return \Magento\Bundle\Model\ResourceModel\Option\Collection */ private function getProductOptionCollections( - $product, + \Magento\Catalog\Model\Product $product, $storeId = \Magento\Store\Model\Store::DEFAULT_STORE_ID ): \Magento\Bundle\Model\ResourceModel\Option\Collection { $productSku = $product->getSku(); diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php index b7f70d18f5c85..93d41c067b229 100644 --- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php +++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php @@ -726,10 +726,10 @@ protected function clear() /** * Get store id by store code. * - * @param string|null $storeCode + * @param string $storeCode * @return int */ - private function getStoreIdByCode($storeCode): int + private function getStoreIdByCode(string $storeCode): int { if (!isset($this->storeIdToCode[$storeCode])) { /** @var $store \Magento\Store\Model\Store */ diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php index af14ef0bf6e8e..6a14eb8b7a817 100644 --- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php @@ -1385,7 +1385,7 @@ protected function getCustomOptionsData($productIds) if (Store::DEFAULT_STORE_ID === $storeId) { $row['required'] = $option['is_require']; $row['price'] = $option['price']; - $row['price_type'] = ($option['price_type'] == 'percent') ? $option['price_type'] : 'fixed'; + $row['price_type'] = ($option['price_type'] === 'percent') ? 'percent' : 'fixed'; $row['sku'] = $option['sku']; if ($option['max_characters']) { $row['max_characters'] = $option['max_characters']; @@ -1406,9 +1406,8 @@ protected function getCustomOptionsData($productIds) $row['option_title'] = $value['title']; if (Store::DEFAULT_STORE_ID === $storeId) { $row['option_title'] = $value['title']; - $valuePriceType = ($value['price_type'] == 'percent') ? $value['price_type'] : 'fixed'; $row['price'] = $value['price']; - $row['price_type'] = $valuePriceType; + $row['price_type'] = ($value['price_type'] === 'percent') ? 'percent' : 'fixed'; $row['sku'] = $value['sku']; } $customOptionsData[$productId][$storeId][] = $this->optionRowToCellString($row); From a35b4686c1b95dc356595246410e527d7c57e2ac Mon Sep 17 00:00:00 2001 From: Ricards Z Date: Mon, 18 Dec 2017 23:49:00 +0200 Subject: [PATCH 0193/1464] Fix too many nested callbacks in jasmine tests --- .../js/model/place-order-mixin.test.js | 74 +++++++++--------- .../set-payment-information-mixin.test.js | 77 +++++++++---------- 2 files changed, 73 insertions(+), 78 deletions(-) diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/place-order-mixin.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/place-order-mixin.test.js index 1906a02f192e7..545daf0a330c9 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/place-order-mixin.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/place-order-mixin.test.js @@ -8,50 +8,48 @@ define([ ], function (Squire) { 'use strict'; - describe('Magento_CheckoutAgreements/js/model/place-order-mixin', function () { - var injector = new Squire(), - mocks = { - 'Magento_Checkout/js/action/place-order': jasmine.createSpy('placeOrderAction'), - 'Magento_CheckoutAgreements/js/model/agreements-assigner': jasmine.createSpy('agreementsAssigner') - }, - defaultContext = require.s.contexts._, - mixin, - placeOrderAction; + var injector = new Squire(), + mocks = { + 'Magento_Checkout/js/action/place-order': jasmine.createSpy('placeOrderAction'), + 'Magento_CheckoutAgreements/js/model/agreements-assigner': jasmine.createSpy('agreementsAssigner') + }, + defaultContext = require.s.contexts._, + mixin, + placeOrderAction; - beforeEach(function (done) { - window.checkoutConfig = { - checkoutAgreements: { - isEnabled: true - } - }; - injector.mock(mocks); - injector.require([ - 'Magento_CheckoutAgreements/js/model/place-order-mixin', - 'Magento_Checkout/js/action/place-order' - ], function (Mixin, placeOrder) { - mixin = Mixin; - placeOrderAction = placeOrder; - done(); - }); + beforeEach(function (done) { + window.checkoutConfig = { + checkoutAgreements: { + isEnabled: true + } + }; + injector.mock(mocks); + injector.require([ + 'Magento_CheckoutAgreements/js/model/place-order-mixin', + 'Magento_Checkout/js/action/place-order' + ], function (Mixin, placeOrder) { + mixin = Mixin; + placeOrderAction = placeOrder; + done(); }); + }); - describe('Magento_Checkout/js/action/place-order', function () { - it('Magento_CheckoutAgreements/js/model/place-order-mixin is applied', function () { - var placeOrderMixins = defaultContext.config.config.mixins['Magento_Checkout/js/action/place-order']; + describe('Magento_CheckoutAgreements/js/model/place-order-mixin', function () { + it('mixin is applied to Magento_Checkout/js/action/place-order', function () { + var placeOrderMixins = defaultContext.config.config.mixins['Magento_Checkout/js/action/place-order']; - expect(placeOrderMixins['Magento_CheckoutAgreements/js/model/place-order-mixin']).toBe(true); - }); + expect(placeOrderMixins['Magento_CheckoutAgreements/js/model/place-order-mixin']).toBe(true); + }); - it('Magento_CheckoutAgreements/js/model/agreements-assigner is called', function () { - var messageContainer = jasmine.createSpy('messageContainer'), - paymentData = {}; + it('Magento_CheckoutAgreements/js/model/agreements-assigner is called', function () { + var messageContainer = jasmine.createSpy('messageContainer'), + paymentData = {}; - mixin(placeOrderAction)(paymentData, messageContainer); - expect(mocks['Magento_CheckoutAgreements/js/model/agreements-assigner']) - .toHaveBeenCalledWith(paymentData); - expect(mocks['Magento_Checkout/js/action/place-order']) - .toHaveBeenCalledWith(paymentData, messageContainer); - }); + mixin(placeOrderAction)(paymentData, messageContainer); + expect(mocks['Magento_CheckoutAgreements/js/model/agreements-assigner']) + .toHaveBeenCalledWith(paymentData); + expect(mocks['Magento_Checkout/js/action/place-order']) + .toHaveBeenCalledWith(paymentData, messageContainer); }); }); }); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/set-payment-information-mixin.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/set-payment-information-mixin.test.js index a33c039992a4b..ed525bfd96a6c 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/set-payment-information-mixin.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/CheckoutAgreements/frontend/js/model/set-payment-information-mixin.test.js @@ -8,52 +8,49 @@ define([ ], function (Squire) { 'use strict'; - describe('Magento_CheckoutAgreements/js/model/set-payment-information-mixin', function () { - var injector = new Squire(), - mocks = { - 'Magento_Checkout/js/action/set-payment-information': jasmine.createSpy('placeOrderAction'), - 'Magento_CheckoutAgreements/js/model/agreements-assigner': jasmine.createSpy('agreementsAssigner') - }, - defaultContext = require.s.contexts._, - mixin, - placeOrderAction; + var injector = new Squire(), + mocks = { + 'Magento_Checkout/js/action/set-payment-information': jasmine.createSpy('placeOrderAction'), + 'Magento_CheckoutAgreements/js/model/agreements-assigner': jasmine.createSpy('agreementsAssigner') + }, + defaultContext = require.s.contexts._, + mixin, + placeOrderAction; - beforeEach(function (done) { - window.checkoutConfig = { - checkoutAgreements: { - isEnabled: true - } - }; - injector.mock(mocks); - injector.require([ - 'Magento_CheckoutAgreements/js/model/set-payment-information-mixin', - 'Magento_Checkout/js/action/set-payment-information' - ], function (Mixin, setPaymentInformation) { - mixin = Mixin; - placeOrderAction = setPaymentInformation; - done(); - }); + beforeEach(function (done) { + window.checkoutConfig = { + checkoutAgreements: { + isEnabled: true + } + }; + injector.mock(mocks); + injector.require([ + 'Magento_CheckoutAgreements/js/model/set-payment-information-mixin', + 'Magento_Checkout/js/action/set-payment-information' + ], function (Mixin, setPaymentInformation) { + mixin = Mixin; + placeOrderAction = setPaymentInformation; + done(); }); + }); - describe('Magento_Checkout/js/action/set-payment-information', function () { - it('Magento_CheckoutAgreements/js/model/set-payment-information-mixin is applied', function () { - var placeOrderMixins = defaultContext - .config.config.mixins['Magento_Checkout/js/action/set-payment-information']; + describe('Magento_CheckoutAgreements/js/model/set-payment-information-mixin', function () { + it('mixin is applied to Magento_Checkout/js/action/set-payment-information', function () { + var placeOrderMixins = defaultContext + .config.config.mixins['Magento_Checkout/js/action/set-payment-information']; - expect(placeOrderMixins['Magento_CheckoutAgreements/js/model/set-payment-information-mixin']) - .toBe(true); - }); + expect(placeOrderMixins['Magento_CheckoutAgreements/js/model/set-payment-information-mixin']).toBe(true); + }); - it('Magento_CheckoutAgreements/js/model/agreements-assigner is called', function () { - var messageContainer = jasmine.createSpy('messageContainer'), - paymentData = {}; + it('Magento_CheckoutAgreements/js/model/agreements-assigner is called', function () { + var messageContainer = jasmine.createSpy('messageContainer'), + paymentData = {}; - mixin(placeOrderAction)(messageContainer, paymentData); - expect(mocks['Magento_CheckoutAgreements/js/model/agreements-assigner']) - .toHaveBeenCalledWith(paymentData); - expect(mocks['Magento_Checkout/js/action/set-payment-information']) - .toHaveBeenCalledWith(messageContainer, paymentData); - }); + mixin(placeOrderAction)(messageContainer, paymentData); + expect(mocks['Magento_CheckoutAgreements/js/model/agreements-assigner']) + .toHaveBeenCalledWith(paymentData); + expect(mocks['Magento_Checkout/js/action/set-payment-information']) + .toHaveBeenCalledWith(messageContainer, paymentData); }); }); }); From 8d6234124c08699e1891c121266be61946306a9f Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Tue, 19 Dec 2017 16:13:22 +0200 Subject: [PATCH 0194/1464] magento/magento2#11897: Catalog product list widget not working with multiple sku --- .../Condition/Product/AbstractProduct.php | 36 ++++++++++++++++++- .../Block/Product/ProductListTest.php | 28 +++++++++++++-- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php index 9a6f1b48620dc..10da7c7a65ebe 100644 --- a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php +++ b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php @@ -137,6 +137,7 @@ public function getDefaultOperatorInputByType() */ $this->_defaultOperatorInputByType['category'] = ['==', '!=', '{}', '!{}', '()', '!()']; $this->_arrayInputTypes[] = 'category'; + $this->_defaultOperatorInputByType['sku'] = ['==', '!=', '{}', '!{}', '()', '!()']; } return $this->_defaultOperatorInputByType; } @@ -382,6 +383,9 @@ public function getInputType() if ($this->getAttributeObject()->getAttributeCode() == 'category_ids') { return 'category'; } + if ($this->getAttributeObject()->getAttributeCode() == 'sku') { + return 'sku'; + } switch ($this->getAttributeObject()->getFrontendInput()) { case 'select': return 'select'; @@ -606,7 +610,10 @@ public function getBindArgumentValue() $this->getValueParsed() )->__toString() ); + } elseif ($this->getAttribute() === 'sku') { + $this->isMultipleSku(); } + return parent::getBindArgumentValue(); } @@ -704,7 +711,7 @@ protected function _getAttributeSetId($productId) public function getOperatorForValidate() { $operator = $this->getOperator(); - if ($this->getInputType() == 'category') { + if ($this->getInputType() == 'category' || $this->isMultipleSku()) { if ($operator == '==') { $operator = '{}'; } elseif ($operator == '!=') { @@ -753,4 +760,31 @@ private function removeTagsFromLabel(array $selectOptions) return $selectOptions; } + + /** + * Check condition contains multiple sku. + * + * @return bool + */ + private function isMultipleSku() + { + $result = false; + if ($this->getInputType() === 'sku') { + if ($this->hasValueParsed()) { + $value = $this->getData('value_parsed'); + if (count($value > 1)) { + $result = true; + } + } else { + $value = $this->getData('value'); + $value = preg_split('#\s*[,;]\s*#', $value, null, PREG_SPLIT_NO_EMPTY); + if (count($value > 1)) { + $this->setValueParsed($value); + $result = true; + } + } + } + + return $result; + } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php b/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php index 6892f7b3a8a88..3b270bb42c544 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogWidget/Block/Product/ProductListTest.php @@ -67,12 +67,36 @@ public function testCreateCollection() . '`attribute`:`multiselect_attribute`,`operator`:`^[^]`,' . '`value`:[`' . implode(',', $multiselectAttributeOptionIds) . '`]^]^]'; $this->block->setData('conditions_encoded', $encodedConditions); + $this->performAssertions(1); + } + + /** + * Test product list widget can process condition with multiple product sku. + * + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + */ + public function testCreateCollectionWithMultipleSkuCondition() + { + $encodedConditions = '^[`1`:^[`type`:`Magento||CatalogWidget||Model||Rule||Condition||Combine`,' . + '`aggregator`:`all`,`value`:`1`,`new_child`:``^],`1--1`:^[`type`:`Magento||CatalogWidget||Model||Rule|' . + '|Condition||Product`,`attribute`:`sku`,`operator`:`==`,`value`:`simple1, simple2`^]^]'; + $this->block->setData('conditions_encoded', $encodedConditions); + $this->performAssertions(2); + } - // Load products collection filtered using specified conditions and perform assesrions + /** + * Check product collection includes correct amount of products. + * + * @param int $count + * @return void + */ + private function performAssertions(int $count) + { + // Load products collection filtered using specified conditions and perform assertions. $productCollection = $this->block->createCollection(); $productCollection->load(); $this->assertEquals( - 1, + $count, $productCollection->count(), "Product collection was not filtered according to the widget condition." ); From 054d3bbf992306f7a2766cc67f1cde3a63563096 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov Date: Tue, 19 Dec 2017 16:31:07 +0200 Subject: [PATCH 0195/1464] MAGETWO-84448: Product Import does not allow store-specific Custom Option labels --- .../Magento/BundleImportExport/Model/Export/RowCustomizer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php index 840accf098c4d..fe96f31f3034d 100644 --- a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php +++ b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php @@ -472,7 +472,7 @@ private function getProductOptionCollections( $product->unsetData($this->optionCollectionCacheKey); $product->setStoreId($storeId); $this->optionCollections[$productSku][$storeId] = $product->getTypeInstance() - ->getOptionCollections($product) + ->getOptionsCollection($product) ->setOrder('position', Collection::SORT_ORDER_ASC); } return $this->optionCollections[$productSku][$storeId]; From 5debdf5a13e748634b3a18300c7f8ce8ee9a6450 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Tue, 19 Dec 2017 17:11:38 +0200 Subject: [PATCH 0196/1464] MAGETWO-71393: Incorrect catalog rule price for bundle product with custom option --- .../Bundle/Pricing/Price/BundleRegularPrice.php | 4 ++-- .../Bundle/Pricing/Price/BundleSelectionPrice.php | 6 +++++- app/code/Magento/Catalog/Model/Product.php | 8 +++++--- .../Magento/Catalog/Model/Product/Option/Value.php | 5 +++-- .../Catalog/Pricing/Price/CustomOptionPrice.php | 11 +++++++---- .../testsuite/Magento/Catalog/Helper/ProductTest.php | 1 + .../Magento/Catalog/Model/ProductPriceTest.php | 1 + 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleRegularPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleRegularPrice.php index 034b735764011..184f8b1e85eaa 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleRegularPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleRegularPrice.php @@ -52,7 +52,7 @@ public function getAmount() if ($this->product->getPriceType() == Price::PRICE_TYPE_FIXED) { /** @var \Magento\Catalog\Pricing\Price\CustomOptionPrice $customOptionPrice */ $customOptionPrice = $this->priceInfo->getPrice(CustomOptionPrice::PRICE_CODE); - $price += $customOptionPrice->getCustomOptionRange(true); + $price += $customOptionPrice->getCustomOptionRange(true, $this->getPriceCode()); } $this->amount[$this->getValue()] = $this->calculator->getMinRegularAmount($price, $this->product); } @@ -71,7 +71,7 @@ public function getMaximalPrice() if ($this->product->getPriceType() == Price::PRICE_TYPE_FIXED) { /** @var \Magento\Catalog\Pricing\Price\CustomOptionPrice $customOptionPrice */ $customOptionPrice = $this->priceInfo->getPrice(CustomOptionPrice::PRICE_CODE); - $price += $customOptionPrice->getCustomOptionRange(false); + $price += $customOptionPrice->getCustomOptionRange(false, $this->getPriceCode()); } $this->maximalPrice = $this->calculator->getMaxRegularAmount($price, $this->product); } diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php index 71c1b5c5e98cb..0d3ed665f5f7d 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php @@ -128,7 +128,11 @@ public function getValue() 'catalog_product_get_final_price', ['product' => $product, 'qty' => $this->bundleProduct->getQty()] ); - $value = $product->getData('final_price') * ($selectionPriceValue / 100); + if ($this->useRegularPrice) { + $value = $product->getData('price') * ($selectionPriceValue / 100); + } else { + $value = $product->getData('final_price') * ($selectionPriceValue / 100); + } } else { // calculate price for selection type fixed $value = $this->priceCurrency->convert($selectionPriceValue); diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index cb5669a4bb42e..90ffbf338bdde 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -610,6 +610,7 @@ public function getUpdatedAt() * * @param bool $calculate * @return void + * @deprecated */ public function setPriceCalculation($calculate = true) { @@ -1159,10 +1160,11 @@ public function setFinalPrice($price) */ public function getFinalPrice($qty = null) { - if ($this->_getData('final_price') === null) { - $this->setFinalPrice($this->getPriceModel()->getFinalPrice($qty, $this)); + if ($this->_calculatePrice || $this->_getData('final_price') === null) { + return $this->getPriceModel()->getFinalPrice($qty, $this); + } else { + return $this->_getData('final_price'); } - return $this->_getData('final_price'); } /** diff --git a/app/code/Magento/Catalog/Model/Product/Option/Value.php b/app/code/Magento/Catalog/Model/Product/Option/Value.php index d92646769b13b..87e234c5b8429 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Value.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Value.php @@ -220,12 +220,13 @@ public function saveValues() * return converted percent to price * * @param bool $flag + * @param string $priceCode * @return float|int */ - public function getPrice($flag = false) + public function getPrice($flag = false, $priceCode = \Magento\Catalog\Pricing\Price\BasePrice::PRICE_CODE) { if ($flag && $this->getPriceType() == self::TYPE_PERCENT) { - $basePrice = $this->getOption()->getProduct()->getPriceInfo()->getPrice(BasePrice::PRICE_CODE)->getValue(); + $basePrice = $this->getOption()->getProduct()->getPriceInfo()->getPrice($priceCode)->getValue(); $price = $basePrice * ($this->_getData(self::KEY_PRICE) / 100); return $price; } diff --git a/app/code/Magento/Catalog/Pricing/Price/CustomOptionPrice.php b/app/code/Magento/Catalog/Pricing/Price/CustomOptionPrice.php index 5026286610118..ca9673a4f6e1f 100644 --- a/app/code/Magento/Catalog/Pricing/Price/CustomOptionPrice.php +++ b/app/code/Magento/Catalog/Pricing/Price/CustomOptionPrice.php @@ -56,11 +56,12 @@ public function __construct( /** * Get minimal and maximal option values * + * @param string $priceCode * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ - public function getValue() + public function getValue($priceCode = \Magento\Catalog\Pricing\Price\BasePrice::PRICE_CODE) { $optionValues = []; $options = $this->product->getOptions(); @@ -85,7 +86,8 @@ public function getValue() } else { /** @var $optionValue \Magento\Catalog\Model\Product\Option\Value */ foreach ($optionItem->getValues() as $optionValue) { - $price = $optionValue->getPrice($optionValue->getPriceType() == Value::TYPE_PERCENT); + $price = + $optionValue->getPrice($optionValue->getPriceType() == Value::TYPE_PERCENT, $priceCode); if ($min === null) { $min = $price; } elseif ($price < $min) { @@ -133,12 +135,13 @@ public function getCustomAmount($amount = null, $exclude = null, $context = []) * Return the minimal or maximal price for custom options * * @param bool $getMin + * @param string $priceCode * @return float */ - public function getCustomOptionRange($getMin) + public function getCustomOptionRange($getMin, $priceCode = \Magento\Catalog\Pricing\Price\BasePrice::PRICE_CODE) { $optionValue = 0.; - $options = $this->getValue(); + $options = $this->getValue($priceCode); foreach ($options as $option) { if ($getMin) { $optionValue += $option['min']; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Helper/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Helper/ProductTest.php index 7d7625f485cfb..623182651b45f 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Helper/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Helper/ProductTest.php @@ -60,6 +60,7 @@ public function testGetFinalPrice() $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Catalog\Model\Product::class ); + $product->setPrice(49.95); $product->setFinalPrice(49.95); $this->assertEquals(49.95, $this->helper->getFinalPrice($product)); } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php index 290b408419784..b867b403f34ac 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductPriceTest.php @@ -68,6 +68,7 @@ public function testGetFormatedPrice() public function testSetGetFinalPrice() { $this->assertEquals(0, $this->_model->getFinalPrice()); + $this->_model->setPrice(10); $this->_model->setFinalPrice(10); $this->assertEquals(10, $this->_model->getFinalPrice()); } From 20bce8d76c6dde17e6ee2ea8d71486fe82422c74 Mon Sep 17 00:00:00 2001 From: Sergey Shvets Date: Tue, 19 Dec 2017 17:54:25 +0200 Subject: [PATCH 0197/1464] MAGETWO-81128: Credit Card form is no longer displayed when creating an order in the admin(enabled Braintree only) --- .../order/create/billing/method/form.phtml | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml index 9dda4e7e067ed..fe7b2929ffed8 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml @@ -12,13 +12,13 @@ $_methods = $block->getMethods(); $_methodsCount = count($_methods); $_counter = 0; + $currentSelectedMethod = $block->getSelectedMethodCode(); ?> getCode(); $_counter++; ?>
- 1) : ?> class="admin__control-radioescapeHtml($className); ?>"/> - - - - -