Compare commits

..

2 Commits

4 changed files with 24 additions and 13 deletions

@ -25,6 +25,7 @@
### Improved ### Improved
* game overview: simplify playtime range display * game overview: simplify playtime range display
* new session: order devices alphabetically
## 1.3.0 / 2023-11-05 15:09+01:00 ## 1.3.0 / 2023-11-05 15:09+01:00

9
common/utils.py Normal file

@ -0,0 +1,9 @@
def safe_division(numerator: int | float, denominator: int | float) -> int | float:
"""
Divides without triggering division by zero exception.
Returns 0 if denominator is 0.
"""
try:
return numerator / denominator
except ZeroDivisionError:
return 0

@ -19,6 +19,8 @@ class SessionForm(forms.ModelForm):
widget=autofocus_select_widget, widget=autofocus_select_widget,
) )
device = forms.ModelChoiceField(queryset=Device.objects.order_by("name"))
class Meta: class Meta:
widgets = { widgets = {
"timestamp_start": custom_datetime_widget, "timestamp_start": custom_datetime_widget,

@ -1,4 +1,5 @@
from common.time import format_duration, now as now_with_tz from common.time import format_duration, now as now_with_tz
from common.utils import safe_division
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.conf import settings from django.conf import settings
from django.db.models import Sum, F, Count from django.db.models import Sum, F, Count
@ -304,17 +305,13 @@ def stats(request, year: int = 0):
purchased_unfinished = all_purchased_without_refunded_this_year.filter( purchased_unfinished = all_purchased_without_refunded_this_year.filter(
date_finished__isnull=True date_finished__isnull=True
) )
if (
purchased_unfinished.count() == 0 unfinished_purchases_percent = int(
or all_purchased_refunded_this_year.count() == 0 safe_division(
): purchased_unfinished.count(), all_purchased_refunded_this_year.count()
unfinished_purchases_percent = 0
else:
unfinished_purchases_percent = int(
purchased_unfinished.count()
/ all_purchased_refunded_this_year.count()
* 100
) )
* 100
)
all_finished_this_year = Purchase.objects.filter(date_finished__year=year).order_by( all_finished_this_year = Purchase.objects.filter(date_finished__year=year).order_by(
"date_finished" "date_finished"
@ -374,7 +371,7 @@ def stats(request, year: int = 0):
"total_spent_currency": selected_currency, "total_spent_currency": selected_currency,
"all_purchased_this_year": all_purchased_without_refunded_this_year, "all_purchased_this_year": all_purchased_without_refunded_this_year,
"spent_per_game": int( "spent_per_game": int(
total_spent / all_purchased_without_refunded_this_year.count() safe_division(total_spent, all_purchased_without_refunded_this_year.count())
), ),
"all_finished_this_year": all_finished_this_year, "all_finished_this_year": all_finished_this_year,
"this_year_finished_this_year": this_year_finished_this_year, "this_year_finished_this_year": this_year_finished_this_year,
@ -385,8 +382,10 @@ def stats(request, year: int = 0):
"purchased_unfinished": purchased_unfinished, "purchased_unfinished": purchased_unfinished,
"unfinished_purchases_percent": unfinished_purchases_percent, "unfinished_purchases_percent": unfinished_purchases_percent,
"refunded_percent": int( "refunded_percent": int(
all_purchased_refunded_this_year.count() safe_division(
/ all_purchased_this_year.count() all_purchased_refunded_this_year.count(),
all_purchased_this_year.count(),
)
* 100 * 100
), ),
"all_purchased_refunded_this_year": all_purchased_refunded_this_year, "all_purchased_refunded_this_year": all_purchased_refunded_this_year,