From c7402e52ee399d3df5b07e3f636f71171fad745b Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 17 Mar 2026 12:52:35 +0000 Subject: [PATCH 1/2] If inventory not tracked assume we can sell it --- src/Jobs/ImportSingleProductJob.php | 6 ++- tests/Unit/ImportSingleProductJobTest.php | 45 ++++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/Jobs/ImportSingleProductJob.php b/src/Jobs/ImportSingleProductJob.php index a87f4a9..c14e765 100644 --- a/src/Jobs/ImportSingleProductJob.php +++ b/src/Jobs/ImportSingleProductJob.php @@ -364,6 +364,7 @@ private function buildVariantFields(): string } } } + tracked }' : 'inventoryItem { measurement { @@ -373,6 +374,7 @@ private function buildVariantFields(): string } } requiresShipping + tracked }'; $contextualPricingFields = ''; @@ -557,7 +559,7 @@ private function importVariants(array $returnedVariants, string $product_slug, G 'product_slug' => $product_slug, 'title' => $variant['title'] === 'Default Title' ? 'Default' : $variant['title'], 'inventory_quantity' => $variant['inventoryQuantity'] ?? null, - 'inventory_policy' => $variant['inventoryPolicy'] ?? null, + 'inventory_policy' => Arr::get($variant, 'inventoryItem.tracked') ? ($variant['inventoryPolicy'] ?? null) : 'CONTINUE', 'inventory_management' => 'shopify', // @deprecated, left in for backwards JS compatibility 'price' => $variant['price'], 'compare_at_price' => $variant['compareAtPrice'], @@ -577,7 +579,7 @@ private function importVariants(array $returnedVariants, string $product_slug, G 'price' => $variant['price'], 'compare_at_price' => $variant['compareAtPrice'], 'inventory_quantity' => $variant['inventoryQuantity'] ?? null, - 'inventory_policy' => $variant['inventoryPolicy'] ?? null, + 'inventory_policy' => Arr::get($variant, 'inventoryItem.tracked') ? ($variant['inventoryPolicy'] ?? null) : 'CONTINUE', ]; $existingMultiStoreData = $entry->get('multi_store_data', []); diff --git a/tests/Unit/ImportSingleProductJobTest.php b/tests/Unit/ImportSingleProductJobTest.php index 36fcd1c..6acbf03 100644 --- a/tests/Unit/ImportSingleProductJobTest.php +++ b/tests/Unit/ImportSingleProductJobTest.php @@ -352,6 +352,48 @@ public function clears_variant_metafields_removed_in_shopify() $this->assertSame([], $variant->get('shopify_metafield_keys')); } + #[Test] + public function uses_shopify_inventory_policy_when_variant_is_tracked() + { + Facades\Collection::make(config('shopify.collection_handle', 'products'))->save(); + Facades\Collection::make('variants')->save(); + Facades\Taxonomy::make()->handle('collections')->save(); + Facades\Taxonomy::make()->handle('tags')->save(); + Facades\Taxonomy::make()->handle('type')->save(); + Facades\Taxonomy::make()->handle('vendor')->save(); + + $this->mock(Graphql::class, function (MockInterface $mock) { + $mock->shouldReceive('query')->andReturn(new HttpResponse(status: 200, body: $this->getProductJson())); + }); + + Jobs\ImportSingleProductJob::dispatch(1); + + $variant = Facades\Entry::whereCollection('variants')->first(); + $this->assertSame('DENY', $variant->get('inventory_policy')); + } + + #[Test] + public function sets_inventory_policy_to_continue_when_variant_is_not_tracked() + { + Facades\Collection::make(config('shopify.collection_handle', 'products'))->save(); + Facades\Collection::make('variants')->save(); + Facades\Taxonomy::make()->handle('collections')->save(); + Facades\Taxonomy::make()->handle('tags')->save(); + Facades\Taxonomy::make()->handle('type')->save(); + Facades\Taxonomy::make()->handle('vendor')->save(); + + $json = str_replace('"tracked": true', '"tracked": false', $this->getProductJson()); + + $this->mock(Graphql::class, function (MockInterface $mock) use ($json) { + $mock->shouldReceive('query')->andReturn(new HttpResponse(status: 200, body: $json)); + }); + + Jobs\ImportSingleProductJob::dispatch(1); + + $variant = Facades\Entry::whereCollection('variants')->first(); + $this->assertSame('CONTINUE', $variant->get('inventory_policy')); + } + private function getProductJson(): string { return '{ @@ -490,7 +532,8 @@ private function getProductJson(): string "value": 0 } }, - "requiresShipping": true + "requiresShipping": true, + "tracked": true }, "inventoryPolicy": "DENY", "inventoryQuantity": 0, From 0db32ed0a0671f3415d3c2d7f922bd2360e6dcee Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 17 Mar 2026 12:55:05 +0000 Subject: [PATCH 2/2] fix merge --- tests/Unit/ImportSingleProductJobTest.php | 45 ++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/tests/Unit/ImportSingleProductJobTest.php b/tests/Unit/ImportSingleProductJobTest.php index f5ba85d..f0d87e5 100644 --- a/tests/Unit/ImportSingleProductJobTest.php +++ b/tests/Unit/ImportSingleProductJobTest.php @@ -464,6 +464,48 @@ public function imports_product_when_in_sales_channel_and_filter_enabled() $this->assertSame($entry->product_id, '108828309'); } + #[Test] + public function uses_shopify_inventory_policy_when_variant_is_tracked() + { + Facades\Collection::make(config('shopify.collection_handle', 'products'))->save(); + Facades\Collection::make('variants')->save(); + Facades\Taxonomy::make()->handle('collections')->save(); + Facades\Taxonomy::make()->handle('tags')->save(); + Facades\Taxonomy::make()->handle('type')->save(); + Facades\Taxonomy::make()->handle('vendor')->save(); + + $this->mock(Graphql::class, function (MockInterface $mock) { + $mock->shouldReceive('query')->andReturn(new HttpResponse(status: 200, body: $this->getProductJson())); + }); + + Jobs\ImportSingleProductJob::dispatch(1); + + $variant = Facades\Entry::whereCollection('variants')->first(); + $this->assertSame('DENY', $variant->get('inventory_policy')); + } + + #[Test] + public function sets_inventory_policy_to_continue_when_variant_is_not_tracked() + { + Facades\Collection::make(config('shopify.collection_handle', 'products'))->save(); + Facades\Collection::make('variants')->save(); + Facades\Taxonomy::make()->handle('collections')->save(); + Facades\Taxonomy::make()->handle('tags')->save(); + Facades\Taxonomy::make()->handle('type')->save(); + Facades\Taxonomy::make()->handle('vendor')->save(); + + $json = str_replace('"tracked": true', '"tracked": false', $this->getProductJson()); + + $this->mock(Graphql::class, function (MockInterface $mock) use ($json) { + $mock->shouldReceive('query')->andReturn(new HttpResponse(status: 200, body: $json)); + }); + + Jobs\ImportSingleProductJob::dispatch(1); + + $variant = Facades\Entry::whereCollection('variants')->first(); + $this->assertSame('CONTINUE', $variant->get('inventory_policy')); + } + private function getProductJson(): string { return '{ @@ -602,7 +644,8 @@ private function getProductJson(): string "value": 0 } }, - "requiresShipping": true + "requiresShipping": true, + "tracked": true }, "inventoryPolicy": "DENY", "inventoryQuantity": 0,