mirror of
https://github.com/ae-utbm/sith.git
synced 2025-12-09 14:45:59 +00:00
add checks on ProductForm
This commit is contained in:
@@ -5,7 +5,7 @@ from datetime import date, datetime, timezone
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import MaxValueValidator
|
||||
from django.db.models import Exists, OuterRef, Q
|
||||
from django.forms import BaseModelFormSet
|
||||
from django.utils.timezone import now
|
||||
@@ -318,7 +318,6 @@ class ProductForm(forms.ModelForm):
|
||||
}
|
||||
|
||||
counters = forms.ModelMultipleChoiceField(
|
||||
help_text=None,
|
||||
label=_("Counters"),
|
||||
required=False,
|
||||
widget=AutoCompleteSelectMultipleCounter,
|
||||
@@ -329,10 +328,31 @@ class ProductForm(forms.ModelForm):
|
||||
super().__init__(*args, instance=instance, **kwargs)
|
||||
if self.instance.id:
|
||||
self.fields["counters"].initial = self.instance.counters.all()
|
||||
if hasattr(self.instance, "formula"):
|
||||
self.formula_init(self.instance.formula)
|
||||
self.action_formset = ScheduledProductActionFormSet(
|
||||
*args, product=self.instance, **kwargs
|
||||
)
|
||||
|
||||
def formula_init(self, formula: ProductFormula):
|
||||
"""Part of the form initialisation specific to formula products."""
|
||||
self.fields["selling_price"].help_text = _(
|
||||
"This product is a formula. "
|
||||
"Its price cannot be greater than the price "
|
||||
"of the products constituting it, which is %(price)s €"
|
||||
) % {"price": formula.max_selling_price}
|
||||
self.fields["special_selling_price"].help_text = _(
|
||||
"This product is a formula. "
|
||||
"Its special price cannot be greater than the price "
|
||||
"of the products constituting it, which is %(price)s €"
|
||||
) % {"price": formula.max_special_selling_price}
|
||||
for key, price in (
|
||||
("selling_price", formula.max_selling_price),
|
||||
("special_selling_price", formula.max_special_selling_price),
|
||||
):
|
||||
self.fields[key].widget.attrs["max"] = price
|
||||
self.fields[key].validators.append(MaxValueValidator(price))
|
||||
|
||||
def is_valid(self):
|
||||
return super().is_valid() and self.action_formset.is_valid()
|
||||
|
||||
@@ -362,11 +382,25 @@ class ProductFormulaForm(forms.ModelForm):
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if cleaned_data["result"] in cleaned_data["products"]:
|
||||
self.add_error(
|
||||
None,
|
||||
_(
|
||||
"The same product cannot be at the same time "
|
||||
"the result and a part of the formula."
|
||||
),
|
||||
)
|
||||
prices = [p.selling_price for p in cleaned_data["products"]]
|
||||
special_prices = [p.special_selling_price for p in cleaned_data["products"]]
|
||||
selling_price = cleaned_data["result"].selling_price
|
||||
if selling_price > sum(prices):
|
||||
raise ValidationError(
|
||||
_("This formula is more expensive than its constituant products.")
|
||||
special_selling_price = cleaned_data["result"].special_selling_price
|
||||
if selling_price > sum(prices) or special_selling_price > sum(special_prices):
|
||||
self.add_error(
|
||||
"result",
|
||||
_(
|
||||
"The result cannot be more expensive "
|
||||
"than the total of the other products."
|
||||
),
|
||||
)
|
||||
return cleaned_data
|
||||
|
||||
|
||||
@@ -464,6 +464,7 @@ class ProductFormula(models.Model):
|
||||
)
|
||||
result = models.OneToOneField(
|
||||
Product,
|
||||
related_name="formula",
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name=_("result product"),
|
||||
help_text=_("The product got with the formula."),
|
||||
@@ -472,6 +473,18 @@ class ProductFormula(models.Model):
|
||||
def __str__(self):
|
||||
return self.result.name
|
||||
|
||||
@cached_property
|
||||
def max_selling_price(self) -> float:
|
||||
# iterating over all products is less efficient than doing
|
||||
# a simple aggregation, but this method is likely to be used in
|
||||
# coordination with `max_special_selling_price`,
|
||||
# and Django caches the result of the `all` queryset.
|
||||
return sum(p.selling_price for p in self.products.all())
|
||||
|
||||
@cached_property
|
||||
def max_special_selling_price(self) -> float:
|
||||
return sum(p.special_selling_price for p in self.products.all())
|
||||
|
||||
|
||||
class CounterQuerySet(models.QuerySet):
|
||||
def annotate_has_barman(self, user: User) -> Self:
|
||||
|
||||
Reference in New Issue
Block a user