-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
156 lines (121 loc) · 4.36 KB
/
app.py
File metadata and controls
156 lines (121 loc) · 4.36 KB
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
"""
Expense Tracker Application
A simple Flask-based expense tracking application with CRUD operations.
"""
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from datetime import datetime
import json
app = Flask(__name__)
app.secret_key = 'dev-secret-key-change-in-production'
# In-memory data store
expenses = []
next_id = 1
CATEGORIES = [
'Food & Dining',
'Transportation',
'Shopping',
'Entertainment',
'Bills & Utilities',
'Healthcare',
'Other'
]
class Expense:
"""Represents a single expense entry."""
def __init__(self, amount, category, description, date=None, expense_id=None):
global next_id
self.id = expense_id if expense_id else next_id
if not expense_id:
next_id += 1
self.amount = float(amount)
self.category = category
self.description = description
self.date = date if date else datetime.now().strftime('%Y-%m-%d')
def to_dict(self):
"""Convert expense to dictionary."""
return {
'id': self.id,
'amount': self.amount,
'category': self.category,
'description': self.description,
'date': self.date
}
@app.route('/')
def index():
"""Display all expenses with optional filtering."""
category_filter = request.args.get('category', '')
filtered_expenses = expenses
if category_filter:
filtered_expenses = [e for e in expenses if e.category == category_filter]
total = sum(e.amount for e in filtered_expenses)
return render_template(
'index.html',
expenses=filtered_expenses,
categories=CATEGORIES,
selected_category=category_filter,
total=total
)
@app.route('/add', methods=['POST'])
def add_expense():
"""Add a new expense."""
try:
amount = request.form.get('amount')
category = request.form.get('category')
description = request.form.get('description')
date = request.form.get('date')
# Validation
if not amount or not category or not description:
flash('All fields are required!', 'error')
return redirect(url_for('index'))
if float(amount) <= 0:
flash('Amount must be greater than zero!', 'error')
return redirect(url_for('index'))
expense = Expense(amount, category, description, date)
expenses.append(expense)
flash(f'Expense of ${expense.amount:.2f} added successfully!', 'success')
return redirect(url_for('index'))
except ValueError:
flash('Invalid amount! Please enter a valid number.', 'error')
return redirect(url_for('index'))
except Exception as e:
flash(f'Error adding expense: {str(e)}', 'error')
return redirect(url_for('index'))
@app.route('/delete/<int:expense_id>', methods=['POST'])
def delete_expense(expense_id):
"""Delete an expense by ID."""
global expenses
expense = next((e for e in expenses if e.id == expense_id), None)
if expense:
expenses[:] = [e for e in expenses if e.id != expense_id] # Update in place
flash(f'Expense deleted successfully!', 'success')
else:
flash('Expense not found!', 'error')
return redirect(url_for('index'))
@app.route('/api/expenses', methods=['GET'])
def get_expenses_api():
"""API endpoint to get all expenses as JSON."""
return jsonify([e.to_dict() for e in expenses])
@app.route('/api/summary', methods=['GET'])
def get_summary_api():
"""API endpoint to get expense summary by category."""
summary = {}
for expense in expenses:
if expense.category in summary:
summary[expense.category] += expense.amount
else:
summary[expense.category] = expense.amount
total = sum(summary.values())
return jsonify({
'by_category': summary,
'total': total,
'count': len(expenses)
})
@app.route('/clear', methods=['POST'])
def clear_expenses():
"""Clear all expenses (useful for testing)."""
global expenses, next_id
expenses[:] = [] # Clear in place instead of reassigning
next_id = 1
flash('All expenses cleared!', 'success')
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)