From dddf7fbd838c4d6598cd8ee9291d2b390337ea60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Mon, 13 Jul 2026 07:54:37 +0300 Subject: [PATCH] =?UTF-8?q?feat(chat):=20=D0=B2=20=D0=BF=D0=B8=D1=81=D1=8C?= =?UTF-8?q?=D0=BC=D0=B5=20=D0=B2=D0=BB=D0=B0=D0=B4=D0=B5=D0=BB=D1=8C=D1=86?= =?UTF-8?q?=D1=83=20=D0=B2=D1=81=D1=8F=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF?= =?UTF-8?q?=D0=B8=D1=81=D0=BA=D0=B0=20=D0=B8=20=D0=BE=D1=82=D0=BA=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=20=D0=BA=D0=BB=D0=B8=D0=B5=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/Jobs/Bot/ProcessChatMessageJob.php | 13 ++--- app/app/Mail/BotContactRequestMail.php | 8 +++- .../emails/bot_contact_request.blade.php | 9 ++++ .../Feature/Bot/ChatEscalationMailTest.php | 48 +++++++++++++++++++ 4 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 app/tests/Feature/Bot/ChatEscalationMailTest.php diff --git a/app/app/Jobs/Bot/ProcessChatMessageJob.php b/app/app/Jobs/Bot/ProcessChatMessageJob.php index 70a3d2fe..75bf1514 100644 --- a/app/app/Jobs/Bot/ProcessChatMessageJob.php +++ b/app/app/Jobs/Bot/ProcessChatMessageJob.php @@ -107,11 +107,8 @@ class ProcessChatMessageJob implements ShouldQueue $rows = BotDialog::query() ->where('chat_id', $this->chatId) - ->orderByDesc('id') - ->limit(8) - ->get(['direction', 'message']) - ->reverse() - ->values(); + ->orderBy('id') + ->get(['direction', 'message', 'source', 'user_id']); $question = $rows ->filter(fn (BotDialog $d) => $d->direction === 'in') @@ -122,12 +119,16 @@ class ProcessChatMessageJob implements ShouldQueue ->map(fn (BotDialog $d) => ($d->direction === 'in' ? 'Клиент: ' : 'Бот: ').$d->message) ->all(); + $client = $rows->firstWhere(fn (BotDialog $d) => $d->direction === 'in'); + $source = (string) ($client->source ?? 'portal'); + $userId = $client->user_id !== null ? (int) $client->user_id : null; + $to = (string) config('services.support.email'); if ($to !== '') { // Письмо — В ОЧЕРЕДЬ. Прогон 12.07.2026: почта не ответила → упала вся задача // (tries=1), и клиент, оставивший номер, не получил НИЧЕГО. try { - Mail::to($to)->queue(new BotContactRequestMail($phone, $question, $this->chatId, $transcript)); + Mail::to($to)->queue(new BotContactRequestMail($phone, $question, $this->chatId, $transcript, $source, $userId)); } catch (\Throwable $e) { Log::error('Не удалось поставить в очередь письмо с контактом', [ 'chat_id' => $this->chatId, diff --git a/app/app/Mail/BotContactRequestMail.php b/app/app/Mail/BotContactRequestMail.php index 0ea8f84f..22dd4188 100644 --- a/app/app/Mail/BotContactRequestMail.php +++ b/app/app/Mail/BotContactRequestMail.php @@ -23,13 +23,17 @@ class BotContactRequestMail extends Mailable /** * @param string $phone нормализованный номер (79161234567) * @param string $question вопрос, на котором бот спасовал - * @param list $transcript последние реплики чата («Клиент: …», «Бот: …») + * @param list $transcript вся переписка чата («Клиент: …», «Бот: …») + * @param string $source 'portal' (личный кабинет) или 'landing' (гость) + * @param int|null $userId ID клиента, если он вошёл в кабинет; null для гостя */ public function __construct( public readonly string $phone, public readonly string $question, public readonly string $chatId, public readonly array $transcript = [], + public readonly string $source = 'portal', + public readonly ?int $userId = null, ) {} public function envelope(): Envelope @@ -48,6 +52,8 @@ class BotContactRequestMail extends Mailable 'question' => $this->question, 'chatId' => $this->chatId, 'transcript' => $this->transcript, + 'source' => $this->source, + 'userId' => $this->userId, ], ); } diff --git a/app/resources/views/emails/bot_contact_request.blade.php b/app/resources/views/emails/bot_contact_request.blade.php index 0d92caeb..6e4479ef 100644 --- a/app/resources/views/emails/bot_contact_request.blade.php +++ b/app/resources/views/emails/bot_contact_request.blade.php @@ -1,6 +1,15 @@

Клиент писал в чат Лидерры, бот не смог ответить сам и попросил телефон для связи.

  • Телефон клиента: {{ $phone }}
  • +
  • Откуда: + @if ($source === 'portal' && $userId !== null) + личный кабинет, клиент вошёл (ID {{ $userId }}) + @elseif ($source === 'portal') + личный кабинет + @else + лендинг liderra.ru (гость, не зарегистрирован) + @endif +
  • Вопрос клиента: {{ $question }}
  • Чат: {{ $chatId }}
  • Время: {{ now()->format('d.m.Y H:i') }} МСК
  • diff --git a/app/tests/Feature/Bot/ChatEscalationMailTest.php b/app/tests/Feature/Bot/ChatEscalationMailTest.php new file mode 100644 index 00000000..735df83f --- /dev/null +++ b/app/tests/Feature/Bot/ChatEscalationMailTest.php @@ -0,0 +1,48 @@ + 'support@liderra.ru']); + $chat = str_repeat('a', 32); + + // Длинный разговор: 13 реплик — старый лимит в 8 их бы обрезал. + for ($i = 1; $i <= 6; $i++) { + BotDialog::create(['chat_id' => $chat, 'direction' => 'in', 'message' => "вопрос {$i}", 'source' => 'portal', 'user_id' => 42, 'created_at' => now()]); + BotDialog::create(['chat_id' => $chat, 'direction' => 'out', 'message' => "ответ {$i}", 'created_at' => now()]); + } + BotDialog::create(['chat_id' => $chat, 'direction' => 'out', 'message' => 'Оставьте номер телефона, и специалист свяжется.', 'created_at' => now()]); + $in = BotDialog::create(['chat_id' => $chat, 'direction' => 'in', 'message' => '+7 999 000-11-22', 'source' => 'portal', 'user_id' => 42, 'created_at' => now()]); + + (new ProcessChatMessageJob($chat, (int) $in->id, '+7 999 000-11-22'))->handle(); + + Mail::assertQueued(BotContactRequestMail::class, function (BotContactRequestMail $mail) { + return count($mail->transcript) >= 13 + && str_contains($mail->transcript[0], 'вопрос 1') + && $mail->source === 'portal' + && $mail->userId === 42; + }); +}); + +it('письмо про гостя с лендинга помечено как гость', function () { + Mail::fake(); + config(['services.support.email' => 'support@liderra.ru']); + $chat = str_repeat('b', 32); + + BotDialog::create(['chat_id' => $chat, 'direction' => 'in', 'message' => 'а вы вообще законно работаете?', 'source' => 'landing', 'user_id' => null, 'created_at' => now()]); + BotDialog::create(['chat_id' => $chat, 'direction' => 'out', 'message' => 'Оставьте номер телефона, и специалист свяжется.', 'created_at' => now()]); + $in = BotDialog::create(['chat_id' => $chat, 'direction' => 'in', 'message' => '89990001122', 'source' => 'landing', 'user_id' => null, 'created_at' => now()]); + + (new ProcessChatMessageJob($chat, (int) $in->id, '89990001122'))->handle(); + + Mail::assertQueued(BotContactRequestMail::class, fn (BotContactRequestMail $mail) => $mail->source === 'landing' && $mail->userId === null); +});