From 6f631607b8c289f117bd462a5de42a29fcb0364b Mon Sep 17 00:00:00 2001
From: "Edgar P. Burkhart" <git@edgarpierre.fr>
Date: Thu, 28 Dec 2023 16:31:13 +0100
Subject: [PATCH] Reduce computations in history generation

---
 .../templates/category/category_form.html     |  2 +-
 nummi/history/templates/history/plot.html     | 85 ++++++++++---------
 nummi/history/utils.py                        | 40 +++------
 nummi/main/static/main/css/plot.css           |  3 +
 nummi/main/templates/main/index.html          |  2 +-
 5 files changed, 63 insertions(+), 69 deletions(-)

diff --git a/nummi/category/templates/category/category_form.html b/nummi/category/templates/category/category_form.html
index aa16a70..ed9e399 100644
--- a/nummi/category/templates/category/category_form.html
+++ b/nummi/category/templates/category/category_form.html
@@ -11,7 +11,7 @@
 {% block tables %}
     <h3>{% translate "Transactions" %}</h3>
     {% include "transaction/transaction_table.html" %}
-    {% if history.data %}
+    {% if history %}
         <h3>{% translate "History" %}</h3>
         {% include "history/plot.html" %}
     {% endif %}
diff --git a/nummi/history/templates/history/plot.html b/nummi/history/templates/history/plot.html
index cba9e18..3f0b456 100644
--- a/nummi/history/templates/history/plot.html
+++ b/nummi/history/templates/history/plot.html
@@ -19,43 +19,51 @@
         </thead>
         <tbody>
             {% spaceless %}
-                {% for date in history.data %}
-                    <tr>
-                        <td class="icon">
-                            <span class="ri-{% if date.sum > 0 %}arrow-up-s-line green{% elif date.sum < 0 %}arrow-down-s-line red{% endif %}"></span>
-                        </td>
-                        <th class="date" scope="row">
-                            {% if date.has_transactions %}
-                                {% if account %}
-                                    <a href="{% url "transaction_month" account=account.pk year=date.month.year month=date.month.month %}">{{ date.month|date:"Y-m" }}</a>
-                                {% elif category %}
-                                    <a href="{% url "transaction_month" category=category.pk year=date.month.year month=date.month.month %}">{{ date.month|date:"Y-m" }}</a>
-                                {% else %}
-                                    <a href="{% url "transaction_month" year=date.month.year month=date.month.month %}">{{ date.month|date:"Y-m" }}</a>
-                                {% endif %}
-                            {% else %}
-                                {{ date.month|date:"Y-m" }}
-                            {% endif %}
-                        </th>
-                        <td class="value">{{ date.sum_m|pmrvalue }}</td>
-                        <td class="bar m">
-                            <div style="width: {% widthratio date.sum_m history.max -100 %}%"></div>
-                            {% if date.sum < 0 %}
-                                <div class="tot" style="width:{% widthratio date.sum history.max -100 %}%">
-                                    <span>{{ date.sum|pmrvalue }}</span>
-                                </div>
-                            {% endif %}
-                        </td>
-                        <td class="bar p">
-                            <div style="width: {% widthratio date.sum_p history.max 100 %}%"></div>
-                            {% if date.sum > 0 %}
-                                <div class="tot" style="width:{% widthratio date.sum history.max 100 %}%">
-                                    <span>{{ date.sum|pmrvalue }}</span>
-                                </div>
-                            {% endif %}
-                        </td>
-                        <td class="value">{{ date.sum_p|pmrvalue }}</td>
-                    </tr>
+                {% for y in history.years reversed %}
+                    {% for date in y.d reversed %}
+                        {% if date %}
+                            <tr>
+                                <td class="icon">
+                                    <span class="ri-{% if date.sum > 0 %}arrow-up-s-line green{% elif date.sum < 0 %}arrow-down-s-line red{% endif %}"></span>
+                                </td>
+                                <th class="date" scope="row">
+                                    {% if date.has_transactions %}
+                                        {% if account %}
+                                            <a href="{% url "transaction_month" account=account.pk year=date.month.year month=date.month.month %}">{{ date.month|date:"Y-m" }}</a>
+                                        {% elif category %}
+                                            <a href="{% url "transaction_month" category=category.pk year=date.month.year month=date.month.month %}">{{ date.month|date:"Y-m" }}</a>
+                                        {% else %}
+                                            <a href="{% url "transaction_month" year=date.month.year month=date.month.month %}">{{ date.month|date:"Y-m" }}</a>
+                                        {% endif %}
+                                    {% else %}
+                                        {{ date.month|date:"Y-m" }}
+                                    {% endif %}
+                                </th>
+                                <td class="value">{{ date.sum_m|pmrvalue }}</td>
+                                <td class="bar m">
+                                    <div style="width: {% widthratio date.sum_m history.max -100 %}%"></div>
+                                    {% if date.sum < 0 %}
+                                        <div class="tot" style="width:{% widthratio date.sum history.max -100 %}%">
+                                            <span>{{ date.sum|pmrvalue }}</span>
+                                        </div>
+                                    {% endif %}
+                                </td>
+                                <td class="bar p">
+                                    <div style="width: {% widthratio date.sum_p history.max 100 %}%"></div>
+                                    {% if date.sum > 0 %}
+                                        <div class="tot" style="width:{% widthratio date.sum history.max 100 %}%">
+                                            <span>{{ date.sum|pmrvalue }}</span>
+                                        </div>
+                                    {% endif %}
+                                </td>
+                                <td class="value">{{ date.sum_p|pmrvalue }}</td>
+                            </tr>
+                        {% else %}
+                            <tr class="empty">
+                                <td colspan="5" class="empty"></td>
+                            </tr>
+                        {% endif %}
+                    {% endfor %}
                 {% endfor %}
             {% endspaceless %}
         </tbody>
