From: fomichev Date: Tue, 4 Mar 2025 14:25:54 +0000 (+0300) Subject: Отправка сообщений X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=5c5fedcb4a37800c950f9d67857554ed5b0c8ed4;p=erp24_rep%2Fyii-erp24%2F.git Отправка сообщений --- diff --git a/erp24/commands/CronController.php b/erp24/commands/CronController.php index 45e98faf..1d810703 100644 --- a/erp24/commands/CronController.php +++ b/erp24/commands/CronController.php @@ -4,6 +4,7 @@ namespace yii_app\commands; use app\jobs\SendTelegramMessageDBJob; use app\jobs\SendTelegramMessageJob; +use app\jobs\SendWhatsappMessageJob; use DateTime; use DateTimeZone; use Yii; @@ -707,6 +708,127 @@ class CronController extends Controller return ExitCode::OK; } + + public function actionSendWhatsappMessage() + { + $messagesSettings = UsersMessageManagement::find()->one(); + if (!$messagesSettings) { + $this->stdout( + "Рассылка неактивна (не найдена настройка). Отправка сообщений прервана.\n", + BaseConsole::FG_RED + ); + return ExitCode::UNAVAILABLE; + } + + if (!$messagesSettings->active) { + $this->stdout( + "Рассылка неактивна (поле active = 0). Отправка сообщений прервана.\n", + BaseConsole::FG_RED + ); + return ExitCode::UNAVAILABLE; + } + + $this->stdout("Рассылка активна. Начинаем отправку второго сообщения...\n", BaseConsole::FG_GREEN); + date_default_timezone_set('Europe/Moscow'); + + $step1 = $messagesSettings ? $messagesSettings->day_before_step1 : 10; + $step2 = $messagesSettings ? $messagesSettings->day_before_step2 : 4; + $currentDate = date('Y-m-d'); + $targetDate = date('Y-m-d', strtotime("+$step2 days", strtotime($currentDate))); + $kogortDate = date('Y-m-d', strtotime("-$step1 days", strtotime($targetDate))); + + $kogortPhones = SentKogort::find() + ->select('phone') + ->andWhere(['kogort_number' => 2]) + ->andWhere(['target_date' => $targetDate]) + ->andWhere(['purchase' => 0]) + ->column(); + + if (!empty($kogortPhones)) { + $countPhones = count($kogortPhones); + $this->stdout( + "Всего телефонов в когорте {$countPhones} записей.\n", + BaseConsole::FG_GREEN + ); + + $sentStatusKogort = SentKogort::find() + ->select('phone') + ->andWhere(['kogort_number' => 2]) + ->andWhere(['target_date' => $targetDate]) + ->andWhere(['status' => 3]) + ->column(); + + $phonesArray = array_diff($kogortPhones, $sentStatusKogort); + $countWhatsappPhones = count($phonesArray); + $this->stdout( + "Всего телефонов в рассылке телеграма {$countWhatsappPhones} записей.\n", + BaseConsole::FG_GREEN + ); + + $channel = self::getChannelByName('WABA'); + $limit = $channel['limit'] ?? 250; + + if (!empty($phonesArray)) { + $messageText = $messagesSettings + ->replaceShortcodes($messagesSettings->offer_whatsapp, $targetDate); + $phonesSentArray = []; + foreach ($phonesArray as $index => $phone) { + if ($index >= $limit) { + break; + } + $messageData = []; + $messageData['phone'] = $phone; + $messageData['kogort_date'] = $kogortDate; + $messageData['target_date'] = $targetDate; + $messageData['message'] = $messageText; + + Yii::$app->queue->push(new SendWhatsappMessageJob([ + 'messageData' => $messageData, + 'isTest' => false + ])); + $phonesSentArray[] = $phone; + } + //TODO - перенос в отправку + $updatedCount = SentKogort::updateAll( + [ + 'status' => SentKogort::STATUSES['second'], // Устанавливаем статус "вторая рассылка" + 'updated_at' => date('Y-m-d H:i:s'), + ], + [ + 'target_date' => $targetDate, + 'kogort_number' => SentKogort::KOGORT_NUMBERS['whatsapp'], + 'phone' => $phonesSentArray, + ] + ); + + if ($updatedCount) { + $this->stdout( + "Статус записей для когорты {$kogortDate} обновлён на 'second' для {$updatedCount} записей.\n", + BaseConsole::FG_GREEN + ); + } else { + $this->stdout( + "Не найдено записей для обновления статуса на 'second'.\n", + BaseConsole::FG_RED + ); + } + } + } else { + $this->stdout( + "Нет данных для отправки второго сообщения в телеграм + на {$kogortDate} для целевой даты {$targetDate}.\n", + BaseConsole::FG_RED + ); + } + + $this->stdout( + "Отправка второго сообщения в телеграм для корорты (ватсап) + на {$kogortDate} для целевой даты {$targetDate}.\n", + BaseConsole::FG_GREEN + ); + return ExitCode::OK; + } + public function actionGenerateCallKogorts() { $messagesSettings = UsersMessageManagement::find()->one(); diff --git a/erp24/config/params.php b/erp24/config/params.php index 85aa30a0..8efe83b3 100644 --- a/erp24/config/params.php +++ b/erp24/config/params.php @@ -1,6 +1,7 @@ '10c81eda-1dfb-42ed-a458-944f8dae4a67', 'API2_URL' => YII_DEBUG ? 'http://host.docker.internal:5555' : 'https://api2.bazacvetov24.ru', //'TELEGRAM_API_URL' => "https://api.telegram.org/bot6189425433:AAFQ91OYiMiyj2jgIgmx3O2yTBl4enywySM/", 'TELEGRAM_API_URL' => "https://api.telegram.org/bot8063257458:AAGnMf4cxwJWlYLF1wS_arn4PrOaLs9ERQQ/", diff --git a/erp24/controllers/UsersWhatsappMessageController.php b/erp24/controllers/UsersWhatsappMessageController.php index 21f1d091..a32d7133 100644 --- a/erp24/controllers/UsersWhatsappMessageController.php +++ b/erp24/controllers/UsersWhatsappMessageController.php @@ -2,11 +2,15 @@ namespace app\controllers; +use app\jobs\SendWhatsappMessageJob; +use Yii; +use yii\web\Response; use yii_app\records\UsersWhatsappMessage; use yii_app\records\UsersWhatsappMessageSearch; use yii\web\Controller; use yii\web\NotFoundHttpException; use yii\filters\VerbFilter; +use yii_app\services\WhatsAppService; /** * UsersWhatsappMessageController implements the CRUD actions for UsersWhatsappMessage model. @@ -131,4 +135,78 @@ class UsersWhatsappMessageController extends Controller throw new NotFoundHttpException('The requested page does not exist.'); } + + /** + * Отображает форму для тестирования отправки сообщений и вызова методов API. + */ + public function actionTest() + { + return $this->render('test'); + } + + /** + * Обрабатывает нажатие кнопки "Отправить сообщения". + * Из поля ввода берутся телефоны, разделённые запятыми, и для каждого телефона + * ставится задача в очередь на отправку сообщения. + */ + public function actionSendMessages() + { + $phonesStr = Yii::$app->request->post('phones', ''); + $phones = array_filter(array_map('trim', explode(',', $phonesStr))); + + if (empty($phones)) { + Yii::$app->session->setFlash('error', 'Не указаны телефоны.'); + return $this->redirect(['index']); + } + + foreach ($phones as $phone) { + $messageData = [ + 'phone' => $phone, + 'message' => '', + 'kogort_date' => date('Y-m-d'), + 'target_date' => date('Y-m-d'), + ]; + Yii::$app->queue->push(new SendWhatsappMessageJob([ + 'messageData' => $messageData, + 'isTest' => true + ])); + } + + Yii::$app->session->setFlash('success', 'Сообщения поставлены в очередь для отправки.'); + return $this->redirect(['index']); + } + + /** + * Вызывает метод получения канала по имени и возвращает результат в формате JSON. + */ + public function actionGetChannel() + { + Yii::$app->response->format = Response::FORMAT_JSON; + $channelName = Yii::$app->request->post('channelName', ''); + $result = WhatsAppService::getChannelByName($channelName); + return ['result' => $result]; + } + + /** + * Вызывает метод получения id каскада по имени и возвращает результат в формате JSON. + */ + public function actionGetCascade() + { + Yii::$app->response->format = Response::FORMAT_JSON; + $cascadeName = Yii::$app->request->post('cascadeName', ''); + $result = WhatsAppService::getCascadeIdByName($cascadeName); + return ['result' => $result]; + } + + /** + * Вызывает метод получения id шаблона по subjectId и имени шаблона и возвращает результат в формате JSON. + */ + public function actionGetTemplate() + { + Yii::$app->response->format = Response::FORMAT_JSON; + $subjectId = Yii::$app->request->post('subjectId', ''); + $templateName = Yii::$app->request->post('templateName', ''); + $result = WhatsAppService::getMessageMatcherIdBySubjectId($subjectId, $templateName); + return ['result' => $result]; + } } diff --git a/erp24/jobs/SendWhatsappMessageJob.php b/erp24/jobs/SendWhatsappMessageJob.php new file mode 100644 index 00000000..f25cfe07 --- /dev/null +++ b/erp24/jobs/SendWhatsappMessageJob.php @@ -0,0 +1,88 @@ + 1) { + self::$lastResetTime = microtime(true); + self::$messagesSent = 0; + } + if (self::$messagesSent >= 30) { + $delay = 1 - (microtime(true) - self::$lastResetTime); + if ($delay > 0) { + usleep($delay * 1e6); // Спим оставшееся время в микросекундах + } + self::$lastResetTime = microtime(true); + self::$messagesSent = 0; + } + + $phone = $this->messageData['phone']; + + $apiKey = Yii::$app->params['WHATSAPP_API_KEY']; + $cascadeId = WhatsAppService::getCascadeIdByName('WABA') ?? 5686; + $whatsappService = new WhatsAppService($apiKey, $cascadeId); + $requestId = uniqid(); + try { + + $message = $this->messageData['message']; + if ($this->isTest) { + $message = "Здравствуйте\n + Узнать подробности вы можете на нашем сайте https://bazacvetov24.ru."; + } + $response = $whatsappService->sendMessage($requestId, $phone, $message, $this->isTest); + + + $status = 'sent'; + if (!$status instanceof WhatsAppMessageResponse) { + $status = $response ?? 'error'; + } + $record = new UsersWhatsappMessage(); + $record->request_id = $requestId; + $record->phone = $phone; + $record->message = $message; + $record->kogort_date = $this->messageData['kogort_date']; + $record->target_date = $this->messageData['target_date']; + $record->status = $status; + $record->created_at = date('Y-m-d H:i:s'); + + if ($record->save()) { + Yii::warning("WhatsApp сообщение успешно отправлено и сохранено для телефона {$phone}. Request ID: " . $response->requestId, 'whatsapp'); + } else { + Yii::warning("WhatsApp сообщение отправлено, но не удалось сохранить запись для телефона {$phone}.", 'whatsapp'); + } + } catch (\Exception $e) { + Yii::error("Ошибка отправки WhatsApp сообщения для телефона {$phone}: " . $e->getMessage(), 'whatsapp'); + } + + self::$messagesSent++; + } +} \ No newline at end of file diff --git a/erp24/media/controllers/WhatsappMessageStatus.php b/erp24/media/controllers/WhatsappMessageStatus.php new file mode 100644 index 00000000..b11f23cd --- /dev/null +++ b/erp24/media/controllers/WhatsappMessageStatus.php @@ -0,0 +1,87 @@ +response->format = Response::FORMAT_JSON; + $request = Yii::$app->request; + + if (!$request->isPost) { + throw new MethodNotAllowedHttpException("Метод не разрешён. Используйте POST."); + } + + $rawBody = $request->getRawBody(); + $data = json_decode($rawBody, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + Yii::error("Неверный JSON: " . $rawBody, __METHOD__); + throw new BadRequestHttpException("Неверный формат JSON."); + } + + if (empty($data['requestId'])) { + throw new BadRequestHttpException("Отсутствует обязательный параметр: requestId."); + } + + $requestId = $data['requestId']; + + $model = UsersWhatsappMessage::findOne(['request_id' => $requestId]); + if (!$model) { + Yii::warning("Запись с request_id {$requestId} не найдена.", __METHOD__); + return ['message' => "Запись с request_id {$requestId} не найдена."]; + } + + if (isset($data['status'])) { + $model->status = $data['status']; + } else { + throw new BadRequestHttpException("Отсутствует обязательный параметр: status."); + } + + if ($model->save()) { + Yii::info("Статус сообщения с request_id {$requestId} обновлён на {$model->status}.", __METHOD__); + return ['message' => "Статус сообщения обновлён."]; + } else { + Yii::error("Не удалось сохранить обновлённый статус для request_id {$requestId}.", __METHOD__); + throw new ServerErrorHttpException("Не удалось сохранить обновлённый статус."); + } + } +} \ No newline at end of file diff --git a/erp24/services/WhatsAppMessageResponse.php b/erp24/services/WhatsAppMessageResponse.php new file mode 100644 index 00000000..b1b4c29f --- /dev/null +++ b/erp24/services/WhatsAppMessageResponse.php @@ -0,0 +1,26 @@ +requestId = $data['requestId'] ?? null; + } +} diff --git a/erp24/services/WhatsAppService.php b/erp24/services/WhatsAppService.php new file mode 100644 index 00000000..7ad5f0a5 --- /dev/null +++ b/erp24/services/WhatsAppService.php @@ -0,0 +1,386 @@ +apiKey = $apiKey; + $this->cascadeId = $cascadeId; + $this->client = new Client(); + } + + /** + * + * @param string $text Исходный текст. + * + * @return string Обработанный текст. + */ + protected function escapeText($text) + { + return str_replace( + ['"', '“', '”', '‘', '’'], + ['\"', '\"', '\"', "\'", "\'"], + $text + ); + } + + /** + * + * @param int $statusCode Код ответа HTTP. + * @param string|null $errorKey Код ошибки, полученный из ответа API. + * + * @return string|null Описание ошибки или null, если соответствие не найдено. + */ + protected function getErrorMessage($statusCode, $errorKey) + { + $errorMappings = [ + 400 => [ + 'requestId-is-not-unique' => 'Такой идентификатор запроса уже использовался. Используйте новый идентификатор для каждого запроса.', + 'content-not-specified' => 'Не указан тип контента и его свойства. Например, smsContent, viberContent или whatsappContent.', + 'contentType-not-specified' => 'Не указан тип контента. Например, text или image.', + 'text-not-specified' => 'Не заполнено текстовое поле.', + 'caption-not-specified' => 'Не заполнено текстовое поле подписи.', + 'action-not-specified' => 'Не указано действие для кнопки.', + 'attachmentName-not-specified' => 'Не указано имя прикрепляемого документа.', + 'attachmentName-is-too-long' => 'Имя прикрепляемого документа слишком длинное. Максимальная длина — 70 символов.', + 'latitude-not-specified' => 'Не задана широта при указании координат.', + 'longitude-not-specified' => 'Не задана долгота при указании координат.', + 'cascade-not-found' => 'Указан неверный идентификатор каскада. Проверьте корректность указанного вами идентификатора.', + 'request-doesn’t-contain-content-for-all-cascade-stages' => 'Каскад содержит много каналов. Добавьте еще один канал в объект content запроса.', + 'matched-template-not-found' => 'Схема тела запроса не соответствует схеме шаблона. Проверьте взаимное расположение и наличие всех свойств запроса.', + 'cascade-scheduling-request-not-valid' => 'Переданный контент для каскада не соответствует настройкам каскада. Проверьте корректность заполнения данных.', + 'template-parameter-is-not-valid' => 'Длина значений параметров listPicker.sections.items.title или listPicker.sections.items.subtitle превышает 24 символа с учетом пробелов.', + 'out-of-balance' => 'Недостаточно средств на балансе.', + 'button-validation-error' => 'Ошибка валидации шаблона WhatsApp с кнопками. Превышено максимальное количество кнопок или неверный тип кнопки.', + ], + 401 => [ + 'auth-error' => 'Ошибка авторизации. Проверьте правильность написания и срок действия ключа API.', + ], + 404 => [ + 'not-found' => 'Запрошенный URL-адрес не найден. Проверьте корректность указанного вами адреса.', + ], + 405 => [ + 'method-not-allowed' => 'Метод HTTP-запроса не разрешен. Используйте POST, GET и другие запросы согласно документации.', + ], + 500 => [ + 'system-error' => 'Ошибка сервера. Обратитесь в службу технической поддержки support@edna.ru.', + ], + ]; + + if (isset($errorMappings[$statusCode][$errorKey])) { + return $errorMappings[$statusCode][$errorKey]; + } + return null; + } + + /** + * Отправляет сообщение WhatsApp для заданного номера телефона. + * + * @param string $phone Номер телефона получателя (например, "79000000000"). + * @param string|null $startTime Время отправки (ISO 8601) или null для немедленной отправки. + * @param string|null $ttl Время жизни задания (например, 'PT1M'). + * + * @return WhatsAppMessageResponse|null|string Объект с данными ответа API. + * + + */ + public function sendMessage($requestId, $phone, $message, $startTime = null, $ttl = null, $isTest = false) + { + + if (!$message) { + Yii::error("Текст сообщения для WhatsApp не передан."); + return null; + } + $channel = self::getChannelByName('WABA'); + $subjectId = $channel['subjectId'] ?? 11374; + + $requestId = $requestId ?? uniqid(); + // Формируем фильтр получателя по номеру телефона + $subscriberFilter = [ + 'address' => $phone, + 'type' => 'PHONE' + ]; + + $buttons = [ + 'rows' => [ + [ + 'buttons' => [ + [ + 'text' => 'Наш сайт', + 'url' => 'https://bazacvetov24.ru', + 'urlPostfix' => '', + 'type' => 'URL' + ], + [ + 'text' => '1000 руб. забрать', + 'url' => 'https://bazacvetov24.ru/akcii', + 'urlPostfix' => '', + 'type' => 'URL' + ] + ] + ] + ] + ]; + // Формируем содержимое WhatsApp-сообщения + $whatsappContent = [ + 'contentType' => 'TEXT', + 'text' => $this->escapeText($message), + ]; + + if (!$isTest) { + $whatsappContent['keyboard'] = $buttons; + $whatsappContent['messageMatcherId'] = self::getMessageMatcherIdBySubjectId($subjectId, 'kogort_message') ?? 120669; + } else { + $whatsappContent['messageMatcherId'] = self::getMessageMatcherIdBySubjectId($subjectId, 'podrobnosti') ?? 117216; + } + + + $payload = [ + 'requestId' => $requestId, + 'cascadeId' => $this->cascadeId, + 'subscriberFilter' => $subscriberFilter, + 'content' => [ + 'whatsappContent' => $whatsappContent, + ], + 'errorIfNotMatched' => true, + 'comment' => '', + 'priority' => 'DEFAULT', + ]; + + if ($startTime !== null) { + $payload['startTime'] = $startTime; + } + if ($ttl !== null) { + $payload['ttl'] = $ttl; + } + $apiUrl = self::$apiBaseUrl . '/cascade/schedule'; + try { + $response = $this->client->request('POST', $apiUrl, [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'X-API-KEY' => $this->apiKey, + ], + 'json' => $payload, + ]); + + if ($response->getStatusCode() == 200) { + $data = json_decode($response->getBody(), true); + return new WhatsAppMessageResponse($data); + } else { + $data = json_decode($response->getBody(), true); + $errorKey = $data['title'] ?? null; + $errorDetail = $data['detail'] ?? ''; + $errorMessage = $this->getErrorMessage($response->getStatusCode(), $errorKey); + if (!$errorMessage) { + $errorMessage = "Ошибка: код " . $response->getStatusCode() . ". " . $errorDetail; + } + Yii::error($errorMessage); + return $errorKey; + } + } catch (RequestException $e) { + Yii::error("Ошибка при выполнении запроса: " . $e->getMessage()); + return null; + } + } + + + /** + * Получает subjectId канала по его имени. + * + * @param string $channelName Название канала (например, "WABA"). + * + * @return int|null subjectId, если найден, иначе null. + * + */ + public static function getChannelByName($channelName) + { + $apiKey = Yii::$app->params['WHATSAPP_API_KEY']; + $client = new Client(); + + $url = self::$apiBaseUrl . '/channel-profile?types=WHATSAPP'; + + try { + $response = $client->request('GET', $url, [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'X-API-KEY' => $apiKey, + ], + 'json' => (object)[] + ]); + + if ($response->getStatusCode() == 200) { + $data = json_decode($response->getBody(), true); + foreach ($data as $channel) { + if (isset($channel['name']) && $channel['name'] === $channelName) { + return $channel ?? null; + } + } + return null; + } else { + self::handleErrorResponse($response); + return null; + } + } catch (RequestException $e) { + Yii::error("Ошибка при выполнении запроса: " . $e->getMessage()); + return null; + } + } + + public static function getCascadeIdByName($cascadeName) + { + $apiKey = Yii::$app->params['WHATSAPP_API_KEY']; + $client = new Client(); + $url = self::$apiBaseUrl . '/cascade/get-all'; + + try { + $response = $client->request('POST', $url, [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'X-API-KEY' => $apiKey, + ], + 'json' => (object)[] + ]); + + if ($response->getStatusCode() == 200) { + $data = json_decode($response->getBody(), true); + if (!is_array($data)) { + throw new Exception("Некорректный формат ответа."); + } + foreach ($data as $cascade) { + if ( + isset($cascade['name'], $cascade['status'], $cascade['id']) && + $cascade['name'] === $cascadeName && + strtoupper($cascade['status']) === 'ACTIVE' + ) { + return $cascade['id']; + } + } + return null; + } else { + self::handleErrorResponse($response); + return null; + } + } catch (RequestException $e) { + Yii::error("Ошибка при выполнении запроса: " . $e->getMessage()); + return null; + } + } + + public static function getMessageMatcherIdBySubjectId( + $subjectId, + $templateName, + $matcherTypes = ["OPERATOR", "USER", "CUSTOM"] + ) { + $apiKey = Yii::$app->params['WHATSAPP_API_KEY']; + $client = new Client(); + $url = self::$apiBaseUrl . '/message-matchers/get-by-request'; + + try { + $response = $client->request('POST', $url, [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'X-API-KEY' => $apiKey, + ], + 'json' => [ + 'subjectId' => $subjectId, + 'matcherTypes' => $matcherTypes, + ] + ]); + + if ($response->getStatusCode() == 200) { + $data = json_decode($response->getBody(), true); + if (!is_array($data)) { + throw new Exception("Некорректный формат ответа."); + } + + // Ищем шаблон с нужным именем и каналом WHATSAPP + foreach ($data as $matcher) { + if ( + isset($matcher['name'], $matcher['channelType'], $matcher['id']) && + $matcher['name'] === $templateName && + strtoupper($matcher['channelType']) === 'WHATSAPP' + ) { + return $matcher['id']; + } + } + return null; + } else { + self::handleErrorResponse($response); + return null; + } + } catch (RequestException $e) { + Yii::error("Ошибка при выполнении запроса: " . $e->getMessage()); + return null; + } + } + + /** + * Обрабатывает ошибку ответа API. + * + * @param ResponseInterface $response + * + */ + private static function handleErrorResponse($response) + { + $data = json_decode($response->getBody(), true); + $errorKey = $data['title'] ?? $data['error'] ?? 'unknown_error'; + $errorDetail = $data['detail'] ?? ''; + + $errorMessages = [ + 'error-subject-unknown' => 'Указанное имя подписи отсутствует.', + 'error-syntax' => 'Неверно указан тип канала.', + ]; + + $errorMessage = $errorMessages[$errorKey] ?? + "Ошибка: " . $response->getStatusCode() . ". " . $errorKey . ". " . $errorDetail; + Yii::error($errorMessage); + } + +} \ No newline at end of file diff --git a/erp24/views/users-whatsapp-message/index.php b/erp24/views/users-whatsapp-message/index.php index f4579bae..c8d3d239 100644 --- a/erp24/views/users-whatsapp-message/index.php +++ b/erp24/views/users-whatsapp-message/index.php @@ -10,15 +10,15 @@ use yii\grid\GridView; /** @var yii_app\records\UsersWhatsappMessageSearch $searchModel */ /** @var yii\data\ActiveDataProvider $dataProvider */ -$this->title = 'Users Whatsapp Messages'; +$this->title = 'Сообщения из WA когорты'; $this->params['breadcrumbs'][] = $this->title; ?> -
+

title) ?>

- 'btn btn-success']) ?> + 'btn btn-primary']) ?>

