from datetime import date from decimal import Decimal, InvalidOperation from django.db.models import Sum from django.template.loader import render_to_string from liveview import liveview_handler, send from app.monthly.services import update_budget from app.monthly.models import Income def _render_income_table(year, month, editing_id=None): incomes = Income.objects.filter( date__year=year, date__month=month, ) total = incomes.aggregate(total=Sum("amount"))["total"] or Decimal("0") return render_to_string( "pages/monthly/partials/income_table.html", { "incomes": incomes, "total": total, "year": year, "month": month, "today": date.today().isoformat(), "editing_id": editing_id, }, ) @liveview_handler("add_income") def add_income(consumer, content): form = content.get("form", {}) year = int(form.get("year", 0)) month = int(form.get("month", 0)) concept = form.get("income_concept", "").strip() amount_raw = form.get("income_amount", "").replace(",", ".") date_raw = form.get("income_date", "") if not concept or not amount_raw or not date_raw or not year or not month: return try: amount = Decimal(amount_raw) income_date = date.fromisoformat(date_raw) except (InvalidOperation, ValueError): return Income.objects.create( date=income_date, concept=concept, amount=amount, ) html = _render_income_table(year, month) send(consumer, {"target": "#income-table", "html": html}) update_budget(consumer, year, month) @liveview_handler("delete_income") def delete_income(consumer, content): data = content.get("data", {}) income_id = data.get("data_id", "") year = int(data.get("data_year", 0)) month = int(data.get("data_month", 0)) if not income_id or not year or not month: return Income.objects.filter(id=income_id).delete() html = _render_income_table(year, month) send(consumer, {"target": "#income-table", "html": html}) update_budget(consumer, year, month) @liveview_handler("edit_income") def edit_income(consumer, content): data = content.get("data", {}) income_id = data.get("data_id", "") year = int(data.get("data_year", 0)) month = int(data.get("data_month", 0)) if not income_id: return try: income = Income.objects.get(id=income_id) except Income.DoesNotExist: return html = _render_income_table(year, month, editing_id=income.id) send(consumer, {"target": "#income-table", "html": html}) @liveview_handler("cancel_edit_income") def cancel_edit_income(consumer, content): data = content.get("data", {}) year = int(data.get("data_year", 0)) month = int(data.get("data_month", 0)) if not year or not month: return html = _render_income_table(year, month) send(consumer, {"target": "#income-table", "html": html}) @liveview_handler("save_income") def save_income(consumer, content): form = content.get("form", {}) income_id = form.get("income_id", "") year = int(form.get("year", 0)) month = int(form.get("month", 0)) concept = form.get("income_concept", "").strip() amount_raw = form.get("income_amount", "").replace(",", ".") date_raw = form.get("income_date", "") if not income_id or not concept or not amount_raw or not date_raw: return try: amount = Decimal(amount_raw) income_date = date.fromisoformat(date_raw) income = Income.objects.get(id=income_id) except (InvalidOperation, ValueError, Income.DoesNotExist): return income.date = income_date income.concept = concept income.amount = amount income.save() html = _render_income_table(year, month) send(consumer, {"target": "#income-table", "html": html}) update_budget(consumer, year, month) @liveview_handler("clone_income") def clone_income(consumer, content): form = content.get("form", {}) source = form.get("clone_source", "") year = int(form.get("year", 0)) month = int(form.get("month", 0)) if not source or not year or not month: return try: src_year, src_month = source.split("-") src_year, src_month = int(src_year), int(src_month) except ValueError: return source_incomes = Income.objects.filter( date__year=src_year, date__month=src_month, ) today = date.today() for inc in source_incomes: Income.objects.create( date=today, concept=inc.concept, amount=inc.amount, ) html = _render_income_table(year, month) send(consumer, {"target": "#income-table", "html": html}) update_budget(consumer, year, month)