feat(chat): в письме владельцу вся переписка и откуда клиент

This commit is contained in:
Дмитрий
2026-07-13 07:54:37 +03:00
parent 06ad38ecb7
commit dddf7fbd83
4 changed files with 71 additions and 7 deletions
+7 -6
View File
@@ -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,
+7 -1
View File
@@ -23,13 +23,17 @@ class BotContactRequestMail extends Mailable
/**
* @param string $phone нормализованный номер (79161234567)
* @param string $question вопрос, на котором бот спасовал
* @param list<string> $transcript последние реплики чата («Клиент: …», «Бот: …»)
* @param list<string> $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,
],
);
}
@@ -1,6 +1,15 @@
<p>Клиент писал в чат Лидерры, бот не смог ответить сам и попросил телефон для связи.</p>
<ul>
<li><strong>Телефон клиента:</strong> {{ $phone }}</li>
<li><strong>Откуда:</strong>
@if ($source === 'portal' && $userId !== null)
личный кабинет, клиент вошёл (ID {{ $userId }})
@elseif ($source === 'portal')
личный кабинет
@else
лендинг liderra.ru (гость, не зарегистрирован)
@endif
</li>
<li><strong>Вопрос клиента:</strong> {{ $question }}</li>
<li><strong>Чат:</strong> {{ $chatId }}</li>
<li><strong>Время:</strong> {{ now()->format('d.m.Y H:i') }} МСК</li>
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
use App\Jobs\Bot\ProcessChatMessageJob;
use App\Mail\BotContactRequestMail;
use App\Models\BotDialog;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Mail;
uses(RefreshDatabase::class);
it('в письме владельцу — вся переписка и откуда клиент', function () {
Mail::fake();
config(['services.support.email' => '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);
});