render('_search', ['model' => $searchModel]); ?> diff --git a/erp24/views/users-whatsapp-message/test.php b/erp24/views/users-whatsapp-message/test.php new file mode 100644 index 00000000..8d6de0fe --- /dev/null +++ b/erp24/views/users-whatsapp-message/test.php @@ -0,0 +1,86 @@ +addRule(['phones', 'channelName', 'cascadeName', 'subjectId', 'templateName'], 'safe'); + +?> +
+

+ 'btn btn-primary']) ?> +

+ + + +

Отправка сообщений

+field($model, 'phones')->textInput([ + 'maxlength' => true, + 'placeholder' => 'Введите телефоны через запятую' +]) ?> + +
+ 'btn btn-primary', + 'formaction' => Url::to(['users-whatsapp-message/send-messages']) + ]) ?> +
+ +
+ +

Получить канал по имени

+field($model, 'channelName')->textInput([ + 'maxlength' => true, + 'placeholder' => 'Введите имя канала' +]) ?> + +
+ 'btn btn-info', + 'formaction' => Url::to(['users-whatsapp-message/get-channel']) + ]) ?> +
+ +
+ +

Получить каскад по имени

+field($model, 'cascadeName')->textInput([ + 'maxlength' => true, + 'placeholder' => 'Введите имя каскада' +]) ?> + +
+ 'btn btn-info', + 'formaction' => Url::to(['users-whatsapp-message/get-cascade']) + ]) ?> +
+ +
+ +

Получить шаблон по subjectId и имени шаблона

+field($model, 'subjectId')->textInput([ + 'maxlength' => true, + 'placeholder' => 'Введите subjectId' +]) ?> +field($model, 'templateName')->textInput([ + 'maxlength' => true, + 'placeholder' => 'Введите имя шаблона' +]) ?> + +
+ 'btn btn-info', + 'formaction' => Url::to(['users-whatsapp-message/get-template']) + ]) ?> +
+ + + +