create(['tier_no' => 1, 'leads_in_tier' => 300, 'price_per_lead_kopecks' => 5000]); PricingTier::factory()->create(['tier_no' => 2, 'leads_in_tier' => null, 'price_per_lead_kopecks' => 4000]); } it('называет баланс, сколько это заявок и на сколько дней хватит', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 0]); Project::factory()->create(['tenant_id' => $tenant->id, 'is_active' => true, 'daily_limit_target' => 10]); $user = User::factory()->create(['tenant_id' => $tenant->id]); $card = app(ClientFacts::class)->card((int) $user->id); // 1000 ₽ по 50 ₽ = 20 заявок; заказ 10/день → на 2 дня. expect($card)->toContain('1 000 ₽') ->and($card)->toContain('20 заявок') ->and($card)->toContain('на 2 дня'); }); it('честно говорит, что тратить нечего, когда активных проектов нет', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 0]); $user = User::factory()->create(['tenant_id' => $tenant->id]); expect(app(ClientFacts::class)->card((int) $user->id)) ->toContain('активных проектов нет'); }); it('предупреждает о заморозке заказа из-за нулевого баланса', function () { tiers(); $tenant = Tenant::factory()->create([ 'balance_rub' => '0.00', 'delivered_in_month' => 0, 'frozen_by_balance_at' => now(), ]); $user = User::factory()->create(['tenant_id' => $tenant->id]); expect(app(ClientFacts::class)->card((int) $user->id)) ->toContain('Заказ заморожен'); }); it('отдаёт null, когда такого пользователя нет', function () { expect(app(ClientFacts::class)->card(999999))->toBeNull(); }); it('называет ступень, цену заявки и сколько заявок до следующей ступени', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 180]); $user = User::factory()->create(['tenant_id' => $tenant->id]); $card = app(ClientFacts::class)->card((int) $user->id); expect($card)->toContain('Ступень: 1-я, 50 ₽ за заявку') ->and($card)->toContain('получено в этом месяце 180') ->and($card)->toContain('до следующей ступени — 120'); }); it('на границе ступени называет уже СЛЕДУЮЩУЮ цену: 300 заявок пройдено — цена новая', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 300]); $user = User::factory()->create(['tenant_id' => $tenant->id]); // 301-й лид идёт уже по цене второй ступени — так считает биллинг, так должен говорить бот. expect(app(ClientFacts::class)->card((int) $user->id)) ->toContain('Ступень: 2-я, 40 ₽ за заявку'); }); it('при пустой сетке цен не сочиняет арифметику, а честно говорит, что считать нечем', function () { // ступени НЕ создаём $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 0]); Project::factory()->create(['tenant_id' => $tenant->id, 'is_active' => true, 'daily_limit_target' => 10]); $user = User::factory()->create(['tenant_id' => $tenant->id]); $card = app(ClientFacts::class)->card((int) $user->id); expect($card)->toContain('1 000 ₽') ->and($card)->toContain('Сетка цен не настроена') ->and($card)->not->toContain('на 0 дней') ->and($card)->not->toContain('≈ 0 заявок'); }); it('на последней ступени говорит, что выше ступеней нет', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 500]); $user = User::factory()->create(['tenant_id' => $tenant->id]); $card = app(ClientFacts::class)->card((int) $user->id); expect($card)->toContain('Ступень: 2-я, 40 ₽ за заявку') ->and($card)->toContain('это последняя ступень'); }); it('склоняет слова по-русски: одна заявка, один день', function () { tiers(); // 50 ₽ по цене 50 ₽ = ровно 1 заявка; заказ 1/день → 1 день. $tenant = Tenant::factory()->create(['balance_rub' => '50.00', 'delivered_in_month' => 0]); Project::factory()->create(['tenant_id' => $tenant->id, 'is_active' => true, 'daily_limit_target' => 1]); $user = User::factory()->create(['tenant_id' => $tenant->id]); $card = app(ClientFacts::class)->card((int) $user->id); expect($card)->toContain('1 заявка') ->and($card)->toContain('на 1 день') ->and($card)->not->toContain('дня(дней)'); }); it('перечисляет проекты и их состояние', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 0]); $user = User::factory()->create(['tenant_id' => $tenant->id]); Project::factory()->create([ 'tenant_id' => $tenant->id, 'name' => 'Стоматология МСК', 'is_active' => true, 'daily_limit_target' => 20, 'delivered_today' => 12, ]); Project::factory()->create([ 'tenant_id' => $tenant->id, 'name' => 'Клиника СПб', 'is_active' => true, 'paused_at' => now(), ]); Project::factory()->create([ 'tenant_id' => $tenant->id, 'name' => 'Без денег', 'is_active' => true, 'preflight_blocked_at' => now(), ]); Project::factory()->create([ 'tenant_id' => $tenant->id, 'name' => 'Выключенный', 'is_active' => false, ]); $card = app(ClientFacts::class)->card((int) $user->id); expect($card)->toContain('Проекты (4)') ->and($card)->toContain('«Стоматология МСК» — работает, лимит 20 в день, сегодня 12') ->and($card)->toContain('«Клиника СПб» — на паузе') ->and($card)->toContain('«Без денег» — остановлен из-за нехватки денег') ->and($card)->toContain('«Выключенный» — выключен'); }); it('считает заявки за периоды, списания за месяц и последнее пополнение', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '1000.00', 'delivered_in_month' => 0]); $user = User::factory()->create(['tenant_id' => $tenant->id]); $project = Project::factory()->create(['tenant_id' => $tenant->id]); // Сегодня 2 заявки, вчера 1. Даты держим ВНУТРИ текущего месяца — партиции deals помесячные. Deal::factory()->count(2)->create([ 'tenant_id' => $tenant->id, 'project_id' => $project->id, 'received_at' => now()->startOfDay()->addHours(9), ]); Deal::factory()->create([ 'tenant_id' => $tenant->id, 'project_id' => $project->id, 'received_at' => now()->subDay()->startOfDay()->addHours(9), ]); LeadCharge::factory()->count(2)->create([ 'tenant_id' => $tenant->id, 'price_per_lead_kopecks' => 5000, // 50 ₽ × 2 = 100 ₽ 'charged_at' => now(), ]); BalanceTransaction::factory()->create([ 'tenant_id' => $tenant->id, 'type' => BalanceTransaction::TYPE_TOPUP, 'amount_rub' => '5000.00', 'created_at' => now()->subDays(2), ]); $card = app(ClientFacts::class)->card((int) $user->id); expect($card)->toContain('Заявки: сегодня 2, вчера 1') ->and($card)->toContain('Списано за месяц: 100 ₽') ->and($card)->toContain('Последнее пополнение: 5 000 ₽'); }); it('не падает на пустом клиенте', function () { tiers(); $tenant = Tenant::factory()->create(['balance_rub' => '0.00', 'delivered_in_month' => 0]); $user = User::factory()->create(['tenant_id' => $tenant->id]); $card = app(ClientFacts::class)->card((int) $user->id); expect($card)->toContain('Проектов нет') ->and($card)->toContain('Заявки: сегодня 0, вчера 0') ->and($card)->toContain('Пополнений ещё не было'); });