forked from alexey-goloburdin/telegram-finance-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexpenses.py
133 lines (108 loc) · 5.38 KB
/
expenses.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
""" Работа с расходами — их добавление, удаление, статистики"""
import datetime
import re
from typing import List, NamedTuple, Optional
import pytz
import db
import exceptions
from categories import Categories
class Message(NamedTuple):
"""Структура распаршенного сообщения о новом расходе"""
amount: int
category_text: str
class Expense(NamedTuple):
"""Структура добавленного в БД нового расхода"""
id: Optional[int]
amount: int
category_name: str
def add_expense(raw_message: str) -> Expense:
"""Добавляет новое сообщение.
Принимает на вход текст сообщения, пришедшего в бот."""
parsed_message = _parse_message(raw_message)
category = Categories().get_category(
parsed_message.category_text)
inserted_row_id = db.insert("expense", {
"amount": parsed_message.amount,
"created": _get_now_formatted(),
"category_codename": category.codename,
"raw_text": raw_message
})
return Expense(id=None,
amount=parsed_message.amount,
category_name=category.name)
def get_today_statistics() -> str:
"""Возвращает строкой статистику расходов за сегодня"""
cursor = db.get_cursor()
cursor.execute("select sum(amount)"
"from expense where date(created)=date('now', 'localtime')")
result = cursor.fetchone()
if not result[0]:
return "Сегодня ещё нет расходов"
all_today_expenses = result[0]
cursor.execute("select sum(amount) "
"from expense where date(created)=date('now', 'localtime') "
"and category_codename in (select codename "
"from category where is_base_expense=true)")
result = cursor.fetchone()
base_today_expenses = result[0] if result[0] else 0
return (f"Расходы сегодня:\n"
f"всего — {all_today_expenses} руб.\n"
f"базовые — {base_today_expenses} руб. из {_get_budget_limit()} руб.\n\n"
f"За текущий месяц: /month")
def get_month_statistics() -> str:
"""Возвращает строкой статистику расходов за текущий месяц"""
now = _get_now_datetime()
first_day_of_month = f'{now.year:04d}-{now.month:02d}-01'
cursor = db.get_cursor()
cursor.execute(f"select sum(amount) "
f"from expense where date(created) >= '{first_day_of_month}'")
result = cursor.fetchone()
if not result[0]:
return "В этом месяце ещё нет расходов"
all_today_expenses = result[0]
cursor.execute(f"select sum(amount) "
f"from expense where date(created) >= '{first_day_of_month}' "
f"and category_codename in (select codename "
f"from category where is_base_expense=true)")
result = cursor.fetchone()
base_today_expenses = result[0] if result[0] else 0
return (f"Расходы в текущем месяце:\n"
f"всего — {all_today_expenses} руб.\n"
f"базовые — {base_today_expenses} руб. из "
f"{now.day * _get_budget_limit()} руб.")
def last() -> List[Expense]:
"""Возвращает последние несколько расходов"""
cursor = db.get_cursor()
cursor.execute(
"select e.id, e.amount, c.name "
"from expense e left join category c "
"on c.codename=e.category_codename "
"order by created desc limit 10")
rows = cursor.fetchall()
last_expenses = [Expense(id=row[0], amount=row[1], category_name=row[2]) for row in rows]
return last_expenses
def delete_expense(row_id: int) -> None:
"""Удаляет сообщение по его идентификатору"""
db.delete("expense", row_id)
def _parse_message(raw_message: str) -> Message:
"""Парсит текст пришедшего сообщения о новом расходе."""
regexp_result = re.match(r"([\d ]+) (.*)", raw_message)
if not regexp_result or not regexp_result.group(0) \
or not regexp_result.group(1) or not regexp_result.group(2):
raise exceptions.NotCorrectMessage(
"Не могу понять сообщение. Напишите сообщение в формате, "
"например:\n1500 метро")
amount = regexp_result.group(1).replace(" ", "")
category_text = regexp_result.group(2).strip().lower()
return Message(amount=amount, category_text=category_text)
def _get_now_formatted() -> str:
"""Возвращает сегодняшнюю дату строкой"""
return _get_now_datetime().strftime("%Y-%m-%d %H:%M:%S")
def _get_now_datetime() -> datetime.datetime:
"""Возвращает сегодняшний datetime с учётом времненной зоны Мск."""
tz = pytz.timezone("Europe/Moscow")
now = datetime.datetime.now(tz)
return now
def _get_budget_limit() -> int:
"""Возвращает дневной лимит трат для основных базовых трат"""
return db.fetchall("budget", ["daily_limit"])[0]["daily_limit"]