From e2dfd22471f33cda9829454584e3c27b5ca701a3 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: Thu, 2 Jul 2026 20:58:24 +0300 Subject: [PATCH] =?UTF-8?q?feat(bot):=20JivoBotClient=20=E2=80=94=20BOT=5F?= =?UTF-8?q?MESSAGE/INVITE=5FAGENT,=20dev-=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=20?= =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/app/Services/Bot/JivoBotClient.php | 56 ++++++++++++++++++++++++ app/tests/Unit/Bot/JivoBotClientTest.php | 44 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 app/app/Services/Bot/JivoBotClient.php create mode 100644 app/tests/Unit/Bot/JivoBotClientTest.php diff --git a/app/app/Services/Bot/JivoBotClient.php b/app/app/Services/Bot/JivoBotClient.php new file mode 100644 index 00000000..d28bfe9e --- /dev/null +++ b/app/app/Services/Bot/JivoBotClient.php @@ -0,0 +1,56 @@ +post([ + 'event' => 'BOT_MESSAGE', + 'id' => (string) Str::uuid(), + 'chat_id' => $chatId, + 'client_id' => $clientId, + 'message' => ['type' => 'TEXT', 'text' => $text, 'timestamp' => now()->getTimestamp()], + ]); + } + + public function inviteAgent(string $chatId, string $clientId): void + { + $this->post([ + 'event' => 'INVITE_AGENT', + 'id' => (string) Str::uuid(), + 'chat_id' => $chatId, + 'client_id' => $clientId, + ]); + } + + /** @param array $payload */ + private function post(array $payload): void + { + $url = (string) config('services.jivo_bot.outbound_url'); + if ($url === '') { + Log::info('JivoBot outbound skipped (no outbound_url)', ['event' => $payload['event']]); + + return; + } + + try { + Http::timeout(5)->post($url, $payload)->throw(); + } catch (\Throwable $e) { + Log::warning('JivoBot outbound failure', ['event' => $payload['event'], 'error' => $e->getMessage()]); + } + } +} diff --git a/app/tests/Unit/Bot/JivoBotClientTest.php b/app/tests/Unit/Bot/JivoBotClientTest.php new file mode 100644 index 00000000..04d042fa --- /dev/null +++ b/app/tests/Unit/Bot/JivoBotClientTest.php @@ -0,0 +1,44 @@ +set('services.jivo_bot.outbound_url', 'https://bot.jivosite.com/webhooks/prov-1/tok-1'); +}); + +it('BOT_MESSAGE уходит с chat_id/client_id и текстом', function () { + Http::fake(['bot.jivosite.com/*' => Http::response(['ok' => true])]); + + app(JivoBotClient::class)->sendMessage('chat-1', 'client-1', 'Проект — это…'); + + Http::assertSent(function ($request) { + return $request->url() === 'https://bot.jivosite.com/webhooks/prov-1/tok-1' + && $request['event'] === 'BOT_MESSAGE' + && $request['chat_id'] === 'chat-1' + && $request['client_id'] === 'client-1' + && $request['message']['type'] === 'TEXT' + && $request['message']['text'] === 'Проект — это…'; + }); +}); + +it('INVITE_AGENT уходит без message', function () { + Http::fake(['bot.jivosite.com/*' => Http::response(['ok' => true])]); + + app(JivoBotClient::class)->inviteAgent('chat-1', 'client-1'); + + Http::assertSent(fn ($r) => $r['event'] === 'INVITE_AGENT' && $r['chat_id'] === 'chat-1'); +}); + +it('пустой outbound_url (dev/CI) → ничего не шлёт и не падает', function () { + config()->set('services.jivo_bot.outbound_url', ''); + Http::fake(); + + app(JivoBotClient::class)->sendMessage('chat-1', 'client-1', 'x'); + + Http::assertNothingSent(); +});