UniformFlow/tests/Feature/UniformWorkflowTest.php

116 lines
5.1 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Employee;
use App\Models\StockVariant;
use App\Models\UniformItem;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class UniformWorkflowTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->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_bulk_receiving_updates_multiple_sizes_in_one_submission(): void
{
$medium = $this->variant(3);
$large = $medium->item->variants()->create(['size' => 'L', 'quantity' => 2, 'reorder_level' => 2]);
$this->post(route('inventory.restock'), [
'uniform_item_id' => $medium->uniform_item_id,
'stocks' => [$medium->id => 5, $large->id => 8],
'notes' => 'Delivery GRN-100',
])->assertSessionHasNoErrors();
$this->assertSame(8, $medium->fresh()->quantity);
$this->assertSame(10, $large->fresh()->quantity);
$this->assertDatabaseHas('stock_movements', ['stock_variant_id' => $medium->id, 'quantity_change' => 5, 'notes' => 'Delivery GRN-100']);
$this->assertDatabaseHas('stock_movements', ['stock_variant_id' => $large->id, 'quantity_change' => 8, 'notes' => 'Delivery GRN-100']);
}
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);
}
}