diff --git a/src/purchase/admin.py b/src/purchase/admin.py index 308c300..04e7171 100644 --- a/src/purchase/admin.py +++ b/src/purchase/admin.py @@ -9,8 +9,15 @@ from purchase.templatetags.purchase import currency @register(Product) class ProductAdmin(admin.ModelAdmin): - list_display = ["name", "display_order", "unit_price", "sold", "turnover"] - list_editable = ["display_order"] + list_display = [ + "name", + "display_order", + "initials", + "unit_price", + "sold", + "turnover", + ] + list_editable = ["display_order", "initials"] search_fields = ["name"] def get_queryset(self, request): diff --git a/src/purchase/fixtures/products.json b/src/purchase/fixtures/products.json index f766d2f..11efa22 100644 --- a/src/purchase/fixtures/products.json +++ b/src/purchase/fixtures/products.json @@ -3,10 +3,10 @@ "model": "purchase.product", "fields": { "created_at": "2022-04-26T20:30:22.959Z", - "updated_at": "2022-04-26T20:30:22.959Z", + "updated_at": "2023-04-02T13:47:16.252Z", "name": "Clou", - "image": "", - "unit_price_cents": 134, + "unit_price_cents": 140, + "initials": "C", "display_order": 1 } }, @@ -14,10 +14,10 @@ "model": "purchase.product", "fields": { "created_at": "2022-04-26T20:30:22.959Z", - "updated_at": "2022-04-27T21:04:04.197Z", + "updated_at": "2023-04-02T13:47:52.602Z", "name": "Villard'Ain", - "image": "", - "unit_price_cents": 290, + "unit_price_cents": 310, + "initials": "V", "display_order": 2 } }, @@ -25,10 +25,10 @@ "model": "purchase.product", "fields": { "created_at": "2022-04-26T20:30:22.959Z", - "updated_at": "2022-04-28T16:09:00.142Z", + "updated_at": "2023-04-02T13:47:52.608Z", "name": "Herbier", - "image": "", - "unit_price_cents": 330, + "unit_price_cents": 360, + "initials": "Hb", "display_order": 4 } }, @@ -36,21 +36,21 @@ "model": "purchase.product", "fields": { "created_at": "2022-04-26T20:30:22.959Z", - "updated_at": "2022-04-27T21:04:04.192Z", + "updated_at": "2023-04-02T13:47:52.622Z", "name": "Blanc vache", - "image": "", - "unit_price_cents": 650, - "display_order": 3 + "unit_price_cents": 360, + "initials": "BV", + "display_order": 10 } }, { "model": "purchase.product", "fields": { "created_at": "2022-04-28T16:08:08.298Z", - "updated_at": "2022-04-28T16:09:13.196Z", + "updated_at": "2023-04-02T13:47:52.610Z", "name": "Ap\u00e9rich\u00e8vres", - "image": "", - "unit_price_cents": 330, + "unit_price_cents": 360, + "initials": "Ac", "display_order": 5 } }, @@ -58,10 +58,10 @@ "model": "purchase.product", "fields": { "created_at": "2022-04-28T16:08:16.542Z", - "updated_at": "2022-04-28T16:09:25.690Z", + "updated_at": "2023-04-02T13:47:52.614Z", "name": "Clougert", - "image": "", - "unit_price_cents": 450, + "unit_price_cents": 470, + "initials": "CM", "display_order": 6 } }, @@ -69,10 +69,10 @@ "model": "purchase.product", "fields": { "created_at": "2022-04-28T16:08:20.471Z", - "updated_at": "2022-04-28T16:09:34.003Z", + "updated_at": "2023-04-02T13:47:52.617Z", "name": "Brique", - "image": "", - "unit_price_cents": 290, + "unit_price_cents": 310, + "initials": "Bq", "display_order": 7 } }, @@ -80,11 +80,154 @@ "model": "purchase.product", "fields": { "created_at": "2022-04-28T16:08:20.471Z", - "updated_at": "2022-04-28T16:09:34.003Z", + "updated_at": "2023-04-02T13:47:52.619Z", "name": "Tomme de ch\u00e8vre", - "image": "", "unit_price_cents": 0, + "initials": "T", "display_order": 8 } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T12:47:15.522Z", + "updated_at": "2023-04-02T13:47:52.640Z", + "name": "Cr\u00eapes chocolat", + "unit_price_cents": 200, + "initials": "CrC", + "display_order": 20 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:02:38.149Z", + "updated_at": "2023-04-02T13:47:52.605Z", + "name": "Caprinoux", + "unit_price_cents": 100, + "initials": "Cap", + "display_order": 3 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:31:13.712Z", + "updated_at": "2023-04-02T13:47:52.624Z", + "name": "Clou affin\u00e9", + "unit_price_cents": 160, + "initials": "CA", + "display_order": 11 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:32:12.289Z", + "updated_at": "2023-04-02T13:47:52.626Z", + "name": "Ap\u00e9rich\u00e8vres frais", + "unit_price_cents": 250, + "initials": "AcF", + "display_order": 12 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:32:29.365Z", + "updated_at": "2023-04-02T13:47:52.628Z", + "name": "Blanc ch\u00e8vre", + "unit_price_cents": 480, + "initials": "BC", + "display_order": 13 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:32:41.308Z", + "updated_at": "2023-04-02T13:47:52.629Z", + "name": "Gros de vache", + "unit_price_cents": 200, + "initials": "GV", + "display_order": 14 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:32:48.404Z", + "updated_at": "2023-04-02T13:47:52.631Z", + "name": "P'tit clou", + "unit_price_cents": 60, + "initials": "PC", + "display_order": 15 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:33:12.184Z", + "updated_at": "2023-04-02T13:47:52.633Z", + "name": "Ap\u00e9rivache", + "unit_price_cents": 300, + "initials": "AV", + "display_order": 16 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:33:24.357Z", + "updated_at": "2023-04-02T13:47:52.635Z", + "name": "Fromage fort", + "unit_price_cents": 360, + "initials": "FF", + "display_order": 17 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:33:49.793Z", + "updated_at": "2023-04-02T13:47:52.636Z", + "name": "Lait de ch\u00e8vre", + "unit_price_cents": 200, + "initials": "L", + "display_order": 18 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:33:54.405Z", + "updated_at": "2023-04-02T13:47:52.638Z", + "name": "Verre", + "unit_price_cents": 100, + "initials": "V", + "display_order": 19 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:34:34.802Z", + "updated_at": "2023-04-02T13:47:52.641Z", + "name": "Cr\u00eape sucre", + "unit_price_cents": 150, + "initials": "CrS", + "display_order": 21 + } + }, + { + "model": "purchase.product", + "fields": { + "created_at": "2023-04-02T13:34:44.535Z", + "updated_at": "2023-04-02T13:47:52.643Z", + "name": "Cr\u00eape nature", + "unit_price_cents": 140, + "initials": "CrN", + "display_order": 22 + } } ] diff --git a/src/purchase/migrations/0015_remove_product_image_product_initials.py b/src/purchase/migrations/0015_remove_product_image_product_initials.py new file mode 100644 index 0000000..36d5bb9 --- /dev/null +++ b/src/purchase/migrations/0015_remove_product_image_product_initials.py @@ -0,0 +1,22 @@ +# Generated by Django 4.1.7 on 2023-04-02 13:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("purchase", "0014_alter_basket_payment_method"), + ] + + operations = [ + migrations.RemoveField( + model_name="product", + name="image", + ), + migrations.AddField( + model_name="product", + name="initials", + field=models.CharField(default="", max_length=10, verbose_name="initials"), + preserve_default=False, + ), + ] diff --git a/src/purchase/models.py b/src/purchase/models.py index 4470d77..fc2344b 100644 --- a/src/purchase/models.py +++ b/src/purchase/models.py @@ -9,7 +9,6 @@ from django.db.models.functions import Coalesce from django.urls import reverse from django.utils.translation import gettext from django.utils.translation import gettext_lazy as _ -from PIL import Image, ImageOps from solo.models import SingletonModel @@ -91,13 +90,18 @@ class ProductManager(models.Manager): class Product(Model): name = models.CharField(max_length=250, unique=True, verbose_name=_("name")) - image = models.ImageField(null=True, blank=True, verbose_name=_("image")) unit_price_cents = models.PositiveIntegerField( verbose_name=_("unit price (cents)"), help_text=_( "Unit price in cents. Use zero to denote that the product has no fixed price.", ), ) + initials = models.CharField( + max_length=10, + verbose_name=_("initials"), + blank=False, + null=False, + ) display_order = models.PositiveIntegerField( default=default_product_display_order, verbose_name=_("display order"), @@ -127,42 +131,6 @@ class Product(Model): def has_fixed_price(self) -> bool: return self.unit_price_cents > 0 - def save(self, *args, **kwargs): - super().save(*args, **kwargs) - if not self.image: - return - with Image.open(self.image.path) as img_file: - img = ImageOps.exif_transpose(img_file) - - width, height = img.size # Get dimensions - - image_max_size = 300 - if width > image_max_size and height > image_max_size: - # keep ratio but shrink down - img.thumbnail((width, height)) - - # check which one is smaller - if height < width: - # make square by cutting off equal amounts left and right - left = (width - height) / 2 - right = (width + height) / 2 - top = 0 - bottom = height - img = img.crop((left, top, right, bottom)) - - elif width < height: - # make square by cutting off bottom - left = 0 - right = width - top = 0 - bottom = width - img = img.crop((left, top, right, bottom)) - - if width > image_max_size and height > image_max_size: - img.thumbnail((image_max_size, image_max_size)) - - img.save(self.image.path) - class BasketQuerySet(models.QuerySet): def priced(self) -> BasketQuerySet: diff --git a/src/purchase/templates/purchase/snippets/basket_item.html b/src/purchase/templates/purchase/snippets/basket_item.html index 55ec52a..c91ab0e 100644 --- a/src/purchase/templates/purchase/snippets/basket_item.html +++ b/src/purchase/templates/purchase/snippets/basket_item.html @@ -7,7 +7,7 @@
- {{ product.name|slice:"1" }} + {{ product.initials }}
{% endif %} diff --git a/src/purchase/templates/purchase/snippets/basket_unpriced_item.html b/src/purchase/templates/purchase/snippets/basket_unpriced_item.html index 79cf126..0c9ea87 100644 --- a/src/purchase/templates/purchase/snippets/basket_unpriced_item.html +++ b/src/purchase/templates/purchase/snippets/basket_unpriced_item.html @@ -7,7 +7,7 @@
- {{ product.name|slice:"1" }} + {{ product.initials }}
{% endif %}