From e7ed349356880208eae4260d3de10a3832b4ff8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Wed, 8 Nov 2023 18:13:48 +0100 Subject: [PATCH] Add more stats * Finished (count) * Unfinished (count) * Refunded (count) --- CHANGELOG.md | 5 +- games/models.py | 13 +++++ games/static/base.css | 4 ++ games/templates/stats.html | 97 ++++++++++++++++++++++---------------- games/views.py | 52 ++++++++++++++++---- 5 files changed, 119 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e511804..4f0d3e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,11 @@ * All finished games * All finished 2023 games * All finished games that were purchased this year - * Total sessions + * Sessions (count) * Days played + * Finished (count) + * Unfinished (count) + * Refunded (count) ### Improved * game overview: simplify playtime range display diff --git a/games/models.py b/games/models.py index 082631d..c16943f 100644 --- a/games/models.py +++ b/games/models.py @@ -33,6 +33,17 @@ class Edition(models.Model): return self.name +class PurchaseQueryset(models.QuerySet): + def refunded(self): + return self.filter(date_refunded__isnull=False) + + def not_refunded(self): + return self.filter(date_refunded__isnull=True) + + def finished(self): + return self.filter(date_finished__isnull=False) + + class Purchase(models.Model): PHYSICAL = "ph" DIGITAL = "di" @@ -53,6 +64,8 @@ class Purchase(models.Model): (PIRATED, "Pirated"), ] + objects = PurchaseQueryset().as_manager() + edition = models.ForeignKey("Edition", on_delete=models.CASCADE) platform = models.ForeignKey( "Platform", on_delete=models.CASCADE, default=None, null=True, blank=True diff --git a/games/static/base.css b/games/static/base.css index e159d66..9790306 100644 --- a/games/static/base.css +++ b/games/static/base.css @@ -1438,6 +1438,10 @@ th label { display: block; } + .md\:w-1\/2 { + width: 50%; + } + .md\:w-auto { width: auto; } diff --git a/games/templates/stats.html b/games/templates/stats.html index 08816b3..48acd3c 100644 --- a/games/templates/stats.html +++ b/games/templates/stats.html @@ -16,47 +16,62 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StatisticValue
Hours{{ total_hours }}
Sessions{{ total_sessions }}
Days Played{{ unique_days }} ({{ unique_days_percent }}%)
Games{{ total_games }}
Games ({{ year }}){{ total_2023_games }}
Purchases{{ all_purchased_this_year.count }}
Spendings ({{ total_spent_currency }}){{ total_spent }}
{{ total_spent_currency }}/game{{ spent_per_game }}
+
+
+

Playtime

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hours{{ total_hours }}
Sessions{{ total_sessions }}
Days{{ unique_days }} ({{ unique_days_percent }}%)
Games{{ total_games }}
Games ({{ year }}){{ total_2023_games }}
Finished{{ all_finished_this_year.count }}
+
+
+

Purchases

+ + + + + + + + + + + + + + + + + + + +
Total{{ all_purchased_this_year.count }}
Refunded{{ all_purchased_refunded_this_year.count }} ({{ refunded_percent }}%)
Unfinished{{ purchased_unfinished.count }} ({{ unfinished_purchases_percent }}%)
Spendings ({{ total_spent_currency }}){{ total_spent }} ({{ spent_per_game }}/game)
+
+

Top games by playtime

diff --git a/games/views.py b/games/views.py index 6989c2d..5196801 100644 --- a/games/views.py +++ b/games/views.py @@ -291,19 +291,40 @@ def stats(request, year: int = 0): all_purchased_this_year = ( Purchase.objects.filter(date_purchased__year=year) .filter(price_currency__exact=selected_currency) - .filter(date_refunded__exact=None) + .order_by("date_purchased") + ) + all_purchased_without_refunded_this_year = all_purchased_this_year.not_refunded() + all_purchased_refunded_this_year = ( + Purchase.objects.filter(date_purchased__year=year) + .filter(price_currency__exact=selected_currency) + .refunded() .order_by("date_purchased") ) - all_finished_this_year = Purchase.objects.filter(date_finished__year=year) - this_year_finished_this_year = Purchase.objects.filter( - date_finished__year=year - ).filter(edition__year_released=year) - purchased_this_year_finished_this_year = all_purchased_this_year.filter( - date_finished__year=year + purchased_unfinished = all_purchased_without_refunded_this_year.filter( + date_finished__isnull=True + ) + unfinished_purchases_percent = int( + purchased_unfinished.count() / all_purchased_refunded_this_year.count() * 100 ) - this_year_spendings = all_purchased_this_year.aggregate(total_spent=Sum(F("price"))) + all_finished_this_year = Purchase.objects.filter(date_finished__year=year).order_by( + "date_finished" + ) + this_year_finished_this_year = ( + Purchase.objects.filter(date_finished__year=year) + .filter(edition__year_released=year) + .order_by("date_finished") + ) + purchased_this_year_finished_this_year = ( + all_purchased_without_refunded_this_year.filter( + date_finished__year=year + ).order_by("date_finished") + ) + + this_year_spendings = all_purchased_without_refunded_this_year.aggregate( + total_spent=Sum(F("price")) + ) total_spent = this_year_spendings["total_spent"] games_with_playtime = ( @@ -343,14 +364,25 @@ def stats(request, year: int = 0): "total_playtime_per_platform": total_playtime_per_platform, "total_spent": total_spent, "total_spent_currency": selected_currency, - "all_purchased_this_year": all_purchased_this_year, - "spent_per_game": int(total_spent / all_purchased_this_year.count()), + "all_purchased_this_year": all_purchased_without_refunded_this_year, + "spent_per_game": int( + total_spent / all_purchased_without_refunded_this_year.count() + ), "all_finished_this_year": all_finished_this_year, "this_year_finished_this_year": this_year_finished_this_year, "purchased_this_year_finished_this_year": purchased_this_year_finished_this_year, "total_sessions": year_sessions.count(), "unique_days": unique_days["dates"], "unique_days_percent": int(unique_days["dates"] / 365 * 100), + "purchased_unfinished": purchased_unfinished, + "unfinished_purchases_percent": unfinished_purchases_percent, + "refunded_percent": int( + all_purchased_refunded_this_year.count() + / all_purchased_this_year.count() + * 100 + ), + "all_purchased_refunded_this_year": all_purchased_refunded_this_year, + "all_purchased_this_year": all_purchased_this_year, } request.session["return_path"] = request.path