create(); $project = Project::factory()->for($tenant)->create(['daily_limit_target' => 10]); $sp = SupplierProject::factory()->create(); linkProjectToSupplier($project, $sp); $result = app(ProjectService::class)->update($project, ['daily_limit_target' => 5]); expect($result->applies_from)->toBeInstanceOf(CarbonImmutable::class); expect($result->applies_from->format('Y-m-d H:i'))->toBe('2026-05-28 21:00'); Carbon::setTestNow(); }); it('returns applies_from = tomorrow 21:00 MSK when edit after 18:00 MSK', function (): void { Carbon::setTestNow('2026-05-28 19:30:00', 'Europe/Moscow'); $tenant = Tenant::factory()->create(); $project = Project::factory()->for($tenant)->create(['daily_limit_target' => 10]); $sp = SupplierProject::factory()->create(); linkProjectToSupplier($project, $sp); $result = app(ProjectService::class)->update($project, ['daily_limit_target' => 7]); expect($result->applies_from->format('Y-m-d H:i'))->toBe('2026-05-29 21:00'); Carbon::setTestNow(); }); it('returns applies_from = null when only non-slepok fields changed (e.g. name)', function (): void { Carbon::setTestNow('2026-05-28 14:00:00', 'Europe/Moscow'); $tenant = Tenant::factory()->create(); $project = Project::factory()->for($tenant)->create(); $sp = SupplierProject::factory()->create(); linkProjectToSupplier($project, $sp); $result = app(ProjectService::class)->update($project, ['name' => 'Renamed project']); expect($result->applies_from)->toBeNull(); Carbon::setTestNow(); }); it('returns applies_from = null when project has no supplier links', function (): void { Carbon::setTestNow('2026-05-28 14:00:00', 'Europe/Moscow'); $tenant = Tenant::factory()->create(); $project = Project::factory()->for($tenant)->create(['daily_limit_target' => 10]); // нет linkProjectToSupplier — нет slepok-риска $result = app(ProjectService::class)->update($project, ['daily_limit_target' => 5]); expect($result->applies_from)->toBeNull(); Carbon::setTestNow(); });