Stage 3 Task 3.2. BalancePreflightSweepJob now mirrors freeze/unfreeze state
onto projects.paused_at so SupplierSnapshotGuard has the right hook to block
delete/change_source while the supplier slepok tail can still arrive:
- On freeze: capture freezeAt = now() once, set tenant.frozen_by_balance_at
AND projects.paused_at (only WHERE paused_at IS NULL) to the same moment.
This gives the snapshot guard a uniform recent paused_at across all of the
tenant's projects.
- On unfreeze: capture frozen_at_was BEFORE save, then clear paused_at only
on projects whose paused_at >= frozen_at_was (== auto-paused by us).
Manual pauses set by the client BEFORE freeze have paused_at < frozen_at_was
and stay preserved.
Spec §4.3.2.
При переходе active→frozen или frozen→active BalancePreflightSweepJob теперь дёргает SyncSupplierProjectJob per-project, если admin-переключатель в режиме online. В batch (рабочем для будущего масштаба) — sync отложен до cut-off cron 18:00 MSK через SyncSupplierProjectsJob.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
liderra_testing persistent (RefreshDatabase off) — DemoSeeder тенанты
могут попасть в sweep и тоже получить BalanceFrozenMail. Без per-tenant
фильтра Mail::assertNotQueued() ловил 154 фоновых письма и валил тест.
Логика BalancePreflightSweepJob корректна — фикс только в test isolation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task 1.4+1.5 Спека C. BalancePreflightSweepJob (chunkById всех тенантов,
переход active->frozen / frozen->active, идемпотентность, журнал balance_freeze_log
через pgsql_supplier) + BillingPreflightSweepCommand + cron billing:preflight-sweep
@18:00 MSK (SyncSupplierProjectsJob сдвинут 18:00->18:05). 4 Mailable
(Frozen/Reminder/Final/Unfrozen) + blade. Job шлёт Frozen/Unfrozen при переходах;
Reminder/Final (T+24h/T+72h) — классы готовы, рассылка по дате — следующий шаг.
11 Phase 1 billing-тестов GREEN. Адаптации под факт схемы: contact_email (не email),
organization_name (не name), is_active+daily_limit_target (не status+daily_limit).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>