domain = 'inventory-test-' . Str::random(8) . '.erp.local'; $tenantId = 'test_tenant_inv_' . Str::random(8); tenancy()->central(function () use ($tenantId) { $this->tenant = Tenant::create([ 'id' => $tenantId, 'name' => 'Inventory Test Tenant', ]); $this->tenant->domains()->create(['domain' => $this->domain]); }); tenancy()->initialize($this->tenant); Artisan::call('tenants:migrate'); $this->user = User::factory()->create(['name' => 'Inventory Admin']); // 建立測試資料 $cat = Category::firstOrCreate(['name' => '飲品'], ['code' => 'CAT-DRINK']); $unit = Unit::firstOrCreate(['name' => '瓶'], ['code' => 'BO']); $p1 = Product::create([ 'name' => '可口可樂', 'code' => 'COKE-001', 'barcode' => '4710001', 'external_pos_id' => 'POS-COKE', 'price' => 25, 'category_id' => $cat->id, 'base_unit_id' => $unit->id, 'is_active' => true, ]); $p2 = Product::create([ 'name' => '百事可樂', 'code' => 'PEPSI-001', 'barcode' => '4710002', 'external_pos_id' => 'POS-PEPSI', 'price' => 23, 'category_id' => $cat->id, 'base_unit_id' => $unit->id, 'is_active' => true, ]); $this->warehouse = Warehouse::create([ 'name' => '台北門市倉', 'code' => 'WH-TP-01', 'type' => 'retail', ]); // 建立庫存 Inventory::create([ 'warehouse_id' => $this->warehouse->id, 'product_id' => $p1->id, 'quantity' => 100, 'unit_cost' => 15, 'total_value' => 1500, 'batch_number' => 'BATCH-001', 'arrival_date' => now(), ]); Inventory::create([ 'warehouse_id' => $this->warehouse->id, 'product_id' => $p2->id, 'quantity' => 50, 'unit_cost' => 12, 'total_value' => 600, 'batch_number' => 'BATCH-002', 'arrival_date' => now(), ]); tenancy()->end(); } protected function tearDown(): void { if ($this->tenant) { $this->tenant->delete(); } parent::tearDown(); } public function test_can_query_all_inventory_for_warehouse() { Sanctum::actingAs($this->user, ['*']); $response = $this->withHeaders([ 'X-Tenant-Domain' => $this->domain, 'Accept' => 'application/json', ])->getJson("/api/v1/integration/inventory/{$this->warehouse->code}"); $response->assertStatus(200) ->assertJsonPath('status', 'success') ->assertJsonCount(2, 'data'); } public function test_can_filter_inventory_by_product_id() { Sanctum::actingAs($this->user, ['*']); // 先找出可樂的 ERP ID $productId = Product::where('code', 'COKE-001')->value('id'); $response = $this->withHeaders([ 'X-Tenant-Domain' => $this->domain, 'Accept' => 'application/json', ])->getJson("/api/v1/integration/inventory/{$this->warehouse->code}?product_id={$productId}"); $response->assertStatus(200) ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.product_code', 'COKE-001') ->assertJsonPath('data.0.quantity', 100); } public function test_can_filter_inventory_by_external_pos_id() { Sanctum::actingAs($this->user, ['*']); $response = $this->withHeaders([ 'X-Tenant-Domain' => $this->domain, 'Accept' => 'application/json', ])->getJson("/api/v1/integration/inventory/{$this->warehouse->code}?external_pos_id=POS-COKE"); $response->assertStatus(200) ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.external_pos_id', 'POS-COKE') ->assertJsonPath('data.0.quantity', 100); } public function test_can_filter_inventory_by_barcode() { Sanctum::actingAs($this->user, ['*']); $response = $this->withHeaders([ 'X-Tenant-Domain' => $this->domain, 'Accept' => 'application/json', ])->getJson("/api/v1/integration/inventory/{$this->warehouse->code}?barcode=4710002"); $response->assertStatus(200) ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.product_code', 'PEPSI-001') ->assertJsonPath('data.0.quantity', 50); } public function test_can_filter_inventory_by_code() { Sanctum::actingAs($this->user, ['*']); $response = $this->withHeaders([ 'X-Tenant-Domain' => $this->domain, 'Accept' => 'application/json', ])->getJson("/api/v1/integration/inventory/{$this->warehouse->code}?code=COKE-001"); $response->assertStatus(200) ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.product_code', 'COKE-001'); } public function test_returns_empty_when_no_match() { Sanctum::actingAs($this->user, ['*']); $response = $this->withHeaders([ 'X-Tenant-Domain' => $this->domain, 'Accept' => 'application/json', ])->getJson("/api/v1/integration/inventory/{$this->warehouse->code}?product_id=NON-EXISTENT"); $response->assertStatus(200) ->assertJsonCount(0, 'data'); } public function test_returns_404_when_warehouse_not_found() { Sanctum::actingAs($this->user, ['*']); $response = $this->withHeaders([ 'X-Tenant-Domain' => $this->domain, 'Accept' => 'application/json', ])->getJson("/api/v1/integration/inventory/INVALID-WH"); $response->assertStatus(404); } }