mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-05-19 11:28:49 +02:00
Remove Ahorro from budget UI, add SALARY type and savings auto-accrual
All checks were successful
Deploy to VPS / deploy (push) Successful in 23s
All checks were successful
Deploy to VPS / deploy (push) Successful in 23s
Ahorro was already deducted from gross salary so displaying it in budget projections was misleading. This removes the Ahorro card, summary line, Proyecciones column, and Ahorro Anual card from the UI, and strips all savings fields from budget API responses. Adds SALARY TransactionType so salary deposits can be distinguished from generic DEPOSITO transfers. When a SALARY transaction arrives, the system auto-increments MEMP and MPAT savings account balances (+200K CRC each) once per month via an idempotent accrual log. New CRUD endpoints at /api/v1/savings-accrual/ allow manual correction of the accrual history. Feb+Mar 2026 are seeded as historical baseline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
62
backend/app/services/savings_accrual.py
Normal file
62
backend/app/services/savings_accrual.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from app.models.models import (
|
||||
Account,
|
||||
AccountType,
|
||||
Bank,
|
||||
SavingsAccrual,
|
||||
Transaction,
|
||||
)
|
||||
|
||||
MEMP_MONTHLY = 200000.0
|
||||
MPAT_MONTHLY = 200000.0
|
||||
|
||||
|
||||
def _get_savings_account(session: Session, bank: Bank) -> Account | None:
|
||||
return session.exec(
|
||||
select(Account).where(
|
||||
Account.account_type == AccountType.SAVINGS,
|
||||
Account.bank == bank,
|
||||
)
|
||||
).first()
|
||||
|
||||
|
||||
def maybe_apply_monthly_savings(session: Session, tx: Transaction) -> SavingsAccrual | None:
|
||||
"""Apply monthly savings contribution if this is the first salary of the month.
|
||||
|
||||
Idempotent: if a SavingsAccrual row already exists for (year, month), do nothing.
|
||||
Bumps MEMP and MPAT savings account balances and records the accrual.
|
||||
"""
|
||||
year = tx.date.year
|
||||
month = tx.date.month
|
||||
|
||||
existing = session.exec(
|
||||
select(SavingsAccrual).where(
|
||||
SavingsAccrual.year == year,
|
||||
SavingsAccrual.month == month,
|
||||
)
|
||||
).first()
|
||||
if existing:
|
||||
return None
|
||||
|
||||
memp = _get_savings_account(session, Bank.MEMP)
|
||||
mpat = _get_savings_account(session, Bank.MPAT)
|
||||
if memp is None or mpat is None:
|
||||
return None
|
||||
|
||||
memp.balance += MEMP_MONTHLY
|
||||
mpat.balance += MPAT_MONTHLY
|
||||
session.add(memp)
|
||||
session.add(mpat)
|
||||
|
||||
accrual = SavingsAccrual(
|
||||
year=year,
|
||||
month=month,
|
||||
memp_amount=MEMP_MONTHLY,
|
||||
mpat_amount=MPAT_MONTHLY,
|
||||
trigger_transaction_id=tx.id,
|
||||
)
|
||||
session.add(accrual)
|
||||
session.commit()
|
||||
session.refresh(accrual)
|
||||
return accrual
|
||||
Reference in New Issue
Block a user