Skip to content

Commit 9e0e950

Browse files
authored
ENGCOM-6635: FIX #25856 / Group Ordered Products report by SKU #25858
2 parents 9b1ce24 + 53f14ae commit 9e0e950

File tree

7 files changed

+256
-23
lines changed

7 files changed

+256
-23
lines changed

app/code/Magento/Reports/Model/ResourceModel/Product/Sold/Collection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public function addOrderedQty($from = '', $to = '')
8484
)->columns(
8585
'SUM(order_items.qty_ordered) as ordered_qty'
8686
)->group(
87-
'order_items.product_id'
87+
'order_items.sku'
8888
);
8989
return $this;
9090
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
10+
<actionGroup name="AdminGenerateProductsOrderedReportActionGroup">
11+
<annotations>
12+
<description>Navigate to Reports > Products > Ordered page. Enters the provided Order From/To Dates. Clicks on 'Refresh'.</description>
13+
</annotations>
14+
<arguments>
15+
<argument name="orderFromDate" type="string"/>
16+
<argument name="orderToDate" type="string"/>
17+
</arguments>
18+
19+
<amOnPage url="{{SoldReportPage.url}}" stepKey="navigateToOrderedProductPage"/>
20+
<fillField selector="{{SoldReportFilterSection.dateFrom}}" userInput="{{orderFromDate}}" stepKey="fillFromDate"/>
21+
<fillField selector="{{SoldReportFilterSection.dateTo}}" userInput="{{orderToDate}}" stepKey="fillToDate"/>
22+
<click selector="{{SoldReportFilterSection.buttonRefresh}}" stepKey="clickRefresh"/>
23+
</actionGroup>
24+
</actionGroups>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
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+
<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd">
9+
<page name="SoldReportPage" url="reports/report_product/sold/" area="admin" module="Reports">
10+
<section name="SoldReportMainSection"/>
11+
</page>
12+
</pages>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
11+
<section name="SoldReportFilterSection">
12+
<element name="dateFrom" type="input" selector="#gridProductsSold_period_date_from"/>
13+
<element name="dateTo" type="input" selector="#gridProductsSold_period_date_to"/>
14+
<element name="buttonRefresh" type="button" selector="//button/span[contains(text(),'Refresh')]" />
15+
<element name="gridProduct" type="text" selector="#gridProductsSold_table"/>
16+
</section>
17+
</sections>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
10+
<test name="AdminReportsOrderedGroupedBySkuTest">
11+
<annotations>
12+
<title value="Verify grouped by SKU on report"/>
13+
<description value="Verify the list of configurable product grouped by SKU, on report page 'Reports > Products > Ordered'"/>
14+
<group value="reports"/>
15+
</annotations>
16+
<before>
17+
<createData entity="_defaultCategory" stepKey="createCategory"/>
18+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
19+
<actionGroup ref="CreateConfigurableProductActionGroup" stepKey="createConfigurableProduct">
20+
<argument name="product" value="_defaultProduct"/>
21+
<argument name="category" value="$$createCategory$$"/>
22+
</actionGroup>
23+
<createData entity="Simple_US_Customer" stepKey="createCustomer"/>
24+
</before>
25+
<after>
26+
<deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/>
27+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
28+
<actionGroup ref="DeleteProductBySkuActionGroup" stepKey="deleteConfigurableProduct">
29+
<argument name="sku" value="{{_defaultProduct.sku}}"/>
30+
</actionGroup>
31+
<actionGroup ref="DeleteProductAttributeByLabelActionGroup" stepKey="deleteAttributeSet">
32+
<argument name="ProductAttribute" value="colorProductAttribute"/>
33+
</actionGroup>
34+
<actionGroup ref="logout" stepKey="logout"/>
35+
</after>
36+
37+
<!--Add first configurable product to order-->
38+
<actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="navigateToFirstOrderWithExistingCustomer">
39+
<argument name="customer" value="$$createCustomer$$"/>
40+
</actionGroup>
41+
<actionGroup ref="AddConfigurableProductToOrderActionGroup" stepKey="addFirstConfigurableProductToOrder">
42+
<argument name="product" value="_defaultProduct"/>
43+
<argument name="attribute" value="colorProductAttribute"/>
44+
<argument name="option" value="colorProductAttribute1"/>
45+
</actionGroup>
46+
<click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="submitFirstOrder"/>
47+
48+
<!--Add second configurable product to order-->
49+
<actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="navigateToSecondOrderWithExistingCustomer">
50+
<argument name="customer" value="$$createCustomer$$"/>
51+
</actionGroup>
52+
<actionGroup ref="AddConfigurableProductToOrderActionGroup" stepKey="addSecondConfigurableProductToOrder">
53+
<argument name="product" value="_defaultProduct"/>
54+
<argument name="attribute" value="colorProductAttribute"/>
55+
<argument name="option" value="colorProductAttribute2"/>
56+
</actionGroup>
57+
<click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="submitSecondOrder"/>
58+
59+
<!-- Get date -->
60+
<generateDate stepKey="generateStartDate" date="-1 minute" format="m/d/Y"/>
61+
<generateDate stepKey="generateEndDate" date="+1 minute" format="m/d/Y"/>
62+
<actionGroup ref="AdminGenerateProductsOrderedReportActionGroup" stepKey="generateReport">
63+
<argument name="orderFromDate" value="$generateStartDate"/>
64+
<argument name="orderToDate" value="$generateEndDate" />
65+
</actionGroup>
66+
67+
<!-- Verify data -->
68+
<grabTextFrom selector="{{SoldReportFilterSection.gridProduct}}" stepKey="grabData"/>
69+
<assertContains stepKey="assertFirst">
70+
<actualResult type="string">{$grabData}</actualResult>
71+
<expectedResult type="string">{{_defaultProduct.sku}}-{{colorProductAttribute1.name}}</expectedResult>
72+
</assertContains>
73+
<assertContains stepKey="assertSecond">
74+
<actualResult type="string">{$grabData}</actualResult>
75+
<expectedResult type="string">{{_defaultProduct.sku}}-{{colorProductAttribute2.name}}</expectedResult>
76+
</assertContains>
77+
</test>
78+
</tests>

