33 * Copyright © Magento, Inc. All rights reserved.
44 * See COPYING.txt for license details.
55 */
6+
67namespace Magento \ConfigurableProduct \Api ;
78
89use Magento \Catalog \Api \Data \ProductInterface ;
910use Magento \Catalog \Api \ProductRepositoryInterface ;
1011use Magento \Catalog \Model \Entity \Attribute ;
12+ use Magento \ConfigurableProduct \Model \Product \Type \Configurable ;
1113use Magento \Eav \Model \Config ;
1214use Magento \Eav \Model \ResourceModel \Entity \Attribute \Option \Collection ;
1315use Magento \Framework \Api \ExtensibleDataInterface ;
1416use Magento \Framework \ObjectManagerInterface ;
1517use Magento \Framework \Webapi \Rest \Request ;
1618use Magento \TestFramework \Helper \Bootstrap ;
17- use Magento \ConfigurableProduct \Model \Product \Type \Configurable ;
1819use Magento \TestFramework \TestCase \WebapiAbstract ;
1920
2021/**
@@ -102,18 +103,18 @@ protected function createConfigurableProduct()
102103
103104 $ configurableProductOptions = [
104105 [
105- "attribute_id " => $ this ->configurableAttribute ->getId (),
106+ "attribute_id " => $ this ->configurableAttribute ->getId (),
106107 "label " => $ label ,
107108 "position " => 0 ,
108109 "values " => [
109110 [
110- "value_index " => $ options [0 ]['option_id ' ],
111+ "value_index " => $ options [0 ]['option_id ' ],
111112 ],
112113 [
113- "value_index " => $ options [1 ]['option_id ' ],
114- ]
114+ "value_index " => $ options [1 ]['option_id ' ],
115+ ],
115116 ],
116- ]
117+ ],
117118 ];
118119
119120 $ product = [
@@ -173,6 +174,20 @@ public function testCreateConfigurableProduct()
173174 $ this ->assertEquals ([$ productId1 , $ productId2 ], $ resultConfigurableProductLinks );
174175 }
175176
177+ /**
178+ * Verify configurable product creation passes validation with required attribute not specified in product itself.
179+ *
180+ * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
181+ */
182+ public function testCreateConfigurableProductWithRequiredAttribute (): void
183+ {
184+ $ configurableAttribute = $ this ->eavConfig ->getAttribute ('catalog_product ' , 'test_configurable ' );
185+ $ configurableAttribute ->setIsRequired (true );
186+ $ configurableAttribute ->save ();
187+ $ response = $ this ->createConfigurableProductWithRequiredAttribute ();
188+ $ this ->assertEquals (self ::CONFIGURABLE_PRODUCT_SKU , $ response [ProductInterface::SKU ]);
189+ }
190+
176191 /**
177192 * Create configurable with simple which has zero attribute value
178193 *
@@ -340,10 +355,10 @@ public function testUpdateConfigurableProductLinks()
340355 = [$ productId1 , $ productId2 ];
341356 //set the value for required attribute
342357 $ response ["custom_attributes " ][] =
343- [
344- "attribute_code " => $ this ->configurableAttribute ->getAttributeCode (),
345- "value " => $ resultConfigurableProductOptions [0 ]['values ' ][0 ]['value_index ' ],
346- ];
358+ [
359+ "attribute_code " => $ this ->configurableAttribute ->getAttributeCode (),
360+ "value " => $ resultConfigurableProductOptions [0 ]['values ' ][0 ]['value_index ' ],
361+ ];
347362
348363 $ response = $ this ->saveProduct ($ response );
349364
@@ -364,7 +379,8 @@ public function testUpdateConfigurableProductLinksWithNonExistingProduct()
364379 //leave existing option untouched
365380 unset($ response [ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY ]['configurable_product_options ' ]);
366381 $ response [ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY ]['configurable_product_links ' ] = [
367- $ productId1 , $ nonExistingId
382+ $ productId1 ,
383+ $ nonExistingId ,
368384 ];
369385
370386 $ expectedMessage = 'The product that was requested doesn \'t exist. Verify the product and try again. ' ;
@@ -400,14 +416,15 @@ public function testUpdateConfigurableProductLinksWithDuplicateAttributes()
400416 [
401417 'attribute_code ' => 'test_configurable ' ,
402418 'value ' => $ optionValue1 ,
403- ]
419+ ],
404420 ];
405421 $ this ->saveProduct ($ product2 );
406422
407423 //leave existing option untouched
408424 unset($ response [ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY ]['configurable_product_options ' ]);
409425 $ response [ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY ]['configurable_product_links ' ] = [
410- $ productId1 , $ productId2
426+ $ productId1 ,
427+ $ productId2 ,
411428 ];
412429
413430 $ expectedMessage = 'Products "%1" and "%2" have the same set of attribute values. ' ;
@@ -440,7 +457,8 @@ public function testUpdateConfigurableProductLinksWithWithoutVariationAttributes
440457 /** delete all variation attribute */
441458 $ response [ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY ]['configurable_product_options ' ] = [];
442459 $ response [ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY ]['configurable_product_links ' ] = [
443- $ productId1 , $ productId2
460+ $ productId1 ,
461+ $ productId2 ,
444462 ];
445463
446464 $ expectedMessage = 'The product that was requested doesn \'t exist. Verify the product and try again. ' ;
@@ -496,7 +514,7 @@ protected function createProduct($product)
496514 $ serviceInfo = [
497515 'rest ' => [
498516 'resourcePath ' => self ::RESOURCE_PATH ,
499- 'httpMethod ' => Request::HTTP_METHOD_POST
517+ 'httpMethod ' => Request::HTTP_METHOD_POST ,
500518 ],
501519 'soap ' => [
502520 'service ' => self ::SERVICE_NAME ,
@@ -521,7 +539,7 @@ protected function deleteProductBySku($productSku)
521539 $ serviceInfo = [
522540 'rest ' => [
523541 'resourcePath ' => $ resourcePath ,
524- 'httpMethod ' => Request::HTTP_METHOD_DELETE
542+ 'httpMethod ' => Request::HTTP_METHOD_DELETE ,
525543 ],
526544 'soap ' => [
527545 'service ' => self ::SERVICE_NAME ,
@@ -544,7 +562,7 @@ protected function saveProduct($product)
544562 {
545563 if (isset ($ product ['custom_attributes ' ])) {
546564 $ count = count ($ product ['custom_attributes ' ]);
547- for ($ i= 0 ; $ i < $ count ; $ i ++) {
565+ for ($ i = 0 ; $ i < $ count ; $ i ++) {
548566 if ($ product ['custom_attributes ' ][$ i ]['attribute_code ' ] == 'category_ids '
549567 && !is_array ($ product ['custom_attributes ' ][$ i ]['value ' ])
550568 ) {
@@ -556,7 +574,7 @@ protected function saveProduct($product)
556574 $ serviceInfo = [
557575 'rest ' => [
558576 'resourcePath ' => $ resourcePath ,
559- 'httpMethod ' => Request::HTTP_METHOD_PUT
577+ 'httpMethod ' => Request::HTTP_METHOD_PUT ,
560578 ],
561579 'soap ' => [
562580 'service ' => self ::SERVICE_NAME ,
@@ -568,4 +586,43 @@ protected function saveProduct($product)
568586 $ response = $ this ->_webApiCall ($ serviceInfo , $ requestData );
569587 return $ response ;
570588 }
589+
590+ /**
591+ * Create configurable product with required attribute by web api.
592+ *
593+ * @return array
594+ */
595+ private function createConfigurableProductWithRequiredAttribute (): array
596+ {
597+ $ this ->configurableAttribute = $ this ->eavConfig ->getAttribute ('catalog_product ' , 'test_configurable ' );
598+ $ options = $ this ->getConfigurableAttributeOptions ();
599+ $ configurableProductOptions = [
600+ [
601+ "attribute_id " => $ this ->configurableAttribute ->getId (),
602+ "label " => 'color ' ,
603+ "position " => 0 ,
604+ "values " => [
605+ [
606+ "value_index " => $ options [0 ]['option_id ' ],
607+ ],
608+ [
609+ "value_index " => $ options [1 ]['option_id ' ],
610+ ],
611+ ],
612+ ],
613+ ];
614+ $ product = [
615+ "sku " => self ::CONFIGURABLE_PRODUCT_SKU ,
616+ "name " => self ::CONFIGURABLE_PRODUCT_SKU ,
617+ "type_id " => "configurable " ,
618+ "price " => 50 ,
619+ 'attribute_set_id ' => 4 ,
620+ "extension_attributes " => [
621+ "configurable_product_options " => $ configurableProductOptions ,
622+ "configurable_product_links " => [10 , 20 ],
623+ ],
624+ ];
625+
626+ return $ this ->createProduct ($ product );
627+ }
571628}
0 commit comments