@@ -82,7 +90,7 @@
         </thead>
         <tbody>
             {% spaceless %}
-                {% for year in history.years %}
+                {% for year in history.years reversed %}
                     <tr>
                         <th>{{ year.y }}</th>
                         {% for m in year.d %}
@@ -100,3 +108,4 @@
         </tbody>
     </table>
 </div>
+{{ history.years|json_script }}
diff --git a/nummi/history/utils.py b/nummi/history/utils.py
index adf1c35..2af095f 100644
--- a/nummi/history/utils.py
+++ b/nummi/history/utils.py
@@ -1,8 +1,7 @@
 import datetime
 
-from django.db import models
 from django.db.models import Func, Max, Min, Q, Sum, Value
-from django.db.models.functions import Abs, Now, TruncMonth
+from django.db.models.functions import Abs, TruncMonth
 
 
 class GenerateMonth(Func):
@@ -13,31 +12,13 @@ class GenerateMonth(Func):
 def history(transaction_set):
     if not transaction_set.exists():
         return None
+
     _transaction_month = transaction_set.values(month=TruncMonth("date")).order_by(
         "-date"
     )
-    _months = (
-        transaction_set.values(
-            month=GenerateMonth(
-                _transaction_month.last()["month"],
-                Now(output_field=models.DateField()),
-            )
-        )
-        .annotate(
-            sum_m=Value(0),
-            sum_p=Value(0),
-            sum=Value(0),
-            has_transactions=Value(0),
-        )
-        .difference(
-            _transaction_month.annotate(
-                sum_m=Value(0),
-                sum_p=Value(0),
-                sum=Value(0),
-                has_transactions=Value(0),
-            )
-        )
-    )
+    _first_month = _transaction_month.last()["month"]
+    _last_month = _transaction_month.first()["month"]
+
     _history = _transaction_month.annotate(
         sum_p=Sum("value", filter=Q(value__gt=0)),
         sum_m=Sum("value", filter=Q(value__lt=0)),
@@ -46,19 +27,20 @@ def history(transaction_set):
     ).order_by("-month")
 
     return {
-        "data": _history.union(_months).order_by("-month"),
         "years": [
             {
                 "y": y,
                 "d": [
                     _history.filter(month=datetime.date(y, m + 1, 1)).first()
-                    for m in range(12)
+                    for m in range(
+                        0,
+                        _last_month.month if _last_month.year == y else 12,
+                    )
                 ],
             }
             for y in range(
-                _transaction_month.first()["month"].year,
-                _transaction_month.last()["month"].year - 1,
-                -1,
+                _first_month.year,
+                _last_month.year + 1,
             )
         ],
         "max": max(
diff --git a/nummi/main/static/main/css/plot.css b/nummi/main/static/main/css/plot.css
index a55a06f..52dd617 100644
--- a/nummi/main/static/main/css/plot.css
+++ b/nummi/main/static/main/css/plot.css
@@ -63,6 +63,9 @@ table.full-width col.bar {
 .plot td.bar.m div.tot span {
   right: 0;
 }
+.plot tr.empty {
+  height: 0.5rem;
+}
 
 @media (width < 720px) {
   .plot .bar {
diff --git a/nummi/main/templates/main/index.html b/nummi/main/templates/main/index.html
index cdadde8..a6fd1c0 100644
--- a/nummi/main/templates/main/index.html
+++ b/nummi/main/templates/main/index.html
@@ -40,7 +40,7 @@
         <h2>{% translate "Statements" %}</h2>
         {% include "statement/statement_table.html" %}
     {% endif %}
-    {% if history.data %}
+    {% if history %}
         <h2>{% translate "History" %}</h2>
         {% include "history/plot.html" %}
     {% endif %}
