From 572f801db20746e16ced239542bd884b8c451a71 Mon Sep 17 00:00:00 2001 From: rinatomi <2371348756@qq.com> Date: Tue, 14 Apr 2026 17:16:43 +0800 Subject: [PATCH] feat: implement budget monitoring with visual progress bar and alerts --- app.py | 63 +++++++++++++++++++++++++++++++++++++++++-- finance.db | Bin 16384 -> 24576 bytes templates/index.html | 60 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 2 deletions(-) diff --git a/app.py b/app.py index 151f494..1d1e672 100644 --- a/app.py +++ b/app.py @@ -37,11 +37,22 @@ class Transaction(db.Model): category = db.relationship('Category', backref=db.backref('transactions', lazy=True)) +class Budget(db.Model): + id = db.Column(db.Integer, primary_key=True) + month = db.Column(db.Integer, nullable=False) + year = db.Column(db.Integer, nullable=False) + amount = db.Column(db.Float, nullable=False, default=0) + + __table_args__ = (db.UniqueConstraint('month', 'year', name='_month_year_uc'),) + + # Create database and tables if they don't exist with app.app_context(): + db.create_all() if not os.path.exists(DATABASE_PATH): - db.create_all() print("Database created successfully!") + else: + print("Database tables updated successfully!") # Home Page (Redirect to Summary) @@ -53,9 +64,31 @@ def index(): # Summary Page @app.route('/summary') def summary(): + now = datetime.now() + current_month = now.month + current_year = now.year + total_income = db.session.query(db.func.sum(Transaction.amount)).filter_by(type="income").scalar() or 0 total_expense = db.session.query(db.func.sum(Transaction.amount)).filter_by(type="expense").scalar() or 0 + monthly_expense = db.session.query(db.func.sum(Transaction.amount)).filter( + Transaction.type == "expense", + db.func.strftime('%m', Transaction.date) == f'{current_month:02d}', + db.func.strftime('%Y', Transaction.date) == str(current_year) + ).scalar() or 0 + + budget = Budget.query.filter_by(month=current_month, year=current_year).first() + budget_amount = budget.amount if budget else 0 + + budget_percentage = 0 + budget_status = 'normal' + if budget_amount > 0: + budget_percentage = (monthly_expense / budget_amount) * 100 + if budget_percentage >= 100: + budget_status = 'danger' + elif budget_percentage >= 80: + budget_status = 'warning' + income_summary = db.session.query(Category.name, db.func.sum(Transaction.amount), Category.chart_color) \ .join(Transaction).filter(Transaction.type == "income") \ .group_by(Category.name, Category.chart_color).all() @@ -72,9 +105,35 @@ def summary(): total_expense=total_expense, income_summary=income_summary, expense_summary=expense_summary, - categories=categories + categories=categories, + monthly_expense=monthly_expense, + budget_amount=budget_amount, + budget_percentage=min(budget_percentage, 100), + budget_status=budget_status, + current_month=calendar.month_name[current_month], + current_year=current_year ) + +# Set Budget +@app.route('/set_budget', methods=['POST']) +def set_budget(): + now = datetime.now() + current_month = now.month + current_year = now.year + amount = float(request.form.get('budget_amount', 0)) + + budget = Budget.query.filter_by(month=current_month, year=current_year).first() + if budget: + budget.amount = amount + else: + budget = Budget(month=current_month, year=current_year, amount=amount) + db.session.add(budget) + + db.session.commit() + flash("Budget updated successfully!", "success") + return redirect(url_for('summary')) + @app.route('/analytics-data') def analytics_data(): import calendar diff --git a/finance.db b/finance.db index 71871c72d3f40c3725df0e31a8b2a45485250878..27dbf51836d510caabf9aa52d50efa92a76e49ad 100644 GIT binary patch delta 434 zcmZo@U~D+RI6+!aiGhKE4TxcYd7_T7xDtb2-cDZr9}KKKw;1^T^B?DZ$a9N#%f`kO z9{t8}7Itw-NycW*lEkE()TGjs^wbgv$?6>B>KNjx5aQ_MPWei1Wgf4|_6AV;7^g?O+T@gVi_ zrO67Rex8A$t_m7pQ5^-4uqKzLHY=OBz2xMx{1W^S+v5!(G~4Efyvj;)yuAAu`LFOV z=da>d;QPXNg5Q^K4qpMEGoKjmE8cyZ6$R$-MriS|GdMCzGx8c47@6rBnCKdsC>R)6 zfsvj87>J}+6r|=Ar!r~r0@X4}bK+6Uum!4kvzXm0MlN1pI5YBpVc`F=Sy5pI|HKJF jVqA=@42(=nEbOlsPH=&xe=zX>fJ%pPu(L2SaRMa)!76g) delta 96 zcmZoTz}V2hI6+!aj)8%J1&CpQX`+s?upEP4+ACiE9}LXA4;lFW^B?DZxLHvkpLg>^ sUS%aIZay(a{ww^;`K$O9_`dL+;P>U5!&kuP%qIp^^n-V^nB6Nz00*5IB>(^b diff --git a/templates/index.html b/templates/index.html index 603c361..5e969de 100644 --- a/templates/index.html +++ b/templates/index.html @@ -8,6 +8,61 @@

Summary

Remaining Balance: ${{ total_income - total_expense }}

+ +
+
+

{{ current_month }} {{ current_year }} Budget

+ +
+ + {% if budget_amount > 0 %} +
+
+ Spent: ${{ "%.2f"|format(monthly_expense) }} / ${{ "%.2f"|format(budget_amount) }} + {{ "%.1f"|format(budget_percentage) }}% +
+
+
+ {% if budget_percentage >= 10 %} + {{ "%.0f"|format(budget_percentage) }}% + {% endif %} +
+
+ {% if budget_status == 'danger' %} +

⚠️ Budget exceeded! You've spent over 100% of your budget.

+ {% elif budget_status == 'warning' %} +

⚠️ Warning: You've spent over 80% of your budget.

+ {% endif %} +
+ {% else %} +

No budget set for this month. Click "Set Budget" to create one.

+ {% endif %} +
+ + + +
@@ -106,6 +161,11 @@

Add Transaction

const form = document.getElementById("transaction-form"); form.classList.toggle("hidden"); } + + function toggleBudgetForm() { + const form = document.getElementById("budget-form"); + form.classList.toggle("hidden"); + } {% endblock %}