Coverage for website/sales/models/product.py: 100.00%
35 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1from django.core.validators import MinValueValidator
2from django.db import models
3from django.utils.translation import gettext_lazy as _
5from payments.models import PaymentAmountField
8class Product(models.Model):
9 """Products that can be ordered."""
11 name = models.CharField(
12 verbose_name=_("name"), max_length=50, unique=True, null=False, blank=False
13 )
14 age_restricted = models.BooleanField(
15 verbose_name=_("age restricted"), default=False, null=False, blank=False
16 )
18 def __str__(self):
19 return self.name
21 class Meta:
22 """Meta class."""
24 verbose_name = _("product")
25 verbose_name_plural = _("products")
26 ordering = ["name"]
29class ProductList(models.Model):
30 """A list of products with various prices."""
32 class Meta:
33 verbose_name = _("product list")
34 verbose_name_plural = _("product lists")
36 name = models.CharField(
37 verbose_name=_("name"), max_length=50, unique=True, null=False, blank=False
38 )
39 products = models.ManyToManyField(
40 Product, verbose_name=_("products"), through="ProductListItem"
41 )
43 def __str__(self):
44 return self.name
47class ProductListItem(models.Model):
48 class Meta:
49 verbose_name = _("product")
50 verbose_name_plural = _("products")
51 ordering = ("-priority",)
53 product = models.ForeignKey(
54 Product,
55 verbose_name=_("product"),
56 null=False,
57 blank=False,
58 on_delete=models.CASCADE,
59 )
60 product_list = models.ForeignKey(
61 ProductList,
62 verbose_name=_("product list"),
63 related_name="product_items",
64 null=False,
65 blank=False,
66 on_delete=models.CASCADE,
67 )
68 price = PaymentAmountField(
69 verbose_name=_("price"),
70 allow_zero=True,
71 validators=[MinValueValidator(0)],
72 )
73 priority = models.IntegerField(
74 verbose_name=_("priority"),
75 help_text="Determines the order of the products in the list, highest first.",
76 default=1,
77 )
79 def __str__(self):
80 return f"{self.product} ({self.price})"
82 @property
83 def product_name(self):
84 return self.product.name