clean($text, 'При регистрации мы дарим 1000 ₽ на баланс.', personalFactsKnown: false); expect($clean)->not->toContain('У вас уже есть') ->and($clean)->not->toContain('лежат на счёте') // Общее объяснение про подарок остаётся: человек не должен остаться без ответа. ->and($clean)->toContain('дарим 1000 ₽'); }); it('вошедшему не называют его баланс подарком портала', function () use ($card) { $guard = app(AnswerGuard::class); $text = 'У вас на балансе 11 025 ₽ — это подарок портала, первые заявки пойдут за его счёт.'; $clean = $guard->clean($text, $card, personalFactsKnown: true); expect($clean)->not->toContain('подарок портала'); }); it('давнему клиенту не подсовывают сценарий новичка «живите на подарок»', function () use ($card) { $guard = app(AnswerGuard::class); // Подарок в 1000 ₽ этот клиент потратил давно: баланс 11 025 ₽, за месяц списано 1 375 ₽. $text = 'Баланс — у вас уже есть. Первые заявки идут за счёт подарка, пополнять ничего не нужно. Проект создаётся в разделе «Проекты».'; $clean = $guard->clean($text, $card, personalFactsKnown: true); expect($clean)->not->toContain('за счёт подарка') ->and($clean)->not->toContain('пополнять ничего не нужно') ->and($clean)->toContain('разделе «Проекты»'); }); it('новичку, у которого подарок нетронут, про подарок сказать можно', function () { $guard = app(AnswerGuard::class); $freshCard = "ДАННЫЕ ЭТОГО КЛИЕНТА (посчитаны только что):\nБаланс: 1000 ₽ ≈ 18 заявок.\n"; $text = 'Первые заявки идут за счёт подарка, пополнять ничего не нужно.'; expect($guard->clean($text, $freshCard, personalFactsKnown: true))->toContain('за счёт подарка'); }); it('вошедшему не врут про состояние его проектов', function () use ($card) { $guard = app(AnswerGuard::class); // Правда: работает ОДИН проект, один на паузе, один остановлен из-за денег. $text = 'У вас сейчас три проекта: два работают («Стоматология — Москва» и «Отбеливание — Казань»), один на паузе.'; $clean = $guard->clean($text, $card, personalFactsKnown: true); expect($clean)->not->toContain('два работают'); }); it('вошедшему не выдают остановленный проект за работающий', function () use ($card) { $guard = app(AnswerGuard::class); $text = 'Проект «Отбеливание — Казань» работает, заявки по нему идут.'; $clean = $guard->clean($text, $card, personalFactsKnown: true); expect($clean)->not->toContain('«Отбеливание — Казань» работает'); }); it('бот не обещает, что от повышения лимита заявок станет больше', function () { $guard = app(AnswerGuard::class); $text = 'Лимит — это потолок, а не гарантия. Если заявок стабильно меньше, чем нужно, — увеличьте лимит, и их будет больше.'; $clean = $guard->clean($text, 'Лимит — это потолок, а не гарантия.', personalFactsKnown: false); expect($clean)->toContain('потолок') ->and($clean)->not->toContain('их будет больше'); }); it('бот не заявляет «такого не бывает» про списание без заявки', function () { $guard = app(AnswerGuard::class); $text = 'Такого не бывает — каждое списание привязано к конкретной заявке. Проверить каждое списание можно на вкладке «Списания».'; $clean = $guard->clean($text, 'Проверить каждое списание можно на вкладке «Списания».', personalFactsKnown: false); expect($clean)->not->toContain('Такого не бывает') ->and($clean)->toContain('вкладке «Списания»'); }); it('номер и заявка — одно и то же: «поштучно не продаём» бот больше не говорит', function () { // Живой лог 14.07.2026, замечание владельца: «номера это и есть заявки, а он их делит». // Мы продаём любой объём, хоть одну штуку — отказа в поштучной продаже нет и не было. $guard = app(AnswerGuard::class); $text = 'Мы не продаём номера поштучно — платите вы за заявки, которые получаете. Заявка стоит от 55 ₽ до 25 ₽.'; $clean = $guard->clean($text, 'Заявка стоит от 55 ₽ до 25 ₽. Номер, заявка и лид — это одно и то же.', personalFactsKnown: false); expect($clean)->not->toContain('поштучно') ->and($clean)->toContain('от 55 ₽'); }); it('число, названное самим клиентом, сторож не считает выдумкой', function () { $guard = app(AnswerGuard::class); // Клиент спросил «можно купить всего 5 номеров?» — повторить его же «5 номеров» // в ответе не выдумка. Сторожу отдаётся и текст вопроса (BotAnswerService). $context = "Минимального заказа нет.\n\nможно купить всего 5 номеров?"; $text = 'Да, конечно — можно взять и 5 номеров, минимального заказа нет.'; expect($guard->clean($text, $context, personalFactsKnown: false))->toContain('5 номеров'); }); it('сколько заявок выйдет на подарочную тысячу — бот не обещает', function () { $guard = app(AnswerGuard::class); $text = 'При регистрации дарим 1000 ₽ — этого хватит на несколько десятков заявок. Заявка стоит от 55 ₽.'; $clean = $guard->clean($text, 'При регистрации дарим 1000 ₽. Заявка стоит от 55 ₽.', personalFactsKnown: false); expect($clean)->not->toContain('несколько десятков') ->and($clean)->toContain('от 55 ₽'); }); it('правду про возврат ОСТАТКА баланса сторож не режет', function () { $guard = app(AnswerGuard::class); $article = 'Неизрасходованный остаток баланса возвращается по заявлению на support@liderra.ru, ' .'до 3 рабочих дней, за вычетом комиссий. Стоимость уже переданных заявок возврату не подлежит.'; $text = 'Неизрасходованный остаток баланса можно вернуть по заявлению на support@liderra.ru — деньги придут на те же реквизиты.'; $clean = $guard->clean($text, $article, personalFactsKnown: false); expect($clean)->toContain('остаток баланса можно вернуть'); }); it('обещание вернуть деньги ЗА ЗАЯВКУ сторож по-прежнему режет', function () { $guard = app(AnswerGuard::class); $text = 'Мы вернём вам деньги за эту заявку, раз человек не взял трубку.'; $clean = $guard->clean($text, 'Недозвон — не брак.', personalFactsKnown: false); expect($clean)->not->toContain('вернём вам деньги'); }); it('после вырезанного предложения не остаётся обрубок «Они лежат…»', function () { $guard = app(AnswerGuard::class); // Первое предложение — выдумка про гостя, его режем. Второе без него бессмысленно. $text = 'У вас уже есть 1000 ₽ подарка. Они лежат на счёте, и первые заявки идут за их счёт. Пополнять баланс можно картой или по счёту.'; $clean = $guard->clean($text, 'Пополнять баланс можно картой или по счёту.', personalFactsKnown: false); expect($clean)->not->toContain('Они лежат') ->and($clean)->toContain('картой или по счёту'); });