Skip to content

Commit 1cca759

Browse files
committed
Merge pull request #399 from magento-tango/MAGETWO-49681
[Tango] Bug fixes. Product custom options import
2 parents fa74f85 + 9c0d20d commit 1cca759

File tree

15 files changed

+380
-76
lines changed

15 files changed

+380
-76
lines changed

app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,6 @@ protected function getHiddenColumn($columnName, $sortOrder)
364364
];
365365
}
366366

367-
368367
/**
369368
* Get configuration for the modal set: modal and trigger button
370369
*
@@ -579,7 +578,6 @@ protected function getBundleSelections()
579578
'sortOrder' => 100,
580579
'validation' => [
581580
'validate-number' => true,
582-
'validate-digits' => true,
583581
],
584582
],
585583
],
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<?php
2+
/**
3+
* Copyright © 2015 Magento. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Test\Unit\Ui\DataProvider\Product;
7+
8+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
9+
use Magento\Catalog\Ui\DataProvider\Product\ProductCustomOptionsDataProvider;
10+
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
11+
use Magento\Framework\App\RequestInterface;
12+
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
13+
use Magento\Framework\DB\Select as DbSelect;
14+
15+
class ProductCustomOptionsDataProviderTest extends \PHPUnit_Framework_TestCase
16+
{
17+
/**
18+
* @var ObjectManagerHelper
19+
*/
20+
protected $objectManagerHelper;
21+
22+
/**
23+
* @var ProductCustomOptionsDataProvider
24+
*/
25+
protected $dataProvider;
26+
27+
/**
28+
* @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
29+
*/
30+
protected $collectionFactoryMock;
31+
32+
/**
33+
* @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject
34+
*/
35+
protected $requestMock;
36+
37+
/**
38+
* @var AbstractCollection|\PHPUnit_Framework_MockObject_MockObject
39+
*/
40+
protected $collectionMock;
41+
42+
/**
43+
* @var DbSelect|\PHPUnit_Framework_MockObject_MockObject
44+
*/
45+
protected $dbSelectMock;
46+
47+
protected function setUp()
48+
{
49+
$this->collectionFactoryMock = $this->getMockBuilder(CollectionFactory::class)
50+
->disableOriginalConstructor()
51+
->setMethods(['create'])
52+
->getMock();
53+
$this->requestMock = $this->getMockBuilder(RequestInterface::class)
54+
->getMockForAbstractClass();
55+
$this->collectionMock = $this->getMockBuilder(AbstractCollection::class)
56+
->disableOriginalConstructor()
57+
->setMethods(['load', 'getSelect', 'getTable', 'getIterator', 'isLoaded', 'toArray', 'getSize'])
58+
->getMockForAbstractClass();
59+
$this->dbSelectMock = $this->getMockBuilder(DbSelect::class)
60+
->disableOriginalConstructor()
61+
->getMock();
62+
63+
$this->collectionFactoryMock->expects($this->once())
64+
->method('create')
65+
->willReturn($this->collectionMock);
66+
67+
$this->objectManagerHelper = new ObjectManagerHelper($this);
68+
$this->dataProvider = $this->objectManagerHelper->getObject(
69+
ProductCustomOptionsDataProvider::class,
70+
[
71+
'collectionFactory' => $this->collectionFactoryMock,
72+
'request' => $this->requestMock
73+
]
74+
);
75+
}
76+
77+
/**
78+
* @param int $amount
79+
* @param array $collectionArray
80+
* @param array $result
81+
* @dataProvider getDataDataProvider
82+
*/
83+
public function testGetDataCollectionIsLoaded($amount, array $collectionArray, array $result)
84+
{
85+
$this->collectionMock->expects($this->never())
86+
->method('load');
87+
88+
$this->setCommonExpectations(true, $amount, $collectionArray);
89+
90+
$this->assertSame($result, $this->dataProvider->getData());
91+
}
92+
93+
/**
94+
* @param int $amount
95+
* @param array $collectionArray
96+
* @param array $result
97+
* @dataProvider getDataDataProvider
98+
*/
99+
public function testGetData($amount, array $collectionArray, array $result)
100+
{
101+
$tableName = 'catalog_product_option_table';
102+
103+
$this->collectionMock->expects($this->once())
104+
->method('isLoaded')
105+
->willReturn(false);
106+
$this->requestMock->expects($this->once())
107+
->method('getParam')
108+
->with('current_product_id', null)
109+
->willReturn(0);
110+
$this->collectionMock->expects($this->any())
111+
->method('getSelect')
112+
->willReturn($this->dbSelectMock);
113+
$this->dbSelectMock->expects($this->any())
114+
->method('distinct')
115+
->willReturnSelf();
116+
$this->collectionMock->expects($this->any())
117+
->method('getTable')
118+
->with('catalog_product_option')
119+
->willReturn($tableName);
120+
$this->dbSelectMock->expects($this->once())
121+
->method('join')
122+
->with(['opt' => $tableName], 'opt.product_id = e.entity_id', null)
123+
->willReturnSelf();
124+
$this->collectionMock->expects($this->once())
125+
->method('load')
126+
->willReturnSelf();
127+
$this->collectionMock->expects($this->any())
128+
->method('getIterator')
129+
->willReturn(new \ArrayIterator([]));
130+
131+
$this->setCommonExpectations(false, $amount, $collectionArray);
132+
133+
$this->assertSame($result, $this->dataProvider->getData());
134+
}
135+
136+
/**
137+
* @return array
138+
*/
139+
public function getDataDataProvider()
140+
{
141+
return [
142+
0 => [
143+
'amount' => 2,
144+
'collectionArray' => [
145+
'12' => ['id' => '12', 'value' => 'test1'],
146+
'25' => ['id' => '25', 'value' => 'test2']
147+
],
148+
'result' => [
149+
'totalRecords' => 2,
150+
'items' => [
151+
['id' => '12', 'value' => 'test1'],
152+
['id' => '25', 'value' => 'test2']
153+
]
154+
]
155+
]
156+
];
157+
}
158+
159+
/**
160+
* Set common expectations
161+
*
162+
* @param bool $isLoaded
163+
* @param int $amount
164+
* @param array $collectionArray
165+
* @return void
166+
*/
167+
protected function setCommonExpectations($isLoaded, $amount, array $collectionArray)
168+
{
169+
$this->collectionMock->expects($this->once())
170+
->method('isLoaded')
171+
->willReturn($isLoaded);
172+
$this->collectionMock->expects($this->once())
173+
->method('toArray')
174+
->willReturn($collectionArray);
175+
$this->collectionMock->expects($this->once())
176+
->method('getSize')
177+
->willReturn($amount);
178+
}
179+
}

