2022-12-31 13:18:27 +00:00
|
|
|
from django import forms
|
2023-11-15 13:25:42 +00:00
|
|
|
from django.urls import reverse
|
2023-11-15 18:36:22 +00:00
|
|
|
|
|
|
|
from games.models import Device, Edition, Game, Platform, Purchase, Session
|
2022-12-31 13:18:27 +00:00
|
|
|
|
2023-02-20 20:33:15 +00:00
|
|
|
custom_date_widget = forms.DateInput(attrs={"type": "date"})
|
|
|
|
custom_datetime_widget = forms.DateTimeInput(
|
|
|
|
attrs={"type": "datetime-local"}, format="%Y-%m-%d %H:%M"
|
|
|
|
)
|
2023-09-30 10:40:02 +00:00
|
|
|
autofocus_input_widget = forms.TextInput(attrs={"autofocus": "autofocus"})
|
2023-02-20 20:33:15 +00:00
|
|
|
|
2022-12-31 13:18:27 +00:00
|
|
|
|
|
|
|
class SessionForm(forms.ModelForm):
|
2023-09-16 16:18:03 +00:00
|
|
|
# purchase = forms.ModelChoiceField(
|
|
|
|
# queryset=Purchase.objects.filter(date_refunded=None).order_by("edition__name")
|
|
|
|
# )
|
2023-02-18 19:49:46 +00:00
|
|
|
purchase = forms.ModelChoiceField(
|
2023-11-09 13:49:00 +00:00
|
|
|
queryset=Purchase.objects.order_by("edition__sort_name"),
|
|
|
|
widget=forms.Select(attrs={"autofocus": "autofocus"}),
|
2023-02-18 19:49:46 +00:00
|
|
|
)
|
2023-01-20 17:27:30 +00:00
|
|
|
|
2023-11-09 09:09:32 +00:00
|
|
|
device = forms.ModelChoiceField(queryset=Device.objects.order_by("name"))
|
|
|
|
|
2022-12-31 13:18:27 +00:00
|
|
|
class Meta:
|
2023-02-20 20:33:15 +00:00
|
|
|
widgets = {
|
|
|
|
"timestamp_start": custom_datetime_widget,
|
|
|
|
"timestamp_end": custom_datetime_widget,
|
|
|
|
}
|
2022-12-31 13:18:27 +00:00
|
|
|
model = Session
|
|
|
|
fields = [
|
|
|
|
"purchase",
|
|
|
|
"timestamp_start",
|
|
|
|
"timestamp_end",
|
|
|
|
"duration_manual",
|
2023-02-18 20:12:18 +00:00
|
|
|
"device",
|
2022-12-31 13:18:27 +00:00
|
|
|
"note",
|
|
|
|
]
|
|
|
|
|
|
|
|
|
2023-02-20 16:15:21 +00:00
|
|
|
class EditionChoiceField(forms.ModelChoiceField):
|
|
|
|
def label_from_instance(self, obj) -> str:
|
2023-11-09 13:49:00 +00:00
|
|
|
return f"{obj.sort_name} ({obj.platform}, {obj.year_released})"
|
|
|
|
|
|
|
|
|
|
|
|
class IncludePlatformSelect(forms.Select):
|
|
|
|
def create_option(self, name, value, *args, **kwargs):
|
|
|
|
option = super().create_option(name, value, *args, **kwargs)
|
|
|
|
if value:
|
|
|
|
option["attrs"]["data-platform"] = value.instance.platform.id
|
|
|
|
return option
|
2023-02-20 16:15:21 +00:00
|
|
|
|
|
|
|
|
2022-12-31 13:18:27 +00:00
|
|
|
class PurchaseForm(forms.ModelForm):
|
2023-11-15 13:25:42 +00:00
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
# Automatically update related_purchase <select/>
|
|
|
|
# to only include purchases of the selected edition.
|
|
|
|
related_purchase_by_edition_url = reverse("related_purchase_by_edition")
|
|
|
|
self.fields["edition"].widget.attrs.update(
|
|
|
|
{
|
2023-11-16 18:03:16 +00:00
|
|
|
"hx-trigger": "load, click",
|
2023-11-15 13:25:42 +00:00
|
|
|
"hx-get": related_purchase_by_edition_url,
|
|
|
|
"hx-target": "#id_related_purchase",
|
|
|
|
"hx-swap": "outerHTML",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2023-09-30 10:40:02 +00:00
|
|
|
edition = EditionChoiceField(
|
2023-11-09 13:49:00 +00:00
|
|
|
queryset=Edition.objects.order_by("sort_name"),
|
|
|
|
widget=IncludePlatformSelect(attrs={"autoselect": "autoselect"}),
|
2023-09-30 10:40:02 +00:00
|
|
|
)
|
2023-01-20 17:27:30 +00:00
|
|
|
platform = forms.ModelChoiceField(queryset=Platform.objects.order_by("name"))
|
2023-11-14 18:27:00 +00:00
|
|
|
related_purchase = forms.ModelChoiceField(
|
2023-11-14 18:55:19 +00:00
|
|
|
queryset=Purchase.objects.filter(type=Purchase.GAME).order_by(
|
|
|
|
"edition__sort_name"
|
2023-11-15 12:04:47 +00:00
|
|
|
),
|
|
|
|
required=False,
|
2023-11-14 18:27:00 +00:00
|
|
|
)
|
2023-01-20 17:27:30 +00:00
|
|
|
|
2022-12-31 13:18:27 +00:00
|
|
|
class Meta:
|
2023-02-20 20:33:15 +00:00
|
|
|
widgets = {
|
|
|
|
"date_purchased": custom_date_widget,
|
|
|
|
"date_refunded": custom_date_widget,
|
2023-11-06 18:48:12 +00:00
|
|
|
"date_finished": custom_date_widget,
|
2023-02-20 20:33:15 +00:00
|
|
|
}
|
2022-12-31 13:18:27 +00:00
|
|
|
model = Purchase
|
2023-02-18 19:53:47 +00:00
|
|
|
fields = [
|
|
|
|
"edition",
|
|
|
|
"platform",
|
|
|
|
"date_purchased",
|
|
|
|
"date_refunded",
|
2023-11-06 18:48:12 +00:00
|
|
|
"date_finished",
|
2023-02-18 19:53:47 +00:00
|
|
|
"price",
|
|
|
|
"price_currency",
|
2023-02-18 19:57:03 +00:00
|
|
|
"ownership_type",
|
2023-11-14 18:27:00 +00:00
|
|
|
"type",
|
|
|
|
"related_purchase",
|
|
|
|
"name",
|
2023-02-18 19:53:47 +00:00
|
|
|
]
|
2023-02-18 19:49:46 +00:00
|
|
|
|
2023-11-15 12:04:47 +00:00
|
|
|
def clean(self):
|
|
|
|
cleaned_data = super().clean()
|
|
|
|
purchase_type = cleaned_data.get("type")
|
|
|
|
related_purchase = cleaned_data.get("related_purchase")
|
|
|
|
name = cleaned_data.get("name")
|
|
|
|
|
|
|
|
# Set the type on the instance to use get_type_display()
|
|
|
|
# This is safe because we're not saving the instance.
|
|
|
|
self.instance.type = purchase_type
|
|
|
|
|
|
|
|
if purchase_type != Purchase.GAME:
|
|
|
|
type_display = self.instance.get_type_display()
|
|
|
|
if not related_purchase:
|
|
|
|
self.add_error(
|
|
|
|
"related_purchase",
|
|
|
|
f"{type_display} must have a related purchase.",
|
|
|
|
)
|
|
|
|
if not name:
|
|
|
|
self.add_error("name", f"{type_display} must have a name.")
|
|
|
|
return cleaned_data
|
|
|
|
|
2023-02-18 19:49:46 +00:00
|
|
|
|
2023-11-09 13:49:00 +00:00
|
|
|
class IncludeNameSelect(forms.Select):
|
|
|
|
def create_option(self, name, value, *args, **kwargs):
|
|
|
|
option = super().create_option(name, value, *args, **kwargs)
|
|
|
|
if value:
|
|
|
|
option["attrs"]["data-name"] = value.instance.name
|
2023-11-09 14:20:30 +00:00
|
|
|
option["attrs"]["data-year"] = value.instance.year_released
|
2023-11-09 13:49:00 +00:00
|
|
|
return option
|
|
|
|
|
|
|
|
|
|
|
|
class GameModelChoiceField(forms.ModelChoiceField):
|
|
|
|
def label_from_instance(self, obj):
|
|
|
|
# Use sort_name as the label for the option
|
|
|
|
return obj.sort_name
|
|
|
|
|
|
|
|
|
2023-02-18 19:49:46 +00:00
|
|
|
class EditionForm(forms.ModelForm):
|
2023-11-09 13:49:00 +00:00
|
|
|
game = GameModelChoiceField(
|
|
|
|
queryset=Game.objects.order_by("sort_name"),
|
|
|
|
widget=IncludeNameSelect(attrs={"autofocus": "autofocus"}),
|
2023-09-30 10:40:02 +00:00
|
|
|
)
|
2023-11-06 18:48:12 +00:00
|
|
|
platform = forms.ModelChoiceField(
|
|
|
|
queryset=Platform.objects.order_by("name"), required=False
|
|
|
|
)
|
2023-02-20 16:14:43 +00:00
|
|
|
|
2023-02-18 19:49:46 +00:00
|
|
|
class Meta:
|
|
|
|
model = Edition
|
2023-11-09 13:49:00 +00:00
|
|
|
fields = ["game", "name", "sort_name", "platform", "year_released", "wikidata"]
|
2022-12-31 13:18:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
class GameForm(forms.ModelForm):
|
|
|
|
class Meta:
|
|
|
|
model = Game
|
2023-11-09 13:49:00 +00:00
|
|
|
fields = ["name", "sort_name", "year_released", "wikidata"]
|
2023-09-30 10:40:02 +00:00
|
|
|
widgets = {"name": autofocus_input_widget}
|
2023-01-04 16:23:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PlatformForm(forms.ModelForm):
|
|
|
|
class Meta:
|
|
|
|
model = Platform
|
|
|
|
fields = ["name", "group"]
|
2023-09-30 10:40:02 +00:00
|
|
|
widgets = {"name": autofocus_input_widget}
|
2023-02-18 20:12:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
class DeviceForm(forms.ModelForm):
|
|
|
|
class Meta:
|
|
|
|
model = Device
|
|
|
|
fields = ["name", "type"]
|
2023-09-30 10:40:02 +00:00
|
|
|
widgets = {"name": autofocus_input_widget}
|