app/code/Magento/Reports/Test/Unit/Model/ResourceModel/Product/Sold/Collection/CollectionTest.php

Lines changed: 123 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,52 +3,154 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
67

78
namespace Magento\Reports\Test\Unit\Model\ResourceModel\Product\Sold\Collection;
89

10+
use Magento\Framework\DB\Adapter\AdapterInterface;
911
use Magento\Framework\DB\Select;
10-
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
1112
use Magento\Reports\Model\ResourceModel\Product\Sold\Collection;
13+
use Magento\Sales\Model\Order;
14+
use PHPUnit\Framework\TestCase;
15+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
1216

1317
/**
18+
* Verify data collection class.
19+
*
1420
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1521
*/
16-
class CollectionTest extends \PHPUnit\Framework\TestCase
22+
class CollectionTest extends TestCase
1723
{
1824
/**
19-
* @var ObjectManager
25+
* @var AdapterInterface|MockObject
2026
*/
21-
protected $objectManager;
27+
protected $adapterMock;
2228

2329
/**
24-
* @var \PHPUnit_Framework_MockObject_MockObject
30+
* @var Select|MockObject
2531
*/
2632
protected $selectMock;
2733

34+
/**
35+
* @var Collection;
36+
*/
37+
protected $collection;
38+
39+
/**
40+
* @inheritDoc
41+
*/
2842
protected function setUp()
2943
{
30-
$this->objectManager = new ObjectManager($this);
3144
$this->selectMock = $this->createMock(Select::class);
32-
}
33-
34-
public function testGetSelectCountSql()
35-
{
36-
/** @var $collection \PHPUnit_Framework_MockObject_MockObject */
37-
$collection = $this->getMockBuilder(Collection::class)
38-
->setMethods(['getSelect'])
45+
$this->adapterMock = $this->createMock(AdapterInterface::class);
46+
$this->collection = $this->getMockBuilder(Collection::class)
47+
->setMethods([
48+
'getSelect',
49+
'getConnection',
50+
'getTable'
51+
])
3952
->disableOriginalConstructor()
4053
->getMock();
54+
}
4155

42-
$collection->expects($this->atLeastOnce())->method('getSelect')->willReturn($this->selectMock);
43-
44-
$this->selectMock->expects($this->atLeastOnce())->method('reset')->willReturnSelf();
45-
$this->selectMock->expects($this->exactly(2))->method('columns')->willReturnSelf();
56+
/**
57+
* Verify get select count sql.
58+
*
59+
* @return void
60+
*/
61+
public function testGetSelectCountSql(): void
62+
{
63+
$this->collection->expects($this->atLeastOnce())
64+
->method('getSelect')
65+
->willReturn($this->selectMock);
66+
$this->selectMock->expects($this->atLeastOnce())
67+
->method('reset')
68+
->willReturnSelf();
69+
$this->selectMock->expects($this->exactly(2))
70+
->method('columns')
71+
->willReturnSelf();
72+
$this->selectMock->expects($this->at(6))
73+
->method('columns')
74+
->with('COUNT(DISTINCT main_table.entity_id)');
75+
$this->selectMock->expects($this->at(7))
76+
->method('reset')
77+
->with(Select::COLUMNS);
78+
$this->selectMock->expects($this->at(8))
79+
->method('columns')
80+
->with('COUNT(DISTINCT order_items.item_id)');
4681

47-
$this->selectMock->expects($this->at(6))->method('columns')->with('COUNT(DISTINCT main_table.entity_id)');
82+
$this->assertEquals($this->selectMock, $this->collection->getSelectCountSql());
83+
}
4884

49-
$this->selectMock->expects($this->at(7))->method('reset')->with(Select::COLUMNS);
50-
$this->selectMock->expects($this->at(8))->method('columns')->with('COUNT(DISTINCT order_items.item_id)');
85+
/**
86+
* Verify add ordered qty.
87+
*
88+
* @return void
89+
*/
90+
public function testAddOrderedQty(): void
91+
{
92+
$this->collection->expects($this->once())
93+
->method('getConnection')
94+
->willReturn($this->adapterMock);
95+
$this->adapterMock->expects($this->once())
96+
->method('quoteIdentifier')
97+
->with('order')
98+
->willReturn('sales_order');
99+
$this->adapterMock->expects($this->once())
100+
->method('quoteInto')
101+
->with('sales_order.state <> ?', Order::STATE_CANCELED)
102+
->willReturn('');
103+
$this->collection->expects($this->atLeastOnce())
104+
->method('getSelect')
105+
->willReturn($this->selectMock);
106+
$this->collection->expects($this->exactly(2))
107+
->method('getTable')
108+
->withConsecutive(
109+
['sales_order_item'],
110+
['sales_order']
111+
)->willReturnOnConsecutiveCalls(
112+
'sales_order_item',
113+
'sales_order'
114+
);
115+
$this->selectMock->expects($this->atLeastOnce())
116+
->method('reset')
117+
->willReturnSelf();
118+
$this->selectMock->expects($this->atLeastOnce())
119+
->method('from')
120+
->with(
121+
[ 'order_items' => 'sales_order_item'],
122+
[
123+
'ordered_qty' => 'order_items.qty_ordered',
124+
'order_items_name' => 'order_items.name',
125+
'order_items_sku' => 'order_items.sku'
126+
]
127+
)
128+
->willReturnSelf();
129+
$this->selectMock->expects($this->atLeastOnce())
130+
->method('joinInner')
131+
->with(
132+
['order' => 'sales_order'],
133+
'sales_order.entity_id = order_items.order_id AND ',
134+
[]
135+
)
136+
->willReturnSelf();
137+
$this->selectMock->expects($this->atLeastOnce())
138+
->method('where')
139+
->with('order_items.parent_item_id IS NULL')
140+
->willReturnSelf();
141+
$this->selectMock->expects($this->atLeastOnce())
142+
->method('having')
143+
->with('order_items.qty_ordered > ?', 0)
144+
->willReturnSelf();
145+
$this->selectMock->expects($this->atLeastOnce())
146+
->method('columns')
147+
->with('SUM(order_items.qty_ordered) as ordered_qty')
148+
->willReturnSelf();
149+
$this->selectMock->expects($this->atLeastOnce())
150+
->method('group')
151+
->with('order_items.sku')
152+
->willReturnSelf();
51153

52-
$this->assertEquals($this->selectMock, $collection->getSelectCountSql());
154+
$this->assertEquals($this->collection, $this->collection->addOrderedQty());
53155
}
54156
}

app/code/Magento/Reports/etc/db_schema_whitelist.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,4 @@
149149
"REPORT_VIEWED_PRD_AGGRED_YEARLY_PRD_ID_SEQUENCE_PRD_SEQUENCE_VAL": true
150150
}
151151
}
152-
}
152+
}

0 commit comments

Comments
 (0)