withActiveVendor(); $this->withSettings(['sync_product_fields' => 'all']); // Even fully connected variations stay inside the product PATCH. self::assertFalse($this->shouldUpdateSeparately([ 'variants' => [['id' => 43666032, 'primary_price' => 1, 'stock' => 1, 'properties' => []]], ])); } public function testPriceStockModeNeverUsesTheVariationEndpoint(): void { $this->withActiveVendor(); $this->withSettings(['sync_product_fields' => 'price_stock']); self::assertFalse($this->shouldUpdateSeparately([ 'variants' => [['id' => 43666032, 'primary_price' => 1, 'stock' => 1]], ])); } public function testCustomModeWithVariationFieldsUsesPerVariationRequests(): void { $this->withActiveVendor(); $this->withSettings([ 'sync_product_fields' => 'custom', 'sync_product_field_variant_price' => 1, ]); self::assertTrue($this->shouldUpdateSeparately([ 'variants' => [['id' => 43666032, 'primary_price' => 1, 'stock' => 1]], ])); } public function testCustomModeWithoutVariationFieldsDoesNotUsePerVariationRequests(): void { $this->withActiveVendor(); $this->withSettings([ 'sync_product_fields' => 'custom', 'sync_product_field_name' => 1, ]); self::assertFalse($this->shouldUpdateSeparately([ 'variants' => [['id' => 43666032, 'primary_price' => 1, 'stock' => 1]], ])); } public function testUnconnectedVariationFallsBackToTheProductRequest(): void { $this->withActiveVendor(); $this->withSettings([ 'sync_product_fields' => 'custom', 'sync_product_field_variant_price' => 1, ]); self::assertFalse($this->shouldUpdateSeparately([ 'variants' => [ ['id' => 43666032, 'primary_price' => 1, 'stock' => 1], ['primary_price' => 2, 'stock' => 2], // no Basalam id yet ], ])); } public function testRestrictedVendorUsesTheProductRequest(): void { // A limited inactive vendor must also use one product PATCH. The // restricted payload keeps unchanged properties for variant identity // and UpdateSingleProductService removes the stored ids before send. $this->withRestrictedVendor(); $this->withSettings(['sync_product_fields' => 'all']); self::assertFalse($this->shouldUpdateSeparately([ 'variants' => [['id' => 43666032, 'primary_price' => 1, 'stock' => 1, 'properties' => []]], ])); } private function shouldUpdateSeparately(array $productData): bool { $service = new UpdateSingleProductService(new \stdClass(), new \stdClass(), new \stdClass()); $method = new ReflectionMethod(UpdateSingleProductService::class, 'shouldUpdateVariationsSeparately'); $method->setAccessible(true); return $method->invoke($service, 7196, $productData); } private function withSettings(array $settings): void { $GLOBALS['sync_basalam_test_options']['sync_basalam_settings'] = $settings; } private function withActiveVendor(): void { $GLOBALS['sync_basalam_test_container'] = new class { public function get($id) { return new class { public function __call($method, $args) { return false; // shouldRestrictUpdateFields, canUpdate, ... } }; } }; } private function withRestrictedVendor(): void { $GLOBALS['sync_basalam_test_container'] = new class { public function get($id) { return new class { public function __call($method, $args) { // shouldRestrictUpdateFields() === true if (strpos($method, 'shouldRestrict') === 0) return true; return false; } }; } }; } } }