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)
|
||||
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):
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -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.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:
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<div class="card-img product-img-placeholder"
|
||||
style="background-color: hsl({{ product.color_hue }}, 60%, 80%)">
|
||||
<span>
|
||||
{{ product.name|slice:"1" }}
|
||||
{{ product.initials }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<div class="card-img product-img-placeholder"
|
||||
style="background-color: hsl({{ product.color_hue }}, 60%, 80%)">
|
||||
<span>
|
||||
{{ product.name|slice:"1" }}
|
||||
{{ product.initials }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in a new issue