create(['frozen_by_balance_at' => null]); $active = Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'preflight_blocked_at' => null, 'signal_type' => 'call', 'signal_identifier' => '79161234567', ]); $inactive = Project::factory()->for($tenant)->create([ 'is_active' => false, 'delivery_days_mask' => 127, 'signal_type' => 'call', 'signal_identifier' => '79169999999', ]); (new SnapshotProjectRoutingJob)->handle(); $rows = \DB::table('project_routing_snapshots') ->where('snapshot_date', '2026-05-28')->get(); expect($rows)->toHaveCount(1); expect($rows->first()->project_id)->toBe($active->id); }); it('excludes frozen tenants', function () { $tenant = Tenant::factory()->create(['frozen_by_balance_at' => now()]); Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'signal_type' => 'call', 'signal_identifier' => '79161234567', ]); (new SnapshotProjectRoutingJob)->handle(); expect(\DB::table('project_routing_snapshots')->count())->toBe(0); }); it('excludes preflight_blocked projects', function () { $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]); Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'signal_type' => 'call', 'signal_identifier' => '79161234567', 'preflight_blocked_at' => now(), ]); (new SnapshotProjectRoutingJob)->handle(); expect(\DB::table('project_routing_snapshots')->count())->toBe(0); }); it('excludes projects whose days_mask does not match tomorrow', function () { // 2026-05-28 — четверг (isoWeekday=4 → bit 1<<3 = 8). Тест: mask=4 (только среда). $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]); Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 4, // только среда 'daily_limit_target' => 10, 'signal_type' => 'call', 'signal_identifier' => '79161234567', ]); (new SnapshotProjectRoutingJob)->handle(); expect(\DB::table('project_routing_snapshots')->count())->toBe(0); }); it('uses effective_daily_limit_today as daily_limit when set (R-11/OPEN-5 variant A)', function () { $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]); Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'effective_daily_limit_today' => 3, // override 'signal_type' => 'call', 'signal_identifier' => '79161234567', ]); (new SnapshotProjectRoutingJob)->handle(); $row = \DB::table('project_routing_snapshots')->first(); expect($row->daily_limit)->toBe(3); }); it('is idempotent — second run does not duplicate', function () { $tenant = Tenant::factory()->create(['frozen_by_balance_at' => null]); Project::factory()->for($tenant)->create([ 'is_active' => true, 'delivery_days_mask' => 127, 'daily_limit_target' => 10, 'signal_type' => 'call', 'signal_identifier' => '79161234567', ]); (new SnapshotProjectRoutingJob)->handle(); (new SnapshotProjectRoutingJob)->handle(); expect(\DB::table('project_routing_snapshots')->count())->toBe(1); });