mirror of
https://github.com/Crocmagnon/checkout.git
synced 2024-11-25 01:28:02 +01:00
Remove product image and add initials
This commit is contained in:
parent
90787707d1
commit
93829df543
6 changed files with 206 additions and 66 deletions
|
@ -9,8 +9,15 @@ from purchase.templatetags.purchase import currency
|
||||||
|
|
||||||
@register(Product)
|
@register(Product)
|
||||||
class ProductAdmin(admin.ModelAdmin):
|
class ProductAdmin(admin.ModelAdmin):
|
||||||
list_display = ["name", "display_order", "unit_price", "sold", "turnover"]
|
list_display = [
|
||||||
list_editable = ["display_order"]
|
"name",
|
||||||
|
"display_order",
|
||||||
|
"initials",
|
||||||
|
"unit_price",
|
||||||
|
"sold",
|
||||||
|
"turnover",
|
||||||
|
]
|
||||||
|
list_editable = ["display_order", "initials"]
|
||||||
search_fields = ["name"]
|
search_fields = ["name"]
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-26T20:30:22.959Z",
|
"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",
|
"name": "Clou",
|
||||||
"image": "",
|
"unit_price_cents": 140,
|
||||||
"unit_price_cents": 134,
|
"initials": "C",
|
||||||
"display_order": 1
|
"display_order": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -14,10 +14,10 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-26T20:30:22.959Z",
|
"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",
|
"name": "Villard'Ain",
|
||||||
"image": "",
|
"unit_price_cents": 310,
|
||||||
"unit_price_cents": 290,
|
"initials": "V",
|
||||||
"display_order": 2
|
"display_order": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -25,10 +25,10 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-26T20:30:22.959Z",
|
"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",
|
"name": "Herbier",
|
||||||
"image": "",
|
"unit_price_cents": 360,
|
||||||
"unit_price_cents": 330,
|
"initials": "Hb",
|
||||||
"display_order": 4
|
"display_order": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -36,21 +36,21 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-26T20:30:22.959Z",
|
"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",
|
"name": "Blanc vache",
|
||||||
"image": "",
|
"unit_price_cents": 360,
|
||||||
"unit_price_cents": 650,
|
"initials": "BV",
|
||||||
"display_order": 3
|
"display_order": 10
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-28T16:08:08.298Z",
|
"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",
|
"name": "Ap\u00e9rich\u00e8vres",
|
||||||
"image": "",
|
"unit_price_cents": 360,
|
||||||
"unit_price_cents": 330,
|
"initials": "Ac",
|
||||||
"display_order": 5
|
"display_order": 5
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -58,10 +58,10 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-28T16:08:16.542Z",
|
"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",
|
"name": "Clougert",
|
||||||
"image": "",
|
"unit_price_cents": 470,
|
||||||
"unit_price_cents": 450,
|
"initials": "CM",
|
||||||
"display_order": 6
|
"display_order": 6
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69,10 +69,10 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-28T16:08:20.471Z",
|
"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",
|
"name": "Brique",
|
||||||
"image": "",
|
"unit_price_cents": 310,
|
||||||
"unit_price_cents": 290,
|
"initials": "Bq",
|
||||||
"display_order": 7
|
"display_order": 7
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -80,11 +80,154 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2022-04-28T16:08:20.471Z",
|
"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",
|
"name": "Tomme de ch\u00e8vre",
|
||||||
"image": "",
|
|
||||||
"unit_price_cents": 0,
|
"unit_price_cents": 0,
|
||||||
|
"initials": "T",
|
||||||
"display_order": 8
|
"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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -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,
|
||||||
|
),
|
||||||
|
]
|
|
@ -9,7 +9,6 @@ from django.db.models.functions import Coalesce
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext
|
from django.utils.translation import gettext
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from PIL import Image, ImageOps
|
|
||||||
from solo.models import SingletonModel
|
from solo.models import SingletonModel
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,13 +90,18 @@ class ProductManager(models.Manager):
|
||||||
|
|
||||||
class Product(Model):
|
class Product(Model):
|
||||||
name = models.CharField(max_length=250, unique=True, verbose_name=_("name"))
|
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(
|
unit_price_cents = models.PositiveIntegerField(
|
||||||
verbose_name=_("unit price (cents)"),
|
verbose_name=_("unit price (cents)"),
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"Unit price in cents. Use zero to denote that the product has no fixed price.",
|
"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(
|
display_order = models.PositiveIntegerField(
|
||||||
default=default_product_display_order,
|
default=default_product_display_order,
|
||||||
verbose_name=_("display order"),
|
verbose_name=_("display order"),
|
||||||
|
@ -127,42 +131,6 @@ class Product(Model):
|
||||||
def has_fixed_price(self) -> bool:
|
def has_fixed_price(self) -> bool:
|
||||||
return self.unit_price_cents > 0
|
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):
|
class BasketQuerySet(models.QuerySet):
|
||||||
def priced(self) -> BasketQuerySet:
|
def priced(self) -> BasketQuerySet:
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<div class="card-img product-img-placeholder"
|
<div class="card-img product-img-placeholder"
|
||||||
style="background-color: hsl({{ product.color_hue }}, 60%, 80%)">
|
style="background-color: hsl({{ product.color_hue }}, 60%, 80%)">
|
||||||
<span>
|
<span>
|
||||||
{{ product.name|slice:"1" }}
|
{{ product.initials }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<div class="card-img product-img-placeholder"
|
<div class="card-img product-img-placeholder"
|
||||||
style="background-color: hsl({{ product.color_hue }}, 60%, 80%)">
|
style="background-color: hsl({{ product.color_hue }}, 60%, 80%)">
|
||||||
<span>
|
<span>
|
||||||
{{ product.name|slice:"1" }}
|
{{ product.initials }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
Loading…
Reference in a new issue