Дмитрий
9a45346205
fix(tests): RefreshDatabase on LookupsTest + ProjectExtensionsTest — close quirk #62
...
DatabaseTransactions did not prevent cross-session data accumulation in
liderra_testing; count assertions drifted (1465 managers, 519 projects).
RefreshDatabase runs migrate:fresh once per session (RefreshDatabaseState::migrated)
so stale data is wiped at start of each composer test run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-14 05:29:34 +03:00
Дмитрий
1e3c157603
fix(test): Plan 4 Task 1 regression — PricingTierTest::scopeActive baseline-aware
...
Task 1 (a907fea ) добавил $this->call(PricingTierSeeder::class) в DatabaseSeeder,
который автоматически seed'ит 7 ступеней при migrate:fresh --seed на dev/testing.
Существующий PricingTierTest::scopeActive ожидал empty pricing_tiers до factory,
поэтому ->count() == 1 → 8 fail в isolation (pest tests/Feature/Models/PricingTierTest.php).
Fix: scopeActive теперь считает baseline = PricingTier::active()->count() ДО factory create,
ожидает baseline + 1 после factory (1 активный + past, 1 inactive, 1 active + future).
PricingTierTest::current() — не затронут: keyBy('tier_no') корректно перезаписывает
seed-rows (effective_from='1970-01-01') свежими factory-rows (effective_from=now()->subDay()).
Verified:
- pest tests/Feature/Models/PricingTierTest.php — 4/4 PASS, 12 assertions
- pest --parallel — 619 passed / 3 skipped / 0 failed / 1923 assertions
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-11 08:59:06 +03:00
Дмитрий
aa37f4cbed
feat(models): SupplierLead model + factory (raw-payload incoming webhooks)
...
SaaS-level модель для supplier_leads (Plan 2/5 Task 2).
belongsTo(SupplierProject) + array cast на raw_payload + datetime *_at.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 18:24:45 +03:00
Дмитрий
99afcbc25c
feat(models): extend Project with signal_type, sms_senders, supplier_b1/b2/b3 relations + scopes
...
- app/Models/Project.php — добавлены fillable+casts для supplier integration:
signal_type, signal_identifier, sms_senders (jsonb array), sms_keyword,
delivered_in_month, supplier_b{1,2,3}_project_id.
+ supplierB1/B2/B3() BelongsTo relations на SupplierProject (sharing-model).
+ scopeActiveOnDay($iso) — bitmask проверка по delivery_days_mask
(bit 0 = Mon, bit 6 = Sun; ISO=1 → 1<<0 = 1; ISO=7 → 1<<6 = 64).
+ scopeForSignal($type, $identifier) — фильтр по сигналу (для роутинга в Plan 2).
- database/factories/ProjectFactory.php — defaults null/0 для новых полей
(CHECK constraints не нарушаются: signal_type IS NULL → остальные опциональны).
+ state-методы asSiteSignal($domain), asCallSignal($phone), asSmsSignal($senders, $keyword).
- tests/Feature/Models/ProjectExtensionsTest.php — 6 тестов: signal_type fillable,
sms_senders array cast + sms_keyword, SMS без keyword, supplierB1/B2/B3 relations,
scopeActiveOnDay (bitmask Mon/Sat), scopeForSignal (3 сигнала + edge-case).
Pest: 469 / 467 passed / 2 skipped (461 + 6 новых = 467, с retry на transient
PG connection issues — на параллельных тестах с testing_rls_user GRANT тяжёл).
Larastan: 0 errors. Pint passed.
Spec: §2.1
Plan: Task 10
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:59:53 +03:00
Дмитрий
084a952bfa
feat(models): add SupplierSyncLog model + factory (audit trail для AJAX-sync)
...
- app/Models/SupplierSyncLog.php — fillable + casts (jsonb arrays + datetime)
+ supplierProject() BelongsTo relation (nullable, ON DELETE SET NULL —
лог переживает удаление supplier-проекта для audit-trail).
$timestamps = false (только created_at, без updated_at — append-only)
- database/factories/SupplierSyncLogFactory.php — реалистичные действия из enum
- tests/Feature/Models/SupplierSyncLogTest.php — 4 теста: factory,
supplier_project relation, jsonb array casts, nullable FK lifecycle
Pest: 463 / 461 passed / 2 skipped (457 + 4 новых = 461).
Larastan: 0 errors. Pint passed.
Spec: §4.3
Plan: Task 9
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:53:55 +03:00
Дмитрий
31f813315d
feat(models): add LeadCharge ledger model + factory + relations to Tenant/Deal
...
- app/Models/LeadCharge.php — fillable + casts (datetime + integer)
+ tenant() BelongsTo relation
+ deal() BelongsTo relation (по deal_id, без deal_received_at — composite PK
на партиционированной обеспечивается БД-уровнем через FK)
+ accessor priceRubles (kopecks → float)
- database/factories/LeadChargeFactory.php — НЕ создаёт реальный Deal автоматически
(composite FK requires (deal_id, deal_received_at) пары); тесты с FK-целостностью
явно создают Deal::factory() и передают пару в state()
- tests/Feature/Models/LeadChargeTest.php — 4 теста: factory, tenant relation,
deal relation, priceRubles accessor. testing_rls_user setup в beforeEach
для проверки RLS context из не-superuser контекста.
Quirk: SET LOCAL app.current_tenant_id НЕ принимает параметрическое связывание PG —
используем string interpolation с {$tenant->id} как в RlsSmokeTest pattern.
ide-helper:models -W -M -N синхронизировал docblocks (WebhookDedupKey).
Pest: 459 / 457 passed / 2 skipped (453 + 4 новых = 457).
Larastan: 0 errors. Pint passed.
Spec: §7.4
Plan: Task 8
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:52:10 +03:00
Дмитрий
71e38ee0a9
feat(models): add PricingTier model with kopecks→rubles accessor + current() snapshot
...
- app/Models/PricingTier.php — fillable + casts (date, boolean, integer)
+ accessor priceRubles (kopecks → float rubles)
+ scopeActive (is_active=true AND effective_from <= today)
+ static current() — keyed by tier_no Collection<int, PricingTier>
- database/factories/PricingTierFactory.php — реалистичные ступени (300/700/1000/.../null)
- tests/Feature/Models/PricingTierTest.php — 4 теста: factory, accessor,
scopeActive, current() snapshot всех 7 ступеней
ide-helper:models -W -M -N перегенерил docblocks (WebhookDedupKey synced
после schema v8.16).
Pest: 455 / 453 passed / 2 skipped (449 + 4 новых = 453).
Larastan: 0 errors. Pint auto-fix.
Spec: §7.2
Plan: Task 7
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:48:00 +03:00
Дмитрий
62aa55f033
feat(models): add SupplierProject Eloquent model + factory + tests
...
- app/Models/SupplierProject.php — fillable + casts (jsonb arrays + datetime)
+ scopes: active() (inactive_since IS NULL), staleSince(N days),
forSignal(signal_type, unique_key)
- database/factories/SupplierProjectFactory.php — корректно учитывает
chk_supplier_projects_b1_not_for_sms (B1 не порождает SMS-проекты)
- tests/Feature/Models/SupplierProjectTest.php — 6 тестов: factory,
array casts (workdays + regions), scopeActive, scopeStaleSince,
scopeForSignal (3 платформы на один домен — UNIQUE (platform,unique_key))
ide-helper:models -W -M -N перегенерил docblocks для 4 существующих моделей
(SaasAdminAuditLog, SystemSetting, UserRecoveryCode, ImpersonationToken) —
синхронизировал @property после schema v8.16.
Pest: 451 / 449 passed / 2 skipped (было 443+6 новых от Task 6 = 449).
Larastan: 0 errors. Pint: passed.
Spec: §2.2
Plan: Task 6
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 13:59:39 +03:00