Skip to content

Commit

Permalink
Merge branch '2.4-develop' into fix_store_name_rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
engcom-Hotel authored Aug 18, 2020
2 parents 9a98048 + 4930963 commit 5fbb3cf
Show file tree
Hide file tree
Showing 464 changed files with 18,991 additions and 3,212 deletions.
36 changes: 24 additions & 12 deletions app/autoload.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,48 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

use Magento\Framework\Autoload\AutoloaderRegistry;
use Magento\Framework\Autoload\ClassLoaderWrapper;

/**
* Shortcut constant for the root directory
*/
define('BP', dirname(__DIR__));
\define('BP', \dirname(__DIR__));

define('VENDOR_PATH', BP . '/app/etc/vendor_path.php');
\define('VENDOR_PATH', BP . '/app/etc/vendor_path.php');

if (!file_exists(VENDOR_PATH)) {
if (!\is_readable(VENDOR_PATH)) {
throw new \Exception(
'We can\'t read some files that are required to run the Magento application. '
. 'This usually means file permissions are set incorrectly.'
);
}

$vendorDir = require VENDOR_PATH;
$vendorAutoload = BP . "/{$vendorDir}/autoload.php";
$vendorAutoload = (
static function (): ?string {
$vendorDir = require VENDOR_PATH;

$vendorAutoload = BP . "/{$vendorDir}/autoload.php";
if (\is_readable($vendorAutoload)) {
return $vendorAutoload;
}

$vendorAutoload = "{$vendorDir}/autoload.php";
if (\is_readable($vendorAutoload)) {
return $vendorAutoload;
}

return null;
}
)();

/* 'composer install' validation */
if (file_exists($vendorAutoload)) {
$composerAutoloader = include $vendorAutoload;
} else if (file_exists("{$vendorDir}/autoload.php")) {
$vendorAutoload = "{$vendorDir}/autoload.php";
$composerAutoloader = include $vendorAutoload;
} else {
if ($vendorAutoload === null) {
throw new \Exception(
'Vendor autoload is not found. Please run \'composer install\' under application root directory.'
);
}

$composerAutoloader = include $vendorAutoload;
AutoloaderRegistry::registerAutoloader(new ClassLoaderWrapper($composerAutoloader));
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ protected function _getCurrencyList()
/**
* Retrieve filter value
*
* @param null $index
* @param string|null $index
* @return array|null
*/
public function getValue($index = null)
Expand Down Expand Up @@ -194,11 +194,11 @@ public function getCondition()
$rate = $this->_getRate($displayCurrency, $this->_getColumnCurrencyCode());

if (isset($value['from'])) {
$value['from'] *= $rate;
$value['from'] = (float) $value['from'] * $rate;
}

if (isset($value['to'])) {
$value['to'] *= $rate;
$value['to'] = (float) $value['to'] * $rate;
}

$this->prepareRates($displayCurrency);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@
<waitForLoadingMaskToDisappear stepKey="waitForLoadingCheckoutPageWithShippingMethod"/>
<click selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/>
<waitForLoadingMaskToDisappear stepKey="waitForLoadingMask1"/>
<waitForElement selector="{{CheckoutShippingMethodsSection.next}}" time="30" stepKey="waitForNextButton"/>
<click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/>
<actionGroup ref="StorefrontCheckoutClickNextButtonActionGroup" stepKey="clickNext"/>
<!-- Checkout select Check/Money Order payment -->
<comment userInput="Select Check/Money payment" stepKey="checkoutSelectCheckMoneyPayment"/>
<actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyPayment"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Backend\Test\Unit\Block\Widget\Grid\Column\Filter;

use Magento\Backend\Block\Context;
use Magento\Backend\Block\Widget\Grid\Column;
use Magento\Backend\Block\Widget\Grid\Column\Filter\Price;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\DB\Helper;
use Magento\Directory\Model\Currency;
use Magento\Directory\Model\Currency\DefaultLocator;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class PriceTest extends TestCase
{
/** @var RequestInterface|MockObject */
private $requestMock;

/** @var Context|MockObject */
private $context;

/** @var Helper|MockObject */
private $helper;

/** @var Currency|MockObject */
private $currency;

/** @var DefaultLocator|MockObject */
private $currencyLocator;

/** @var Column|MockObject */
private $columnMock;

/** @var Price */
private $blockPrice;

protected function setUp(): void
{
$this->requestMock = $this->getMockForAbstractClass(RequestInterface::class);

$this->context = $this->createMock(Context::class);
$this->context->expects($this->any())->method('getRequest')->willReturn($this->requestMock);

$this->helper = $this->createMock(Helper::class);

$this->currency = $this->getMockBuilder(Currency::class)
->disableOriginalConstructor()
->setMethods(['getAnyRate'])
->getMock();

$this->currencyLocator = $this->createMock(DefaultLocator::class);

$this->columnMock = $this->getMockBuilder(Column::class)
->disableOriginalConstructor()
->setMethods(['getCurrencyCode'])
->getMock();

$helper = new ObjectManager($this);

$this->blockPrice = $helper->getObject(Price::class, [
'context' => $this->context,
'resourceHelper' => $this->helper,
'currencyModel' => $this->currency,
'currencyLocator' => $this->currencyLocator
]);
$this->blockPrice->setColumn($this->columnMock);
}

public function testGetCondition()
{
$this->currencyLocator->expects(
$this->any()
)->method(
'getDefaultCurrency'
)->with(
$this->requestMock
)->willReturn(
'defaultCurrency'
);

$this->currency->expects($this->at(0))
->method('getAnyRate')
->with('defaultCurrency')
->willReturn(1.0);

$testValue = [
'value' => [
'from' => '1234a',
]
];

$this->blockPrice->addData($testValue);
$this->assertEquals(['from' => 1234], $this->blockPrice->getCondition());
}
}
96 changes: 76 additions & 20 deletions app/code/Magento/Bundle/Model/Product/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

namespace Magento\Bundle\Model\Product;

use Magento\Bundle\Model\Option;
use Magento\Bundle\Model\ResourceModel\Option\Collection;
use Magento\Bundle\Model\ResourceModel\Selection\Collection as Selections;
use Magento\Bundle\Model\ResourceModel\Selection\Collection\FilterApplier as SelectionCollectionFilterApplier;
use Magento\Catalog\Api\ProductRepositoryInterface;
Expand Down Expand Up @@ -414,16 +416,13 @@ public function beforeSave($product)
if ($product->getCanSaveBundleSelections()) {
$product->canAffectOptions(true);
$selections = $product->getBundleSelectionsData();
if ($selections && !empty($selections)) {
$options = $product->getBundleOptionsData();
if ($options) {
foreach ($options as $option) {
if (empty($option['delete']) || 1 != (int)$option['delete']) {
$product->setTypeHasOptions(true);
if (1 == (int)$option['required']) {
$product->setTypeHasRequiredOptions(true);
break;
}
if (!empty($selections) && $options = $product->getBundleOptionsData()) {
foreach ($options as $option) {
if (empty($option['delete']) || 1 != (int)$option['delete']) {
$product->setTypeHasOptions(true);
if (1 == (int)$option['required']) {
$product->setTypeHasRequiredOptions(true);
break;
}
}
}
Expand Down Expand Up @@ -464,7 +463,7 @@ public function getOptionsIds($product)
public function getOptionsCollection($product)
{
if (!$product->hasData($this->_keyOptionsCollection)) {
/** @var \Magento\Bundle\Model\ResourceModel\Option\Collection $optionsCollection */
/** @var Collection $optionsCollection */
$optionsCollection = $this->_bundleOption->create()
->getResourceCollection();
$optionsCollection->setProductIdFilter($product->getEntityId());
Expand Down Expand Up @@ -530,10 +529,10 @@ public function getSelectionsCollection($optionIds, $product)
* Example: the catalog inventory validation of decimal qty can change qty to int,
* so need to change quote item qty option value too.
*
* @param array $options
* @param \Magento\Framework\DataObject $option
* @param mixed $value
* @param \Magento\Catalog\Model\Product $product
* @param array $options
* @param \Magento\Framework\DataObject $option
* @param mixed $value
* @param \Magento\Catalog\Model\Product $product
* @return $this
*/
public function updateQtyOption($options, \Magento\Framework\DataObject $option, $value, $product)
Expand Down Expand Up @@ -682,6 +681,11 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p
$options
);

$this->validateRadioAndSelectOptions(
$optionsCollection,
$options
);

$selectionIds = array_values($this->arrayUtility->flatten($options));
// If product has not been configured yet then $selections array should be empty
if (!empty($selectionIds)) {
Expand Down Expand Up @@ -1184,9 +1188,11 @@ public function canConfigure($product)
* @return void
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
// @codingStandardsIgnoreStart
public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
{
}
// @codingStandardsIgnoreEnd

/**
* Return array of specific to type product entities
Expand All @@ -1196,18 +1202,19 @@ public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
*/
public function getIdentities(\Magento\Catalog\Model\Product $product)
{
$identities = parent::getIdentities($product);
$identities = [];
$identities[] = parent::getIdentities($product);
/** @var \Magento\Bundle\Model\Option $option */
foreach ($this->getOptions($product) as $option) {
if ($option->getSelections()) {
/** @var \Magento\Catalog\Model\Product $selection */
foreach ($option->getSelections() as $selection) {
$identities = array_merge($identities, $selection->getIdentities());
$identities[] = $selection->getIdentities();
}
}
}

return $identities;
return array_merge([], ...$identities);
}

/**
Expand Down Expand Up @@ -1272,6 +1279,53 @@ protected function checkIsAllRequiredOptions($product, $isStrictProcessMode, $op
}
}

/**
* Validate Options for Radio and Select input types
*
* @param Collection $optionsCollection
* @param int[] $options
* @return void
* @throws \Magento\Framework\Exception\LocalizedException
*/
private function validateRadioAndSelectOptions($optionsCollection, $options): void
{
$errorTypes = [];

if (is_array($optionsCollection->getItems())) {
foreach ($optionsCollection->getItems() as $option) {
if ($this->isSelectedOptionValid($option, $options)) {
$errorTypes[] = $option->getType();
}
}
}

if (!empty($errorTypes)) {
throw new \Magento\Framework\Exception\LocalizedException(
__(
'Option type (%types) should have only one element.',
['types' => implode(", ", $errorTypes)]
)
);
}
}

/**
* Check if selected option is valid
*
* @param Option $option
* @param array $options
* @return bool
*/
private function isSelectedOptionValid($option, $options): bool
{
return (
($option->getType() == 'radio' || $option->getType() == 'select') &&
isset($options[$option->getOptionId()]) &&
is_array($options[$option->getOptionId()]) &&
count($options[$option->getOptionId()]) > 1
);
}

/**
* Check if selection is salable
*
Expand Down Expand Up @@ -1333,16 +1387,18 @@ protected function checkIsResult($_result)
*/
protected function mergeSelectionsWithOptions($options, $selections)
{
$selections = [];

foreach ($options as $option) {
$optionSelections = $option->getSelections();
if ($option->getRequired() && is_array($optionSelections) && count($optionSelections) == 1) {
$selections = array_merge($selections, $optionSelections);
$selections[] = $optionSelections;
} else {
$selections = [];
break;
}
}

return $selections;
return array_merge([], ...$selections);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->

<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
<actionGroup name="AdminClickAddProductToOptionActionGroup">
<annotations>
<description>Click AddProductToOption button for bundle product.</description>
</annotations>

<waitForElementVisible selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="waitForAddProductsToBundle"/>
<click selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="clickAddProductsToOption"/>
<waitForPageLoad stepKey="waitForPageLoadAfterBundleProducts"/>
</actionGroup>
</actionGroups>
Loading

0 comments on commit 5fbb3cf

Please sign in to comment.