1
0
Fork 0
mirror of https://github.com/EDeev/school_menu.git synced 2026-10-08 04:59:35 +03:00

Compare commits

...

5 commits

Author SHA1 Message Date
6bb94afe64 README на русском и английском 2026-10-02 23:40:56 +00:00
59a97485e8 CI: синтаксис, неопределённые имена и проверка разбора ячеек 2026-10-02 23:40:56 +00:00
6cccfd202d Токен, ID бота и технической группы — из окружения
В base.py стояли замаскированные значения (ID_BOT = **********), из-за которых модуль
не импортировался; теперь BOT_TOKEN, BOT_ID и TECH_GROUP_ID берутся из переменных.
2026-10-02 23:40:56 +00:00
ad20d4adea Разбор граммовки и калорийности без eval
Значения ячеек Excel-меню с сайта школы вычислялись через eval — любой текст в файле
выполнился бы как код. Теперь arithmetic() разбирает только числа и + - * /.
2026-10-02 23:40:56 +00:00
ac866d7df1 Переводы строк приведены к LF 2026-10-02 23:38:04 +00:00
7 changed files with 605 additions and 625 deletions

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
* text=auto eol=lf
*.db binary

29
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- run: pip install ruff==0.14.0 openpyxl==3.1.2 requests==2.31.0
- name: Синтаксис и неопределённые имена
run: ruff check --select E9,F821,F811 . && python -m py_compile code/*.py
- name: Разбор ячеек меню без eval
working-directory: code
run: |
python -c "
from pars import arithmetic
assert arithmetic('150+30') == 180 and arithmetic('12.5') == 12.5
try:
arithmetic('__import__(\"os\")')
raise SystemExit('eval-подобный ввод не отвергнут')
except ValueError:
pass"

41
README.en.md Normal file
View file

@ -0,0 +1,41 @@
# School Menu Bot
[Русский](README.md) · **English**
[![CI](https://github.com/EDeev/school_menu/actions/workflows/ci.yml/badge.svg)](https://github.com/EDeev/school_menu/actions/workflows/ci.yml)
A school cafeteria Telegram bot: every morning it posts the menu from the school website, takes breakfast,
lunch and snack orders by class and compiles a summary for the cafeteria.
**Status:** school project (2021–2022), completed, archived
**Stack:** Python 3.10 · aiogram 2 · SQLite · openpyxl (menu from Excel) · pymorphy2
- Today's and tomorrow's menu (`/today`, `/tomorrow`) and a 06:00 broadcast
- Ordering with buttons, cancelling and changing an order
- Class registration by code, separate groups for students and the cafeteria
- Order summary by class with correct Russian word forms
## Running
```bash
pip install -r requirements.txt
cd code && BOT_TOKEN=token BOT_ID=bot_id TECH_GROUP_ID=group_id python bot.py
```
Portion weights and calories from Excel are parsed without `eval`: only numbers and `+ - * /` are allowed.
## License
School project (2021–2022). The code is open for study; there is no separate license.
## Author
**Egor Deev** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space)
---
<div align="center">
<sub>⭐ If you find this project useful, give it a star on GitHub!</sub>
<p><sub>Made with ❤️ — <a href="https://deev.space">deev.space</a></sub></p>
</div>

153
README.md
View file

@ -1,154 +1,41 @@
# 🍽️ School Menu Bot
# School Menu Bot
Автоматизированная система управления школьным питанием с интеграцией Telegram Bot API для сбора и обработки заказов.
**Русский** · [English](README.en.md)
## 🎯 Описание проекта
[![CI](https://github.com/EDeev/school_menu/actions/workflows/ci.yml/badge.svg)](https://github.com/EDeev/school_menu/actions/workflows/ci.yml)
School Menu Bot представляет собой многофункциональное решение для организации процесса заказа школьного питания. Система обеспечивает автоматический парсинг меню с официального сайта школы, предоставляет интерактивный интерфейс для заказов через Telegram и ведет детальную статистику по группам и пользователям.
Telegram-бот школьной столовой: каждое утро присылает меню с сайта школы, принимает заказы завтраков,
обедов и полдников по классам и собирает сводку для столовой.
## ⭐ Ключевые возможности
**Статус:** школьный проект (2021–2022), завершён, в архиве
### Пользовательский функционал
- **Просмотр меню**: Получение актуального меню на текущий и следующий день
- **Интерактивные заказы**: Система выбора питания через inline-клавиатуры
- **Гибкое планирование**: Возможность заказа комбинаций (завтрак, обед, полдник)
- **Управление заказами**: Отмена и изменение активных заказов
**Стек:** Python 3.10 · aiogram 2 · SQLite · openpyxl (меню из Excel) · pymorphy2
### Административные функции
- **Групповая регистрация**: Система верификации через уникальные коды
- **Аналитика заказов**: Детальная статистика по группам и пользователям
- **Автоматические уведомления**: Ежедневная рассылка меню в 06:00
- **Мультигрупповая поддержка**: Раздельные каналы для учеников и администрации
- Меню на сегодня и завтра (`/today`, `/tomorrow`) и рассылка в 06:00
- Заказ питания кнопками, отмена и изменение заказа
- Регистрация класса по коду, отдельные группы для учеников и для столовой
- Сводка заказов по классам с правильным склонением слов
### Техническая архитектура
- **Парсинг данных**: Автоматическое извлечение меню из Excel-файлов
- **Многоуровневая БД**: Система баз данных для пользователей, групп и заказов
- **Асинхронная обработка**: Неблокирующее выполнение операций
- **Морфологический анализ**: Корректное склонение слов в статистике
## Запуск
## 🛠️ Технологический стек
### Backend Framework
- **Python 3.8+** - Основной язык разработки
- **Aiogram** - Асинхронный фреймворк для Telegram Bot API
- **Asyncio** - Асинхронное программирование
### Data Processing
- **OpenPyXL** - Обработка Excel-файлов с меню
- **Requests** - HTTP-запросы к внешним ресурсам
- **PyMorphy2** - Морфологический анализ русского языка
### Database Management
- **SQLite** - Легковесная встроенная СУБД
- **Многоуровневая архитектура БД**:
- `base.db` - Основные данные групп и пользователей
- `users.db` - Пользовательские связки
- `groups.db` - Групповые данные и статистика
- `now.db` - Текущие активные заказы
## 📁 Структура проекта
```
school_menu/
├── code/
│ ├── bot.py # Основная логика бота
│ ├── pars.py # Парсер школьного меню
│ ├── sql.py # ORM для работы с БД
│ └── base.py # Конфигурация и токены
├── db/
│ ├── base.db # Основная база данных
│ ├── users.db # Пользовательские данные
│ ├── groups.db # Групповая статистика
│ └── now.db # Текущие заказы (пересоздается ежедневно)
├── requirements.txt # Зависимости проекта
└── README.md # Документация
```
## 🚀 Установка и запуск
### Предварительные требования
```bash
pip install -r requirements.txt
cd code && BOT_TOKEN=токен BOT_ID=id_бота TECH_GROUP_ID=id_группы python bot.py
```
### Конфигурация
1. Создайте нового бота через [@BotFather](https://t.me/BotFather)
2. Настройте `code/base.py`:
```python
TOKEN = "ваш_токен_от_BotFather"
ID_BOT = ваш_id_бота
TEX_GROUP = "-id_технической_группы"
```
Граммовка и калорийность из Excel разбираются без `eval`: допускаются только числа и `+ - * /`.
### Запуск системы
```bash
cd code/
python bot.py
```
## Лицензия
## 💡 Алгоритм работы
Школьный проект (2021–2022). Код открыт для изучения, отдельной лицензии нет.
### Процесс регистрации групп
1. Администратор вызывает `/add_group` в личных сообщениях
2. Система генерирует уникальные коды для основной и технической групп
3. Коды вводятся в соответствующих чатах для верификации
4. Создается связка групп с инициализацией статистики
## Автор
### Система заказов
1. Парсинг актуального меню с `school01.ru/food/`
2. Пользователь выбирает комбинацию питания через `/eat`
3. Заказ фиксируется в основной группе и дублируется в техническую
4. Обновление статистики по группам и пользователям
### Автоматизация процессов
- **06:00 ежедневно**: Рассылка меню на следующий день
- **Учет выходных**: Автоматический пропуск воскресений
- **Сброс заказов**: Ежедневная очистка активных заказов
## 📊 Команды бота
| Команда | Описание | Доступность |
|---------|----------|-------------|
| `/start` | Инициализация бота | Личные сообщения |
| `/help` | Справочная информация | Универсально |
| `/today` | Меню на сегодня | Универсально |
| `/tomorrow` | Меню на завтра | Универсально |
| `/eat` | Интерфейс заказа | Только группы |
| `/stat` | Статистика группы | Только группы |
| `/add_group` | Регистрация групп | Личные сообщения |
| `/del_group` | Удаление связки | Личные сообщения |
## 🎯 Особенности реализации
### Безопасность данных
- Уникальная система кодов для верификации
- Раздельное хранение пользовательских и групповых данных
- Автоматическая очистка временных данных
### Производительность
- Асинхронная архитектура для обработки множественных запросов
- Оптимизированные SQL-запросы с контекстными менеджерами
- Кэширование статистических данных
### Масштабируемость
- Модульная архитектура классов для работы с БД
- Поддержка неограниченного количества групп
- Гибкая система расширения функционала
## 📋 Лицензия
Проект распространяется под лицензией MIT.
## 👥 Автор
**Деев Егор Викторович** - Backend Developer
- GitHub: [@EDeev](https://github.com/EDeev)
- Email: egor@deev.space
- Telegram: [@Egor_Deev](https://t.me/Egor_Deev)
**Деев Егор Викторович** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space)
---
<div align="center">
<sub>Разработано для автоматизации процессов школьного питания с упором на удобство использования и надежность системы.</sub>
<p><sub>Создано с ❤️ от вашего дорогого - deev.space ©</sub></p>
<sub>⭐ Если проект оказался полезным, поставьте звёздочку на GitHub!</sub>
<p><sub>Сделано с ❤️ — <a href="https://deev.space">deev.space</a></sub></p>
</div>

View file

@ -1,4 +1,8 @@
TOKEN = "token from BotFather"
ID_BOT = **********
TEX_GROUP = "-*********"
import os
# Токен бота от @BotFather — из переменной окружения BOT_TOKEN
TOKEN = os.environ.get("BOT_TOKEN", "")
# Числовой ID бота и ID технической группы для служебных сообщений — тоже из окружения
ID_BOT = int(os.environ.get("BOT_ID", "0"))
TEX_GROUP = os.environ.get("TECH_GROUP_ID", "")

View file

@ -1,436 +1,436 @@
import logging, asyncio, random, pymorphy2
import base, pars, sql, os
import datetime as dt
from aiogram import Bot, Dispatcher, executor, types
# log level
logging.basicConfig(level=logging.INFO)
morph = pymorphy2.MorphAnalyzer()
# bot init
bot = Bot(token=base.TOKEN)
dp = Dispatcher(bot)
# create now.db
file = open('../db/now.db', 'w+')
file.close()
# db init
db = sql.Base('../db/base.db')
du = sql.User('../db/users.db')
dg = sql.Group('../db/groups.db')
dn = sql.Now('../db/now.db')
@dp.message_handler(commands="start")
async def start(message: types.Message):
if 0 < int(message.chat.id):
await message.answer("Ghdbtn", types.ParseMode.MARKDOWN)
# ОБНОВЛЕНИЕ АЙДИ ГРУППЫ
@dp.message_handler(content_types=['migrate_to_chat_id', 'migrate_from_chat_id'])
async def chat_reload(message: types.Message):
if du.group_exists(message.migrate_from_chat_id):
du.update_group_id(message.migrate_from_chat_id, message.migrate_to_chat_id)
# КОМАНДЫ
@dp.message_handler(commands="help")
async def hlp(message: types.Message):
if 0 < int(message.chat.id):
await message.answer("*Инструкция использования:*\n\n"
"*/eat* - с помощью этой команды вы можете заказать питание\n"
"*/today* - команда выдающая меню на сегодня\n"
"*/tomorrow* - команда выдающая меню на завтра\n\n"
"*/add_group* - команда выдающая меню на завтра\n"
"*/del_group* - команда выдающая меню на завтра\n", types.ParseMode.MARKDOWN)
else:
await message.answer("*Инструкция использования:*\n\n"
"*/eat* - с помощью этой команды вы можете заказать питание\n"
"*/today* - команда выдающая меню на сегодня\n"
"*/tomorrow* - команда выдающая меню на завтра\n", types.ParseMode.MARKDOWN)
@dp.message_handler(commands="stat")
async def stat(message: types.Message):
if 0 > int(message.chat.id):
group_id = message.chat.id
if du.group_exists(group_id):
group_id = du.get_group_id(group_id)
if db.main_group_exists(group_id):
overall = db.stat_group(group_id)
all_users = dg.stat_all_users(group_id)
z = [[user[1], user[0]] for user in all_users if user[1] != 0]
o = [[user[2], user[0]] for user in all_users if user[2] != 0]
p = [[user[3], user[0]] for user in all_users if user[3] != 0]
txt = f"<i><b>Всего было сделано заказов - {sum(overall)}</b></i>\n"
line = morph.parse('заказ')[0]
lst = [[f"\n\t<b>* Завтраков - {str(overall[0])}</b>\n", z], [f"\n\t<b>* Обедов - {str(overall[1])}</b>\n", o],
[f"\n\t<b>* Полдников - {str(overall[2])}</b>\n", p]]
for i in lst:
txt = txt + i[0]
if i[1]:
for n, j in enumerate(i[1][:3]):
txt = txt + "\t\t\t<b>" + str(n + 1) + ". " + j[1] + "</b> " + str(j[0]) + " " + line.make_agree_with_number(j[0]).word + "\n"
await message.answer(txt, types.ParseMode.HTML)
else:
await message.answer("Ваша группа не зарегистрирована!")
else:
await message.answer("Ваша группа не зарегистрирована!")
@dp.message_handler(commands="eat")
async def eat(message: types.Message):
if 0 > int(message.chat.id):
keyboard1 = {"inline_keyboard":
[[{"text": "Завтрак", "callback_data": "z"}, {"text": "Обед", "callback_data": "o"},
{"text": "Полдник", "callback_data": "p"}], [{"text": "Завтрак / Обед", "callback_data": "zo"}],
[{"text": "Завтрак / Полдник", "callback_data": "zp"}],
[{"text": "Обед / Полдник", "callback_data": "op"}],
[{"text": "Завтрак / Обед / Полдник", "callback_data": "zop"}]]}
await bot.send_message(chat_id=message.chat.id,
text='*Это меню выбора притания!* Всё, что вам надо сделать, это лишь выбрать '
'необходимый заказ.\n\nEсли после нажатия бот написал, что вы выбрали, то всё '
'прошло успешно и вы можете не беспокоиться!', parse_mode=types.ParseMode.MARKDOWN,
reply_markup=keyboard1)
keyboard2 = {"inline_keyboard": [[{"text": "Отменить заказ", "callback_data": "cancel"}]]}
await bot.send_message(chat_id=message.chat.id,
text='Если вы хотите сменить заказ, то отмените действующий заказ по кнопке ниже и '
'закажите заново!', parse_mode=types.ParseMode.MARKDOWN,
reply_markup=keyboard2)
else:
await message.answer("Эта команда доступна к использованию *только в чатах*", types.ParseMode.MARKDOWN)
@dp.message_handler(commands="del_group")
async def delg(message: types.Message):
if 0 < int(message.chat.id):
user_id = message.from_user.id
if du.user_exists(user_id):
user_id = du.get_user_id(user_id)
if db.user_main_exists(user_id):
keyboard = {"inline_keyboard": [[{"text": "Подтвердить удаление", "callback_data": "del"}]]}
await bot.send_message(chat_id=message.chat.id,
text='Вы точно хотите удалить статистику и связку групп?',
parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard)
else:
await message.answer("У вас нет связки групп для их удаления!")
else:
await message.answer("У вас нет связки групп для их удаления!")
else:
await message.answer("Эта команда доступна к использованию *только в личном чате*", types.ParseMode.MARKDOWN)
@dp.message_handler(commands="add_group")
async def addg(message: types.Message):
if 0 < int(message.chat.id):
user_id = message.from_user.id
flag = False
if not du.user_exists(user_id):
du.add_user(user_id)
user_id = du.get_user_id(user_id)
all_cods = db.all_cods()
cod1 = random.randint(1000, 9999)
while cod1 in all_cods[0]:
cod1 = random.randint(1000, 9999)
cod2 = random.randint(1000, 9999)
while cod2 in all_cods[1]:
cod2 = random.randint(1000, 9999)
db.add_user_tranzit(user_id, cod1, cod2)
await message.answer(f"Введите этот код в группе с учениками - *{str(cod1)}*, а этот в личной для "
f"фиксации заказа - *{str(cod2)}*", types.ParseMode.MARKDOWN)
flag = True
else:
user_id = du.get_user_id(user_id)
if db.user_tranzit_exists(user_id):
cods = db.get_cods(user_id)
await message.answer(f"Введите этот код в основной группе с учениками - *{str(cods[0])}*, а этот в "
f"личной для фиксации заказа - *{str(cods[1])}*", types.ParseMode.MARKDOWN)
flag = True
else:
if not db.user_main_exists(user_id):
all_cods = db.all_cods()
cod1 = random.randint(1000, 9999)
while cod1 in all_cods[0]:
cod1 = random.randint(1000, 9999)
cod2 = random.randint(1000, 9999)
while cod2 in all_cods[1]:
cod2 = random.randint(1000, 9999)
db.add_user_tranzit(user_id, cod1, cod2)
await message.answer(f"Введите этот код в группе с учениками - *{str(cod1)}*, а этот в личной для "
f"фиксации заказа - *{str(cod2)}*", types.ParseMode.MARKDOWN)
flag = True
else:
await message.answer("У вас уже есть связка группы, вам надо её удалить, прежде чем верифицировать "
"новую!", types.ParseMode.MARKDOWN)
if flag:
keyboard = {"inline_keyboard": [[{"text": "Отменить верификацию", "callback_data": "cnl"}]]}
await bot.send_message(chat_id=message.chat.id,
text='*Вы можете отменить заявку* если не хотите связывать группы для сбора '
'заказов питания!', parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard)
else:
await message.answer("Эта команда доступна к использованию *только в личном чате*", types.ParseMode.MARKDOWN)
@dp.message_handler(commands=["today", "tomorrow"])
async def todtom(message: types.Message):
food = pars.eating(0 if "today" in message.text else 1)
if food[0]:
food = food[1]
if "today" in message.text:
et = f"<b>Питание за {'.'.join(reversed(str(dt.date.today()).split('-')))}</b>\n\n"
else:
et = f"<b>Питание за {'.'.join(reversed(str(dt.date.today() + dt.timedelta(days=1)).split('-')))}</b>\n\n"
for j in food:
et = et + "<i><b>" + str(j) + ":</b></i>\n"
for i in food[j]:
et = et + "<b>* " + str(i[0]) + "</b> <i>[ "
et = et + str(i[1][0]) + " г. " + str(i[1][1]) + " ккал. ]</i>" + "\n"
et = et + "\n\n"
await message.answer(et, types.ParseMode.HTML)
else:
if food[1]:
await message.answer(f"<b>Ошибка в системе бота!</b>\n\nОна будет в скором времени исправлена...",
types.ParseMode.HTML)
await bot.send_message(chat_id=base.TEX_GROUP, text=f"<b>[ {str(dt.datetime.now())[:-10]} ]</b> "
f"<b><i>=></i></b> <i>{food[3]}</i> (ошибка в системе)",
parse_mode=types.ParseMode.HTML)
else:
if food[2] != 6:
await message.answer(f"<b>Нет данных по питанию!</b>\n\nКак только данные появятся вы сможете "
f"их получить этой же командой!", types.ParseMode.HTML)
await bot.send_message(chat_id=base.TEX_GROUP, text=f"<b>[ {str(dt.datetime.now())[:-10]} ]</b> "
f"<b><i>=></i></b> <i>{food[3]}</i> (нет данных по "
f"питанию)", parse_mode=types.ParseMode.HTML)
else:
await message.answer(f"<b>Вы вызывете команду в воскресенье!</b>\n\nНа что вы надеетесь?",
types.ParseMode.HTML)
# ИЛАЙН КЛАВИАТУРА
@dp.callback_query_handler(text=["z", "o", "p", "zo", "zp", "op", "zop"])
async def var(call: types.CallbackQuery):
et = {"z": "завтрак", "o": "обед", "p": "полдник", "zo": "завтрак / обед", "zp": "завтрак / полдник",
"op": "обед / полдник", "zop": "завтрак / обед / полдник"}
group_id = call.message.chat.id
if du.group_exists(group_id):
group_id = du.get_group_id(group_id)
if db.main_group_exists(group_id):
user_id = call.from_user.id
if du.user_exists(user_id):
user_id = du.get_user_id(user_id)
else:
du.add_user(user_id)
user_id = du.get_user_id(user_id)
if db.check_group_inproc(group_id):
if not dn.check_user(group_id, user_id):
flag = True
else:
await call.message.answer(f"{call.from_user.first_name}, вы уже сделали заказ! Отмените его с "
f"помощью кнопки отмены!")
flag = False
else:
dn.created_group(group_id)
db.add_group(group_id)
flag = True
if flag:
for i in str(call.data):
db.upd_stat_group(group_id, i, 1)
dg.upd_stat_user(group_id, user_id, i, 1)
ids = db.get_spec_group(group_id)
msg1 = await bot.send_message(chat_id=str(du.get_first_group_id(ids)),
text=f'[{call.from_user.first_name}](tg://user?id={call.from_user.id}) >> '
f'*{et[call.data].title()}*', parse_mode=types.ParseMode.MARKDOWN)
msg2 = await call.message.answer(text=f'{call.from_user.first_name}, всё принято, вы заказили - '
f'*{"и".join(et[call.data].split("/"))}*',
parse_mode=types.ParseMode.MARKDOWN)
dn.add_user(group_id, user_id, msg2.message_id, msg1.message_id, str(call.data))
else:
await call.message.answer('Вы должны через личные сообщения зарегистрировать этот чат у бота вместе с '
'дополнительным для отправки списка!')
else:
await call.message.answer('Вы должны через личные сообщения зарегистрировать этот чат у бота вместе с '
'дополнительным для отправки списка!')
@dp.callback_query_handler(text=["cnl"])
async def cnl(call: types.CallbackQuery):
user_id = du.get_user_id(call.from_user.id)
if db.user_tranzit_exists(user_id):
db.delete_tranzit(user_id)
await call.message.answer('<b>Заявка удалена!</b> Если ещё захотите связать группы, то зановой вызовите '
'команду <b>/add_group</b>', types.ParseMode.HTML)
else:
await call.message.answer('У вас нет оставленных заявок!')
@dp.callback_query_handler(text=["del"])
async def ver_del(call: types.CallbackQuery):
user_id = du.get_user_id(call.from_user.id)
if db.user_main_exists(user_id):
ids = db.get_main_group(user_id)
db.delete_main_group(user_id)
dg.delete_group(str(ids))
db.del_group(str(ids))
await call.message.answer('Всё успешно удалено!')
else:
await call.message.answer("У вас нет связки групп для их удаления!")
@dp.callback_query_handler(text=["cancel"])
async def cancel(call: types.CallbackQuery):
group_id = call.message.chat.id
if du.group_exists(group_id):
main_group_id = group_id
group_id = du.get_group_id(group_id)
if db.main_group_exists(group_id):
user_id = call.from_user.id
if du.user_exists(user_id):
user_id = du.get_user_id(user_id)
else:
du.add_user(user_id)
user_id = du.get_user_id(user_id)
if db.check_group_inproc(group_id):
if dn.check_user(group_id, user_id):
ord_id = dn.get_ord_id(group_id, user_id)
for i in ord_id:
db.upd_stat_group(group_id, i, -1)
dg.upd_stat_user(group_id, user_id, i, -1)
ids = db.get_spec_group(group_id)
set_group_id = str(du.get_first_group_id(ids))
main, sett = dn.get_message(group_id, user_id)
await bot.delete_message(chat_id=main_group_id, message_id=main)
await bot.delete_message(chat_id=set_group_id, message_id=sett)
dn.del_user(group_id, user_id)
await call.message.answer(f"{call.from_user.first_name}, ваш заказ отменён!")
else:
await call.message.answer(f"{call.from_user.first_name}, у вас нет заказа!")
else:
await call.message.answer(f"{call.from_user.first_name}, у вас нет заказа!")
else:
await call.message.answer('Вы ещё не можете использовать бота, завершите процедуру регистрации!')
else:
await call.message.answer('Вы должны через личные сообщения зарегистрировать этот чат у бота вместе с '
'дополнительным для отправки списка!')
# ТРЕКЕР НОВЫХ ПОЛЬЗОВАТЕЛЕЙ
@dp.message_handler(content_types=["text", "audio", "document", "photo", "sticker", "video",
"video_note", "voice", "location", "contact"])
async def check(message: types.Message):
if 0 > int(message.chat.id):
if du.user_exists(message.from_user.id):
user_id = du.get_user_id(message.from_user.id)
if db.user_tranzit_exists(user_id) and len(message.text) == 4:
cods = db.get_cods(user_id)
flag = False
if not du.group_exists(message.chat.id):
if message.text == str(cods[0]):
du.add_group(message.chat.id)
group_id = du.get_group_id(message.chat.id)
db.add_main_group(user_id, group_id)
flag = True
elif message.text == str(cods[1]):
du.add_group(message.chat.id)
group_id = du.get_group_id(message.chat.id)
db.add_set_group(user_id, group_id)
flag = True
else:
group_id = du.get_group_id(message.chat.id)
if not db.main_group_exists(group_id):
if message.text == str(cods[0]):
db.add_main_group(user_id, group_id)
flag = True
elif message.text == str(cods[1]):
db.add_set_group(user_id, group_id)
flag = True
if flag and db.user_tranzit(user_id):
ids = db.get_groups_ids(user_id)
db.add_active_groups(user_id, ids[0], ids[1])
db.delete_tranzit(user_id)
dg.created_group(ids[0])
dg.add_user(ids[0], user_id, message.from_user.first_name)
else:
if du.group_exists(message.chat.id):
group_id = du.get_group_id(message.chat.id)
if db.main_group_exists(group_id):
dg.update_name(user_id, message.from_user.first_name, group_id)
else:
if du.group_exists(message.chat.id):
group_id = du.get_group_id(message.chat.id)
if db.main_group_exists(group_id):
du.add_user(message.from_user.id)
user_id = du.get_user_id(message.from_user.id)
dg.add_user(group_id, user_id, message.from_user.first_name)
# ОТДЕЛЕНИЕ ДНЯ В ГРУППЕ
async def time(wait_for):
while True:
await asyncio.sleep(wait_for)
hour = dt.datetime.now().hour
date = dt.datetime.now().day
wkd = dt.datetime.today().weekday()
data = db.get_day()
if date != data and hour == 6:
for ids in db.get_spec_groups():
group = du.get_first_group_id(ids[0])
if wkd == 5:
dat = ".".join(reversed(str(dt.date.today() + dt.timedelta(days=2)).split("-")))
await bot.send_message(chat_id=group, text=f'<b>Питание на {dat}</b>',
parse_mode=types.ParseMode.HTML)
elif wkd != 6:
dat = ".".join(reversed(str(dt.date.today() + dt.timedelta(days=1)).split("-")))
await bot.send_message(chat_id=group, text=f'<b>Питание на {dat}</b>',
parse_mode=types.ParseMode.HTML)
db.update_day(date)
db.reset_proc()
os.remove('../db/now.db')
fle = open('../db/now.db', 'w+')
fle.close()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.create_task(time(600)) # ПРОВЕРКА КАЖДЫЕ 10 МИНУТ
executor.start_polling(dp, skip_updates=True)
import logging, asyncio, random, pymorphy2
import base, pars, sql, os
import datetime as dt
from aiogram import Bot, Dispatcher, executor, types
# log level
logging.basicConfig(level=logging.INFO)
morph = pymorphy2.MorphAnalyzer()
# bot init
bot = Bot(token=base.TOKEN)
dp = Dispatcher(bot)
# create now.db
file = open('../db/now.db', 'w+')
file.close()
# db init
db = sql.Base('../db/base.db')
du = sql.User('../db/users.db')
dg = sql.Group('../db/groups.db')
dn = sql.Now('../db/now.db')
@dp.message_handler(commands="start")
async def start(message: types.Message):
if 0 < int(message.chat.id):
await message.answer("Ghdbtn", types.ParseMode.MARKDOWN)
# ОБНОВЛЕНИЕ АЙДИ ГРУППЫ
@dp.message_handler(content_types=['migrate_to_chat_id', 'migrate_from_chat_id'])
async def chat_reload(message: types.Message):
if du.group_exists(message.migrate_from_chat_id):
du.update_group_id(message.migrate_from_chat_id, message.migrate_to_chat_id)
# КОМАНДЫ
@dp.message_handler(commands="help")
async def hlp(message: types.Message):
if 0 < int(message.chat.id):
await message.answer("*Инструкция использования:*\n\n"
"*/eat* - с помощью этой команды вы можете заказать питание\n"
"*/today* - команда выдающая меню на сегодня\n"
"*/tomorrow* - команда выдающая меню на завтра\n\n"
"*/add_group* - команда выдающая меню на завтра\n"
"*/del_group* - команда выдающая меню на завтра\n", types.ParseMode.MARKDOWN)
else:
await message.answer("*Инструкция использования:*\n\n"
"*/eat* - с помощью этой команды вы можете заказать питание\n"
"*/today* - команда выдающая меню на сегодня\n"
"*/tomorrow* - команда выдающая меню на завтра\n", types.ParseMode.MARKDOWN)
@dp.message_handler(commands="stat")
async def stat(message: types.Message):
if 0 > int(message.chat.id):
group_id = message.chat.id
if du.group_exists(group_id):
group_id = du.get_group_id(group_id)
if db.main_group_exists(group_id):
overall = db.stat_group(group_id)
all_users = dg.stat_all_users(group_id)
z = [[user[1], user[0]] for user in all_users if user[1] != 0]
o = [[user[2], user[0]] for user in all_users if user[2] != 0]
p = [[user[3], user[0]] for user in all_users if user[3] != 0]
txt = f"<i><b>Всего было сделано заказов - {sum(overall)}</b></i>\n"
line = morph.parse('заказ')[0]
lst = [[f"\n\t<b>* Завтраков - {str(overall[0])}</b>\n", z], [f"\n\t<b>* Обедов - {str(overall[1])}</b>\n", o],
[f"\n\t<b>* Полдников - {str(overall[2])}</b>\n", p]]
for i in lst:
txt = txt + i[0]
if i[1]:
for n, j in enumerate(i[1][:3]):
txt = txt + "\t\t\t<b>" + str(n + 1) + ". " + j[1] + "</b> " + str(j[0]) + " " + line.make_agree_with_number(j[0]).word + "\n"
await message.answer(txt, types.ParseMode.HTML)
else:
await message.answer("Ваша группа не зарегистрирована!")
else:
await message.answer("Ваша группа не зарегистрирована!")
@dp.message_handler(commands="eat")
async def eat(message: types.Message):
if 0 > int(message.chat.id):
keyboard1 = {"inline_keyboard":
[[{"text": "Завтрак", "callback_data": "z"}, {"text": "Обед", "callback_data": "o"},
{"text": "Полдник", "callback_data": "p"}], [{"text": "Завтрак / Обед", "callback_data": "zo"}],
[{"text": "Завтрак / Полдник", "callback_data": "zp"}],
[{"text": "Обед / Полдник", "callback_data": "op"}],
[{"text": "Завтрак / Обед / Полдник", "callback_data": "zop"}]]}
await bot.send_message(chat_id=message.chat.id,
text='*Это меню выбора притания!* Всё, что вам надо сделать, это лишь выбрать '
'необходимый заказ.\n\nEсли после нажатия бот написал, что вы выбрали, то всё '
'прошло успешно и вы можете не беспокоиться!', parse_mode=types.ParseMode.MARKDOWN,
reply_markup=keyboard1)
keyboard2 = {"inline_keyboard": [[{"text": "Отменить заказ", "callback_data": "cancel"}]]}
await bot.send_message(chat_id=message.chat.id,
text='Если вы хотите сменить заказ, то отмените действующий заказ по кнопке ниже и '
'закажите заново!', parse_mode=types.ParseMode.MARKDOWN,
reply_markup=keyboard2)
else:
await message.answer("Эта команда доступна к использованию *только в чатах*", types.ParseMode.MARKDOWN)
@dp.message_handler(commands="del_group")
async def delg(message: types.Message):
if 0 < int(message.chat.id):
user_id = message.from_user.id
if du.user_exists(user_id):
user_id = du.get_user_id(user_id)
if db.user_main_exists(user_id):
keyboard = {"inline_keyboard": [[{"text": "Подтвердить удаление", "callback_data": "del"}]]}
await bot.send_message(chat_id=message.chat.id,
text='Вы точно хотите удалить статистику и связку групп?',
parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard)
else:
await message.answer("У вас нет связки групп для их удаления!")
else:
await message.answer("У вас нет связки групп для их удаления!")
else:
await message.answer("Эта команда доступна к использованию *только в личном чате*", types.ParseMode.MARKDOWN)
@dp.message_handler(commands="add_group")
async def addg(message: types.Message):
if 0 < int(message.chat.id):
user_id = message.from_user.id
flag = False
if not du.user_exists(user_id):
du.add_user(user_id)
user_id = du.get_user_id(user_id)
all_cods = db.all_cods()
cod1 = random.randint(1000, 9999)
while cod1 in all_cods[0]:
cod1 = random.randint(1000, 9999)
cod2 = random.randint(1000, 9999)
while cod2 in all_cods[1]:
cod2 = random.randint(1000, 9999)
db.add_user_tranzit(user_id, cod1, cod2)
await message.answer(f"Введите этот код в группе с учениками - *{str(cod1)}*, а этот в личной для "
f"фиксации заказа - *{str(cod2)}*", types.ParseMode.MARKDOWN)
flag = True
else:
user_id = du.get_user_id(user_id)
if db.user_tranzit_exists(user_id):
cods = db.get_cods(user_id)
await message.answer(f"Введите этот код в основной группе с учениками - *{str(cods[0])}*, а этот в "
f"личной для фиксации заказа - *{str(cods[1])}*", types.ParseMode.MARKDOWN)
flag = True
else:
if not db.user_main_exists(user_id):
all_cods = db.all_cods()
cod1 = random.randint(1000, 9999)
while cod1 in all_cods[0]:
cod1 = random.randint(1000, 9999)
cod2 = random.randint(1000, 9999)
while cod2 in all_cods[1]:
cod2 = random.randint(1000, 9999)
db.add_user_tranzit(user_id, cod1, cod2)
await message.answer(f"Введите этот код в группе с учениками - *{str(cod1)}*, а этот в личной для "
f"фиксации заказа - *{str(cod2)}*", types.ParseMode.MARKDOWN)
flag = True
else:
await message.answer("У вас уже есть связка группы, вам надо её удалить, прежде чем верифицировать "
"новую!", types.ParseMode.MARKDOWN)
if flag:
keyboard = {"inline_keyboard": [[{"text": "Отменить верификацию", "callback_data": "cnl"}]]}
await bot.send_message(chat_id=message.chat.id,
text='*Вы можете отменить заявку* если не хотите связывать группы для сбора '
'заказов питания!', parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard)
else:
await message.answer("Эта команда доступна к использованию *только в личном чате*", types.ParseMode.MARKDOWN)
@dp.message_handler(commands=["today", "tomorrow"])
async def todtom(message: types.Message):
food = pars.eating(0 if "today" in message.text else 1)
if food[0]:
food = food[1]
if "today" in message.text:
et = f"<b>Питание за {'.'.join(reversed(str(dt.date.today()).split('-')))}</b>\n\n"
else:
et = f"<b>Питание за {'.'.join(reversed(str(dt.date.today() + dt.timedelta(days=1)).split('-')))}</b>\n\n"
for j in food:
et = et + "<i><b>" + str(j) + ":</b></i>\n"
for i in food[j]:
et = et + "<b>* " + str(i[0]) + "</b> <i>[ "
et = et + str(i[1][0]) + " г. " + str(i[1][1]) + " ккал. ]</i>" + "\n"
et = et + "\n\n"
await message.answer(et, types.ParseMode.HTML)
else:
if food[1]:
await message.answer(f"<b>Ошибка в системе бота!</b>\n\nОна будет в скором времени исправлена...",
types.ParseMode.HTML)
await bot.send_message(chat_id=base.TEX_GROUP, text=f"<b>[ {str(dt.datetime.now())[:-10]} ]</b> "
f"<b><i>=></i></b> <i>{food[3]}</i> (ошибка в системе)",
parse_mode=types.ParseMode.HTML)
else:
if food[2] != 6:
await message.answer(f"<b>Нет данных по питанию!</b>\n\nКак только данные появятся вы сможете "
f"их получить этой же командой!", types.ParseMode.HTML)
await bot.send_message(chat_id=base.TEX_GROUP, text=f"<b>[ {str(dt.datetime.now())[:-10]} ]</b> "
f"<b><i>=></i></b> <i>{food[3]}</i> (нет данных по "
f"питанию)", parse_mode=types.ParseMode.HTML)
else:
await message.answer(f"<b>Вы вызывете команду в воскресенье!</b>\n\nНа что вы надеетесь?",
types.ParseMode.HTML)
# ИЛАЙН КЛАВИАТУРА
@dp.callback_query_handler(text=["z", "o", "p", "zo", "zp", "op", "zop"])
async def var(call: types.CallbackQuery):
et = {"z": "завтрак", "o": "обед", "p": "полдник", "zo": "завтрак / обед", "zp": "завтрак / полдник",
"op": "обед / полдник", "zop": "завтрак / обед / полдник"}
group_id = call.message.chat.id
if du.group_exists(group_id):
group_id = du.get_group_id(group_id)
if db.main_group_exists(group_id):
user_id = call.from_user.id
if du.user_exists(user_id):
user_id = du.get_user_id(user_id)
else:
du.add_user(user_id)
user_id = du.get_user_id(user_id)
if db.check_group_inproc(group_id):
if not dn.check_user(group_id, user_id):
flag = True
else:
await call.message.answer(f"{call.from_user.first_name}, вы уже сделали заказ! Отмените его с "
f"помощью кнопки отмены!")
flag = False
else:
dn.created_group(group_id)
db.add_group(group_id)
flag = True
if flag:
for i in str(call.data):
db.upd_stat_group(group_id, i, 1)
dg.upd_stat_user(group_id, user_id, i, 1)
ids = db.get_spec_group(group_id)
msg1 = await bot.send_message(chat_id=str(du.get_first_group_id(ids)),
text=f'[{call.from_user.first_name}](tg://user?id={call.from_user.id}) >> '
f'*{et[call.data].title()}*', parse_mode=types.ParseMode.MARKDOWN)
msg2 = await call.message.answer(text=f'{call.from_user.first_name}, всё принято, вы заказили - '
f'*{"и".join(et[call.data].split("/"))}*',
parse_mode=types.ParseMode.MARKDOWN)
dn.add_user(group_id, user_id, msg2.message_id, msg1.message_id, str(call.data))
else:
await call.message.answer('Вы должны через личные сообщения зарегистрировать этот чат у бота вместе с '
'дополнительным для отправки списка!')
else:
await call.message.answer('Вы должны через личные сообщения зарегистрировать этот чат у бота вместе с '
'дополнительным для отправки списка!')
@dp.callback_query_handler(text=["cnl"])
async def cnl(call: types.CallbackQuery):
user_id = du.get_user_id(call.from_user.id)
if db.user_tranzit_exists(user_id):
db.delete_tranzit(user_id)
await call.message.answer('<b>Заявка удалена!</b> Если ещё захотите связать группы, то зановой вызовите '
'команду <b>/add_group</b>', types.ParseMode.HTML)
else:
await call.message.answer('У вас нет оставленных заявок!')
@dp.callback_query_handler(text=["del"])
async def ver_del(call: types.CallbackQuery):
user_id = du.get_user_id(call.from_user.id)
if db.user_main_exists(user_id):
ids = db.get_main_group(user_id)
db.delete_main_group(user_id)
dg.delete_group(str(ids))
db.del_group(str(ids))
await call.message.answer('Всё успешно удалено!')
else:
await call.message.answer("У вас нет связки групп для их удаления!")
@dp.callback_query_handler(text=["cancel"])
async def cancel(call: types.CallbackQuery):
group_id = call.message.chat.id
if du.group_exists(group_id):
main_group_id = group_id
group_id = du.get_group_id(group_id)
if db.main_group_exists(group_id):
user_id = call.from_user.id
if du.user_exists(user_id):
user_id = du.get_user_id(user_id)
else:
du.add_user(user_id)
user_id = du.get_user_id(user_id)
if db.check_group_inproc(group_id):
if dn.check_user(group_id, user_id):
ord_id = dn.get_ord_id(group_id, user_id)
for i in ord_id:
db.upd_stat_group(group_id, i, -1)
dg.upd_stat_user(group_id, user_id, i, -1)
ids = db.get_spec_group(group_id)
set_group_id = str(du.get_first_group_id(ids))
main, sett = dn.get_message(group_id, user_id)
await bot.delete_message(chat_id=main_group_id, message_id=main)
await bot.delete_message(chat_id=set_group_id, message_id=sett)
dn.del_user(group_id, user_id)
await call.message.answer(f"{call.from_user.first_name}, ваш заказ отменён!")
else:
await call.message.answer(f"{call.from_user.first_name}, у вас нет заказа!")
else:
await call.message.answer(f"{call.from_user.first_name}, у вас нет заказа!")
else:
await call.message.answer('Вы ещё не можете использовать бота, завершите процедуру регистрации!')
else:
await call.message.answer('Вы должны через личные сообщения зарегистрировать этот чат у бота вместе с '
'дополнительным для отправки списка!')
# ТРЕКЕР НОВЫХ ПОЛЬЗОВАТЕЛЕЙ
@dp.message_handler(content_types=["text", "audio", "document", "photo", "sticker", "video",
"video_note", "voice", "location", "contact"])
async def check(message: types.Message):
if 0 > int(message.chat.id):
if du.user_exists(message.from_user.id):
user_id = du.get_user_id(message.from_user.id)
if db.user_tranzit_exists(user_id) and len(message.text) == 4:
cods = db.get_cods(user_id)
flag = False
if not du.group_exists(message.chat.id):
if message.text == str(cods[0]):
du.add_group(message.chat.id)
group_id = du.get_group_id(message.chat.id)
db.add_main_group(user_id, group_id)
flag = True
elif message.text == str(cods[1]):
du.add_group(message.chat.id)
group_id = du.get_group_id(message.chat.id)
db.add_set_group(user_id, group_id)
flag = True
else:
group_id = du.get_group_id(message.chat.id)
if not db.main_group_exists(group_id):
if message.text == str(cods[0]):
db.add_main_group(user_id, group_id)
flag = True
elif message.text == str(cods[1]):
db.add_set_group(user_id, group_id)
flag = True
if flag and db.user_tranzit(user_id):
ids = db.get_groups_ids(user_id)
db.add_active_groups(user_id, ids[0], ids[1])
db.delete_tranzit(user_id)
dg.created_group(ids[0])
dg.add_user(ids[0], user_id, message.from_user.first_name)
else:
if du.group_exists(message.chat.id):
group_id = du.get_group_id(message.chat.id)
if db.main_group_exists(group_id):
dg.update_name(user_id, message.from_user.first_name, group_id)
else:
if du.group_exists(message.chat.id):
group_id = du.get_group_id(message.chat.id)
if db.main_group_exists(group_id):
du.add_user(message.from_user.id)
user_id = du.get_user_id(message.from_user.id)
dg.add_user(group_id, user_id, message.from_user.first_name)
# ОТДЕЛЕНИЕ ДНЯ В ГРУППЕ
async def time(wait_for):
while True:
await asyncio.sleep(wait_for)
hour = dt.datetime.now().hour
date = dt.datetime.now().day
wkd = dt.datetime.today().weekday()
data = db.get_day()
if date != data and hour == 6:
for ids in db.get_spec_groups():
group = du.get_first_group_id(ids[0])
if wkd == 5:
dat = ".".join(reversed(str(dt.date.today() + dt.timedelta(days=2)).split("-")))
await bot.send_message(chat_id=group, text=f'<b>Питание на {dat}</b>',
parse_mode=types.ParseMode.HTML)
elif wkd != 6:
dat = ".".join(reversed(str(dt.date.today() + dt.timedelta(days=1)).split("-")))
await bot.send_message(chat_id=group, text=f'<b>Питание на {dat}</b>',
parse_mode=types.ParseMode.HTML)
db.update_day(date)
db.reset_proc()
os.remove('../db/now.db')
fle = open('../db/now.db', 'w+')
fle.close()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.create_task(time(600)) # ПРОВЕРКА КАЖДЫЕ 10 МИНУТ
executor.start_polling(dp, skip_updates=True)

