getDriverName() !== 'mysql') { $this->markTestSkipped('需 MySQL:machine_stock_movements.type enum 為 MySQL-only DDL。'); } $this->company = Company::create(['name' => 'Test Company']); $this->service = app(TransactionService::class); } private function dispense(string $serial, string $slotNo): array { return [ 'serial_no' => $serial, 'slot_no' => $slotNo, 'product_id' => 101, 'amount' => 50, 'dispense_status' => 1, ]; } /** 庫存賣到 0 → 效期與批號被清空。 */ public function test_clears_expiry_and_batch_when_stock_hits_zero(): void { $serial = '1234567890'; $machine = Machine::factory()->create([ 'company_id' => $this->company->id, 'serial_no' => $serial, ]); $slot = $machine->slots()->create([ 'slot_no' => '1', 'stock' => 1, 'max_stock' => 10, 'expiry_date' => '2030-12-31', 'batch_no' => 'B-001', ]); $this->service->recordDispense($this->dispense($serial, '1')); $fresh = $slot->fresh(); $this->assertEquals(0, $fresh->stock, '庫存應扣為 0'); $this->assertNull($fresh->expiry_date, '售完應清空效期'); $this->assertNull($fresh->batch_no, '售完應清空批號'); } /** 庫存尚未歸 0 → 效期與批號保留(同批貨還在販售)。 */ public function test_keeps_expiry_when_stock_remains(): void { $serial = '1234567891'; $machine = Machine::factory()->create([ 'company_id' => $this->company->id, 'serial_no' => $serial, ]); $slot = $machine->slots()->create([ 'slot_no' => '2', 'stock' => 5, 'max_stock' => 10, 'expiry_date' => '2030-12-31', 'batch_no' => 'B-001', ]); $this->service->recordDispense($this->dispense($serial, '2')); $fresh = $slot->fresh(); $this->assertEquals(4, $fresh->stock, '庫存應扣為 4'); $this->assertEquals('2030-12-31', $fresh->expiry_date->format('Y-m-d'), '未售完應保留效期'); $this->assertEquals('B-001', $fresh->batch_no, '未售完應保留批號'); } }