Skip to content

Commit 1117583

Browse files
authored
Merge pull request #3997 from magento-tsg-csl3/2.2-develop-pr25
[TSG-CSL3] For 2.2 (pr25)
2 parents 9c4350c + 9d44230 commit 1117583

File tree

10 files changed

+283
-9
lines changed

10 files changed

+283
-9
lines changed

app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@
2929
<waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/>
3030
</actionGroup>
3131

32+
<!--Filter the product grid by the Name field-->
33+
<actionGroup name="filterProductGridByName">
34+
<arguments>
35+
<argument name="product" defaultValue="_defaultProduct"/>
36+
</arguments>
37+
<conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/>
38+
<click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/>
39+
<fillField selector="{{AdminProductGridFilterSection.nameFilter}}" userInput="{{product.name}}" stepKey="fillProductNameFilter"/>
40+
<click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFilters"/>
41+
</actionGroup>
42+
3243
<!--Delete a product by filtering grid and using delete action-->
3344
<actionGroup name="deleteProductUsingProductGrid">
3445
<arguments>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
11+
<test name="AdminFilterProductGridByNameByStoreViewTest">
12+
<annotations>
13+
<features value="Catalog"/>
14+
<stories value="Filter products"/>
15+
<title value="Product grid filtering by store view level attribute"/>
16+
<description value="Verify that products grid can be filtered on all store view level by attribute"/>
17+
<severity value="MAJOR"/>
18+
<testCaseId value="MAGETWO-98755"/>
19+
<useCaseId value="MAGETWO-97405"/>
20+
<group value="catalog"/>
21+
</annotations>
22+
<before>
23+
<createData entity="SimpleProduct3" stepKey="createSimpleProduct"/>
24+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
25+
</before>
26+
<after>
27+
<deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/>
28+
<amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/>
29+
<actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearGridFilter"/>
30+
<actionGroup ref="logout" stepKey="logout"/>
31+
</after>
32+
<amOnPage url="{{AdminProductEditPage.url($$createSimpleProduct.id$$)}}" stepKey="goToEditPage"/>
33+
<actionGroup ref="AdminSwitchStoreViewActionGroup" stepKey="switchToDefaultStoreView">
34+
<argument name="scopeName" value="_defaultStore.name"/>
35+
</actionGroup>
36+
<scrollToTopOfPage stepKey="scrollToTopOfAdminProductFormSection"/>
37+
<click selector="{{AdminProductFormSection.productNameUseDefault}}" stepKey="uncheckUseDefault"/>
38+
<fillField selector="{{AdminProductFormSection.productName}}" userInput="{{SimpleProduct.name}}" stepKey="fillNewName"/>
39+
<actionGroup ref="saveProductForm" stepKey="saveSimpleProduct"/>
40+
<amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/>
41+
<actionGroup ref="filterProductGridByName" stepKey="filterGridByName">
42+
<argument name="product" value="SimpleProduct"/>
43+
</actionGroup>
44+
<see selector="{{AdminProductGridSection.firstRow}}" userInput="{{SimpleProduct3.name}}" stepKey="seeProductNameInGrid"/>
45+
</test>
46+
</tests>

app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/ProductCustomOptionsDataProviderTest.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,16 @@ protected function setUp()
5454
->getMockForAbstractClass();
5555
$this->collectionMock = $this->getMockBuilder(AbstractCollection::class)
5656
->disableOriginalConstructor()
57-
->setMethods(['load', 'getSelect', 'getTable', 'getIterator', 'isLoaded', 'toArray', 'getSize'])
57+
->setMethods([
58+
'load',
59+
'getSelect',
60+
'getTable',
61+
'getIterator',
62+
'isLoaded',
63+
'toArray',
64+
'getSize',
65+
'setStoreId',
66+
])
5867
->getMockForAbstractClass();
5968
$this->dbSelectMock = $this->getMockBuilder(DbSelect::class)
6069
->disableOriginalConstructor()

app/code/Magento/Catalog/Ui/DataProvider/Product/ProductCollection.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
*/
66
namespace Magento\Catalog\Ui\DataProvider\Product;
77

