seed(RolePermissionSeeder::class); }); // ─── Helper ─────────────────────────────────────────────── function createStockUserWithPermission(PermissionEnum ...$permissions): User { $user = User::factory()->create(); $user->givePermissionTo( array_merge( [PermissionEnum::DASHBOARD_VIEW->value], array_map(fn (PermissionEnum $p) => $p->value, $permissions) ) ); $user->forgetCachedPermissions(); return $user; } function createCompletedCuttingSetup(): array { $product = Product::factory()->create(); $variant = ProductVariant::factory()->create([ 'product_id' => $product->id, 'stock' => 10, 'reject_stock' => 5, ]); $rawMaterial = RawMaterial::factory()->create(); $rawMaterialPrice = RawMaterialPrice::factory()->create([ 'raw_material_id' => $rawMaterial->id, ]); $cutting = Cutting::factory()->create([ 'status' => CuttingStatus::COMPLETED, ]); CuttingMaterial::factory()->create([ 'cutting_id' => $cutting->id, 'raw_material_price_id' => $rawMaterialPrice->id, ]); CuttingResult::factory()->create([ 'cutting_id' => $cutting->id, 'product_variant_id' => $variant->id, 'cutting_result' => 7, 'sample' => 5, // Good stock result 'original_outside_sample' => 2, // Reject stock result ]); return [ 'cutting' => $cutting, 'variant' => $variant, 'raw_material_price' => $rawMaterialPrice, ]; } // ─── Tests ──────────────────────────────────────────────── describe('Stock Warehouse Management', function () { test('authenticated user with permission can view stocks index', function () { $user = createStockUserWithPermission(PermissionEnum::STOCKS_VIEW); $this->actingAs($user) ->get(route('admin.manage.stocks.index')) ->assertOk(); }); test('user with permission can submit verification for completed cutting', function () { $user = createStockUserWithPermission( PermissionEnum::STOCKS_VIEW, PermissionEnum::CUTTINGS_VERIFY ); $setup = createCompletedCuttingSetup(); $cutting = $setup['cutting']; $payload = [ 'verification_note' => 'Verification notes', 'results' => [ [ 'product_variant_id' => $setup['variant']->id, 'good' => 6, // changed from 5 to 6 'reject' => 1, // changed from 2 to 1 ] ], 'result_prices' => [ [ 'product_variant_id' => $setup['variant']->id, 'prices' => [ [ 'type' => 'harga_modal', 'price' => 50000, ], [ 'type' => 'retail', 'price' => 75000, ] ] ] ], ]; $this->actingAs($user) ->post(route('admin.manage.stocks.verify', $cutting), $payload) ->assertRedirect(route('admin.manage.stocks.index')); $cutting->refresh(); $this->assertEquals(CuttingStatus::PENDING_VERIFICATION, $cutting->status); // Verify cutting results are updated $this->assertDatabaseHas('cutting_results', [ 'cutting_id' => $cutting->id, 'product_variant_id' => $setup['variant']->id, 'sample' => 6, 'original_outside_sample' => 1, ]); }); test('user with permission can approve verification and increase stock', function () { $user = createStockUserWithPermission( PermissionEnum::STOCKS_VIEW, PermissionEnum::OWNER_VERIFICATIONS_VERIFY ); $setup = createCompletedCuttingSetup(); $cutting = $setup['cutting']; $cutting->status = CuttingStatus::PENDING_VERIFICATION; $cutting->save(); $this->actingAs($user) ->post(route('admin.manage.owner_verifications.approve', $cutting), [ 'approval_note' => 'Approved by owner', ]) ->assertRedirect(); $cutting->refresh(); $setup['variant']->refresh(); $this->assertEquals(CuttingStatus::VERIFIED, $cutting->status); // Stock (good) should increment by 5 (10 + 5 = 15) $this->assertEquals(15, $setup['variant']->stock); // Reject stock should increment by 2 (5 + 2 = 7) $this->assertEquals(7, $setup['variant']->reject_stock); }); test('user with permission can reject verification', function () { $user = createStockUserWithPermission( PermissionEnum::STOCKS_VIEW, PermissionEnum::OWNER_VERIFICATIONS_REJECT ); $setup = createCompletedCuttingSetup(); $cutting = $setup['cutting']; $cutting->status = CuttingStatus::PENDING_VERIFICATION; $cutting->save(); $this->actingAs($user) ->post(route('admin.manage.owner_verifications.reject', $cutting), [ 'reason' => 'Invalid results', ]) ->assertRedirect(); $cutting->refresh(); // Status should revert to COMPLETED $this->assertEquals(CuttingStatus::COMPLETED, $cutting->status); $this->assertDatabaseHas('rejections', [ 'rejectable_id' => $cutting->id, 'rejectable_type' => Cutting::class, 'reason' => 'Invalid results', ]); }); });