Skip to main content

Overview

Budgets help you control spending by setting limits for specific categories over defined time periods. FinAI tracks your progress automatically and alerts you when you’re close to or over budget.

Database Schema

The Budget model uses a many-to-many relationship with categories:
# From app/models.py:109-126
budget_category = db.Table('ngansach_danhmuc',
    db.Column('MaNganSach', db.String(8), db.ForeignKey('ngansach.MaNganSach', ondelete='CASCADE'), primary_key=True),
    db.Column('MaDanhMuc', db.String(8), db.ForeignKey('danhmuc.MaDanhMuc', ondelete='CASCADE'), primary_key=True)
)

class Budget(db.Model):
    __tablename__ = 'ngansach'

    id = db.Column('MaNganSach', db.String(8), primary_key=True)
    user_id = db.Column('MaNguoiDung', db.String(8), db.ForeignKey('nguoidung.MaNguoiDung', ondelete='CASCADE'), nullable=False)
    name = db.Column('TenNganSach', db.String(100), nullable=False)
    limit_amount = db.Column('SoTienGioiHan', db.Float, nullable=False)
    start_date = db.Column('NgayBatDau', db.Date, nullable=False)
    end_date = db.Column('NgayKetThuc', db.Date, nullable=False)
    created_at = db.Column('NgayTao', db.DateTime, default=datetime.now)

    # Many-to-Many relationship with Categories
    categories = db.relationship('Category', secondary=budget_category, backref=db.backref('budgets', lazy=True))
A single budget can track multiple categories, allowing flexible grouping like “Entertainment” (covering Movies, Concerts, Gaming).

Creating a Budget

1

Define Budget Parameters

Specify name, amount limit, and date range:
POST /api/budgets
Content-Type: application/json

{
  "name": "Eating Out Budget",
  "amount": 3000000,
  "start_date": "2026-03-01",
  "end_date": "2026-03-31",
  "category_ids": ["cat123", "cat456"]
}
2

Select Categories to Track

Choose which spending categories count toward this budget. For example:
  • “Eating Out Budget” might include: Cafe, Restaurants, Fast Food
  • “Transportation Budget” might include: Gas, Parking, Uber
3

System Creates Budget

The backend creates the budget and links categories (app/routes/budget.py:66-82):
new_budget = Budget(
    id=str(uuid.uuid4())[:8],
    user_id=user_id,
    name=data.get('name'),
    limit_amount=float(data.get('amount')),
    start_date=datetime.strptime(data.get('start_date'), '%Y-%m-%d').date(),
    end_date=datetime.strptime(data.get('end_date'), '%Y-%m-%d').date()
)

# Link selected categories
cat_ids = data.get('category_ids', [])
selected_cats = Category.query.filter(
    Category.id.in_(cat_ids), 
    Category.user_id == user_id
).all()
new_budget.categories.extend(selected_cats)
4

Budget Becomes Active

The budget immediately starts tracking transactions in the selected categories

Tracking Budget Progress

Retrieve all budgets with real-time spending data:
GET /api/budgets
The system calculates spending for each budget:
# From app/routes/budget.py:18-55
budgets = Budget.query.filter_by(user_id=user_id).all()
result = []
today = date.today()

for b in budgets:
    limit_amt = getattr(b, 'limit_amount', 0)
    
    # Get all category IDs linked to this budget
    cat_ids = [c.id for c in b.categories]
    spent = 0
    
    # Calculate total spending across all categories
    if cat_ids:
        spent = db.session.query(func.sum(Transaction.amount)).filter(
            Transaction.user_id == user_id,
            Transaction.type == 'chi',  # Only expenses
            Transaction.category_id.in_(cat_ids),
            Transaction.date >= b.start_date,
            Transaction.date <= b.end_date
        ).scalar() or 0
        
    # Calculate progress percentage
    progress = (spent / limit_amt) * 100 if limit_amt > 0 else 0
    days_left = (b.end_date - today).days
Response:
[
  {
    "id": "bdg12345",
    "name": "Eating Out Budget",
    "amount": 3000000,
    "spent": 2750000,
    "progress": 91.6,
    "is_exceeded": false,
    "start_date": "2026-03-01",
    "end_date": "2026-03-31",
    "days_left": 24,
    "categories": [
      {"id": "cat123", "name": "Ăn uống"},
      {"id": "cat456", "name": "Cafe"}
    ]
  },
  {
    "id": "bdg67890",
    "name": "Entertainment",
    "amount": 1500000,
    "spent": 1650000,
    "progress": 100,
    "is_exceeded": true,
    "start_date": "2026-03-01",
    "end_date": "2026-03-31",
    "days_left": 24,
    "categories": [
      {"id": "cat789", "name": "Giải trí"}
    ]
  }
]

Budget States

On Track

Progress < 80%
Safe spending level

Warning

Progress 80-100%
Approaching limit

Exceeded

Progress > 100%
Over budget
The is_exceeded flag indicates when spending surpasses the limit:
# From app/routes/budget.py:50
'is_exceeded': spent > limit_amt

Progress Calculation

Progress is calculated as a percentage with a cap at 100% for display:
# From app/routes/budget.py:41-49
progress = (spent / limit_amt) * 100 if limit_amt > 0 else 0

result.append({
    'progress': min(progress, 100),  # Capped at 100% for UI
    'is_exceeded': spent > limit_amt  # But exceeded flag shows true status
})
The progress bar shows maximum 100%, but the is_exceeded flag and actual spent amount reveal over-budget situations.

