diff --git a/games/forms.py b/games/forms.py index b67c294..71119a8 100644 --- a/games/forms.py +++ b/games/forms.py @@ -91,6 +91,7 @@ class PurchaseForm(forms.ModelForm): "date_purchased", "date_refunded", "date_finished", + "status", "price", "price_currency", "ownership_type", diff --git a/games/migrations/0034_purchase_status.py b/games/migrations/0034_purchase_status.py new file mode 100644 index 0000000..be0382c --- /dev/null +++ b/games/migrations/0034_purchase_status.py @@ -0,0 +1,26 @@ +# Generated by Django 4.2.7 on 2023-12-22 10:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("games", "0033_alter_edition_unique_together"), + ] + + operations = [ + migrations.AddField( + model_name="purchase", + name="status", + field=models.IntegerField( + choices=[ + (0, "Unplayed"), + (1, "Playing"), + (2, "Dropped"), + (3, "Finished"), + ], + default=0, + ), + ), + ] diff --git a/games/migrations/0035_auto_20231222_1109.py b/games/migrations/0035_auto_20231222_1109.py new file mode 100644 index 0000000..01c774c --- /dev/null +++ b/games/migrations/0035_auto_20231222_1109.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.7 on 2023-12-22 10:09 + +from django.db import migrations + +from games.models import Purchase + + +def set_default_state(apps, schema_editor): + Purchase.objects.filter(session__isnull=False).update( + status=Purchase.PurchaseState.PLAYING + ) + Purchase.objects.filter(date_finished__isnull=False).update( + status=Purchase.PurchaseState.FINISHED + ) + + +class Migration(migrations.Migration): + dependencies = [ + ("games", "0034_purchase_status"), + ] + + operations = [migrations.RunPython(set_default_state)] diff --git a/games/models.py b/games/models.py index 1b23611..3d2c04d 100644 --- a/games/models.py +++ b/games/models.py @@ -133,6 +133,25 @@ class Purchase(models.Model): ) created_at = models.DateTimeField(auto_now_add=True) + class PurchaseState(models.IntegerChoices): + UNPLAYED = ( + 0, + "Unplayed", + ) + PLAYING = (1, "Playing") + DROPPED = ( + 2, + "Dropped", + ) + FINISHED = ( + 3, + "Finished", + ) + + status = models.IntegerField( + choices=PurchaseState.choices, default=PurchaseState.UNPLAYED + ) + def __str__(self): additional_info = [ self.get_type_display() if self.type != Purchase.GAME else "", diff --git a/games/templates/stats.html b/games/templates/stats.html index c6977b9..088c18a 100644 --- a/games/templates/stats.html +++ b/games/templates/stats.html @@ -137,6 +137,7 @@ Name Date + Playtime @@ -153,6 +154,7 @@ {{ purchase.date_finished | date:"d/m/Y" }} + {{ purchase.formatted_playtime }} {% endfor %} diff --git a/games/views.py b/games/views.py index 8cd5eed..6ca4775 100644 --- a/games/views.py +++ b/games/views.py @@ -371,6 +371,16 @@ def stats(request, year: int = 0): ) purchases_finished_this_year = Purchase.objects.filter(date_finished__year=year) + purchases_finished_this_year_with_playtime = purchases_finished_this_year.annotate( + total_playtime=Sum( + F("session__duration_calculated") + F("session__duration_manual") + ) + ) + + for purchase in purchases_finished_this_year_with_playtime: + formatted_playtime = format_duration(purchase.total_playtime, "%2.0H") + setattr(purchase, "formatted_playtime", formatted_playtime) + purchases_finished_this_year_released_this_year = ( purchases_finished_this_year.filter(edition__year_released=year).order_by( "date_finished" @@ -442,7 +452,7 @@ def stats(request, year: int = 0): "spent_per_game": int( safe_division(total_spent, this_year_purchases_without_refunded.count()) ), - "all_finished_this_year": purchases_finished_this_year.order_by( + "all_finished_this_year": purchases_finished_this_year_with_playtime.order_by( "date_finished" ), "this_year_finished_this_year": purchases_finished_this_year_released_this_year.order_by(