Время на прочтение
9 мин
Количество просмотров 49K
«История ничему не учит, а только наказывает за незнание уроков.»
(с) В.О. Ключевский
Друг предложил мне поработать над проектом для нашей кафедры. ТЗ пока не сформулировано, но точно известно, что это будет бот в телеге. Я хоть и питонист, но с ботами дел никогда не имел, поэтому пишу эту статью, как заметку, для себя и молодых перспективных ребят, чтоб у них было от чего оттолкнуться. Постараюсь писать максимально понятным и простым языком. Профессионалам тут особо делать не чего, хотя, может и придёт какая-нибудь идея.
Краткое описание бота
Наш бот будет создан на тематику Белого движения в гражданской войне в России (1917-1922) /сегодня разговор не о политике. Это просто пример/
-
По команде /start бот будет приветствие и посылать стикер;
-
После приветствия появится клавиатура под строкой набора сообщений с двумя кнопками «Вывести случайную цитату белогвардейца» и «Литература»
-
Нажатие на первую кнопку выведет рандомную цитату из excel файла (такое извращение нужно для подготовки к будущему проекту)
-
Нажатие на кнопку «Литература» выдаст инлайновую клавиатуру (далее будет прояснение, для тех кто не понял что это) с названиями произведений белогвардейских авторов или о белогвардейцах.После нажатия клавиатура пропадёт (просто этим навыком, думаю, необходимо обладать), начнётся загрузка pdf файла и появится оповещение «Приятного чтения!»
Вот такой простенький бот у нас по выйдет.
Начало. Создание бота и добавление библиотек.
Для начала добавим библиотеку pyTelegramBotAPI обычным пипом в cmd.
pip install pyTelegramBotAPI
А также загрузим простенькую библиотеку для работы с Excel. (ЧИТАЕТ ТОЛЬКО .xls!!!)
pip install xlrd
Время импортировать все необходимые библиотеки.
import telebot #импорт pyTelegramBotAPI
from telebot import types #также достанем типы
import random #рандом обязательно
import xlrd #библиотка чтения экселевских файлов
Далее нужно создать самого бота в телеграме. Для этого пройдёмся по следующим шагам:
-
Найти в поиске телеграма @BotFather
-
Написать ему команду /newbot
-
Первым сообщение отправить имя бота, а вторым его юзернейм (который пишется с @). Он должен быть уникальный и оканчиваться на Bot или _bot
После этих шагов батя пришлёт нам ссылку на нашёго бота и его API.
Если коротко, то API — это контракт, который предоставляет программа. «Ко мне можно обращаться так и так, я обязуюсь делать то и это».
(Более подробная инфа тут API)
Кодим
Раз библиотеки уже добавили, значит создаём переменную, определяющую бота с помощью API.
bot = telebot.TeleBot("TOKEN")
В начале, при написании команды /start, бот у нас выдаст приветствие. Соответственно, вставляем декоратор обработчика сообщений.
@bot.message_handler(commands=['start'])
Если кто не знает что такое декораторы, то есть достаточно подробная статья, рекомендую ознакомиться.
Коротко: Декораторы — это, по сути, просто своеобразные «обёртки», которые дают нам возможность делать что-либо до и после того, что сделает декорируемая функция, не изменяя её.
Теперь наш бот понимает команду /start, но ещё ничего не делает. Создаём функцию приветственного сообщения.
@bot.message_handler(commands=['start'])
def send_welcome(message):
stic = open('stic/welcome.webp', 'rb') #чтение файла в двоичном формате
# клавиатура
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
but1 = types.KeyboardButton("Вывести случайную цитату белогвардейца")
but2 = types.KeyboardButton("Литература")
markup.add(but1, but2)
bot.reply_to(message, "Здравствуй, {0.first_name}nСмотрю, ты за Единую, Великую и Недилимую".format(message.from_user)
,parse_mode='html',reply_markup=markup)
bot.send_sticker(message.chat.id,stic)
Пробежимся по коду
Строкой stic = open('stic/welcome.webp', 'rb')
мы записываем в переменную путь к нашему стикеру в формате .webp (скачать его можно из сообщений телеграма правой кнопкой мыши, «сохранить как»)
Ниже происходит создание клавиатуры markup = types.ReplyKeyboardMarkup(resize_keyboard=True) ,
а точнее запись в переменную подстрочной клавиатуры. Параметр resize_keyboard=True
подгоняет кнопки по высоте до возможного минимума. Также создаём две кнопочки и добавляем в клавиатуру:
but1 = types.KeyboardButton("Вывести случайную цитату белогвардейца")
but2 = types.KeyboardButton("Литература")
markup.add(but1, but2)
Клавиатура готова, но пока не используется. Пока оставим её и переключимся на сообщение. Одной строкой мы указываем боту отправить сообщение с текстом, именем отправителя ({0.first_name}
, а вытягивает его он из.format(message.from_user)
мы можем дописать .format(message.from_user, bot.get_me())
и вызвать имя бота, добавив в текст {1. first_name}
), правилом оформления parse_mode='html' (
также можно выбрать 'markdown')
и определением клавиатуры, которую создали выше.
bot.reply_to(message, "Здравствуй, {0.first_name}nСмотрю, ты за Единую, Великую и Недилимую".format(message.from_user)
,parse_mode='html',reply_markup=markup)
Последней строкой отправляем стикер bot.send_sticker(message.chat.id,stic)
Время дать возможность боту коммуницировать
@bot.message_handler(func=lambda message: True)
def menu(message):
if message.chat.type == 'private':
if message.text == "Вывести случайную цитату белогвардейца":
#достаём циататы из ворда
rb = xlrd.open_workbook('citat/citat.xls', formatting_info=True)
sheet = rb.sheet_by_index(0)
for rownum in range(sheet.nrows):
rand = int(random.randint(0,rownum))
row = sheet.row_values(rand)
bot.send_message(message.chat.id, row)
elif message.text == "Литература":
#инлайновая клавиатура
inMurkup = types.InlineKeyboardMarkup(row_width=1)
but1 = types.InlineKeyboardButton("И.Ф. Плотников - Александр Васильевич Колчак. Исследователь, адмирал, Верховный правитель России",callback_data='book1')
but2 = types.InlineKeyboardButton("А.В. Туркул - Дроздовцы в огне", callback_data='book2')
but3 = types.InlineKeyboardButton("П.Н. Врангель - Записки", callback_data='book3')
but4 = types.InlineKeyboardButton("М.Г. Дроздовский - Дневник", callback_data='book4')
inMurkup.add(but1, but2, but3, but4)
bot.send_message(message.chat.id, "Книги на любой вкус", reply_markup=inMurkup)
else:
bot.send_message(message.chat.id, "Я не знаю что и ответить")
Букв много, но сейчас всё раскидаем. Берём знакомый декоратор и делаем проверку лямбдой сообщение. Если не в курсе что такое лямбда-функция, то сюда. Бот у нас работает через личные сообщения, поэтому пропишем if message.chat.type == 'private':
, если требуется, то можете указать условия для
“group”, “supergroup” или “channel” , но нам это не нужно.
Далее идёт строка с текстом. ВАЖНО текст должен совпадать с названием кнопки клавиатуры, которую указывали выше.
Создаём экселевский файлик, в первую колонку вписываем цитаты, сохраняем в формате .xls в папку, как делали со стикером.
Со спокойной душой вызываем на файл на чтение rb = xlrd.open_workbook('citat/citat.xls', formatting_info=True),
указываем лист с которого считываем инфу sheet = rb.sheet_by_index(0)
индексы как у массива (первый элемент нулевой).
Далее определяем диапазон заполненных строк в листе и записываем их количество в rownum
. Используем эту переменную как верхнюю границу до которой может сгенерироваться случайное число rand = int(random.randint(0,rownum))
. Получив ячейку, вытаскиваем из неё значение row = sheet.row_values(rand)
отправляем его bot.send_message(message.chat.id, row)
.
Для литературы будем использовать инлайновую клавиатуру.
elif message.text == "Литература":
#инлайновая клавиатура
inMurkup = types.InlineKeyboardMarkup(row_width=1)
but1 = types.InlineKeyboardButton("И.Ф. Плотников - Александр Васильевич Колчак. Исследователь, адмирал, Верховный правитель России", callback_data='book1')
but2 = types.InlineKeyboardButton("А.В. Туркул - Дроздовцы в огне", callback_data='book2')
but3 = types.InlineKeyboardButton("П.Н. Врангель - Записки", callback_data='book3')
but4 = types.InlineKeyboardButton("М.Г. Дроздовский - Дневник", callback_data='book4')
inMurkup.add(but1, but2, but3, but4)
bot.send_message(message.chat.id, "Книги на любой вкус", reply_markup=inMurkup)
Определяем клавиатуру inMurkup = types.InlineKeyboardMarkup(row_width=1)
параметр row_width=1
говорит о том, что на одной строке будет одна кнопка. Принцип кнопок создания такой же как и у обычной клавиатуры, но появляется параметр callback_data
значения которого примет бот после нажатия на кнопку и поймёт что нужно сделать (далле это всё опишем).
Последней строкой отправляем сообщение и цепляем к нему инлайновую клавиатуру.
Работа с callback_data
@bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
try:
if call.message:
if call.data == 'book1':
doc = open('boo/Plotnikov_Ivan-Aleksandr_Vasilevich_Kolchak_Issledovatel_admiral_Verhovnyi_pravitel_Rossii.pdf', 'rb')
bot.send_document(call.message.chat.id, doc)
elif call.data == 'book2':
doc = open('boo/Turkul_-_Drozdovtsy_v_ogne.pdf','rb')
bot.send_document(call.message.chat.id, doc)
elif call.data == 'book3':
doc = open('boo/Vrangel_P_Zapiski_a4.pdf', 'rb')
bot.send_document(call.message.chat.id, doc)
elif call.data == 'book4':
doc = open('boo/Drozdovsky_dnevnik_1963__ocr.pdf', 'rb')
bot.send_document(call.message.chat.id, doc)
#удаляем инлайновую клаву
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Книги на любой вкус",
reply_markup=None)
#Создаём уведомление
bot.answer_callback_query(callback_query_id=call.id, show_alert=False,
text='Приятного чтения!')
except Exception as e:
print(repr(e))
Первым делом вызываем декоратор обработки колбэка и подтверждаем, что он был получен @bot.callback_query_handler(func=lambda call: True)
. Далее создаём функцию с конструкцией try-except (Что это? Чекай). Код хоть и приличный по объёму, но весь однотипный. Через if мы понимает какая «дата» пришла от кнопки, например if call.data == 'book1':
отвечает за первую кнопку с книгой про Колчака. Соответственно, командой
doc = open('boo/Plotnikov_Ivan-Aleksandr_Vasilevich_Kolchak_Issledovatel_admiral_Verhovnyi_pravitel_Rossii.pdf', 'rb')
мы создаём переменную doc в которую «суём» pdf файл, который сохранили в папку «boo» заранее.
Теперь строкой bot.send_document(call.message.chat.id, doc)
отправляем файл в чат.
После леса из наших elif удалим инлайновую клавиатуру, дабы не мешалась. Действие необязательно, но мы же с вами тренируемся, поэтому пусть код будет здесь.
Вызываем функцию bot.edit_message_text
По тексту определяется сообщение и
в параметр, который мы использовали для добавления клавиатуры — reply_markup
вносим значение None
.
Уведомление призывается заклинанием
Параметр show_alert
отвечает за вид оповещения (False — простое временное уведомление, True — уведомление с кнопкой «Ок»)
Завершаем эту ступень кода конструкцией проверки исключений (ошибок).
except Exception as e:
print(repr(e))
Финальный аккорд:
bot.polling(none_stop=True)
Именно этой командой и закончим наш код. Теперь бот постоянно проверяет не написал ли ему кто.
В итоге получился такой код:
import telebot
from telebot import types
import random
import xlrd
bot = telebot.TeleBot("TOKEN")
@bot.message_handler(commands=['start'])
def send_welcome(message):
stic = open('stic/welcome.webp', 'rb')
# клавиатура
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
but1 = types.KeyboardButton("Вывести случайную цитату белогвардейца")
but2 = types.KeyboardButton("Литература")
markup.add(but1, but2)
bot.reply_to(message, "Здравствуй, {0.first_name}nСмотрю, ты за Единую, Великую и Недилимую".format(message.from_user),parse_mode='html',reply_markup=markup)
bot.send_sticker(message.chat.id,stic)
@bot.message_handler(func=lambda message: True)
def menu(message):
if message.chat.type == 'private':
if message.text == "Вывести случайную цитату белогвардейца":
#достаём циататы из ворда
rb = xlrd.open_workbook('citat/citat.xls', formatting_info=True)
sheet = rb.sheet_by_index(0)
for rownum in range(sheet.nrows):
rand = int(random.randint(0,rownum))
row = sheet.row_values(rand)
bot.send_message(message.chat.id, row)
elif message.text == "Литература":
#инлайновая клавиатура
inMurkup = types.InlineKeyboardMarkup(row_width=1)
but1 = types.InlineKeyboardButton("И.Ф. Плотников - Александр Васильевич Колчак. Исследователь, адмирал, Верховный правитель России", callback_data='book1')
but2 = types.InlineKeyboardButton("А.В. Туркул - Дроздовцы в огне", callback_data='book2')
but3 = types.InlineKeyboardButton("П.Н. Врангель - Записки", callback_data='book3')
but4 = types.InlineKeyboardButton("М.Г. Дроздовский - Дневник", callback_data='book4')
inMurkup.add(but1, but2, but3, but4)
bot.send_message(message.chat.id, "Книги на любой вкус", reply_markup=inMurkup)
else:
bot.send_message(message.chat.id, "Я не знаю что и ответить")
#обработка callback
@bot.callback_query_handler(func=lambda call: True)
def callback_inline(call):
try:
if call.message:
if call.data == 'book1':
doc = open('boo/Plotnikov_Ivan-Aleksandr_Vasilevich_Kolchak_Issledovatel_admiral_Verhovnyi_pravitel_Rossii.pdf', 'rb')
bot.send_document(call.message.chat.id, doc)
elif call.data == 'book2':
doc = open('boo/Turkul_-_Drozdovtsy_v_ogne.pdf','rb')
bot.send_document(call.message.chat.id, doc)
elif call.data == 'book3':
doc = open('boo/Vrangel_P_Zapiski_a4.pdf', 'rb')
bot.send_document(call.message.chat.id, doc)
elif call.data == 'book4':
doc = open('boo/Drozdovsky_dnevnik_1963__ocr.pdf', 'rb')
bot.send_document(call.message.chat.id, doc)
#удаляем инлайновую клаву
bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Книги на любой вкус",
reply_markup=None)
#Создаём уведомление
bot.answer_callback_query(callback_query_id=call.id, show_alert=False,
text='Приятного чтения!')
except Exception as e:
print(repr(e))
bot.polling(none_stop=True)
Пара слов от автора
Если есть желание показать друзьям что наворотили, то запускайте код и всё будет работать, но если код остановить или выключить комп, то бот ничего выдавать не будет. Из этого выходит, что для полноценного бота просто необходим хостинг, что, как правило, платно.
Больше функций, параметров и всего прочего находится в документации. Справочник на русском. Библиотеки pyTelegramBotAPI и xlrd.
Огромное спасибо за прочтение статьи! Надеюсь она оказалась полезной. А если понравилась, то поднимай статью в рейтинге и оставляй комменты)
Автор обитает тут: ВК, Инстаграм
Организовать удобный учет и оцифровать процессы можно при помощи простейших и доступных всем инструментов. В данной публикации мы поделимся исходниками своей наработки, которую можно настроить по описанной инструкции или использовать как идею для реализации в своем бизнесе.
О чем пойдет речь
Мы, команда разработчиков helpexcel.pro, постоянно создаем готовые решения в Гугл таблицах для управленческого учета в малом бизнесе и бесплатно публикуем их в открытом доступе.
В этот раз мы поделимся своими наработками для учета небольшого склада. Это мини-сервис для учета небольшого склада, созданный на основе Гугл таблицы с возможностью ввода данных через Телеграм-бота.
Решение подойдет для небольших интернет-магазинов или, например, для учета расходных материалов.
Основные функции таблицы
Таблица устроена так, что в ней есть область для внесения справочников, область для учета приходов, область для учета событий и область аналитики. В качестве аналитики формируются отчеты о дебиторской и кредиторской задолженности, остатки по складу и расчет себестоимости.
В классическом виде представлены ABC и XYZ анализы товаров, что дает аналитику о том, в какие товары стоит дальше вкладываться.
Ниже делимся ссылкой на таблицу, но советуем вам ознакомиться с описанием, чтобы понять принцип ее устройства и использовать 100% возможностей.
Чтобы полноценно воспользоваться таблицей создайте ее копию на своем Гугл диске.
Описание работы таблицы
Для нас это уже не первая версия складской таблицы, и мы предусмотрели потребности пользователей в разных способах подсчета закупочной цены.Для корректного подсчета прибыли, рентабельности и ценности товаров на складе нужно выбрать метод расчета закупочной цены. Настройка находится на листе “Справочник”:
В рамках функций таблицы заложено 3 вида расчета: по средней цене прихода, метод FIFO и метод LIFO.
По средней цене прихода
Этот метод принимает за себестоимость среднее значение за указанный вами период.
Возьмем для примера период в 1 месяц.
Месяц назад закупочная цена была 1000 рублей, 16 дней назад — 1050 рублей, а 3 дня назад — 1000 рублей.
Для данного метода принимается средняя закупочная цена — 1050 рублей.
Метод FIFO
«Первым пришёл — первым ушёл»
Разберем этот принцип на примере. Вы приобрели 2 принтера по 5 000 ₽ за шт. и ещё два абсолютно таких же, но уже по 6 000 ₽.
У вас хотят купить один из них. Для продавца не важно, какой из них взять — они одинаковые. Но бухгалтеру важна общая стоимость товара на складе.
По методу FIFO нужно взять принтер, который поступил на склад раньше всех. То есть за 5 000 рублей.
В таком случае на складе останется 1 принтер стоимостью 5 000 рублей и 2 принтера за 6 000 рублей.
Общая стоимость 3-х принтеров на складе — 17 000 рублей.
Метод LIFO
«Последним пришёл — первым ушёл»
Для удобства возьмем тот же пример с принтерами. Все суммы и количества оставим теми же.
По методу LIFO мы должны взять принтер, который поступил на склад позже всех. За 6 000 рублей.
Тогда на складе останется 2 принтера стоимостью 5 000 рублей и 1 принтер стоимостью 5 000 рублей.
Стоимость оставшихся 3-х принтеров — 16 000 рублей.
Продолжаем заполнять справочник таблицы переменными. Укажите ваш часовой пояс, заполните справочники товаров, поставщиков и покупателей.
Далее переходим к учетной части таблицы.
Принцип работы каждого листа рассмотрим по отдельности.
Лист закупки
Информация о всех пополнениях склада фиксируется на данном листе или через Телеграм-бота.
Некоторые поля таблицы расчетные, в них работают формулы — не заполняйте эти столбцы.
Для обеспечения хранения большого числа строк и возможности связи с ботом к таблице подключена внешняя база данных. Для просмотра исторической информации можно выбрать период и нажать кнопку “обновить”.За счет этой настройки мы ускорили работу таблицы и не выводим невостребованные строки с данными.
Если же какая-то позиция была введена по ошибке или уже не актуальна, то ее можно удалить. Для этого в последнем столбце выделите галочкой нужные строки и нажмите на кнопку “удалить”.
Для ввода данных через telegram-бота нужно перейти по ссылке https://t.me/help_excel_storage_bot. Если вы правильно выполнили настройку бота, то у вас появится блок из 4-х кнопок:
Выберите “Закупки”.
Далее, следуя диалогу бота, вы вводите информацию о закупке. Поля диалога бота идентичны полям таблицы.
Для отображения информации, введенной через бота, нужно нажать кнопку “обновить”.
Лист отгрузки
Поля таблицы отгрузок работают по тому же принципу, что и лист закупок.
В правой части таблицы представлена область расчета себестоимости и показателей дохода от реализации товара. Показатели рассчитываются при нажатии на кнопку “обновить” или “сохранить”.
Лист аналитики
Данный лист состоит из трех блоков.
Область расчета складских запасов:
Дебиторская и кредиторская задолженность:
Сумма задолженности отражается в столбце “задолженность” если вы не поставили галочку напротив суммы в столбце “статус оплаты”. Тогда таблица считает, что платеж еще не проведен.
Также, если вы поставили в столбце “дней отсрочки” количество дней, и эта дата уже прошла, то сумма будет отражена в столбце “просроченная задолженность”.
Лист ABC анализа
Все товары делятся на 3 группы::
А: приносят 80% продаж
В: приносят 15% продаж
С: приносят 5% продаж
Лист XYZ анализа
Отчет показывает колебания спроса, товары разбиваются на 3 группы:.
X — товары продаются стабильно в течение года.
Категория Y — товары сезонного спроса.
Категория Z — спрос нерегулярен, какие-либо тенденции отсутствуют.
Лист ABC XYZ
На данном листе объединяется информация ABC и XYZ анализа. Товарная матрица делится на 9 групп:
- AX – приносящие значительную долю выручки со стабильным спросом;
- AY – большая доля выручки, но спрос подвержен колебаниям;
- AZ – хорошо продаются, но спрос плохо поддается прогнозированию;
- BX – средние объемы выручки, низкие колебания спроса;
- BY – средние объемы выручки, колебания спроса в пределах нормы, например, сезонные;
- BZ – средние объемы выручки, сложно прогнозируемый спрос;
- CX – низкая доля в прибыли, стабильный уровень спроса;
- CY – невысокий уровень прибыли при средних колебаниях спроса;
- CZ – низкий уровень прибыли, высокие колебания спроса.
Пример:
Настройка таблицы
Для начала нужно создать копию таблицы, как показано на картинке ниже:
В таблицу встроен скрипт, который считает себестоимость товаров. Для того, чтобы таблица работала правильно, нужно авторизоваться. Для этого нажмите на значок обновления на листе “Отгрузки”:
У вас появится такое поле:
Нажмите на “Продолжить”.
Выберите свой google-аккаунт
В появившемся окне нажмите на “Дополнительные настройки”:
Затем, на “Перейти на страницу “script”:
В следующем окне пролистайте вниз и нажмите на кнопку “Разрешить”:
Отлично, авторизация скрипта пройдена!
Настройка Telegram-бота
Основное предназначение бота — ввод данных о приходах и отгрузках в таблицу. Он служит больше как вспомогательный интерфейс для возможности мобильного ввода информации.
Для его настройки вам нужно на листе “Пользователи бота” добавить номера сотрудников, которые будут работать с ботом.
Номер телефона обязательно нужно ввести через цифру 7, без “+” и других дополнительных знаков. Так, как показано на скриншоте.
После нажатия на кнопку сохранить вам нужно будет принять соглашение об обработке данных.
Затем вам нужно перейти на страницу бота @help_excel_storage_bot.
В диалоге с ботом следует нажать на кнопку “Запустить” (если вы через ПК) или на кнопку “Старт” (если вы через телефон):
После этого также нужно будет принять соглашение об обработки данных и ввести свой телефон в формате +7##########.
На этом настройка чат-бота окончена. Подробное описание работы чат-бота и таблицы будет далее.
Спасибо, что полностью ознакомились с нашим руководством!
Если у вас еще останутся вопросы по таблице, то можете задать их в нашем телеграмм-чате:
0 / 0 / 0
Регистрация: 07.11.2021
Сообщений: 10
1
07.11.2021, 19:40. Показов 6494. Ответов 2
Хочу совместить вместе Telegram и Python.
Оба коды работают без ошибок, много над ними замучился я.
Внизу коды:
1. Для ответа в телеграм боте;
2. Для импорта нужных данных из Excel по поиску
Нужно сделать так чтобы, когда в боте что та написали, он начал искать это в файле Excel и ответил ползователю.
Если есть другие варианты кода, то я буду рад узнать.
Python | ||
|
Python | ||
|
0
Эксель лайфхаки справочник и чат помощи
Освоить таблицы теперь стало проще📊 Excel Bot — бот с полезной информацией по работе в эксель: лайфхаки, справочник, чат помощи.
Прокачивайте свои навыки: @excel24bot
-
Просмотры
828
-
Рейтинг
0
-
Опубликовано
27.06.21
Excel Bot
Excel Бот-справочник с полезной информацией описывающий работу в Excel от А до Я. • Информация о
Excel Everyday
Excel Everyday @excel_everyday — Уроки которые упростят Вашу жизнь и работу в Excel. Подробные
🔥 ЛАЙФХАКИ ТУРИСТА
@hottoursufa ➡ 🔥 ЛАЙФХАКИ ТУРИСТА, красивые видео, горящие туры, новости 🔥 👍Выгодные туры новости
Комментарии (0)
Комментировать
Информация
Оставить комментарий могут только зарегистрированные пользователи:
Авторизация