fomvasss / laravel-notification-channel-gronosync
Laravel notification channel for GronoSync — send messages via Telegram, WhatsApp, Instagram, Facebook, Viber, SMS, email and other channels through the GronoSync platform.
Package info
github.com/fomvasss/laravel-notification-channel-gronosync
pkg:composer/fomvasss/laravel-notification-channel-gronosync
Requires
- php: >=8.2
- guzzlehttp/guzzle: ^7.0|^8.0
- illuminate/notifications: ^10|^11|^12|^13
- illuminate/support: ^10|^11|^12|^13
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- phpunit/phpunit: ^10.0|^11.0|^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
GronoSync Notification Channel для Laravel
Українська · English
Надсилайте Laravel-нотифікації через GronoSync — мультиканальну платформу обміну повідомленнями з підтримкою Telegram, WhatsApp, Instagram, Facebook, Viber, SMS, email та вбудованого чат-віджету.
Сайт · Кабінет клієнта · API: https://api.gronosync.com
Документація
Цей README — про Laravel-пакет. Усе про сам сервіс GronoSync — на docs.gronosync.com:
- Extern API — контакти, повідомлення, заявки, канали, ліміти
- Помилки й коди — кожен статус і
codeі що з ними робити - Вебхуки — події, payload з повними прикладами JSON, перевірка, повтори
- Віджети на сайт — чат, форма й чат менеджера для вашої CRM
- Ключі API · Зміни API
Зміст
- Встановлення
- Налаштування
- Надсилання сповіщень
- Виклик API напряму
- Помилки
- Отримання вебхуків
- Тестування
Встановлення
composer require fomvasss/laravel-notification-channel-gronosync
Налаштування
Додайте до .env:
GRONOSYNC_URL=https://api.gronosync.com GRONOSYNC_TOKEN=your_organization_token
Додайте до config/services.php:
'gronosync' => [ 'url' => env('GRONOSYNC_URL'), 'token' => env('GRONOSYNC_TOKEN'), ],
token — ключ API організації: кабінет GronoSync → Налаштування → Розширення → API. Показується лише раз, при створенні. Див. Ключі API.
Надсилання сповіщень
use NotificationChannels\Gronosync\GronosyncChannel; use NotificationChannels\Gronosync\GronosyncMessage; class OrderConfirmed extends \Illuminate\Notifications\Notification { public function __construct(protected Order $order) {} public function via(mixed $notifiable): array { return [GronosyncChannel::class]; } public function toGronosync(mixed $notifiable): GronosyncMessage { return GronosyncMessage::make() ->text("Ваше замовлення #{$this->order->id} підтверджено!") ->button('Переглянути замовлення', "https://shop.com/orders/{$this->order->id}"); } }
Маршрутизація
Поверніть контакт із notifiable-моделі — UUID у GronoSync або ваш ID, якщо синхронізуєте контакти через upsertContact() з external_id:
public function routeNotificationForGronosync(): ?string { return $this->gronosync_contact_id; // UUID контакту в GronoSync } public function routeNotificationForGronosyncExternalId(): ?string { return (string) $this->id; // той самий external_id, що передається в upsertContact() }
Якщо визначено обидва, спершу береться routeNotificationForGronosync(), а external ID — лише коли той повертає порожнє значення. Без моделі: Notification::route('GronosyncExternalId', 'crm-42')->notify(...).
Або вкажіть контакт у повідомленні — рівно одним із contactId(), contactExternalId(), to():
GronosyncMessage::make()->contactExternalId((string) $customer->id)->text('Привіт!'); // новий контакт за ідентифікатором у каналі (телефон, Telegram ID, email…) GronosyncMessage::make()->to('+380991234567')->channelId($smsChannelId)->text('Ласкаво просимо!');
Що означає to для кожного типу каналу і коли потрібен channelId() — Повідомлення.
Методи GronosyncMessage
| Метод | Опис |
|---|---|
contactId(string $id) |
UUID контакту в GronoSync |
contactExternalId(string $id) |
ID контакту у вашій системі — external_id, переданий в upsertContact() |
to(string $identifier) |
Ідентифікатор контакту в каналі — для контактів, яких ще немає |
channelId(string $id) |
UUID каналу в GronoSync (обов'язковий з to()) |
text(string $text) |
Текст повідомлення |
attachment(string $url, ?string $filename, string $type) |
Додати файл. Типи: image, audio, video, document |
attachments(array $items, string $type) |
Додати кілька файлів |
button(string $title, string $urlOrCallback, string $type) |
Додати кнопку. Типи: web_url, callback |
buttons(array $items) |
Додати кілька кнопок |
parseMode(string $mode) |
Поки не діє: у Telegram текст завжди йде як HTML (Повідомлення) |
previewUrl(bool $val) |
Поки не діє: на прев'ю посилань не впливає |
replyToId(string $id) |
Повідомлення, на яке це відповідь |
forwardedFromId(string $id) |
Переслане повідомлення |
metadata(array $metadata) |
Ваші дані (до 4 КБ) — повертаються в data.metadata вебхука chat.message.sent |
memberExternalId(string $externalId) |
Хто з людей написав у вашій системі — External ID учасника організації: автор повідомлення в кабінеті (ім'я, аватар) |
Виклик API напряму
GronosyncApi — тонкий клієнт Extern API, повертає розібрану відповідь.
| Метод | Ендпоінт |
|---|---|
sendMessage(GronosyncMessage $message) |
POST /message |
upsertContact(array $data) |
POST /contacts |
getContact(string $id) / getContactByExternalId(string $externalId) |
GET /contacts/{id} — повертає data |
getChannels() |
GET /channels — повертає data |
submitForm(array $data, ?string $idempotencyKey = null) |
POST /form, ключ іде заголовком Idempotency-Key |
sendIncoming(array $data, ?string $idempotencyKey = null) |
POST /incoming — повідомлення від клієнта з вашої системи (тікети, чат), ключ іде заголовком Idempotency-Key. message.text — простим текстом, без HTML: перенос рядка — \n, посилання — повною адресою |
use NotificationChannels\Gronosync\GronosyncApi; $api = app(GronosyncApi::class); $api->upsertContact(['external_id' => (string) $user->id, 'name' => $user->name, 'phone' => $user->phone]); $contact = $api->getContactByExternalId((string) $user->id); $channel = collect($contact['channels'])->firstWhere('can_send', true); $api->submitForm([ 'channel_id' => config('services.gronosync.form_channel_id'), 'fields' => ['name' => $lead->name, 'email' => $lead->email, 'message' => $lead->message], ], idempotencyKey: "lead-{$lead->id}");
Невідомі ключі в upsertContact() / submitForm() / sendIncoming() відкидаються перед відправкою.
Помилки
Збої повертаються як CouldNotSendNotification:
- Прямий виклик
GronosyncApi— виняток кидається. - Через канал сповіщень — виняток не кидається: диспатчиться подія Laravel
NotificationFailedз винятком у$event->data['exception'].
| Метод | Повертає |
|---|---|
getStatusCode() |
HTTP-статус, null при мережевій помилці / таймауті |
getErrorCode() |
Машинний code (напр. chat_blocked) або null |
getResponse() |
Розібране JSON-тіло відповіді з помилкою або null |
use Illuminate\Notifications\Events\NotificationFailed; use NotificationChannels\Gronosync\Exceptions\CouldNotSendNotification; Event::listen(function (NotificationFailed $event) { $exception = $event->data['exception'] ?? null; if ($event->channel === 'Gronosync' && $exception instanceof CouldNotSendNotification && $exception->getErrorCode() === 'chat_blocked') { $event->notifiable->update(['gronosync_blocked' => true]); } });
Орієнтуйтесь на статус і code, а не на текст. Усі коди й що з ними робити — Помилки й коди.
Отримання вебхуків
GronoSync може сповіщати ваш застосунок про нові контакти, вхідні й вихідні повідомлення та чати, яким потрібен менеджер. Налаштування, події, payload і приклад контролера для Laravel — Вебхуки і Laravel.
Тестування
composer test
composer test:coverage
Безпека
Якщо ви виявили проблему безпеки, надішліть листа на fomin.vasil@gmail.com замість використання трекеру задач.
Участь у розробці
Деталі: CONTRIBUTING.md.
Автори
Ліцензія
MIT License. Детальніше: LICENSE.md.