app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AbstractModifier.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
abstract class AbstractModifier implements ModifierInterface
1717
{
18+
const FORM_NAME = 'product_form';
1819
const DATA_SOURCE_DEFAULT = 'product';
1920
const DATA_SCOPE_PRODUCT = 'data.product';
2021

app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class CustomOptions extends AbstractModifier
8484
* Import options values
8585
*/
8686
const IMPORT_OPTIONS_MODAL = 'import_options_modal';
87+
const CUSTOM_OPTIONS_LISTING = 'product_custom_options_listing';
8788
/**#@-*/
8889

8990
/**
@@ -121,36 +122,28 @@ class CustomOptions extends AbstractModifier
121122
*/
122123
protected $meta = [];
123124

124-
/**
125-
* @var string
126-
*/
127-
protected $scopeName;
128-
129125
/**
130126
* @param LocatorInterface $locator
131127
* @param StoreManagerInterface $storeManager
132128
* @param ConfigInterface $productOptionsConfig
133129
* @param ProductOptionsPrice $productOptionsPrice
134130
* @param UrlInterface $urlBuilder
135131
* @param ArrayManager $arrayManager
136-
* @param string $scopeName
137132
*/
138133
public function __construct(
139134
LocatorInterface $locator,
140135
StoreManagerInterface $storeManager,
141136
ConfigInterface $productOptionsConfig,
142137
ProductOptionsPrice $productOptionsPrice,
143138
UrlInterface $urlBuilder,
144-
ArrayManager $arrayManager,
145-
$scopeName = ''
139+
ArrayManager $arrayManager
146140
) {
147141
$this->locator = $locator;
148142
$this->storeManager = $storeManager;
149143
$this->productOptionsConfig = $productOptionsConfig;
150144
$this->productOptionsPrice = $productOptionsPrice;
151145
$this->urlBuilder = $urlBuilder;
152146
$this->arrayManager = $arrayManager;
153-
$this->scopeName = $scopeName;
154147
}
155148

156149
/**
@@ -254,12 +247,18 @@ protected function createCustomOptionsPanel()
254247
static::CONTAINER_HEADER_NAME => $this->getHeaderContainerConfig(10),
255248
static::GRID_OPTIONS_NAME => $this->getOptionsGridConfig(20),
256249
static::FIELD_ENABLE => $this->getEnableFieldConfig(30),
257-
static::IMPORT_OPTIONS_MODAL => $this->getImportOptionsModalConfig()
258250
]
259251
]
260252
]
261253
);
262254

255+
$this->meta = array_merge_recursive(
256+
$this->meta,
257+
[
258+
static::IMPORT_OPTIONS_MODAL => $this->getImportOptionsModalConfig()
259+
]
260+
);
261+
263262
return $this;
264263
}
265264

@@ -295,10 +294,19 @@ protected function getHeaderContainerConfig($sortOrder)
295294
'component' => 'Magento_Ui/js/form/components/button',
296295
'actions' => [
297296
[
298-
'targetName' => $this->scopeName . '.'
299-
. static::GROUP_CUSTOM_OPTIONS_NAME . '.' . static::IMPORT_OPTIONS_MODAL,
300-
'actionName' => 'toggleModal',
301-
]
297+
'targetName' => 'ns=' . static::FORM_NAME . ', index=options',
298+
'actionName' => 'clearDataProvider'
299+
],
300+
[
301+
'targetName' => 'ns=' . static::FORM_NAME . ', index='
302+
. static::IMPORT_OPTIONS_MODAL,
303+
'actionName' => 'openModal',
304+
],
305+
[
306+
'targetName' => 'ns=' . static::CUSTOM_OPTIONS_LISTING
307+
. ', index=' . static::CUSTOM_OPTIONS_LISTING,
308+
'actionName' => 'render',
309+
],
302310
],
303311
'displayAsLink' => true,
304312
'sortOrder' => 10,
@@ -317,7 +325,7 @@ protected function getHeaderContainerConfig($sortOrder)
317325
'sortOrder' => 20,
318326
'actions' => [
319327
[
320-
'targetName' => $this->scopeName . '.'
328+
'targetName' => static::FORM_NAME . '.' . static::FORM_NAME . '.'
321329
. static::GROUP_CUSTOM_OPTIONS_NAME . '.' . static::GRID_OPTIONS_NAME,
322330
'actionName' => 'addChild',
323331
]
@@ -344,6 +352,7 @@ protected function getOptionsGridConfig($sortOrder)
344352
'config' => [
345353
'addButtonLabel' => __('Add Option'),
346354
'componentType' => DynamicRows::NAME,
355+
'component' => 'Magento_Catalog/js/components/dynamic-rows-import-custom-options',
347356
'template' => 'ui/dynamic-rows/templates/collapsible',
348357
'additionalClasses' => 'admin__field-wide',
349358
'deleteProperty' => static::FIELD_IS_DELETE,
@@ -353,6 +362,8 @@ protected function getOptionsGridConfig($sortOrder)
353362
'columnsHeader' => false,
354363
'collapsibleHeader' => true,
355364
'sortOrder' => $sortOrder,
365+
'dataProvider' => static::CUSTOM_OPTIONS_LISTING,
366+
'links' => ['insertData' => '${ $.provider }:${ $.dataProvider }'],
356367
],
357368
],
358369
],
@@ -430,10 +441,9 @@ protected function getImportOptionsModalConfig()
430441
'arguments' => [
431442
'data' => [
432443
'config' => [
433-
'isTemplate' => true,
434444
'componentType' => Modal::NAME,
435445
'dataScope' => '',
436-
'provider' => 'product_form.product_form_data_source',
446+
'provider' => static::FORM_NAME . '.product_form_data_source',
437447
'options' => [
438448
'title' => __('Select Product'),
439449
'buttons' => [
@@ -442,27 +452,30 @@ protected function getImportOptionsModalConfig()
442452
'class' => 'action-primary',
443453
'actions' => [
444454
[
445-
'targetName' => '${ $.name }',
446-
'actionName' => 'actionCancel'
447-
]
448-
]
455+
'targetName' => 'index = ' . static::CUSTOM_OPTIONS_LISTING,
456+
'actionName' => 'save'
457+
],
458+
'closeModal'
459+
],
449460
],
450461
],
451462
],
452463
],
453464
],
454465
],
455466
'children' => [
456-
'grouped_product_listing' => [
467+
static::CUSTOM_OPTIONS_LISTING => [
457468
'arguments' => [
458469
'data' => [
459470
'config' => [
460-
'component' => 'Magento_Ui/js/form/components/insert-listing',
461-
'componentType' => 'container',
462-
'dataScope' => 'product_custom_options_listing',
463-
'externalProvider' =>
464-
'product_custom_options_listing.product_custom_options_listing_data_source',
465-
'ns' => 'product_custom_options_listing',
471+
'autoRender' => false,
472+
'componentType' => 'insertListing',
473+
'dataScope' => static::CUSTOM_OPTIONS_LISTING,
474+
'externalProvider' => static::CUSTOM_OPTIONS_LISTING . '.'
475+
. static::CUSTOM_OPTIONS_LISTING . '_data_source',
476+
'selectionsProvider' => static::CUSTOM_OPTIONS_LISTING . '.'
477+
. static::CUSTOM_OPTIONS_LISTING . '.product_columns.ids',
478+
'ns' => static::CUSTOM_OPTIONS_LISTING,
466479
'render_url' => $this->urlBuilder->getUrl('mui/index/render'),
467480
'realTimeLink' => true,
468481
'behaviourType' => 'edit',
@@ -1015,6 +1028,7 @@ protected function getProductOptionTypes()
10151028
foreach ($this->productOptionsConfig->getAll() as $option) {
10161029
$group = [
10171030
'value' => $groupIndex,
1031+
//TODO: Wrap label with __() or remove this TODO after MAGETWO-49771 is closed
10181032
'label' => $option['label'],
10191033
'optgroup' => []
10201034
];
@@ -1024,6 +1038,7 @@ protected function getProductOptionTypes()
10241038
continue;
10251039
}
10261040

1041+
//TODO: Wrap label with __() or remove this TODO after MAGETWO-49771 is closed
10271042
$group['optgroup'][] = ['label' => $type['label'], 'value' => $type['name']];
10281043
}
10291044

0 commit comments

Comments
 (0)