|
8 | 8 | namespace Magento\Catalog\Api;
|
9 | 9 |
|
10 | 10 | use Magento\Catalog\Api\Data\ProductInterface;
|
| 11 | +use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; |
11 | 12 | use Magento\Store\Model\Store;
|
12 | 13 | use Magento\TestFramework\Helper\Bootstrap;
|
13 | 14 | use Magento\TestFramework\TestCase\WebapiAbstract;
|
@@ -193,4 +194,191 @@ public function testProductDefaultValuesWithTwoWebsites(): void
|
193 | 194 | $storeId
|
194 | 195 | ));
|
195 | 196 | }
|
| 197 | + |
| 198 | + /** |
| 199 | + * @magentoApiDataFixture Magento/Store/_files/second_website_with_two_stores.php |
| 200 | + * @magentoApiDataFixture Magento/Catalog/_files/product_text_attribute.php |
| 201 | + * @magentoApiDataFixture Magento/Catalog/_files/product_varchar_attribute.php |
| 202 | + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) |
| 203 | + */ |
| 204 | + public function testPartialUpdate(): void |
| 205 | + { |
| 206 | + $this->_markTestAsRestOnly( |
| 207 | + 'Test skipped due to known issue with SOAP. NULL value is cast to corresponding attribute type.' |
| 208 | + ); |
| 209 | + $sku = 'api_test_update_product'; |
| 210 | + $store = $this->objectManager->get(Store::class); |
| 211 | + $storeId = (int) $store->load('fixture_third_store', 'code')->getId(); |
| 212 | + $this->updateAttribute('varchar_attribute', ['is_global' => ScopedAttributeInterface::SCOPE_STORE]); |
| 213 | + $this->updateAttribute('text_attribute', ['is_global' => ScopedAttributeInterface::SCOPE_STORE]); |
| 214 | + $request1 = [ |
| 215 | + ProductInterface::SKU => $sku, |
| 216 | + ProductInterface::NAME => 'Test 1', |
| 217 | + ProductInterface::ATTRIBUTE_SET_ID => 4, |
| 218 | + ProductInterface::PRICE => 10, |
| 219 | + ProductInterface::STATUS => 1, |
| 220 | + ProductInterface::VISIBILITY => 4, |
| 221 | + ProductInterface::TYPE_ID => 'simple', |
| 222 | + ProductInterface::WEIGHT => 100, |
| 223 | + ProductInterface::CUSTOM_ATTRIBUTES => [ |
| 224 | + [ |
| 225 | + 'attribute_code' => 'varchar_attribute', |
| 226 | + 'value' => 'api_test_value_varchar', |
| 227 | + ], |
| 228 | + [ |
| 229 | + 'attribute_code' => 'text_attribute', |
| 230 | + 'value' => 'api_test_value_text', |
| 231 | + ] |
| 232 | + ], |
| 233 | + ]; |
| 234 | + $response = $this->saveProduct($request1, 'all'); |
| 235 | + $this->assertResponse($request1, $response); |
| 236 | + $this->fixtureProducts[] = $sku; |
| 237 | + /** @var ProductRepositoryInterface $productRepository */ |
| 238 | + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); |
| 239 | + $product = $productRepository->get($sku); |
| 240 | + $request2 = [ |
| 241 | + ProductInterface::SKU => $sku, |
| 242 | + ProductInterface::CUSTOM_ATTRIBUTES => [ |
| 243 | + [ |
| 244 | + 'attribute_code' => 'varchar_attribute', |
| 245 | + 'value' => 'api_test_value_varchar_changed', |
| 246 | + ] |
| 247 | + ], |
| 248 | + ]; |
| 249 | + $response2 = $this->saveProduct($request2, 'fixture_third_store'); |
| 250 | + $expected = [ |
| 251 | + 'varchar_attribute' => 'api_test_value_varchar_changed', |
| 252 | + 'text_attribute' => 'api_test_value_text' |
| 253 | + ]; |
| 254 | + $this->assertResponse( |
| 255 | + array_merge($request1, $expected), |
| 256 | + $response2 |
| 257 | + ); |
| 258 | + $this->assertOverriddenValues( |
| 259 | + [ |
| 260 | + 'visibility' => false, |
| 261 | + 'tax_class_id' => false, |
| 262 | + 'status' => false, |
| 263 | + 'name' => false, |
| 264 | + 'varchar_attribute' => true, |
| 265 | + 'text_attribute' => false, |
| 266 | + ], |
| 267 | + $product, |
| 268 | + $storeId |
| 269 | + ); |
| 270 | + $request3 = [ |
| 271 | + ProductInterface::SKU => $sku, |
| 272 | + ProductInterface::CUSTOM_ATTRIBUTES => [ |
| 273 | + [ |
| 274 | + 'attribute_code' => 'text_attribute', |
| 275 | + 'value' => 'api_test_value_text_changed', |
| 276 | + ] |
| 277 | + ], |
| 278 | + ]; |
| 279 | + $response3 = $this->saveProduct($request3, 'fixture_third_store'); |
| 280 | + $expected = [ |
| 281 | + 'varchar_attribute' => 'api_test_value_varchar_changed', |
| 282 | + 'text_attribute' => 'api_test_value_text_changed' |
| 283 | + ]; |
| 284 | + $this->assertResponse( |
| 285 | + array_merge($request1, $expected), |
| 286 | + $response3 |
| 287 | + ); |
| 288 | + $this->assertOverriddenValues( |
| 289 | + [ |
| 290 | + 'visibility' => false, |
| 291 | + 'tax_class_id' => false, |
| 292 | + 'status' => false, |
| 293 | + 'name' => false, |
| 294 | + 'varchar_attribute' => true, |
| 295 | + 'text_attribute' => true, |
| 296 | + ], |
| 297 | + $product, |
| 298 | + $storeId |
| 299 | + ); |
| 300 | + $request4 = [ |
| 301 | + ProductInterface::SKU => $sku, |
| 302 | + ProductInterface::CUSTOM_ATTRIBUTES => [ |
| 303 | + [ |
| 304 | + 'attribute_code' => 'text_attribute', |
| 305 | + 'value' => null, |
| 306 | + ] |
| 307 | + ], |
| 308 | + ]; |
| 309 | + $response4 = $this->saveProduct($request4, 'fixture_third_store'); |
| 310 | + $expected = [ |
| 311 | + 'varchar_attribute' => 'api_test_value_varchar_changed', |
| 312 | + 'text_attribute' => 'api_test_value_text' |
| 313 | + ]; |
| 314 | + $this->assertResponse( |
| 315 | + array_merge($request1, $expected), |
| 316 | + $response4 |
| 317 | + ); |
| 318 | + $this->assertOverriddenValues( |
| 319 | + [ |
| 320 | + 'visibility' => false, |
| 321 | + 'tax_class_id' => false, |
| 322 | + 'status' => false, |
| 323 | + 'name' => false, |
| 324 | + 'varchar_attribute' => true, |
| 325 | + 'text_attribute' => false, |
| 326 | + ], |
| 327 | + $product, |
| 328 | + $storeId |
| 329 | + ); |
| 330 | + } |
| 331 | + |
| 332 | + /** |
| 333 | + * @param array $expected |
| 334 | + * @param array $actual |
| 335 | + */ |
| 336 | + private function assertResponse(array $expected, array $actual): void |
| 337 | + { |
| 338 | + $customAttributes = $expected[ProductInterface::CUSTOM_ATTRIBUTES] ?? []; |
| 339 | + unset($expected[ProductInterface::CUSTOM_ATTRIBUTES]); |
| 340 | + $expected = array_merge(array_column($customAttributes, 'value', 'attribute_code'), $expected); |
| 341 | + |
| 342 | + $customAttributes = $actual[ProductInterface::CUSTOM_ATTRIBUTES] ?? []; |
| 343 | + unset($actual[ProductInterface::CUSTOM_ATTRIBUTES]); |
| 344 | + $actual = array_merge(array_column($customAttributes, 'value', 'attribute_code'), $actual); |
| 345 | + |
| 346 | + $this->assertEquals($expected, array_intersect_key($actual, $expected)); |
| 347 | + } |
| 348 | + |
| 349 | + /** |
| 350 | + * @param Product $product |
| 351 | + * @param array $expected |
| 352 | + * @param int $storeId |
| 353 | + */ |
| 354 | + private function assertOverriddenValues(array $expected, Product $product, int $storeId): void |
| 355 | + { |
| 356 | + /** @var ScopeOverriddenValue $scopeOverriddenValue */ |
| 357 | + $scopeOverriddenValue = $this->objectManager->create(ScopeOverriddenValue::class); |
| 358 | + $actual = []; |
| 359 | + foreach (array_keys($expected) as $attribute) { |
| 360 | + $actual[$attribute] = $scopeOverriddenValue->containsValue( |
| 361 | + ProductInterface::class, |
| 362 | + $product, |
| 363 | + $attribute, |
| 364 | + $storeId |
| 365 | + ); |
| 366 | + } |
| 367 | + $this->assertEquals($expected, $actual); |
| 368 | + } |
| 369 | + |
| 370 | + /** |
| 371 | + * Update attribute |
| 372 | + * |
| 373 | + * @param string $code |
| 374 | + * @param array $data |
| 375 | + * @return void |
| 376 | + */ |
| 377 | + private function updateAttribute(string $code, array $data): void |
| 378 | + { |
| 379 | + $attributeRepository = $this->objectManager->create(ProductAttributeRepositoryInterface::class); |
| 380 | + $attribute = $attributeRepository->get($code); |
| 381 | + $attribute->addData($data); |
| 382 | + $attributeRepository->save($attribute); |
| 383 | + } |
196 | 384 | }
|
0 commit comments