setupUser(); $this->outlet = $this->user->outlets->first(); // Create permissions $permissions = [ 'view stock opname', 'create stock opname', 'show stock opname', 'manage stock opname', // Used in Manage but Index might need it for buttons ]; foreach ($permissions as $permission) { Permission::firstOrCreate(['name' => $permission]); } $role = Role::create(['name' => 'Owner']); $role->givePermissionTo($permissions); $this->user->assignRole($role); }); it('renders the stock opname index page', function () { Livewire::actingAs($this->user) ->test(Index::class) ->assertStatus(200); }); it('can request approval for stock opname', function () { $stockOpname = StockOpname::create([ 'outlet_id' => $this->outlet->id, 'period_month' => now()->format('Y-m'), 'status' => StockOpnameStatus::PROCESS, 'note' => 'Ready for approval', ]); Livewire::actingAs($this->user) ->test(Index::class) ->call('requestApproval', $stockOpname->id); $this->assertDatabaseHas('stock_opname', [ 'id' => $stockOpname->id, 'status' => StockOpnameStatus::PENDING_APPROVAL->value, ]); }); it('can approve stock opname and update outlet stock', function () { $stockOpname = StockOpname::create([ 'outlet_id' => $this->outlet->id, 'period_month' => now()->format('Y-m'), 'status' => StockOpnameStatus::PENDING_APPROVAL, ]); $perfume = Perfume::factory()->create(); // Attach to outlet first to mimic existing stock $this->outlet->perfumes()->attach($perfume->id, ['stock' => 10]); $item = StockOpnameItem::create([ 'stock_opname_id' => $stockOpname->id, 'user_id' => $this->user->id, 'itemable_type' => Perfume::class, 'itemable_id' => $perfume->id, 'qty_system' => 10, 'qty_physical' => 8, // Found 8, so stock should become 8 (loss of 2) ]); Livewire::actingAs($this->user) ->test(Index::class) ->call('approveApproval', $stockOpname->id); $this->assertDatabaseHas('stock_opname', [ 'id' => $stockOpname->id, 'status' => StockOpnameStatus::COMPLETED->value, ]); // Verify outlet stock updated $this->assertEquals(8, $this->outlet->perfumes()->find($perfume->id)->pivot->stock); });