diff --git a/app/db_queries.py b/app/db_queries.py index 656bbda..dd79bbe 100644 --- a/app/db_queries.py +++ b/app/db_queries.py @@ -3,6 +3,7 @@ from django.conf import settings from django.db import connection from django.utils.translation import gettext +from calendar import day_name COMBINE_ALPHABET = "abcdefghijklmnopqrstuvwxyz" @@ -15,7 +16,6 @@ def _db_select(sql_select:str): result = cursor.fetchall() return result - def _combine_results(results:list) -> dict: ''' e.g. @@ -80,8 +80,7 @@ def select_history(user, language_code="en") -> list: result = [list(row) for row in result] return result - -def orders_per_month(user) -> list: +def select_orders_per_month(user) -> dict: # number of orders per month (last 12 months) result_user = _db_select(f""" select @@ -102,32 +101,35 @@ def orders_per_month(user) -> list: group by "month" order by "month" desc; """) - return _combine_results([result_user, result_all]) + return _combine_results([result_all, result_user]) - -def orders_per_weekday(user) -> list: +def select_orders_per_weekday(user) -> list: # number of orders per weekday (all time) - result_user = _db_select(f""" - select - to_char(datetime, 'Day') as "day", - sum(amount) as "count" - from app_order - where user_id = {user.pk} - group by "day" - order by "count" desc; + result = _db_select(f""" + with q_all as ( + select + extract(isodow from datetime) as "d", + sum(amount) as "c" + from app_order + group by d + ), q_user as ( + select + extract(isodow from datetime) as "d", + sum(amount) as "c" + from app_order + where user_id = {user.pk} + group by d + ) + select q_all.d as "day", q_all.c, q_user.c from q_all full join q_user on q_all.d = q_user.d + group by day, q_all.c, q_user.c + order by day asc; """) - result_all = _db_select(f""" - select - to_char(datetime, 'Day') as "day", - sum(amount) as "count" - from app_order - group by "day" - order by "count" desc; - """) - return _combine_results([result_user, result_all]) + for i in range(len(result)): + day_, all_, user_ = result[i] + result[i] = (day_name[int(day_)-1], all_, user_) + return result - -def orders_per_drink(user) -> list: +def select_orders_per_drink(user) -> dict: # number of orders per drink (all time) result_user = _db_select(f""" select @@ -148,4 +150,31 @@ def orders_per_drink(user) -> list: group by d.product_name order by "data" desc; """) - return _combine_results([result_user, result_all]) + return _combine_results([result_all, result_user]) + +def select_order_sum_per_user_all_users() -> list: + # sum of all orders per user, for all users + result = _db_select(f""" + select + app_user.username as user, + sum(app_order.price_sum) as sum + from app_user + left outer join app_order on (app_user.id = app_order.user_id) + group by app_user.id + order by app_user asc; + """) + return result + +def select_deposit_sum_per_user_all_users() -> list: + # sum of all orders per user, for all users + result = _db_select(f""" + select + app_user.username as user, + sum(rt.transaction_sum) as sum + from app_user + left outer join app_registertransaction rt on (app_user.id = rt.user_id) + where rt.is_user_deposit is true or rt.is_user_deposit is null + group by app_user.id + order by app_user asc; + """) + return result diff --git a/app/locales/de/LC_MESSAGES/django.mo b/app/locales/de/LC_MESSAGES/django.mo index d7435cb..2e84d2f 100644 Binary files a/app/locales/de/LC_MESSAGES/django.mo and b/app/locales/de/LC_MESSAGES/django.mo differ diff --git a/app/locales/de/LC_MESSAGES/django.po b/app/locales/de/LC_MESSAGES/django.po index fe0dc95..9900f3a 100644 --- a/app/locales/de/LC_MESSAGES/django.po +++ b/app/locales/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-14 23:37+0200\n" +"POT-Creation-Date: 2023-11-01 18:52+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Julian Müller (ChaoticByte)\n" "Language: DE\n" @@ -55,7 +55,7 @@ msgstr "Bestätigen" msgid "Drinks - History" msgstr "Getränke - Verlauf" -#: app/templates/history.html:10 app/templates/userpanel.html:25 +#: app/templates/history.html:10 app/templates/userpanel.html:23 msgid "History" msgstr "Verlauf" @@ -165,49 +165,57 @@ msgstr "Wähle deinen Account" msgid "Drinks - Statistics" msgstr "Getränke - Statistiken" -#: app/templates/statistics.html:10 app/templates/userpanel.html:26 +#: app/templates/statistics.html:10 app/templates/userpanel.html:24 msgid "Statistics" msgstr "Statistiken" #: app/templates/statistics.html:13 -msgid "Orders per drink" -msgstr "Bestellungen pro Getränk" +msgid "orders / drink" +msgstr "Bestellungen / Getränk" #: app/templates/statistics.html:16 msgid "drink" msgstr "Getränk" -#: app/templates/statistics.html:17 app/templates/statistics.html:34 -#: app/templates/statistics.html:51 -msgid "you" -msgstr "Du" - -#: app/templates/statistics.html:18 app/templates/statistics.html:35 -#: app/templates/statistics.html:52 +#: app/templates/statistics.html:17 app/templates/statistics.html:36 +#: app/templates/statistics.html:53 msgid "all" msgstr "Alle" -#: app/templates/statistics.html:30 -msgid "Orders per month (last 12 months)" -msgstr "Bestellungen pro Monat (letzte 12 Monate)" +#: app/templates/statistics.html:18 app/templates/statistics.html:37 +#: app/templates/statistics.html:54 +msgid "you" +msgstr "Du" -#: app/templates/statistics.html:33 +#: app/templates/statistics.html:32 +msgid "orders / month" +msgstr "Bestellungen / Monat" + +#: app/templates/statistics.html:35 msgid "month" msgstr "Monat" -#: app/templates/statistics.html:47 -msgid "Orders per weekday" -msgstr "Bestellungen pro Wochentag" +#: app/templates/statistics.html:49 +msgid "orders / weekday" +msgstr "Bestellungen / Wochentag" -#: app/templates/statistics.html:50 +#: app/templates/statistics.html:52 msgid "day" msgstr "Tag" +#: app/templates/statistics.html:69 +msgid "order sum" +msgstr "Bestellungen" + +#: app/templates/statistics.html:86 +msgid "deposit sum" +msgstr "Einzahlungen" + #: app/templates/supply.html:7 msgid "Drinks - Supply" msgstr "Getränke - Beschaffung" -#: app/templates/supply.html:14 app/templates/userpanel.html:32 +#: app/templates/supply.html:14 app/templates/userpanel.html:30 msgid "Supply" msgstr "Beschaffung" @@ -228,7 +236,6 @@ msgid "You are not allowed to view this site." msgstr "Dir fehlt die Berechtigung, diese Seite anzuzeigen." #: app/templates/transfer.html:6 -#| msgid "Drinks - Order" msgid "Drinks - Transfer" msgstr "Getränke - Geld senden" @@ -248,11 +255,11 @@ msgstr "Saldo" msgid "Logout" msgstr "Abmelden" -#: app/templates/userpanel.html:30 +#: app/templates/userpanel.html:28 msgid "Transfer" msgstr "Geld senden" -#: app/templates/userpanel.html:34 +#: app/templates/userpanel.html:32 msgid "Change Password" msgstr "Passwort ändern" diff --git a/app/static/css/main.css b/app/static/css/main.css index ab3f24a..4ba0fc7 100644 --- a/app/static/css/main.css +++ b/app/static/css/main.css @@ -97,11 +97,12 @@ table { border-radius: var(--border-radius); } -tr { +tr > th, +tr > td { background: var(--bg-color); } -tr:nth-child(2n+2) { +tr:nth-child(2n+2) > td { background: var(--bg-color2); } @@ -507,6 +508,23 @@ main { padding: .8rem 1.1rem; } +/* Statistics */ + +.statistics-container { + display: flex; + flex-direction: row; + align-items: flex-start; + justify-content: center; + flex-wrap: wrap; + max-width: 90vw; + gap: 1rem; +} + +.statistics-container > div { + height: 100%; + width: 16rem; +} + /* Responsive */ @media only screen and (max-width: 1200px) { diff --git a/app/templates/statistics.html b/app/templates/statistics.html index 4f938b9..93f3a9e 100644 --- a/app/templates/statistics.html +++ b/app/templates/statistics.html @@ -8,57 +8,96 @@ {% block content %}

{% translate "Statistics" %}

-
-
-

{% translate "Orders per drink" %}

+
+
+

{% translate "orders / drink" %}

- + {% for key, values in orders_per_drink.items %} - - + + {% endfor %}
{% translate "drink" %}{% translate "you" %} {% translate "all" %}{% translate "you" %}
{{ key }}{{ values.a|default:"0" }}{{ values.b|default:"0" }}{{ values.a|default:0 }}{{ values.b|default:0 }}
-
-

{% translate "Orders per month (last 12 months)" %}

+
+
+
+

{% translate "orders / month" %}

- + {% for key, values in orders_per_month.items %} - - + + {% endfor %}
{% translate "month" %}{% translate "you" %} {% translate "all" %}{% translate "you" %}
{{ key }}{{ values.a|default:"0" }}{{ values.b|default:"0" }}{{ values.a|default:0 }}{{ values.b|default:0 }}
-
-

{% translate "Orders per weekday" %}

+
+

{% translate "orders / weekday" %}

- + - {% for key, values in orders_per_weekday.items %} + {% for values in orders_per_weekday %} - - - + + + {% endfor %}
{% translate "day" %}{% translate "you" %} {% translate "all" %}{% translate "you" %}
{{ key }}{{ values.a|default:"0" }}{{ values.b|default:"0" }}{{ values.0 }}{{ values.1|default:0 }}{{ values.2|default:0 }}
+
+
+ {% if user.is_superuser or perms.app.view_order %} +
+

{% translate "order sum" %}

+ + + + + + {% for values in order_sum_per_user %} + + + + + {% endfor %} +
{% translate "user" %}{% translate "sum" %}
{{ values.0 }}{{ values.1|default:0.0 }} {{ currency_suffix }}
+
+ {% endif %} + {% if user.is_superuser or perms.app.view_registertransaction %} +
+

{% translate "deposit sum" %}

+ + + + + + {% for values in deposit_sum_per_user %} + + + + + {% endfor %} +
{% translate "user" %}{% translate "sum" %}
{{ values.0 }}{{ values.1|default:0.0 }} {{ currency_suffix }}
+
+ {% endif %} +
{% endblock %} \ No newline at end of file diff --git a/app/views.py b/app/views.py index b7f936b..ba864a4 100644 --- a/app/views.py +++ b/app/views.py @@ -80,11 +80,17 @@ def deposit(request): @login_required def statistics(request): + user = request.user context = { - "orders_per_month": db_queries.orders_per_month(request.user), - "orders_per_weekday": db_queries.orders_per_weekday(request.user), - "orders_per_drink": db_queries.orders_per_drink(request.user), + "orders_per_month": db_queries.select_orders_per_month(user), + "orders_per_weekday": db_queries.select_orders_per_weekday(user), + "orders_per_drink": db_queries.select_orders_per_drink(user), } + # Advanced statistics + if user.has_perm("app.view_order") or user.is_superuser: + context["order_sum_per_user"] = db_queries.select_order_sum_per_user_all_users() + if user.has_perm("app.view_registertransaction") or user.is_superuser: + context["deposit_sum_per_user"] = db_queries.select_deposit_sum_per_user_all_users() return render(request, "statistics.html", context) @login_required diff --git a/scripts/_bootstrap.py b/scripts/_bootstrap.py index 71ce28d..142781e 100755 --- a/scripts/_bootstrap.py +++ b/scripts/_bootstrap.py @@ -32,6 +32,7 @@ configuration_file = data_directory / "config.yml" caddyfile = data_directory / "Caddyfile" logfile_caddy = logfile_directory / "caddy.log" logfile_app = logfile_directory / "app.log" +logfile_sessioncleanup = logfile_directory / "session-cleanup.log" class MonitoredSubprocess: @@ -183,6 +184,6 @@ if __name__ == "__main__": MonitoredSubprocess( "Session Autocleaner", ["./scripts/_session-autocleaner.py", str(config["app"]["session_clear_interval"])], - logfile_app) + logfile_sessioncleanup) ] start_and_monitor(procs) diff --git a/start.sh b/start.sh index 8f4ba06..ab9ea5b 100755 --- a/start.sh +++ b/start.sh @@ -11,6 +11,6 @@ chmod -c -R g-w,o-rwx .gitignore export PYTHONPATH="$basedir" export DJANGO_SETTINGS_MODULE="project.settings" -export APP_VERSION="17" +export APP_VERSION="19" exec ./scripts/_bootstrap.py "$@"