from __future__ import annotations from decimal import Decimal from app.models import MonthlyAllocation, MonthlyEntryValue, MonthlyIncome, to_decimal class ComparisonService: def month_delta(self, current_month, previous_month) -> dict: if previous_month is None: zero = Decimal("0.00") return { "income_delta": zero, "cost_delta": zero, "remainder_delta": zero, "allocation_delta": zero, } return { "income_delta": self._total_income(current_month) - self._total_income(previous_month), "cost_delta": self._total_costs(current_month) - self._total_costs(previous_month), "remainder_delta": self._remainder(current_month) - self._remainder(previous_month), "allocation_delta": self._total_allocations(current_month) - self._total_allocations(previous_month), } def top_entry_changes(self, current_month, previous_month, limit: int = 6) -> list[dict]: if previous_month is None: return [] previous_values = { item.entry_id: to_decimal(item.planned_amount) for item in previous_month.entry_values } changes = [] for item in current_month.entry_values: previous_amount = previous_values.get(item.entry_id, Decimal("0.00")) current_amount = to_decimal(item.planned_amount) delta = current_amount - previous_amount if delta: changes.append( { "entry_name": item.entry.name, "category_name": item.entry.category.name, "delta": delta, "current_amount": current_amount, "previous_amount": previous_amount, } ) changes.sort(key=lambda item: abs(item["delta"]), reverse=True) return changes[:limit] def _total_income(self, month) -> Decimal: return sum((to_decimal(item.amount) for item in month.incomes), Decimal("0.00")) def _total_costs(self, month) -> Decimal: return sum((to_decimal(item.planned_amount) for item in month.entry_values), Decimal("0.00")) def _total_allocations(self, month) -> Decimal: return sum((to_decimal(item.amount) for item in month.allocations), Decimal("0.00")) def _remainder(self, month) -> Decimal: return self._total_income(month) - self._total_costs(month)