Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/backend/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class User(db.Model):
email = db.Column(db.String(255), unique=True, nullable=False)
password_hash = db.Column(db.String(255), nullable=False)
preferred_currency = db.Column(db.String(10), default="INR", nullable=False)
preferred_locale = db.Column(db.String(10), default="en_US", nullable=False)
role = db.Column(db.String(20), default=Role.USER.value, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)

Expand Down
7 changes: 7 additions & 0 deletions packages/backend/app/routes/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def register():
email=email,
password_hash=generate_password_hash(password),
preferred_currency="INR",
preferred_locale="en_US",
)
db.session.add(user)
db.session.commit()
Expand Down Expand Up @@ -77,6 +78,7 @@ def me():
id=user.id,
email=user.email,
preferred_currency=user.preferred_currency or "INR",
preferred_locale=user.preferred_locale or "en_US",
)


Expand All @@ -93,11 +95,16 @@ def update_me():
if cur not in SUPPORTED_CURRENCIES:
return jsonify(error="unsupported preferred_currency"), 400
user.preferred_currency = cur
if "preferred_locale" in data:
loc = str(data.get("preferred_locale") or "").strip()
# Basic format check: xx_XX or xx
user.preferred_locale = loc
db.session.commit()
return jsonify(
id=user.id,
email=user.email,
preferred_currency=user.preferred_currency or "INR",
preferred_locale=user.preferred_locale or "en_US",
)


Expand Down
3 changes: 3 additions & 0 deletions packages/backend/app/routes/bills.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from ..extensions import db
from ..models import Bill, BillCadence, User
from ..services.cache import cache_delete_patterns
from ..services.locale import LocaleService
import logging

bp = Blueprint("bills", __name__)
Expand All @@ -28,7 +29,9 @@ def list_bills():
"name": b.name,
"amount": float(b.amount),
"currency": b.currency,
"amount_formatted": LocaleService.format_currency(b.amount, b.currency, locale=LocaleService.get_user_locale(b.user_id)),
"next_due_date": b.next_due_date.isoformat(),
"next_due_date_formatted": LocaleService.format_date(b.next_due_date, locale=LocaleService.get_user_locale(b.user_id)),
"cadence": b.cadence.value,
"autopay_enabled": b.autopay_enabled,
"channel_whatsapp": b.channel_whatsapp,
Expand Down
11 changes: 10 additions & 1 deletion packages/backend/app/routes/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ..extensions import db
from ..models import Bill, Expense, Category
from ..services.cache import cache_get, cache_set, dashboard_summary_key
from ..services.locale import LocaleService

bp = Blueprint("dashboard", __name__)

Expand Down Expand Up @@ -63,11 +64,16 @@ def dashboard_summary():
)
payload["summary"]["monthly_income"] = float(income or 0)
payload["summary"]["monthly_expenses"] = float(expenses or 0)
user_locale = LocaleService.get_user_locale(uid)
user_currency = db.session.get(User, uid).preferred_currency or "INR"
payload["summary"]["monthly_income_formatted"] = LocaleService.format_currency(payload["summary"]["monthly_income"], user_currency, locale=user_locale)
payload["summary"]["monthly_expenses_formatted"] = LocaleService.format_currency(payload["summary"]["monthly_expenses"], user_currency, locale=user_locale)
payload["summary"]["net_flow"] = round(
payload["summary"]["monthly_income"]
- payload["summary"]["monthly_expenses"],
2,
)
payload["summary"]["net_flow_formatted"] = LocaleService.format_currency(payload["summary"]["net_flow"], user_currency, locale=user_locale)
except Exception:
payload["errors"].append("summary_unavailable")

Expand All @@ -84,7 +90,9 @@ def dashboard_summary():
"id": e.id,
"description": e.notes or "Transaction",
"amount": float(e.amount),
"amount_formatted": LocaleService.format_currency(e.amount, e.currency, locale=user_locale),
"date": e.spent_at.isoformat(),
"date_formatted": LocaleService.format_date(e.spent_at, locale=user_locale),
"type": e.expense_type,
"category_id": e.category_id,
"currency": e.currency,
Expand All @@ -111,8 +119,9 @@ def dashboard_summary():
"id": b.id,
"name": b.name,
"amount": float(b.amount),
"currency": b.currency,
"amount_formatted": LocaleService.format_currency(b.amount, b.currency, locale=user_locale),
"next_due_date": b.next_due_date.isoformat(),
"next_due_date_formatted": LocaleService.format_date(b.next_due_date, locale=user_locale),
"cadence": b.cadence.value,
"channel_email": b.channel_email,
"channel_whatsapp": b.channel_whatsapp,
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/app/routes/expenses.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ..models import Expense, RecurringCadence, RecurringExpense, User
from ..services.cache import cache_delete_patterns, monthly_summary_key
from ..services import expense_import
from ..services.locale import LocaleService
import logging

bp = Blueprint("expenses", __name__)
Expand Down Expand Up @@ -312,14 +313,17 @@ def import_commit():


def _expense_to_dict(e: Expense) -> dict:
locale = LocaleService.get_user_locale(e.user_id)
return {
"id": e.id,
"amount": float(e.amount),
"currency": e.currency,
"amount_formatted": LocaleService.format_currency(e.amount, e.currency, locale=locale),
"category_id": e.category_id,
"expense_type": e.expense_type,
"description": e.notes or "",
"date": e.spent_at.isoformat(),
"date_formatted": LocaleService.format_date(e.spent_at, locale=locale),
}


Expand Down
1 change: 1 addition & 0 deletions packages/backend/app/routes/insights.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from flask import Blueprint, jsonify, request
from flask_jwt_extended import jwt_required, get_jwt_identity
from ..services.ai import monthly_budget_suggestion
from ..services.locale import LocaleService
import logging

bp = Blueprint("insights", __name__)
Expand Down
24 changes: 24 additions & 0 deletions packages/backend/app/services/locale.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from babel import numbers, dates
from datetime import date, datetime
from .models import User
from .extensions import db

class LocaleService:
@staticmethod
def format_currency(amount, currency_code, locale='en_US'):
try:
return numbers.format_currency(amount, currency_code, locale=locale)
except:
return f"{currency_code} {amount:.2f}"

@staticmethod
def format_date(d, locale='en_US', format='medium'):
try:
return dates.format_date(d, locale=locale, format=format)
except:
return str(d)

@staticmethod
def get_user_locale(user_id):
user = db.session.get(User, user_id)
return user.preferred_locale if user else 'en_US'