8+
use Magento\Catalog\Model\ResourceModel\Eav\Attribute;
9+
use Magento\Framework\Exception\LocalizedException;
10+
use Magento\Eav\Model\Entity\Attribute\AttributeInterface;
11+
812
/**
913
* Collection which is used for rendering product list in the backend.
1014
*
@@ -25,4 +29,63 @@ protected function _productLimitationJoinPrice()
2529
$this->_productLimitationFilters->setUsePriceIndex(false);
2630
return $this->_productLimitationPrice(true);
2731
}
32+
33+
/**
34+
* Add attribute filter to collection
35+
*
36+
* @param AttributeInterface|integer|string|array $attribute
37+
* @param null|string|array $condition
38+
* @param string $joinType
39+
* @return $this
40+
* @throws LocalizedException
41+
*/
42+
public function addAttributeToFilter($attribute, $condition = null, $joinType = 'inner')
43+
{
44+
$storeId = (int)$this->getStoreId();
45+
if ($attribute === 'is_saleable'
46+
|| is_array($attribute)
47+
|| $storeId !== $this->getDefaultStoreId()
48+
) {
49+
return parent::addAttributeToFilter($attribute, $condition, $joinType);
50+
}
51+
52+
if ($attribute instanceof AttributeInterface) {
53+
$attributeModel = $attribute;
54+
} else {
55+
$attributeModel = $this->getEntity()->getAttribute($attribute);
56+
if ($attributeModel === false) {
57+
throw new LocalizedException(
58+
__('Invalid attribute identifier for filter (%1)', get_class($attribute))
59+
);
60+
}
61+
}
62+
63+
if ($attributeModel->isScopeGlobal() || $attributeModel->getBackend()->isStatic()) {
64+
return parent::addAttributeToFilter($attribute, $condition, $joinType);
65+
}
66+
67+
$this->addAttributeToFilterAllStores($attributeModel, $condition);
68+
69+
return $this;
70+
}
71+
72+
/**
73+
* Add attribute to filter by all stores
74+
*
75+
* @param Attribute $attributeModel
76+
* @param array $condition
77+
* @return void
78+
*/
79+
private function addAttributeToFilterAllStores(Attribute $attributeModel, array $condition)
80+
{
81+
$tableName = $this->getTable($attributeModel->getBackendTable());
82+
$entity = $this->getEntity();
83+
$fKey = 'e.' . $this->getEntityPkName($entity);
84+
$pKey = $tableName . '.' . $this->getEntityPkName($entity);
85+
$condition = "({$pKey} = {$fKey}) AND ("
86+
. $this->_getConditionSql("{$tableName}.value", $condition)
87+
. ')';
88+
$selectExistsInAllStores = $this->getConnection()->select()->from($tableName);
89+
$this->getSelect()->exists($selectExistsInAllStores, $condition);
90+
}
2891
}

app/code/Magento/Catalog/Ui/DataProvider/Product/ProductDataProvider.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Catalog\Ui\DataProvider\Product;
77

88
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
9+
use Magento\Store\Model\Store;
910

1011
/**
1112
* Class ProductDataProvider
@@ -58,6 +59,7 @@ public function __construct(
5859
$this->collection = $collectionFactory->create();
5960
$this->addFieldStrategies = $addFieldStrategies;
6061
$this->addFilterStrategies = $addFilterStrategies;
62+
$this->collection->setStoreId(Store::DEFAULT_STORE_ID);
6163
}
6264

6365
/**

app/code/Magento/Sales/Block/Adminhtml/Totals.php

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
*/
66
namespace Magento\Sales\Block\Adminhtml;
77

