В этом материале расскажем, как автоматизировать отправку сообщений-уведомлений по данным из таблицы.
Допустим, есть заранее приготовленная база данных в CMS, куда попадают заявки от покупателей — возможно, это заказ товаров или в ресторане. Наша задача: используя указанный номер телефона, уведомить пользователя о том, что его заказ готов к выдаче. Добавим, что нам потребуется имя покупателя и адрес пункта выдачи.
Основная идея работы заключается в том, чтобы связать базу данных с формой SMS-рассылки. Она, в свою очередь, использует API Exolve для отправки ранее заготовленного сообщения. Для упрощения задачи мы расскажем про реализацию проекта с применением Google Таблиц, но благодаря одному из наших прошлых гайдов можно легко произвести привязку к CMS.
Форму рассылки из браузера мы уже реализовали ранее — это метод упрощения передачи данных, который позволяет не влезать в тонкости программирования, если нужно срочно отправить сообщение.
Именно поэтому алгоритм работы будет следующий:
Создать Excel-файл со всей необходимой информацией (имя, адрес, номер телефона, номер заказа).
Создать форму для автоматической отправки сообщений (с автоматической подстановкой данных, кодом авторизации).
Сделать привязку Excel-файла к форме для автоматической передачи данных каждые 20 секунд.
Profit.
Это решение может показаться немного «костыльным» из-за формы — без нее можно обойтись, автоматизировав чтение и отправку сообщений.
Для того, чтобы система работала в автоматическом режиме, потребуется сервер. Нагрузка не очень большая, можно использовать даже просто рабочий ноутбук — из требований к серверу можно выделить только go 1.20, наличие SSL (https), а также маршрутизацию.
Этап 1. Создание Excel-файла
Лучший вариант — воспользоваться онлайн-системой по типу Google Docs. Это потребует постоянного подключения к интернету или общей сети, но гарантирует практически моментальный отклик при необходимости.
Из обязательных полей можно выделить:
номер получателя;
имя покупателя;
текст для рассылки («Ваш заказ номер НН готов»);
адрес получения («подойдите туда-то»);
номер отправителя (если внутри Exolve арендовали несколько номеров для разных филиалов, например).
Итоговый вариант таблицы может выглядеть следующим образом:
![](https://habrastorage.org/getpro/habr/upload_files/259/865/91f/25986591f0b3ebe750b2c9a519022e4d.png)
При необходимости можно добавить несколько полей и реализовать это в программном коде. Также MTC Exolve позволяет использовать имя отправителя для юрлиц, чтобы пользователи в поле отправителя видели не просто номер, а название организации — для этого нужно лишь подтвердить аккаунт и заключить договор.
Также нужно создать программу, которая будет обрабатывать данные этой таблицы — считывать их и переводить далее. Для этого нужно скачать любой компилятор Python, вставить в него следующий код и сохранить файл:
import asyncio
import json
import requests as requests
from google.oauth2 import service_account
from googleapiclient.discovery import build
async def send_message_client(data):
url = 'https://api.exolve.ru/messaging/v1/SendSMS'
# для сайта
response = requests.post(url=url, headers={
"Authorization": "”Код авторизации”",
}, json=data)
print(type(response.json))
print(response.json)
print(response)
return response
class GoogleSheetData:
def __init__(self):
# Путь к файлу JSON с учетными данными
self.SERVICE_ACCOUNT_FILE = 'credentials.json'
# Создание учетных данных из файла JSON
self.creds = service_account.Credentials.from_service_account_file(
self.SERVICE_ACCOUNT_FILE,
scopes=[
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive',
]
)
# Создание клиента API
self.service = build('sheets', 'v4', credentials=self.creds)
# ID вашей таблицы Google Sheets
self.spreadsheet_id = 'ID'
async def processing_google_sheet(self):
try:
# открываем файл JSON, читаем данные и записываем их в переменную 'data'
# если файл не найден, создаем новую пустую переменную 'data'
try:
with open('data.json', "r") as file:
data = json.load(file)
except FileNotFoundError:
data = {1: ['Имя', 'Ваш заказ номер НН готов', 'подойдите туда-то', 'Номер']}
# получаем номер строки с которым будем работать
row = int(list(data.keys())[0]) + 1
# Запрос на получение данных из таблицы Google Sheets(получаем определенную строку в range)
response = self.service.spreadsheets().values().get(
spreadsheetId=self.spreadsheet_id,
range=f"Лист1!A{row}:E{row}",
).execute()
# получаем строку с данными
values = response.get('values', [])
print(values)
# проверяем на наличие данных
if not values:
print('No data found.')
elif len(values[0]) >= 5 and '' not in values[0]:
data_excel = {"number": values[0][4], "destination": values[0][0], "text": f"{values[0][1]}, Ваш заказ номер {values[0][2]} готов, подойдите {values[0][3]}"}
print(data_excel)
result_send_message = await send_message_client(data_excel)
data = {row: values[0]}
print(data)
# записываем новые данные в файл 'data.json'
with open('data.json', "w") as file:
json.dump(data, file, indent=4, ensure_ascii=False)
except Exception as e:
print(f"An error occurred: {e}")
async def run_processing_google_sheet(google_sheet_req):
while True:
await google_sheet_req.processing_google_sheet()
await asyncio.sleep(20)
if __name__ == "__main__":
google_sheet_req = GoogleSheetData()
asyncio.run(run_processing_google_sheet(google_sheet_req))
Мы постарались расписать все шаги максимально понятно, чтобы даже рядовой пользователь мог скопировать код и попробовать его на своей таблице. В итоге мы получаем таблицу с полным доступом для программы, которая считывает данные и передает их в форму отправки. Помимо этого, мы сделали обработку на наличие пустых клеток (тогда код просто пропустит такие строки), а также уже отработанных заявок. Проверка производится раз в 20 секунд, но можно установить собственное значение.
Этап 2. Создание формы отправки
Несмотря на то, что мы уже создали связь таблицы с API Exolve для отправки сообщений, для перестраховки и ручной отправки мы соберем форму. Значения в нее будут подставляться автоматически. Также это защитит нашу программу от сбоев при неправильном заполнении полей.
В первую очередь займемся написанием кода обработки, а после дополним его внешней составляющей — кстати, кастомизировать ее можно по своему усмотрению и даже включить в пользовательский интерфейс.
Для удобства дальнейшего использования мы написали код работы формы на Python. Остается вставить его в любой компилятор и сохранить в виде отдельного файла:
import asyncio
import json
import re
import requests as requests
from google.oauth2 import service_account
from googleapiclient.discovery import build
from quart import Quart, render_template, request
app = Quart(__name__)
async def send_message_client(data):
url = 'https://api.exolve.ru/messaging/v1/SendSMS'
# для сайта
response = requests.post(url=url, headers={
"Authorization": "Код авторизации",
}, json=data)
return response
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
data = dict(request.form)
for key in request.form:
if request.form[key] == '':
return render_template('index.html', error='Не все поля заполнены!')
if key == 'destination':
if not re.match('7\d{9}', request.form[key]):
return render_template('index.html', error='Неправильный формат номера телефона')
result_send_message = send_message_client(data)
if "error" in result_send_message.json:
return render_template('index.html', error=f"Ошибка, вид ошибки: {result_send_message.json()}")
return render_template('index.html', error=f"Запрос обработан!, id message: {result_send_message.json()}")
return render_template('index.html')
if __name__ == "__main__":
app.run()
Этот код, помимо отправки сообщений, еще может проверять поля на корректность заполнения — правильно ли указан номер телефона, например. В остальном же это потребует параллельного запуска с основным табличным файлом.
Формируем файл JavaScript, в котором распишем, что должна делать эта форма: в частности, получать значения в специальные поля и передавать их в API Exolve:
async function postData(formProps) {
const url = 'https://api.exolve.ru/messaging/v1/SendSMS';
const data = { number: number, destination: destination, text: text };
try {
console.log(JSON.stringify(data));
const response = await fetch(url, {
method: "POST",
body: JSON.stringify(formProps),
headers: {
"Authorization": "Код авторизации",
},
});
const json = await response.json();
console.log("Успех:", JSON.stringify(json));
} catch (error) {
console.error("Ошибка:", error);
}
}
function logSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const formProps = Object.fromEntries(formData);
postData(formProps);
}
const form = document.getElementById("form");
form.addEventListener("submit", logSubmit);
Более подробно о том, что за что отвечает, и как именно мы собирали эту форму, вы можете прочитать в одной из наших прошлых статей.
В процессе настройки наша форма будет выглядеть следующим образом:
![](https://habrastorage.org/getpro/habr/upload_files/519/5fa/125/5195fa125f04195375e5e5a4b36886a1.png)
Рабочий, но не очень эстетичный момент, не так ли? Последний шаг — добавить визуальную составляющую — стиль в CSS.
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
padding: 50px;
display: flex;
align-items: center;
justify-content: center;
background-color: #18191c;
color: #FFFFFF;
font-family: 'Kanit', sans-serif;
font-family: 'Roboto', sans-serif;
font-size: 18px;
}
h4 {
color: red;
margin-bottom: 2vh;
}
input, textarea{
width: 100%;
padding: 12px;
margin-bottom: 25px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
resize: vertical;
}
label {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 25px;
}
.input, .button {
width: 350px;
}
.input {
border: 1px solid #ffffff;
border-radius: 6px;
padding: 10px 15px;
background-color: transparent;
color: #ffffff;
font-family: inherit;
font-size: inherit;
font-weight: 300;
-webkit-appearance: none;
appearance: none;
}
.input:focus {
border-color: #FFD829;
outline: none;
}
.button {
display: block;
min-width: 210px;
border: 2px solid transparent;
border-radius: 6px;
margin-left: auto;
padding: 9px 15px;
color: #000000;
font-size: 18px;
font-weight: 300;
font-family: inherit;
transition: background-color 0.2s linear;
}
.button:hover {
background-color: #FF0032;
cursor: pointer;
transition: background-color 0.2s linear;
}
.button:focus-visible {
border: 2px solid #ffffff;
outline: none;
}
.button:focus {
border: 2px solid #ffffff;
outline: none;
}
.button-yellow {
background-color: #FFD829;
}
.button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.hidden {
display:none;
}
@media (max-width: 768px) {
body {
padding: 30px;
}
label {
display: block;
}
.input, .button {
display: block;
width: 100%;
}
}
Для того, чтобы получить доступ к форме, нужно вручную запустить сайт — потребуется подключение к Интернету, а также запущенный ранее созданный нами файл. При желании можно «вшить» код в пользовательский интерфейс, а также настроить.
Этап 3. Настройка
Чтобы все работало корректно и не требовало доработок, необходимо дополнительно создать файл настройки с актуализацией версий используемых библиотек:
aiofiles==23.2.1
anyio==4.1.0
beautifulsoup4==4.12.2
blinker==1.7.0
cachetools==5.3.2
certifi==2023.11.17
charset-normalizer==3.3.2
click==8.1.7
Flask==3.0.0
google==3.0.0
google-api-core==2.15.0
google-api-python-client==2.111.0
google-auth==2.25.2
google-auth-httplib2==0.2.0
google-auth-oauthlib==1.2.0
googleapis-common-protos==1.62.0
greenlet==3.0.2
h11==0.14.0
h2==4.1.0
hpack==4.0.0
httpcore==1.0.2
httplib2==0.22.0
httpx==0.25.2
Hypercorn==0.15.0
hyperframe==6.0.1
idna==3.6
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.3
oauth2client==4.1.3
oauthlib==3.2.2
priority==2.0.0
protobuf==4.25.1
pyasn1==0.5.1
pyasn1-modules==0.3.0
pyparsing==3.1.1
python-telegram-bot==20.7
Quart==0.19.4
requests==2.31.0
requests-oauthlib==1.3.1
rsa==4.9
six==1.16.0
sniffio==1.3.0
soupsieve==2.5
SQLAlchemy==2.0.17
typing_extensions==4.9.0
uritemplate==4.1.1
urllib3==2.1.0
Werkzeug==3.0.1
wsproto==1.2.0
Для всех желающих оставляем ссылку на готовый код в GitHub с полной сборкой и всеми составляющими.
Работу алгоритма можно представить следующим образом: сотрудник заполняет соответствующую форму (создается автоматически для рабочего интерфейса или с помощью Google Форм), которая передает данные в общую таблицу. Возможно также ручное заполнение — например, если нужно вносить правки в уже созданные заявки.
После этого автоматический алгоритм каждые 20 секунд (возможно увеличить срок до 20 минут, часа и так далее) проверяет, появились ли новые строки. И если они есть, считывает их, отправляя значения в форму отправки. Она, в свою очередь, проверяет корректность ввода и служит для того, чтобы сотрудник мог также самостоятельно вводить и отправлять данные.
![](https://habrastorage.org/getpro/habr/upload_files/e6d/bd2/66e/e6dbd266efd13f9839f31c6ac002b84c.png)
Последний шаг — непосредственная работа API Exolve для отправки сообщения на указанный номер телефона. В коде уже прописаны автоматические комментарии к полям («подойдите туда-то»), их можно изменить самостоятельно. Как итог — покупатели получат следующие сообщения:
![](https://habrastorage.org/getpro/habr/upload_files/307/142/98b/30714298bacb584c4d8cc625baca7495.png)
Мы повторимся, что этот код можно упростить, автоматизировав его и убрав форму — то есть, передавать данные напрямую в API. Но в таком случае исключается возможность ручного воздействия — изменения данных и отправки сообщений «вне очереди».