View file

@ -1,52 +1,69 @@
import requests as req
import datetime as dt
import openpyxl, os, re
def eating(day):
if day == 0:
wkd = dt.datetime.today().weekday()
else:
wkd = (dt.date.today() + dt.timedelta(days=1)).weekday()
if wkd != 6:
flag = False
try:
if day == 0:
eat = f"https://www.school01.ru/food/{str(dt.date.today())}-sm.xlsx"
else:
eat = f"https://www.school01.ru/food/{str(dt.date.today() + dt.timedelta(days=1))}-sm.xlsx"
file, xls = open("school_food.xlsx", "wb"), req.get(eat)
file.write(xls.content)
file.close()
excel_file = openpyxl.load_workbook('school_food.xlsx')
employees_sheet = excel_file[excel_file.sheetnames[0]]
food = {employees_sheet["A4"].value: [], employees_sheet["A12"].value: []}
food_info = [[employees_sheet["A4"].value, 4, 8], [employees_sheet["A12"].value, 12, 9]]
flag = True
if employees_sheet["A22"].value is not None:
food[employees_sheet["A22"].value] = []
food_info.append([employees_sheet["A22"].value, 21, 2])
for j in food_info:
for i in range(j[2]):
if employees_sheet[f"D{j[1] + i}"].value is None:
continue
gramm = str(int(eval(str(employees_sheet[f"E{j[1] + i}"].value).strip())))
kkal = str(eval("".join(str(employees_sheet[f"J{j[1] + i}"].value).split()).replace(",", ".", 1)))
food[j[0]].append([employees_sheet[f"D{j[1] + i}"].value, [gramm, kkal]])
os.remove("school_food.xlsx")
return [True, food]
except Exception as e:
return [False, flag, wkd, repr(e)]
else:
return [False, False, wkd]
import ast
import operator
import requests as req
import datetime as dt
import openpyxl, os, re
_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv}
def arithmetic(text):
"""Значение ячейки вида «150» или «150+30»: только числа и + - * /, без eval."""
def calc(node):
if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
return node.value
if isinstance(node, ast.BinOp) and type(node.op) in _OPS:
return _OPS[type(node.op)](calc(node.left), calc(node.right))
if isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub):
return -calc(node.operand)
raise ValueError(f"недопустимое значение в ячейке: {text!r}")
return calc(ast.parse(text, mode="eval").body)
def eating(day):
if day == 0:
wkd = dt.datetime.today().weekday()
else:
wkd = (dt.date.today() + dt.timedelta(days=1)).weekday()
if wkd != 6:
flag = False
try:
if day == 0:
eat = f"https://www.school01.ru/food/{str(dt.date.today())}-sm.xlsx"
else:
eat = f"https://www.school01.ru/food/{str(dt.date.today() + dt.timedelta(days=1))}-sm.xlsx"
file, xls = open("school_food.xlsx", "wb"), req.get(eat)
file.write(xls.content)
file.close()
excel_file = openpyxl.load_workbook('school_food.xlsx')
employees_sheet = excel_file[excel_file.sheetnames[0]]
food = {employees_sheet["A4"].value: [], employees_sheet["A12"].value: []}
food_info = [[employees_sheet["A4"].value, 4, 8], [employees_sheet["A12"].value, 12, 9]]
flag = True
if employees_sheet["A22"].value is not None:
food[employees_sheet["A22"].value] = []
food_info.append([employees_sheet["A22"].value, 21, 2])
for j in food_info:
for i in range(j[2]):
if employees_sheet[f"D{j[1] + i}"].value is None:
continue
gramm = str(int(arithmetic(str(employees_sheet[f"E{j[1] + i}"].value).strip())))
kkal = str(arithmetic("".join(str(employees_sheet[f"J{j[1] + i}"].value).split()).replace(",", ".", 1)))
food[j[0]].append([employees_sheet[f"D{j[1] + i}"].value, [gramm, kkal]])
os.remove("school_food.xlsx")
return [True, food]
except Exception as e:
return [False, flag, wkd, repr(e)]
else:
return [False, False, wkd]