8+
use Magento\Sales\Model\Order;
9+
10+
/**
11+
* Adminhtml sales totals block
12+
*/
813
class Totals extends \Magento\Sales\Block\Order\Totals
914
{
1015
/**
@@ -67,12 +72,16 @@ protected function _initTotals()
6772
if (!$this->getSource()->getIsVirtual() && ((double)$this->getSource()->getShippingAmount() ||
6873
$this->getSource()->getShippingDescription())
6974
) {
75+
$shippingLabel = __('Shipping & Handling');
76+
if ($this->isFreeShipping($this->getOrder()) && $this->getSource()->getDiscountDescription()) {
77+
$shippingLabel .= sprintf(' (%s)', $this->getSource()->getDiscountDescription());
78+
}
7079
$this->_totals['shipping'] = new \Magento\Framework\DataObject(
7180
[
7281
'code' => 'shipping',
7382
'value' => $this->getSource()->getShippingAmount(),
7483
'base_value' => $this->getSource()->getBaseShippingAmount(),
75-
'label' => __('Shipping & Handling'),
84+
'label' => $shippingLabel,
7685
]
7786
);
7887
}
@@ -109,4 +118,23 @@ protected function _initTotals()
109118

110119
return $this;
111120
}
121+
122+
/**
123+
* Availability of free shipping in at least one order item
124+
*
125+
* @param Order $order
126+
* @return bool
127+
*/
128+
private function isFreeShipping(Order $order): bool
129+
{
130+
$isFreeShipping = false;
131+
foreach ($order->getItems() as $orderItem) {
132+
if ($orderItem->getFreeShipping() == '1') {
133+
$isFreeShipping = true;
134+
break;
135+
}
136+
}
137+
138+
return $isFreeShipping;
139+
}
112140
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Sales\Block\Adminhtml;
9+
10+
use Magento\Framework\View\LayoutInterface;
11+
use Magento\Sales\Model\Order;
12+
use Magento\Sales\Model\OrderFactory;
13+
14+
/**
15+
* Test class for \Magento\Sales\Block\Adminhtml\Totals
16+
*/
17+
class TotalsTest extends \Magento\TestFramework\TestCase\AbstractBackendController
18+
{
19+
/** @var LayoutInterface */
20+
private $layout;
21+
22+
/** @var Totals */
23+
private $block;
24+
25+
/** @var OrderFactory */
26+
private $orderFactory;
27+
28+
/**
29+
* @inheritdoc
30+
*/
31+
protected function setUp()
32+
{
33+
parent::setUp();
34+
$this->layout = $this->_objectManager->get(LayoutInterface::class);
35+
$this->block = $this->layout->createBlock(Totals::class, 'totals_block');
36+
$this->orderFactory = $this->_objectManager->get(OrderFactory::class);
37+
}
38+
39+
/**
40+
* @magentoDataFixture Magento/Sales/_files/order_with_free_shipping_by_coupon.php
41+
*/
42+
public function testShowShippingCoupon()
43+
{
44+
/** @var Order $order */
45+
$order = $this->orderFactory->create();
46+
$order->loadByIncrementId('100000001');
47+
48+
$this->block->setOrder($order);
49+
$this->block->toHtml();
50+
51+
$shippingTotal = $this->block->getTotal('shipping');
52+
$this->assertNotFalse($shippingTotal, 'Shipping method is absent on the total\'s block.');
53+
$this->assertContains(
54+
'1234567890',
55+
$shippingTotal->getLabel(),
56+
'Coupon code is absent in the shipping method label name.'
57+
);
58+
}
59+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Sales\Api\OrderRepositoryInterface;
9+
use Magento\Sales\Model\Order;
10+
use Magento\Sales\Model\Order\Item as OrderItem;
11+
12+
require __DIR__ . '/../../../Magento/Sales/_files/order.php';
13+
/** @var \Magento\Catalog\Model\Product $product */
14+
15+
/** @var OrderItem $orderItem */
16+
$orderItem = $objectManager->create(OrderItem::class);
17+
$orderItem->setProductId($product->getId())
18+
->setQtyOrdered(2)
19+
->setBasePrice($product->getPrice())
20+
->setPrice($product->getPrice())
21+
->setRowTotal($product->getPrice())
22+
->setProductType('simple')
23+
->setName($product->getName())
24+
->setFreeShipping('1');
25+
26+
/** @var Order $order */
27+
$order->setShippingDescription('Flat Rate - Fixed')
28+
->setShippingAmount(0)
29+
->setCouponCode('1234567890')
30+
->setDiscountDescription('1234567890')
31+
->addItem($orderItem);
32+
33+
/** @var OrderRepositoryInterface $orderRepository */
34+
$orderRepository = $objectManager->create(OrderRepositoryInterface::class);
35+
$orderRepository->save($order);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
require 'default_rollback.php';

lib/internal/Magento/Framework/Data/Form/Element/Date.php

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,19 @@ public function __construct(
4949
}
5050
}
5151

52+
/**
53+
* Check if a string is a date value
54+
*
55+
* @param string $value
56+
* @return bool
57+
*/
58+
private function isDate(string $value): bool
59+
{
60+
$date = date_parse($value);
61+
62+
return !empty($date['year']) && !empty($date['month']) && !empty($date['day']);
63+
}
64+
5265
/**
5366
* If script executes on x64 system, converts large
5467
* numeric values to timestamp limit
@@ -82,14 +95,14 @@ public function setValue($value)
8295
$this->_value = $value;
8396
return $this;
8497
}
85-
if (preg_match('/^[0-9]+$/', $value)) {
86-
$this->_value = (new \DateTime())->setTimestamp($this->_toTimestamp($value));
87-
88-
return $this;
89-
}
90-
9198
try {
92-
$this->_value = new \DateTime($value, new \DateTimeZone($this->localeDate->getConfigTimezone()));
99+
if (preg_match('/^[0-9]+$/', $value)) {
100+
$this->_value = (new \DateTime())->setTimestamp($this->_toTimestamp($value));
101+
} else if (is_string($value) && $this->isDate($value)) {
102+
$this->_value = new \DateTime($value, new \DateTimeZone($this->localeDate->getConfigTimezone()));
103+
} else {
104+
$this->_value = '';
105+
}
93106
} catch (\Exception $e) {
94107
$this->_value = '';
95108
}

0 commit comments

Comments
 (0)