def __init__(self, *args, **kwargs):
     user = kwargs.pop("user", None)
     super().__init__(*args, **kwargs)
     self.fields["category"].queryset = Category.objects.filter(
         user=user).order_by("order")
     self.fields["date"].default = today_date().strftime("%Y-%m-%d")
     self.fields["description"].required = False
Example #2
0
def exp_template_actions(the_template, show_title=False, show_date=False):
    return {
        "template": the_template,
        "show_title": show_title,
        "show_date": show_date,
        "today": today_date()
    }
Example #3
0
def expense_table(context, expenses):
    show_form = context.get("show_form", False)
    ctx = {"expenses": expenses, "show_form": show_form, "pid": context["pid"]}
    if show_form:
        ctx["categories"] = context.get("categories", None)
        ctx["today"] = today_date()
    return ctx
Example #4
0
def template_run(request, pk):
    template = get_object_or_404(ExpenseTemplate, pk=pk, user=request.user)
    expense = Expense(vendor=template.vendor, category=template.category)
    if "date" in request.GET:
        expense.date = request.GET["date"]
    else:
        expense.date = today_date()

    if template.type == "count":
        if not request.GET.get("count"):
            count = decimal.Decimal(1)
        else:
            count = parse_amount_input(request.GET["count"])
            if count is None:
                return HttpResponseBadRequest()

        expense.amount = round_money(template.amount * count)
        desc_lines = template.description.strip().split("\n")
        desc_possibilities = len(desc_lines)
        desc = desc_lines[0]
        if count % 1 != 0:
            # Is decimal, use last possibility
            desc = desc_lines[desc_possibilities - 1]
        elif desc_possibilities == 2:
            # 0 → 1, 1 → anything else (English)
            desc = desc_lines[int(count != 1)]
        elif desc_possibilities in {3, 4}:
            # Polish scheme
            if count == 1:
                desc = desc_lines[0]
            else:
                # Expression from gettext, simplified
                desc = desc_lines[1 if (2 <= count % 10 <= 4 and (count % 100 < 10 or count % 100 >= 20)) else 2]

        expense.description = desc.replace("!count!", str(count))
    elif template.type == "description":
        expense.amount = template.amount
        expense.description = template.description.replace("!description!", request.GET["description"])
    elif template.type == "desc_select":
        main_desc, *desc_options = template.description.strip().split("\n")
        desc_id = int(request.GET["desc_id"])
        expense.amount = template.amount
        expense.description = main_desc.strip().replace("!description!", desc_options[desc_id].strip())
    elif template.type == "menu":
        desc_id = int(request.GET["desc_id"])
        desc_options = template.description.strip().split("\n")
        amount_str, desc = desc_options[desc_id].strip().split(" ", 1)
        expense.amount = parse_amount_input(amount_str.strip())
        if expense.amount is None:
            return HttpResponseBadRequest()
        expense.description = desc.strip()
    else:
        expense.amount = template.amount
        expense.description = template.description

    expense.user = request.user
    expense.save()
    return HttpResponseRedirect(expense.get_absolute_url())
def expense_repeat(request, pk):
    old_expense = get_object_or_404(Expense, pk=pk, user=request.user, is_bill=False)
    new_expense = Expense(
        date=today_date(),
        vendor=old_expense.vendor,
        category=old_expense.category,
        amount=old_expense.amount,
        description=old_expense.description,
        user=request.user,
        is_bill=False,
    )
    new_expense.save()
    messages.add_message(request, messages.SUCCESS, _("Expense has been repeated successfully."))
    return HttpResponseRedirect(reverse("expenses:expense_show", args=[new_expense.pk]))
Example #6
0
def index(request):
    last_n_expenses = revchron(Expense.objects.filter(user=request.user).select_related("category"))[
        : settings.EXPENSES_INDEX_COUNT
    ]
    with connection.cursor() as cursor:
        cursor.execute(
            """
            SELECT date, SUM(amount)
            FROM expenses_expense
            WHERE user_id = %s
            GROUP BY date
            ORDER BY date DESC
            LIMIT 3""",
            [request.user.pk],
        )
        last_3_days = cursor.fetchall()
    last_3_days_sum = sum(r[1] for r in last_3_days)
    last_3_days = reversed(last_3_days)

    today = today_date()
    prev_month = today.month - 1
    prev_year = today.year
    while prev_month < 0:
        prev_month += 12
        prev_year -= 1

    current_months_total = Expense.objects.filter(
        user=request.user, date__year=today.year, date__month=today.month
    ).aggregate(Sum("amount"))["amount__sum"]
    previous_months_total = (
        Expense.objects.filter(user=request.user, date__year=prev_year, date__month=prev_month).aggregate(
            Sum("amount")
        )["amount__sum"]
        or 0
    )

    spending_per_category_qs = (
        Expense.objects.filter(user=request.user).values("category").annotate(sum=Sum("amount")).order_by("-sum")
    )
    categories = {cat.pk: cat for cat in Category.objects.filter(user=request.user)}
    spending_per_category = [(categories[i["category"]], i["sum"]) for i in spending_per_category_qs]

    pie_chart = pygal.Pie(
        disable_xml_declaration=True,
        margin=0,
        legend_at_bottom=True,
        print_values=True,
        print_labels=True,
        style=pygal.style.DefaultStyle(
            plot_background="white",
            background="white",
            font_family="var(--font-family-sans-serif)",
            label_font_size=20,
            value_font_size=20,
            value_label_font_size=20,
            tooltip_font_size=20,
            legend_font_size=20,
        ),
    )
    for c, s in spending_per_category:
        pie_chart.add(c.name, float(s), formatter=format_money)
    category_chart = mark_safe(pie_chart.render())

    return render(
        request,
        "expenses/index.html",
        {
            "htmltitle": _("Expenses Dashboard"),
            "pid": "expenses_index",
            "last_n_expenses": last_n_expenses,
            "EXPENSES_INDEX_COUNT": settings.EXPENSES_INDEX_COUNT,
            "last_3_days": last_3_days,
            "last_3_days_sum": last_3_days_sum,
            "current_months_total": current_months_total,
            "previous_months_total": previous_months_total,
            "spending_per_category": spending_per_category,
            "category_chart": category_chart,
        },
    )