-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPROJECT-budget-app.py
157 lines (124 loc) · 5.15 KB
/
PROJECT-budget-app.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
OUTPUT_SPACES = 1
DESC_MAX_LEN = 23
AMOUNT_MAX_LEN = 7
class Category:
def __init__(self, category='other'):
self.ledger = []
self.category = category
def __str__(self):
width = DESC_MAX_LEN + AMOUNT_MAX_LEN
stars_amount = (width - len(self.category)) // 2
category_str = ''
category_str += '*' * stars_amount
category_str += str(self.category)
category_str += '*' * stars_amount
while len(category_str) < width:
category_str += '*'
category_str += '\n'
for item in self.ledger:
category_str += f'{item["description"][:DESC_MAX_LEN]:{DESC_MAX_LEN}}' + \
f'{self.format_amount(item["amount"])[:AMOUNT_MAX_LEN]:>{AMOUNT_MAX_LEN}}\n'
category_str += f'Total: {self.format_amount(self.get_balance())}'
return category_str
def get_name(self):
return str(self.category)
def format_amount(self, amount):
return str("{:.2f}".format(amount))
def deposit(self, amount, description=''):
if amount:
self.ledger.append({'amount': amount,
'description': description})
else:
print('No deposit amount')
def withdraw(self, amount, description=''):
if not self.check_funds(float(amount)):
return False
self.ledger.append({'amount': -float(amount),
'description': description})
return True
def get_balance(self):
return sum(map(lambda x: float(x['amount']), self.ledger))
def transfer(self, amount, dest_category):
if not amount:
print('No amount to transfer')
return False
elif self.get_balance() < amount:
print('Not enought funds for transfer')
return False
transfer_description = f'Transfer to {dest_category.get_name()}'
if self.withdraw(amount, f'Transfer to {dest_category.get_name()}'):
dest_category.deposit(amount, f'Transfer from {self.get_name()}')
return True
def check_funds(self, amount):
return float(amount) <= sum(map(lambda x: float(x['amount']), self.ledger))
def total_spent(self):
return self.format_amount(sum(map(lambda x: x['amount'] if x['amount'] < 0 else 0, self.ledger)))
CHART_OFFSET = 1
CATEGORY_START_INDEX = 5
def create_spend_chart(categories):
cat_amount = len(categories)
line_width = (cat_amount * 3) + 1
chart_str_lines = ['Percentage spent by category\n']
for i in range(10, -1, -1):
chart_str_lines.append(f'{str(i * 10):>3}|{" " * line_width}\n')
chart_str_lines.append(' ' * 4 + '-' * line_width + '\n')
total_spent = 0
cat_spent = []
for cat in categories:
total_spent += -float(cat.total_spent()) if cat.total_spent() != 0 else 0
cat_spent.append(-float(cat.total_spent()) if cat.total_spent() != 0 else 0)
cat_index = CATEGORY_START_INDEX
for cat in cat_spent:
percent = (cat / total_spent) * 100
for i in range(int(percent / 10)):
line_index = 10 - i
chart_str_lines[line_index] = chart_str_lines[line_index][:cat_index] + 'o' + \
chart_str_lines[line_index][cat_index + 1:]
cat_index += 3
# fill zero line
cat_index = CATEGORY_START_INDEX
for i in range(len(categories)):
chart_str_lines[11] = chart_str_lines[11][:cat_index] + 'o' + \
chart_str_lines[11][cat_index + 1:]
cat_index += 3
# add category description
max_category_name = max(map(lambda x: len(x.get_name()), categories))
for i in range(max_category_name):
chart_str_lines.append(' ' * 4 + ' ' * line_width + ('\n' if i < max_category_name - 1 else ''))
cat_index = CATEGORY_START_INDEX
start_legend_line = 13
for cat in categories:
cat_name_idx = 0
for line_idx in range(start_legend_line, start_legend_line + max_category_name):
chart_str_lines[line_idx] = chart_str_lines[line_idx][:cat_index] + \
cat.get_name()[cat_name_idx] + \
chart_str_lines[line_idx][cat_index + 1:]
if cat_name_idx < len(cat.get_name()) - 1:
cat_name_idx += 1
else:
break
cat_index += 3
cat_name_idx = 0
return ''.join(chart_str_lines)
if __name__ == '__main__':
food = Category('Food')
food.deposit(1000, 'deposit')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(10.15, 'groceries')
food.withdraw(15.89, 'restaurant and more food for dessert')
clothing = Category('Clothing')
food.transfer(50, clothing)
clothing.withdraw(20.15, 'groceries')
entertainment = Category('Entertainment')
entertainment.deposit(1000, 'deposit')
entertainment.withdraw(200, 'concert')
print(food)
print(create_spend_chart([food, clothing, entertainment]))