NotificationService.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. <?php
  2. namespace App\Services;
  3. use App\Events\SendPersistentNotificationEvent;
  4. use App\Helpers\DateHelper;
  5. use App\Jobs\SendUserNotificationChannelJob;
  6. use App\Models\ChatMessage;
  7. use App\Models\NotificationDeliveryLog;
  8. use App\Models\Order;
  9. use App\Models\Reclamation;
  10. use App\Models\Role;
  11. use App\Models\Schedule;
  12. use App\Models\User;
  13. use App\Models\UserNotification;
  14. use App\Models\UserNotificationSetting;
  15. use App\Notifications\FireBaseNotification;
  16. use Illuminate\Database\Eloquent\Collection;
  17. use Illuminate\Support\Facades\Mail;
  18. use Illuminate\Support\Str;
  19. class NotificationService
  20. {
  21. public function notifyChatMessage(ChatMessage $chatMessage, array $recipientIds = []): void
  22. {
  23. $chatMessage->loadMissing([
  24. 'user',
  25. 'targetUser',
  26. 'order.user',
  27. 'order.brigadier',
  28. 'reclamation.order',
  29. 'reclamation.user',
  30. 'reclamation.brigadier',
  31. ]);
  32. $type = $chatMessage->order_id ? UserNotification::TYPE_PLATFORM : UserNotification::TYPE_RECLAMATION;
  33. $sourceKey = $chatMessage->order_id ? 'platform' : 'reclamation';
  34. $title = $chatMessage->order_id ? 'Чат площадки' : 'Чат рекламации';
  35. [$message, $messageHtml, $payload] = $this->buildChatNotificationContent($chatMessage, $type);
  36. foreach ($this->chatRecipients($chatMessage, $recipientIds) as $user) {
  37. $settings = $this->settingsForUser($user->id);
  38. if (!$settings->isSectionEnabled('chat_settings')) {
  39. continue;
  40. }
  41. $channels = $settings->getChannelsForKey('chat_settings', $sourceKey);
  42. if (empty($channels)) {
  43. continue;
  44. }
  45. $notification = $this->createInAppNotification(
  46. $user,
  47. $type,
  48. UserNotification::EVENT_CHAT_MESSAGE,
  49. $title,
  50. $message,
  51. $messageHtml,
  52. $payload,
  53. );
  54. $this->dispatchDeliveryJobs($notification, [
  55. NotificationDeliveryLog::CHANNEL_BROWSER => !empty($channels['browser']),
  56. NotificationDeliveryLog::CHANNEL_PUSH => !empty($channels['push']),
  57. NotificationDeliveryLog::CHANNEL_EMAIL => !empty($channels['email']),
  58. ]);
  59. }
  60. }
  61. public function notifyOrderCreated(Order $order): void
  62. {
  63. $statusName = $order->orderStatus?->name ?? (Order::STATUS_NAMES[$order->order_status_id] ?? '-');
  64. $this->notifyOrderEvent(
  65. $order,
  66. UserNotification::EVENT_CREATED,
  67. 'Площадки',
  68. sprintf('Добавлена новая площадка %s', $order->object_address),
  69. sprintf(
  70. 'Добавлена новая площадка <a href="%s">%s</a>.',
  71. route('order.show', ['order' => $order->id, 'sync_year' => 1]),
  72. e($order->object_address)
  73. ),
  74. $statusName,
  75. );
  76. }
  77. public function notifyOrderStatusChanged(Order $order): void
  78. {
  79. $statusName = $order->orderStatus?->name ?? (Order::STATUS_NAMES[$order->order_status_id] ?? '-');
  80. $this->notifyOrderEvent(
  81. $order,
  82. UserNotification::EVENT_STATUS_CHANGED,
  83. 'Площадки',
  84. sprintf('Статус площадки %s изменен на %s', $order->object_address, $statusName),
  85. sprintf(
  86. 'Статус площадки <a href="%s">%s</a> изменен на %s.',
  87. route('order.show', ['order' => $order->id, 'sync_year' => 1]),
  88. e($order->object_address),
  89. e($statusName)
  90. ),
  91. $statusName,
  92. );
  93. }
  94. public function notifyReclamationCreated(Reclamation $reclamation): void
  95. {
  96. $order = $reclamation->order;
  97. if (!$order) {
  98. return;
  99. }
  100. $message = sprintf(
  101. 'Добавлена новая рекламация по адресу %s #%d',
  102. $order->object_address,
  103. $reclamation->id,
  104. );
  105. $messageHtml = sprintf(
  106. 'Добавлена новая рекламация по адресу <a href="%s">%s</a> <a href="%s">#%d</a>.',
  107. route('order.show', ['order' => $order->id, 'sync_year' => 1]),
  108. e($order->object_address),
  109. route('reclamations.show', ['reclamation' => $reclamation->id]),
  110. $reclamation->id,
  111. );
  112. $this->notifyReclamationEvent(
  113. $reclamation,
  114. UserNotification::EVENT_CREATED,
  115. 'Рекламации',
  116. $message,
  117. $messageHtml,
  118. (int)$reclamation->status_id,
  119. );
  120. }
  121. public function notifyReclamationStatusChanged(Reclamation $reclamation): void
  122. {
  123. $order = $reclamation->order;
  124. if (!$order) {
  125. return;
  126. }
  127. $statusName = $reclamation->status?->name ?? (Reclamation::STATUS_NAMES[$reclamation->status_id] ?? '-');
  128. $message = sprintf(
  129. 'Статус рекламации %s #%d изменен на %s',
  130. $order->object_address,
  131. $reclamation->id,
  132. $statusName,
  133. );
  134. $messageHtml = sprintf(
  135. 'Статус рекламации по адресу <a href="%s">%s</a> <a href="%s">#%d</a> изменен на %s.',
  136. route('order.show', ['order' => $order->id, 'sync_year' => 1]),
  137. e($order->object_address),
  138. route('reclamations.show', ['reclamation' => $reclamation->id]),
  139. $reclamation->id,
  140. e($statusName),
  141. );
  142. $this->notifyReclamationEvent(
  143. $reclamation,
  144. UserNotification::EVENT_STATUS_CHANGED,
  145. 'Рекламации',
  146. $message,
  147. $messageHtml,
  148. (int)$reclamation->status_id,
  149. );
  150. }
  151. public function notifyScheduleAdded(Schedule $schedule): void
  152. {
  153. $sourceKey = $this->sourceToSettingKey((string)$schedule->source);
  154. if (!$sourceKey) {
  155. return;
  156. }
  157. $brigadierName = $schedule->brigadier?->name ?? '-';
  158. $date = DateHelper::getHumanDate((string)$schedule->installation_date, true);
  159. if ((string)$schedule->source === 'Рекламации') {
  160. $reclamationId = $this->extractReclamationId((string)$schedule->address_code);
  161. $message = sprintf(
  162. 'Рекламация №%s по адресу %s добавлена в график на %s, Бригадир %s.',
  163. $reclamationId ?? '—',
  164. $schedule->object_address,
  165. $date,
  166. $brigadierName,
  167. );
  168. $reclamationLink = $reclamationId
  169. ? route('reclamations.show', ['reclamation' => $reclamationId])
  170. : route('schedule.index');
  171. $orderLink = $schedule->order_id
  172. ? route('order.show', ['order' => $schedule->order_id, 'sync_year' => 1])
  173. : null;
  174. $addressHtml = $orderLink
  175. ? sprintf('<a href="%s">%s</a>', $orderLink, e($schedule->object_address))
  176. : e($schedule->object_address);
  177. $messageHtml = sprintf(
  178. '<a href="%s">Рекламация №%s</a> по адресу %s добавлена в график на %s, Бригадир %s.',
  179. $reclamationLink,
  180. $reclamationId ?? '—',
  181. $addressHtml,
  182. e($date),
  183. e($brigadierName),
  184. );
  185. } else {
  186. $message = sprintf(
  187. '%s добавлено в график монтажей на %s, Бригадир %s.',
  188. $schedule->object_address,
  189. $date,
  190. $brigadierName,
  191. );
  192. $orderLink = $schedule->order_id
  193. ? route('order.show', ['order' => $schedule->order_id, 'sync_year' => 1])
  194. : route('schedule.index');
  195. $messageHtml = sprintf(
  196. '<a href="%s">%s</a> добавлено в график монтажей на %s, Бригадир %s.',
  197. $orderLink,
  198. e($schedule->object_address),
  199. e($date),
  200. e($brigadierName),
  201. );
  202. }
  203. $users = $this->scheduleRecipients($schedule);
  204. foreach ($users as $user) {
  205. $settings = $this->settingsForUser($user->id);
  206. if (!$settings->isSectionEnabled('schedule_settings')) {
  207. continue;
  208. }
  209. $channels = $settings->getChannelsForKey('schedule_settings', $sourceKey);
  210. if (empty($channels)) {
  211. continue;
  212. }
  213. $notification = $this->createInAppNotification(
  214. $user,
  215. UserNotification::TYPE_SCHEDULE,
  216. UserNotification::EVENT_SCHEDULE_ADDED,
  217. 'График монтажей',
  218. $message,
  219. $messageHtml,
  220. [
  221. 'schedule_id' => $schedule->id,
  222. 'source' => $schedule->source,
  223. ],
  224. );
  225. $this->dispatchDeliveryJobs($notification, [
  226. NotificationDeliveryLog::CHANNEL_BROWSER => !empty($channels['browser']),
  227. NotificationDeliveryLog::CHANNEL_PUSH => !empty($channels['push']),
  228. NotificationDeliveryLog::CHANNEL_EMAIL => !empty($channels['email']),
  229. ]);
  230. }
  231. }
  232. public function deliverChannel(int $userNotificationId, string $channel, int $attempt): void
  233. {
  234. $notification = UserNotification::query()->with('user')->find($userNotificationId);
  235. if (!$notification || !$notification->user) {
  236. return;
  237. }
  238. try {
  239. if ($channel === NotificationDeliveryLog::CHANNEL_BROWSER) {
  240. event(new SendPersistentNotificationEvent($notification->user_id, [
  241. 'id' => $notification->id,
  242. 'type' => $notification->type,
  243. 'title' => $notification->title,
  244. 'message' => $notification->message,
  245. 'message_html' => $notification->message_html,
  246. 'created_at' => $notification->created_at?->toDateTimeString(),
  247. ]));
  248. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_SENT, $attempt, null);
  249. return;
  250. }
  251. if ($channel === NotificationDeliveryLog::CHANNEL_PUSH) {
  252. if (!$notification->user->token_fcm) {
  253. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_SKIPPED, $attempt, 'Отсутствует token_fcm');
  254. return;
  255. }
  256. $notification->user->notify(new FireBaseNotification($notification->title, Str::limit(strip_tags($notification->message), 200)));
  257. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_SENT, $attempt, null);
  258. return;
  259. }
  260. if ($channel === NotificationDeliveryLog::CHANNEL_EMAIL) {
  261. $email = $notification->user->notification_email;
  262. if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
  263. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_SKIPPED, $attempt, 'Отсутствует валидный notification_email');
  264. return;
  265. }
  266. Mail::html($notification->message_html, function ($message) use ($email, $notification) {
  267. $message->to($email)
  268. ->subject($notification->title);
  269. });
  270. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_SENT, $attempt, null);
  271. return;
  272. }
  273. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_SKIPPED, $attempt, 'Неизвестный канал');
  274. } catch (\Throwable $exception) {
  275. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_FAILED, $attempt, $exception->getMessage());
  276. throw $exception;
  277. }
  278. }
  279. public function markDeadLetter(int $userNotificationId, string $channel, int $attempt, ?string $error = null): void
  280. {
  281. $notification = UserNotification::query()->find($userNotificationId);
  282. if (!$notification) {
  283. return;
  284. }
  285. $this->createLog($notification, $channel, NotificationDeliveryLog::STATUS_DEAD_LETTER, $attempt, $error);
  286. }
  287. private function notifyOrderEvent(
  288. Order $order,
  289. string $event,
  290. string $title,
  291. string $message,
  292. string $messageHtml,
  293. string $statusName,
  294. ): void {
  295. $users = $this->orderRecipients($order);
  296. $statusId = (int) $order->order_status_id;
  297. foreach ($users as $user) {
  298. $settings = $this->settingsForUser($user->id);
  299. if (!$settings->isSectionEnabled('order_settings')) {
  300. continue;
  301. }
  302. $channels = $settings->getChannelsForKey('order_settings', $statusId);
  303. if (empty($channels)) {
  304. continue;
  305. }
  306. $notification = $this->createInAppNotification(
  307. $user,
  308. UserNotification::TYPE_PLATFORM,
  309. $event,
  310. $title,
  311. $message,
  312. $messageHtml,
  313. [
  314. 'order_id' => $order->id,
  315. 'status' => $statusName,
  316. ],
  317. );
  318. $this->dispatchDeliveryJobs($notification, [
  319. NotificationDeliveryLog::CHANNEL_BROWSER => !empty($channels['browser']),
  320. NotificationDeliveryLog::CHANNEL_PUSH => !empty($channels['push']),
  321. NotificationDeliveryLog::CHANNEL_EMAIL => !empty($channels['email']),
  322. ]);
  323. }
  324. }
  325. private function notifyReclamationEvent(
  326. Reclamation $reclamation,
  327. string $event,
  328. string $title,
  329. string $message,
  330. string $messageHtml,
  331. int $statusId,
  332. ): void {
  333. $users = $this->reclamationRecipients($reclamation);
  334. foreach ($users as $user) {
  335. $settings = $this->settingsForUser($user->id);
  336. if (!$settings->isSectionEnabled('reclamation_settings')) {
  337. continue;
  338. }
  339. $channels = $settings->getChannelsForKey('reclamation_settings', $statusId);
  340. if (empty($channels)) {
  341. continue;
  342. }
  343. $notification = $this->createInAppNotification(
  344. $user,
  345. UserNotification::TYPE_RECLAMATION,
  346. $event,
  347. $title,
  348. $message,
  349. $messageHtml,
  350. [
  351. 'reclamation_id' => $reclamation->id,
  352. 'status_id' => $statusId,
  353. ],
  354. );
  355. $this->dispatchDeliveryJobs($notification, [
  356. NotificationDeliveryLog::CHANNEL_BROWSER => !empty($channels['browser']),
  357. NotificationDeliveryLog::CHANNEL_PUSH => !empty($channels['push']),
  358. NotificationDeliveryLog::CHANNEL_EMAIL => !empty($channels['email']),
  359. ]);
  360. }
  361. }
  362. private function dispatchDeliveryJobs(UserNotification $notification, array $channels): void
  363. {
  364. foreach ($channels as $channel => $enabled) {
  365. if (!$enabled) {
  366. continue;
  367. }
  368. SendUserNotificationChannelJob::dispatch($notification->id, $channel);
  369. }
  370. }
  371. private function createInAppNotification(
  372. User $user,
  373. string $type,
  374. string $event,
  375. string $title,
  376. string $message,
  377. string $messageHtml,
  378. array $payload,
  379. ): UserNotification {
  380. $notification = UserNotification::query()->create([
  381. 'user_id' => $user->id,
  382. 'type' => $type,
  383. 'event' => $event,
  384. 'title' => $title,
  385. 'message' => $message,
  386. 'message_html' => $messageHtml,
  387. 'data' => $payload,
  388. ]);
  389. $this->createLog($notification, NotificationDeliveryLog::CHANNEL_IN_APP, NotificationDeliveryLog::STATUS_SENT, 1, null);
  390. return $notification;
  391. }
  392. private function createLog(
  393. UserNotification $notification,
  394. string $channel,
  395. string $status,
  396. int $attempt,
  397. ?string $error,
  398. ): void {
  399. NotificationDeliveryLog::query()->create([
  400. 'user_notification_id' => $notification->id,
  401. 'user_id' => $notification->user_id,
  402. 'channel' => $channel,
  403. 'status' => $status,
  404. 'attempt' => $attempt,
  405. 'message' => $notification->message,
  406. 'error' => $error,
  407. ]);
  408. }
  409. private function settingsForUser(int $userId): UserNotificationSetting
  410. {
  411. return UserNotificationSetting::query()->firstOrCreate(
  412. ['user_id' => $userId],
  413. UserNotificationSetting::defaultsForUser($userId),
  414. );
  415. }
  416. private function orderRecipients(Order $order): Collection
  417. {
  418. $query = User::query()
  419. ->whereIn('role', [Role::ADMIN, Role::ASSISTANT_HEAD, Role::WAREHOUSE_HEAD]);
  420. if ($order->user_id) {
  421. $query->orWhere('id', $order->user_id);
  422. }
  423. return $query->distinct()->get();
  424. }
  425. private function reclamationRecipients(Reclamation $reclamation): Collection
  426. {
  427. $query = User::query()
  428. ->whereIn('role', [Role::ADMIN, Role::ASSISTANT_HEAD, Role::WAREHOUSE_HEAD]);
  429. $managerId = $reclamation->user_id;
  430. if ($managerId) {
  431. $query->orWhere('id', $managerId);
  432. }
  433. return $query->distinct()->get();
  434. }
  435. private function scheduleRecipients(Schedule $schedule): Collection
  436. {
  437. $query = User::query()
  438. ->whereIn('role', [Role::ADMIN, Role::ASSISTANT_HEAD, Role::WAREHOUSE_HEAD]);
  439. if ($schedule->brigadier_id) {
  440. $query->orWhere('id', $schedule->brigadier_id);
  441. }
  442. $managerId = null;
  443. if ((string)$schedule->source === 'Площадки' && $schedule->order_id) {
  444. $managerId = Order::query()
  445. ->withoutGlobalScope(\App\Models\Scopes\YearScope::class)
  446. ->where('id', $schedule->order_id)
  447. ->value('user_id');
  448. }
  449. if ((string)$schedule->source === 'Рекламации') {
  450. $reclamationId = $this->extractReclamationId((string)$schedule->address_code);
  451. if ($reclamationId) {
  452. $reclamation = Reclamation::query()
  453. ->withoutGlobalScope(\App\Models\Scopes\YearScope::class)
  454. ->with('order')
  455. ->find($reclamationId);
  456. $managerId = $reclamation?->order?->user_id ?: $reclamation?->user_id;
  457. }
  458. }
  459. if ($managerId) {
  460. $query->orWhere('id', $managerId);
  461. }
  462. return $query->distinct()->get();
  463. }
  464. private function extractReclamationId(string $addressCode): ?int
  465. {
  466. if (preg_match('/^РЕКЛ-(\d+)$/u', $addressCode, $matches)) {
  467. return (int)$matches[1];
  468. }
  469. return null;
  470. }
  471. private function sourceToSettingKey(string $source): ?string
  472. {
  473. return match ($source) {
  474. 'Площадки' => 'platform',
  475. 'Рекламации' => 'reclamation',
  476. default => null,
  477. };
  478. }
  479. private function chatRecipients(ChatMessage $chatMessage, array $recipientIds = []): Collection
  480. {
  481. $recipientIds = array_values(array_unique(array_map(static fn ($id) => (int) $id, $recipientIds)));
  482. $recipientIds = array_values(array_diff($recipientIds, [(int) $chatMessage->user_id]));
  483. if (!empty($recipientIds)) {
  484. return User::query()
  485. ->whereIn('id', $recipientIds)
  486. ->get();
  487. }
  488. if ($chatMessage->notification_type === ChatMessage::NOTIFICATION_USER) {
  489. if (!$chatMessage->target_user_id || (int) $chatMessage->target_user_id === (int) $chatMessage->user_id) {
  490. return new Collection();
  491. }
  492. return User::query()
  493. ->where('id', $chatMessage->target_user_id)
  494. ->get();
  495. }
  496. if (!in_array($chatMessage->notification_type, [
  497. ChatMessage::NOTIFICATION_ALL,
  498. ChatMessage::NOTIFICATION_RESPONSIBLES,
  499. ], true)) {
  500. return new Collection();
  501. }
  502. $recipientIds = [];
  503. if ($chatMessage->order) {
  504. $recipientIds = $chatMessage->notification_type === ChatMessage::NOTIFICATION_ALL
  505. ? $this->allChatRecipientIds()
  506. : $this->chatResponsibleRecipientIdsForOrder($chatMessage->order);
  507. }
  508. if ($chatMessage->reclamation) {
  509. $recipientIds = $chatMessage->notification_type === ChatMessage::NOTIFICATION_ALL
  510. ? $this->allChatRecipientIds()
  511. : $this->chatResponsibleRecipientIdsForReclamation($chatMessage->reclamation);
  512. }
  513. $recipientIds = array_values(array_unique(array_filter($recipientIds)));
  514. $recipientIds = array_values(array_diff($recipientIds, [(int) $chatMessage->user_id]));
  515. if (empty($recipientIds)) {
  516. return new Collection();
  517. }
  518. return User::query()
  519. ->whereIn('id', $recipientIds)
  520. ->get();
  521. }
  522. private function allChatRecipientIds(): array
  523. {
  524. return User::query()
  525. ->pluck('id')
  526. ->map(static fn ($id) => (int) $id)
  527. ->all();
  528. }
  529. private function chatResponsibleRecipientIdsForOrder(Order $order): array
  530. {
  531. $adminIds = User::query()
  532. ->where('role', Role::ADMIN)
  533. ->pluck('id')
  534. ->map(static fn ($id) => (int) $id)
  535. ->all();
  536. return array_merge($adminIds, [
  537. $order->user_id ? (int) $order->user_id : null,
  538. $order->brigadier_id ? (int) $order->brigadier_id : null,
  539. ]);
  540. }
  541. private function chatResponsibleRecipientIdsForReclamation(Reclamation $reclamation): array
  542. {
  543. $adminIds = User::query()
  544. ->where('role', Role::ADMIN)
  545. ->pluck('id')
  546. ->map(static fn ($id) => (int) $id)
  547. ->all();
  548. return array_merge($adminIds, [
  549. $reclamation->user_id ? (int) $reclamation->user_id : null,
  550. $reclamation->brigadier_id ? (int) $reclamation->brigadier_id : null,
  551. ]);
  552. }
  553. private function buildChatNotificationContent(ChatMessage $chatMessage, string $type): array
  554. {
  555. $senderName = $chatMessage->user?->name ?? 'Пользователь';
  556. $text = trim((string) $chatMessage->message);
  557. $text = $text !== '' ? Str::limit($text, 200) : 'Вложение';
  558. if ($type === UserNotification::TYPE_PLATFORM) {
  559. $order = $chatMessage->order;
  560. $address = $order?->object_address ?? '-';
  561. $orderUrl = $order ? route('order.show', ['order' => $order->id, 'sync_year' => 1]) : route('order.index');
  562. $message = sprintf('Новое сообщение в чате площадки %s от %s: %s', $address, $senderName, $text);
  563. $messageHtml = sprintf(
  564. 'Новое сообщение в <a href="%s">чате площадки %s</a> от %s: %s',
  565. $orderUrl,
  566. e($address),
  567. e($senderName),
  568. e($text)
  569. );
  570. return [$message, $messageHtml, [
  571. 'chat_message_id' => $chatMessage->id,
  572. 'order_id' => $order?->id,
  573. ]];
  574. }
  575. $reclamation = $chatMessage->reclamation;
  576. $address = $reclamation?->order?->object_address ?? '-';
  577. $reclamationUrl = $reclamation
  578. ? route('reclamations.show', ['reclamation' => $reclamation->id, 'sync_year' => 1])
  579. : route('reclamations.index');
  580. $reclamationNumber = $reclamation?->id ? ('#' . $reclamation->id) : '#-';
  581. $message = sprintf('Новое сообщение в чате рекламации %s по адресу %s от %s: %s', $reclamationNumber, $address, $senderName, $text);
  582. $messageHtml = sprintf(
  583. 'Новое сообщение в <a href="%s">чате рекламации %s</a> по адресу %s от %s: %s',
  584. $reclamationUrl,
  585. e($reclamationNumber),
  586. e($address),
  587. e($senderName),
  588. e($text)
  589. );
  590. return [$message, $messageHtml, [
  591. 'chat_message_id' => $chatMessage->id,
  592. 'reclamation_id' => $reclamation?->id,
  593. ]];
  594. }
  595. }