mirror of
https://github.com/Crocmagnon/checkout.git
synced 2024-11-25 01:28:02 +01:00
Add product category for color hue
This commit is contained in:
parent
24a46d398d
commit
5998a280ba
8 changed files with 236 additions and 20 deletions
|
@ -3,7 +3,14 @@ from django.contrib.admin import register
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from solo.admin import SingletonModelAdmin
|
from solo.admin import SingletonModelAdmin
|
||||||
|
|
||||||
from purchase.models import Basket, BasketItem, Cache, PaymentMethod, Product
|
from purchase.models import (
|
||||||
|
Basket,
|
||||||
|
BasketItem,
|
||||||
|
Cache,
|
||||||
|
PaymentMethod,
|
||||||
|
Product,
|
||||||
|
ProductCategory,
|
||||||
|
)
|
||||||
from purchase.templatetags.purchase import currency
|
from purchase.templatetags.purchase import currency
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,15 +20,16 @@ class ProductAdmin(admin.ModelAdmin):
|
||||||
"name",
|
"name",
|
||||||
"display_order",
|
"display_order",
|
||||||
"initials",
|
"initials",
|
||||||
|
"category",
|
||||||
"unit_price",
|
"unit_price",
|
||||||
"sold",
|
"sold",
|
||||||
"turnover",
|
"turnover",
|
||||||
]
|
]
|
||||||
list_editable = ["display_order", "initials"]
|
list_editable = ["display_order"]
|
||||||
search_fields = ["name"]
|
search_fields = ["name"]
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return super().get_queryset(request).with_sold().with_turnover()
|
return super().get_queryset(request).with_category().with_sold().with_turnover()
|
||||||
|
|
||||||
@admin.display(description=_("unit price"))
|
@admin.display(description=_("unit price"))
|
||||||
def unit_price(self, instance: Product):
|
def unit_price(self, instance: Product):
|
||||||
|
@ -49,6 +57,12 @@ class PaymentMethodAdmin(admin.ModelAdmin):
|
||||||
return currency(instance.turnover)
|
return currency(instance.turnover)
|
||||||
|
|
||||||
|
|
||||||
|
@register(ProductCategory)
|
||||||
|
class ProductCategoryAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ["name", "color_hue"]
|
||||||
|
search_fields = ["name"]
|
||||||
|
|
||||||
|
|
||||||
class BasketItemInline(admin.TabularInline):
|
class BasketItemInline(admin.TabularInline):
|
||||||
model = BasketItem
|
model = BasketItem
|
||||||
fields = ["product", "quantity", "price"]
|
fields = ["product", "quantity", "price"]
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"created_at": "2022-04-26T20:30:22.959Z",
|
"created_at": "2022-04-26T20:30:22.959Z",
|
||||||
"updated_at": "2023-04-02T13:47:16.252Z",
|
"updated_at": "2023-04-02T13:47:16.252Z",
|
||||||
"name": "Clou",
|
"name": "Clou",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 140,
|
"unit_price_cents": 140,
|
||||||
"initials": "C",
|
"initials": "C",
|
||||||
"display_order": 1
|
"display_order": 1
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
"created_at": "2022-04-26T20:30:22.959Z",
|
"created_at": "2022-04-26T20:30:22.959Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.038Z",
|
"updated_at": "2023-04-02T14:16:24.038Z",
|
||||||
"name": "Villard'Ain",
|
"name": "Villard'Ain",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 310,
|
"unit_price_cents": 310,
|
||||||
"initials": "V",
|
"initials": "V",
|
||||||
"display_order": 3
|
"display_order": 3
|
||||||
|
@ -27,6 +29,7 @@
|
||||||
"created_at": "2022-04-26T20:30:22.959Z",
|
"created_at": "2022-04-26T20:30:22.959Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.046Z",
|
"updated_at": "2023-04-02T14:16:24.046Z",
|
||||||
"name": "Herbier",
|
"name": "Herbier",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 360,
|
"unit_price_cents": 360,
|
||||||
"initials": "Hb",
|
"initials": "Hb",
|
||||||
"display_order": 9
|
"display_order": 9
|
||||||
|
@ -36,8 +39,9 @@
|
||||||
"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": "2023-04-02T14:16:24.053Z",
|
"updated_at": "2023-04-02T17:27:16.954Z",
|
||||||
"name": "Blanc vache",
|
"name": "Blanc vache",
|
||||||
|
"category": 3,
|
||||||
"unit_price_cents": 360,
|
"unit_price_cents": 360,
|
||||||
"initials": "BV",
|
"initials": "BV",
|
||||||
"display_order": 15
|
"display_order": 15
|
||||||
|
@ -49,6 +53,7 @@
|
||||||
"created_at": "2022-04-28T16:08:08.298Z",
|
"created_at": "2022-04-28T16:08:08.298Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.048Z",
|
"updated_at": "2023-04-02T14:16:24.048Z",
|
||||||
"name": "Ap\u00e9rich\u00e8vres",
|
"name": "Ap\u00e9rich\u00e8vres",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 360,
|
"unit_price_cents": 360,
|
||||||
"initials": "Ac",
|
"initials": "Ac",
|
||||||
"display_order": 7
|
"display_order": 7
|
||||||
|
@ -60,6 +65,7 @@
|
||||||
"created_at": "2022-04-28T16:08:16.542Z",
|
"created_at": "2022-04-28T16:08:16.542Z",
|
||||||
"updated_at": "2023-04-02T13:47:52.614Z",
|
"updated_at": "2023-04-02T13:47:52.614Z",
|
||||||
"name": "Clougert",
|
"name": "Clougert",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 470,
|
"unit_price_cents": 470,
|
||||||
"initials": "CM",
|
"initials": "CM",
|
||||||
"display_order": 6
|
"display_order": 6
|
||||||
|
@ -71,6 +77,7 @@
|
||||||
"created_at": "2022-04-28T16:08:20.471Z",
|
"created_at": "2022-04-28T16:08:20.471Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.050Z",
|
"updated_at": "2023-04-02T14:16:24.050Z",
|
||||||
"name": "Brique",
|
"name": "Brique",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 310,
|
"unit_price_cents": 310,
|
||||||
"initials": "Bq",
|
"initials": "Bq",
|
||||||
"display_order": 4
|
"display_order": 4
|
||||||
|
@ -82,6 +89,7 @@
|
||||||
"created_at": "2022-04-28T16:08:20.471Z",
|
"created_at": "2022-04-28T16:08:20.471Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.051Z",
|
"updated_at": "2023-04-02T14:16:24.051Z",
|
||||||
"name": "Tomme de ch\u00e8vre",
|
"name": "Tomme de ch\u00e8vre",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 0,
|
"unit_price_cents": 0,
|
||||||
"initials": "T",
|
"initials": "T",
|
||||||
"display_order": 50
|
"display_order": 50
|
||||||
|
@ -91,8 +99,9 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T12:47:15.522Z",
|
"created_at": "2023-04-02T12:47:15.522Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.070Z",
|
"updated_at": "2023-04-02T17:27:16.961Z",
|
||||||
"name": "Cr\u00eapes chocolat",
|
"name": "Cr\u00eapes chocolat",
|
||||||
|
"category": 4,
|
||||||
"unit_price_cents": 200,
|
"unit_price_cents": 200,
|
||||||
"initials": "CrC",
|
"initials": "CrC",
|
||||||
"display_order": 18
|
"display_order": 18
|
||||||
|
@ -104,6 +113,7 @@
|
||||||
"created_at": "2023-04-02T13:02:38.149Z",
|
"created_at": "2023-04-02T13:02:38.149Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.043Z",
|
"updated_at": "2023-04-02T14:16:24.043Z",
|
||||||
"name": "Caprinoux",
|
"name": "Caprinoux",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 100,
|
"unit_price_cents": 100,
|
||||||
"initials": "Cap",
|
"initials": "Cap",
|
||||||
"display_order": 5
|
"display_order": 5
|
||||||
|
@ -115,6 +125,7 @@
|
||||||
"created_at": "2023-04-02T13:31:13.712Z",
|
"created_at": "2023-04-02T13:31:13.712Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.055Z",
|
"updated_at": "2023-04-02T14:16:24.055Z",
|
||||||
"name": "Clou affin\u00e9",
|
"name": "Clou affin\u00e9",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 160,
|
"unit_price_cents": 160,
|
||||||
"initials": "CA",
|
"initials": "CA",
|
||||||
"display_order": 2
|
"display_order": 2
|
||||||
|
@ -126,6 +137,7 @@
|
||||||
"created_at": "2023-04-02T13:32:12.289Z",
|
"created_at": "2023-04-02T13:32:12.289Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.057Z",
|
"updated_at": "2023-04-02T14:16:24.057Z",
|
||||||
"name": "Ap\u00e9rich\u00e8vres frais",
|
"name": "Ap\u00e9rich\u00e8vres frais",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 250,
|
"unit_price_cents": 250,
|
||||||
"initials": "AcF",
|
"initials": "AcF",
|
||||||
"display_order": 8
|
"display_order": 8
|
||||||
|
@ -137,6 +149,7 @@
|
||||||
"created_at": "2023-04-02T13:32:29.365Z",
|
"created_at": "2023-04-02T13:32:29.365Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.059Z",
|
"updated_at": "2023-04-02T14:16:24.059Z",
|
||||||
"name": "Blanc ch\u00e8vre",
|
"name": "Blanc ch\u00e8vre",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 480,
|
"unit_price_cents": 480,
|
||||||
"initials": "BC",
|
"initials": "BC",
|
||||||
"display_order": 10
|
"display_order": 10
|
||||||
|
@ -146,8 +159,9 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T13:32:41.308Z",
|
"created_at": "2023-04-02T13:32:41.308Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.060Z",
|
"updated_at": "2023-04-02T17:27:16.948Z",
|
||||||
"name": "Gros de vache",
|
"name": "Gros de vache",
|
||||||
|
"category": 3,
|
||||||
"unit_price_cents": 200,
|
"unit_price_cents": 200,
|
||||||
"initials": "GV",
|
"initials": "GV",
|
||||||
"display_order": 13
|
"display_order": 13
|
||||||
|
@ -157,8 +171,9 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T13:32:48.404Z",
|
"created_at": "2023-04-02T13:32:48.404Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.062Z",
|
"updated_at": "2023-04-02T17:27:16.952Z",
|
||||||
"name": "P'tit clou",
|
"name": "P'tit clou",
|
||||||
|
"category": 3,
|
||||||
"unit_price_cents": 60,
|
"unit_price_cents": 60,
|
||||||
"initials": "PC",
|
"initials": "PC",
|
||||||
"display_order": 14
|
"display_order": 14
|
||||||
|
@ -168,8 +183,9 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T13:33:12.184Z",
|
"created_at": "2023-04-02T13:33:12.184Z",
|
||||||
"updated_at": "2023-04-02T13:47:52.633Z",
|
"updated_at": "2023-04-02T17:27:16.957Z",
|
||||||
"name": "Ap\u00e9rivache",
|
"name": "Ap\u00e9rivache",
|
||||||
|
"category": 3,
|
||||||
"unit_price_cents": 300,
|
"unit_price_cents": 300,
|
||||||
"initials": "AV",
|
"initials": "AV",
|
||||||
"display_order": 16
|
"display_order": 16
|
||||||
|
@ -181,6 +197,7 @@
|
||||||
"created_at": "2023-04-02T13:33:24.357Z",
|
"created_at": "2023-04-02T13:33:24.357Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.064Z",
|
"updated_at": "2023-04-02T14:16:24.064Z",
|
||||||
"name": "Fromage fort",
|
"name": "Fromage fort",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 360,
|
"unit_price_cents": 360,
|
||||||
"initials": "FF",
|
"initials": "FF",
|
||||||
"display_order": 11
|
"display_order": 11
|
||||||
|
@ -192,6 +209,7 @@
|
||||||
"created_at": "2023-04-02T13:33:49.793Z",
|
"created_at": "2023-04-02T13:33:49.793Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.066Z",
|
"updated_at": "2023-04-02T14:16:24.066Z",
|
||||||
"name": "Lait de ch\u00e8vre",
|
"name": "Lait de ch\u00e8vre",
|
||||||
|
"category": 1,
|
||||||
"unit_price_cents": 200,
|
"unit_price_cents": 200,
|
||||||
"initials": "L",
|
"initials": "L",
|
||||||
"display_order": 12
|
"display_order": 12
|
||||||
|
@ -201,8 +219,9 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T13:33:54.405Z",
|
"created_at": "2023-04-02T13:33:54.405Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.068Z",
|
"updated_at": "2023-04-02T17:27:16.959Z",
|
||||||
"name": "Verre",
|
"name": "Verre",
|
||||||
|
"category": 4,
|
||||||
"unit_price_cents": 100,
|
"unit_price_cents": 100,
|
||||||
"initials": "Ve",
|
"initials": "Ve",
|
||||||
"display_order": 17
|
"display_order": 17
|
||||||
|
@ -212,8 +231,9 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T13:34:34.802Z",
|
"created_at": "2023-04-02T13:34:34.802Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.072Z",
|
"updated_at": "2023-04-02T17:27:16.963Z",
|
||||||
"name": "Cr\u00eape sucre",
|
"name": "Cr\u00eape sucre",
|
||||||
|
"category": 4,
|
||||||
"unit_price_cents": 150,
|
"unit_price_cents": 150,
|
||||||
"initials": "CrS",
|
"initials": "CrS",
|
||||||
"display_order": 19
|
"display_order": 19
|
||||||
|
@ -223,8 +243,9 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T13:34:44.535Z",
|
"created_at": "2023-04-02T13:34:44.535Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.073Z",
|
"updated_at": "2023-04-02T17:27:16.966Z",
|
||||||
"name": "Cr\u00eape nature",
|
"name": "Cr\u00eape nature",
|
||||||
|
"category": 4,
|
||||||
"unit_price_cents": 140,
|
"unit_price_cents": 140,
|
||||||
"initials": "CrN",
|
"initials": "CrN",
|
||||||
"display_order": 20
|
"display_order": 20
|
||||||
|
@ -234,11 +255,42 @@
|
||||||
"model": "purchase.product",
|
"model": "purchase.product",
|
||||||
"fields": {
|
"fields": {
|
||||||
"created_at": "2023-04-02T14:02:56.130Z",
|
"created_at": "2023-04-02T14:02:56.130Z",
|
||||||
"updated_at": "2023-04-02T14:16:24.075Z",
|
"updated_at": "2023-04-02T17:27:16.968Z",
|
||||||
"name": "Facture",
|
"name": "Facture",
|
||||||
|
"category": 4,
|
||||||
"unit_price_cents": 0,
|
"unit_price_cents": 0,
|
||||||
"initials": "Fa",
|
"initials": "Fa",
|
||||||
"display_order": 51
|
"display_order": 51
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "purchase.productcategory",
|
||||||
|
"pk": 1,
|
||||||
|
"fields": {
|
||||||
|
"created_at": "2023-04-02T17:24:02.168Z",
|
||||||
|
"updated_at": "2023-04-02T17:30:07.195Z",
|
||||||
|
"name": "Ch\u00e8vre",
|
||||||
|
"color_hue": 145
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "purchase.productcategory",
|
||||||
|
"pk": 3,
|
||||||
|
"fields": {
|
||||||
|
"created_at": "2023-04-02T17:25:41.912Z",
|
||||||
|
"updated_at": "2023-04-02T17:30:04.093Z",
|
||||||
|
"name": "Vache",
|
||||||
|
"color_hue": 276
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "purchase.productcategory",
|
||||||
|
"pk": 4,
|
||||||
|
"fields": {
|
||||||
|
"created_at": "2023-04-02T17:25:57.992Z",
|
||||||
|
"updated_at": "2023-04-02T17:29:59.720Z",
|
||||||
|
"name": "Autres",
|
||||||
|
"color_hue": 38
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -40,7 +40,7 @@ class BasketForm(forms.ModelForm):
|
||||||
for item in basket.items.all():
|
for item in basket.items.all():
|
||||||
products[item.product] = item.quantity
|
products[item.product] = item.quantity
|
||||||
fields = []
|
fields = []
|
||||||
for product in Product.objects.with_fixed_price():
|
for product in Product.objects.with_category().with_fixed_price():
|
||||||
field_name = f"{PRICED_PREFIX}{product.id}"
|
field_name = f"{PRICED_PREFIX}{product.id}"
|
||||||
self.fields.update(
|
self.fields.update(
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-02 18:32+0200\n"
|
"POT-Creation-Date: 2023-04-02 19:31+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -56,6 +56,26 @@ msgstr ""
|
||||||
msgid "payment methods"
|
msgid "payment methods"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "color hue"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "Color hue in degrees (0-360)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "product category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "product categories"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: purchase/models.py
|
#: purchase/models.py
|
||||||
msgid "unit price (cents)"
|
msgid "unit price (cents)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -5,7 +5,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-02 18:32+0200\n"
|
"POT-Creation-Date: 2023-04-02 19:31+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -55,6 +55,27 @@ msgstr "moyen de paiement"
|
||||||
msgid "payment methods"
|
msgid "payment methods"
|
||||||
msgstr "moyens de paiement"
|
msgstr "moyens de paiement"
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "color hue"
|
||||||
|
msgstr "teinte de couleur"
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "Color hue in degrees (0-360)"
|
||||||
|
msgstr "Teinte de couleur en degrés (0-360)"
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
#, fuzzy
|
||||||
|
msgid "product category"
|
||||||
|
msgstr "catégorie de produits"
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "product categories"
|
||||||
|
msgstr "catégories de produits"
|
||||||
|
|
||||||
|
#: purchase/models.py
|
||||||
|
msgid "category"
|
||||||
|
msgstr "catégorie"
|
||||||
|
|
||||||
#: purchase/models.py
|
#: purchase/models.py
|
||||||
msgid "unit price (cents)"
|
msgid "unit price (cents)"
|
||||||
msgstr "prix unitaire (centimes)"
|
msgstr "prix unitaire (centimes)"
|
||||||
|
|
62
src/purchase/migrations/0017_productcategory.py
Normal file
62
src/purchase/migrations/0017_productcategory.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# Generated by Django 4.1.7 on 2023-04-02 17:21
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def create_default_categories(apps, schema_editor):
|
||||||
|
ProductCategory = apps.get_model("purchase", "ProductCategory") # noqa: N806
|
||||||
|
ProductCategory.objects.using(schema_editor.connection.alias).create(
|
||||||
|
name="default",
|
||||||
|
color_hue=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("purchase", "0016_alter_paymentmethod_options"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="ProductCategory",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created_at",
|
||||||
|
models.DateTimeField(auto_now_add=True, verbose_name="created at"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"updated_at",
|
||||||
|
models.DateTimeField(auto_now=True, verbose_name="updated at"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"name",
|
||||||
|
models.CharField(max_length=250, unique=True, verbose_name="name"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"color_hue",
|
||||||
|
models.PositiveIntegerField(
|
||||||
|
help_text="Color hue in degrees (0-360)",
|
||||||
|
validators=[django.core.validators.MaxValueValidator(360)],
|
||||||
|
verbose_name="color hue",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
create_default_categories,
|
||||||
|
reverse_code=migrations.RunPython.noop,
|
||||||
|
),
|
||||||
|
]
|
24
src/purchase/migrations/0018_product_category.py
Normal file
24
src/purchase/migrations/0018_product_category.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 4.1.7 on 2023-04-02 17:23
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("purchase", "0017_productcategory"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="product",
|
||||||
|
name="category",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
default=1,
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
to="purchase.productcategory",
|
||||||
|
verbose_name="category",
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,8 +1,8 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import hashlib
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from django.core.validators import MaxValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Avg, Count, F, Sum
|
from django.db.models import Avg, Count, F, Sum
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
|
@ -65,6 +65,22 @@ def default_product_display_order():
|
||||||
return last.display_order + 1
|
return last.display_order + 1
|
||||||
|
|
||||||
|
|
||||||
|
class ProductCategory(Model):
|
||||||
|
name = models.CharField(max_length=250, unique=True, verbose_name=_("name"))
|
||||||
|
color_hue = models.PositiveIntegerField(
|
||||||
|
validators=[MaxValueValidator(360)],
|
||||||
|
verbose_name=_("color hue"),
|
||||||
|
help_text=_("Color hue in degrees (0-360)"),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("product category")
|
||||||
|
verbose_name_plural = _("product categories")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
class ProductQuerySet(models.QuerySet):
|
class ProductQuerySet(models.QuerySet):
|
||||||
def with_turnover(self):
|
def with_turnover(self):
|
||||||
return self.annotate(
|
return self.annotate(
|
||||||
|
@ -83,6 +99,9 @@ class ProductQuerySet(models.QuerySet):
|
||||||
def with_no_fixed_price(self):
|
def with_no_fixed_price(self):
|
||||||
return self.filter(unit_price_cents=0)
|
return self.filter(unit_price_cents=0)
|
||||||
|
|
||||||
|
def with_category(self):
|
||||||
|
return self.select_related("category")
|
||||||
|
|
||||||
|
|
||||||
class ProductManager(models.Manager):
|
class ProductManager(models.Manager):
|
||||||
def get_by_natural_key(self, name):
|
def get_by_natural_key(self, name):
|
||||||
|
@ -91,6 +110,13 @@ 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"))
|
||||||
|
category = models.ForeignKey(
|
||||||
|
ProductCategory,
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
verbose_name=_("category"),
|
||||||
|
null=False,
|
||||||
|
blank=False,
|
||||||
|
)
|
||||||
unit_price_cents = models.PositiveIntegerField(
|
unit_price_cents = models.PositiveIntegerField(
|
||||||
verbose_name=_("unit price (cents)"),
|
verbose_name=_("unit price (cents)"),
|
||||||
help_text=_(
|
help_text=_(
|
||||||
|
@ -123,10 +149,7 @@ class Product(Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color_hue(self):
|
def color_hue(self):
|
||||||
return int(
|
return self.category.color_hue
|
||||||
hashlib.sha256(bytes(self.name, encoding="utf-8")).hexdigest()[:2],
|
|
||||||
base=16,
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_fixed_price(self) -> bool:
|
def has_fixed_price(self) -> bool:
|
||||||
|
|
Loading…
Reference in a new issue