diff --git a/counter/forms.py b/counter/forms.py index c7df1d9d..4d299701 100644 --- a/counter/forms.py +++ b/counter/forms.py @@ -1,13 +1,19 @@ import math from django import forms +from django.core.exceptions import ValidationError from django.db.models import Q from django.utils.translation import gettext_lazy as _ +from django_celery_beat.models import ClockedSchedule, PeriodicTask from phonenumber_field.widgets import RegionalPhoneNumberWidget from club.widgets.ajax_select import AutoCompleteSelectClub from core.models import User -from core.views.forms import NFCTextInput, SelectDate, SelectDateTime +from core.views.forms import ( + NFCTextInput, + SelectDate, + SelectDateTime, +) from core.views.widgets.ajax_select import ( AutoCompleteSelect, AutoCompleteSelectMultipleGroup, @@ -158,6 +164,66 @@ class CounterEditForm(forms.ModelForm): } +class ProductArchiveForm(forms.Form): + """Form for automatic product archiving.""" + + enabled = forms.BooleanField( + label=_("Enabled"), + widget=forms.CheckboxInput(attrs={"class": "switch"}), + required=False, + ) + archive_at = forms.DateTimeField( + label=_("Date and time of archiving"), widget=SelectDateTime, required=False + ) + + def __init__(self, *args, product: Product, **kwargs): + self.product = product + self.instance = PeriodicTask.objects.filter( + task="counter.tasks.archive_product", args=f"[{product.id}]" + ).first() + super().__init__(*args, **kwargs) + if self.instance: + self.fields["enabled"].initial = self.instance.enabled + self.fields["archive_at"].initial = self.instance.clocked.clocked_time + + def clean(self): + cleaned_data = super().clean() + if cleaned_data["enabled"] is True and cleaned_data["archive_at"] is None: + raise ValidationError( + _( + "Automatic archiving cannot be enabled " + "without providing a archiving date." + ) + ) + + def save(self): + if not self.changed_data: + return + if not self.instance: + PeriodicTask.objects.create( + task="counter.tasks.archive_product", + args=f"[{self.product.id}]", + name=f"Archive product {self.product}", + clocked=ClockedSchedule.objects.create( + clocked_time=self.cleaned_data["archive_at"] + ), + enabled=self.cleaned_data["enabled"], + one_off=True, + ) + return + if ( + "archive_at" in self.changed_data + and self.cleaned_data["archive_at"] is None + ): + self.instance.delete() + elif "archive_at" in self.changed_data: + self.instance.clocked.clocked_time = self.cleaned_data["archive_at"] + self.instance.clocked.save() + self.instance.enabled = self.cleaned_data["enabled"] + self.instance.save() + return self.instance + + class ProductEditForm(forms.ModelForm): error_css_class = "error" required_css_class = "required" @@ -199,22 +265,19 @@ class ProductEditForm(forms.ModelForm): queryset=Counter.objects.all(), ) - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, *args, instance=None, **kwargs): + super().__init__(*args, instance=instance, **kwargs) if self.instance.id: self.fields["counters"].initial = self.instance.counters.all() + self.archive_form = ProductArchiveForm(*args, product=self.instance, **kwargs) + + def is_valid(self): + return super().is_valid() and self.archive_form.is_valid() def save(self, *args, **kwargs): ret = super().save(*args, **kwargs) - if self.fields["counters"].initial: - # Remove the product from all counter it was added to - # It will then only be added to selected counters - for counter in self.fields["counters"].initial: - counter.products.remove(self.instance) - counter.save() - for counter in self.cleaned_data["counters"]: - counter.products.add(self.instance) - counter.save() + self.instance.counters.set(self.cleaned_data["counters"]) + self.archive_form.save() return ret diff --git a/counter/models.py b/counter/models.py index d2b9a927..c1181de7 100644 --- a/counter/models.py +++ b/counter/models.py @@ -445,7 +445,8 @@ class Product(models.Model): buying_groups = list(self.buying_groups.all()) if not buying_groups: return True - return any(user.is_in_group(pk=group.id) for group in buying_groups) + res = any(user.is_in_group(pk=group.id) for group in buying_groups) + return res @property def profit(self): diff --git a/counter/tasks.py b/counter/tasks.py new file mode 100644 index 00000000..6c6a46b7 --- /dev/null +++ b/counter/tasks.py @@ -0,0 +1,13 @@ +# Create your tasks here + +from celery import shared_task + +from counter.models import Product + + +@shared_task +def archive_product(product_id): + product = Product.objects.get(id=product_id) + product.archived = True + product.save() + product.counters.clear() diff --git a/counter/templates/counter/product_form.jinja b/counter/templates/counter/product_form.jinja new file mode 100644 index 00000000..f4980f51 --- /dev/null +++ b/counter/templates/counter/product_form.jinja @@ -0,0 +1,31 @@ +{% extends "core/base.jinja" %} + +{% block content %} + {% if object %} +