Days Remaining

The system calculates days left in the budget period:
# From app/routes/budget.py:42-53
days_left = (b.end_date - today).days

result.append({
    'days_left': max(days_left, 0)  # Never negative
})
This helps you pace your spending throughout the budget period.

Deleting a Budget

Remove a budget when no longer needed:
DELETE /api/budgets/{budget_id}
Implementation:
# From app/routes/budget.py:91-104
budget = Budget.query.filter_by(id=budget_id, user_id=session['user_id']).first()
if not budget:
    return jsonify({'status': 'error', 'message': 'Không tìm thấy'}), 404
    
db.session.delete(budget)
db.session.commit()
Deleting a budget does NOT delete transactions or categories. It only removes the budget tracking structure.

Budget Workflows

Scenario: Monthly Food Budget

1

Identify Food Categories

Review your categories and identify all food-related ones:
  • Ăn uống (Dining)
  • Cafe
  • Siêu thị (Groceries)
2

Set Realistic Limit

Check last month’s spending in Reports, then set a budget:
  • Last month: 4,200,000 VND
  • Target: 3,500,000 VND (reduce by 16%)
3

Create Budget

Set up the budget for the current month including all three categories
4

Monitor Throughout Month

Check progress regularly:
  • Day 10: 1,100,000 VND (31% - on track)
  • Day 20: 2,800,000 VND (80% - warning zone)
  • Day 31: 3,450,000 VND (98% - success!)

Scenario: Quarterly Entertainment Budget

Create a budget for Q1 (Jan 1 - Mar 31):
{
  "name": "Q1 Entertainment",
  "amount": 6000000,
  "start_date": "2026-01-01",
  "end_date": "2026-03-31",
  "category_ids": ["movies", "concerts", "gaming", "hobbies"]
}
This allows flexible month-to-month spending while controlling the quarterly total.Example progression:
  • January: 1,800,000 VND (30%)
  • February: 2,500,000 VND (41.7%)
  • March: Stay under 1,700,000 VND to meet goal

Budget Best Practices

Instead of one large “All Expenses” budget, create specific budgets:
  • Food & Dining: 3,500,000 VND
  • Transportation: 1,200,000 VND
  • Entertainment: 1,000,000 VND
This provides better control and insights into spending patterns.
If you’re paid monthly, create monthly budgets starting on payday:
  • Payday: 5th of each month
  • Budget period: 5th to 4th of following month
This prevents running out of money before the next paycheck.
After each budget period:
  1. Check if you met, exceeded, or under-spent
  2. Analyze which categories drove spending
  3. Adjust limits for next period based on reality
  4. Celebrate successes to build momentum

Integration with Other Features

AI Chatbot Budget Queries

Ask the chatbot about your budgets:
  • “Am I on track with my food budget?”
  • “How much budget do I have left for entertainment?”
  • “Which budget am I closest to exceeding?”
The chatbot can access budget data through the API and provide conversational answers.

Reports Integration

Use Reports to inform budget creation:
  1. Generate report for last month
  2. Identify high-spending categories
  3. Set budgets for those categories
  4. Use historical data to set realistic limits

Error Handling

The budget system includes comprehensive error handling:
# From app/routes/budget.py:84-89
except Exception as e:
    db.session.rollback()
    print("=== LỖI API POST BUDGETS ===")
    import traceback
    traceback.print_exc()
    return jsonify({'status': 'error', 'message': str(e)}), 500
Errors are logged with full stack traces for debugging while returning user-friendly messages.

Database Relationships

The many-to-many relationship enables flexible budget structures:
# From app/models.py:126
categories = db.relationship('Category', secondary=budget_category, backref=db.backref('budgets', lazy=True))
This means:
  • One budget can track multiple categories
  • One category can be in multiple budgets
  • The budget_category junction table manages the associations
Example: “Ăn uống” category might be in both:
  • “Monthly Food Budget” (all food)
  • “Dining Out Only” (restaurants, excluding groceries)

Performance Considerations

Budget calculations are optimized:
# From app/routes/budget.py:32-38
# Single aggregated query instead of summing in Python
spent = db.session.query(func.sum(Transaction.amount)).filter(
    Transaction.user_id == user_id,
    Transaction.type == 'chi',
    Transaction.category_id.in_(cat_ids),
    Transaction.date >= b.start_date,
    Transaction.date <= b.end_date
).scalar() or 0
The database handles aggregation, not the application layer.

API Reference

Get All Budgets

GET /api/budgets
Authentication: Required (session-based)
Returns array of budget objects with calculated progress and spending.

Create Budget

POST /api/budgets
Content-Type: application/json
Authentication: Required (session-based)

{
  "name": "Budget Name",
  "amount": 3000000,
  "start_date": "2026-03-01",
  "end_date": "2026-03-31",
  "category_ids": ["cat1", "cat2"]
}
Success Response:
{
  "status": "success",
  "message": "Đã tạo ngân sách!"
}

Delete Budget

DELETE /api/budgets/{budget_id}
Authentication: Required (session-based)
Success Response:
{
  "status": "success"
}
Error Response:
{
  "status": "error",
  "message": "Không tìm thấy"
}
  • Transactions - Budget tracking depends on transaction data
  • Reports - Analyze spending to set realistic budgets
  • Chatbot - Ask questions about budget progress
  • AI Categorization - Accurate categorization ensures accurate budget tracking

Build docs developers (and LLMs) love