actingAs(User::factory()->create(['is_admin' => true])); } private function employee(): Employee { return Employee::create(['employee_no' => 'E-100', 'name' => 'Test Employee', 'department' => 'Operations']); } private function variant(int $quantity = 5): StockVariant { $item = UniformItem::create(['code' => 'TS-01', 'name' => 'Test Shirt']); return $item->variants()->create(['size' => 'M', 'quantity' => $quantity, 'reorder_level' => 2]); } public function test_restock_increases_the_correct_size_balance(): void { $variant = $this->variant(3); $this->post(route('inventory.restock'), ['uniform_item_id' => $variant->uniform_item_id, 'stocks' => [$variant->id => 4]])->assertSessionHasNoErrors(); $this->assertSame(7, $variant->fresh()->quantity); $this->assertDatabaseHas('stock_movements', ['stock_variant_id' => $variant->id, 'type' => 'restock', 'quantity_change' => 4]); } public function test_uniform_type_is_created_with_selected_sizes(): void { $this->post(route('inventory.items.store'), [ 'code' => 'JKT-01', 'name' => 'Work Jacket', 'sizes' => ['S', 'M', 'XL'], 'reorder_level' => 3, ])->assertSessionHasNoErrors(); $item = UniformItem::where('code', 'JKT-01')->firstOrFail(); $this->assertEqualsCanonicalizing(['S', 'M', 'XL'], $item->variants()->pluck('size')->all()); } public function test_issuing_a_uniform_reduces_stock(): void { $employee = $this->employee(); $variant = $this->variant(5); $this->post(route('issues.store'), ['employee_id' => $employee->id, 'stock_variant_id' => $variant->id, 'quantity' => 2, 'issued_at' => '2026-07-13'])->assertSessionHasNoErrors(); $this->assertSame(3, $variant->fresh()->quantity); $this->assertDatabaseHas('uniform_issues', ['employee_id' => $employee->id, 'stock_variant_id' => $variant->id, 'quantity' => 2, 'status' => 'issued']); } public function test_issue_is_rejected_when_stock_is_insufficient(): void { $employee = $this->employee(); $variant = $this->variant(1); $this->post(route('issues.store'), ['employee_id' => $employee->id, 'stock_variant_id' => $variant->id, 'quantity' => 2, 'issued_at' => '2026-07-13'])->assertSessionHasErrors('quantity'); $this->assertSame(1, $variant->fresh()->quantity); } public function test_exit_handover_returns_only_reusable_uniforms_to_stock(): void { $employee = $this->employee(); $variant = $this->variant(5); $this->post(route('issues.store'), ['employee_id' => $employee->id, 'stock_variant_id' => $variant->id, 'quantity' => 2, 'issued_at' => '2026-07-13']); $issue = $employee->issues()->first(); $this->post(route('handovers.store', $employee), ['handover_date' => '2026-07-14', 'items' => [['issue_id' => $issue->id, 'condition' => 'reusable']]])->assertSessionHasNoErrors(); $this->assertSame(5, $variant->fresh()->quantity); $this->assertSame('left', $employee->fresh()->status); $this->assertDatabaseHas('uniform_issues', ['id' => $issue->id, 'status' => 'returned', 'returned_quantity' => 2]); } public function test_damaged_handover_items_do_not_return_to_available_stock(): void { $employee = $this->employee(); $variant = $this->variant(5); $this->post(route('issues.store'), ['employee_id' => $employee->id, 'stock_variant_id' => $variant->id, 'quantity' => 1, 'issued_at' => '2026-07-13']); $issue = $employee->issues()->first(); $this->post(route('handovers.store', $employee), ['handover_date' => '2026-07-14', 'items' => [['issue_id' => $issue->id, 'condition' => 'damaged']]])->assertSessionHasNoErrors(); $this->assertSame(4, $variant->fresh()->quantity); $this->assertSame('left', $employee->fresh()->status); } }