Features: 1) Add sku field to Product model with improvements, including unique constraint and default generation; 2) Implement migration to backfill SKUs for existing products.

Fixes: None.

Extra: 1) Adjust `.po` and `.mo` files for version change to `2.9.3`; 2) Update translations with minor formatting improvements; 3) Clean up comments in locale files.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-09-01 20:50:48 +03:00
parent e020fe7d08
commit ec147984ab
191 changed files with 10243 additions and 9577 deletions

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-03 18:33+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"

View file

@ -67,11 +67,22 @@ class FieldsetsMixin:
fieldsets.append((_("relations"), {"fields": self.relation_fields})) fieldsets.append((_("relations"), {"fields": self.relation_fields}))
opts = self.model._meta opts = self.model._meta
meta_fields = []
if any(f.name == "uuid" for f in opts.fields): if any(f.name == "uuid" for f in opts.fields):
meta_fields.append("uuid")
if any(f.name == "slug" for f in opts.fields): if any(f.name == "slug" for f in opts.fields):
fieldsets.append((_("metadata"), {"fields": ["uuid", "slug"]})) meta_fields.append("slug")
else:
fieldsets.append((_("metadata"), {"fields": ["uuid"]})) if any(f.name == "sku" for f in opts.fields):
meta_fields.append("sku")
if any(f.name == "human_readable_id" for f in opts.fields):
meta_fields.append("sku")
if meta_fields:
fieldsets.append((_("metadata"), {"fields": meta_fields}))
ts = [] ts = []
for name in ("created", "modified"): for name in ("created", "modified"):
@ -243,8 +254,8 @@ class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type:
# noinspection PyClassVar # noinspection PyClassVar
model = Product # type: ignore [misc] model = Product # type: ignore [misc]
list_display = ( list_display = (
"sku",
"name", "name",
"partnumber",
"is_active", "is_active",
"category", "category",
"brand", "brand",
@ -269,6 +280,7 @@ class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type:
"category__slug", "category__slug",
"uuid", "uuid",
"slug", "slug",
"sku",
) )
readonly_fields = ("slug", "uuid", "modified", "created") readonly_fields = ("slug", "uuid", "modified", "created")
autocomplete_fields = ("category", "brand", "tags") autocomplete_fields = ("category", "brand", "tags")

View file

@ -152,7 +152,7 @@ CATEGORY_SCHEMA = {
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS}, responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
), ),
"seo": extend_schema( "seo": extend_schema(
summary=_("SEO Meta Snapshot"), summary=_("SEO Meta snapshot"),
description=_("returns a snapshot of the category's SEO meta data"), description=_("returns a snapshot of the category's SEO meta data"),
parameters=[ parameters=[
OpenApiParameter( OpenApiParameter(
@ -550,7 +550,7 @@ PRODUCT_SCHEMA = {
}, },
), ),
"seo": extend_schema( "seo": extend_schema(
summary=_("SEO Meta Snapshot"), summary=_("SEO Meta snapshot"),
description=_("returns a snapshot of the product's SEO meta data"), description=_("returns a snapshot of the product's SEO meta data"),
parameters=[ parameters=[
OpenApiParameter( OpenApiParameter(

View file

@ -78,6 +78,7 @@ class ProductFilter(FilterSet):
method="filter_include_personal_ordered", method="filter_include_personal_ordered",
label=_("Include personal ordered"), label=_("Include personal ordered"),
) )
sku = CharFilter(field_name="sku", lookup_expr="iexact", label=_("SKU"))
order_by = OrderingFilter( order_by = OrderingFilter(
fields=( fields=(
@ -88,6 +89,7 @@ class ProductFilter(FilterSet):
("created", "created"), ("created", "created"),
("modified", "modified"), ("modified", "modified"),
("price_order", "price"), ("price_order", "price"),
("sku", "sku"),
("?", "random"), ("?", "random"),
), ),
initial="uuid", initial="uuid",
@ -107,6 +109,7 @@ class ProductFilter(FilterSet):
"is_active", "is_active",
"tags", "tags",
"slug", "slug",
"sku",
"min_price", "min_price",
"max_price", "max_price",
"brand", "brand",

View file

@ -114,7 +114,7 @@ class AttributeGroupType(DjangoObjectType):
class BrandType(DjangoObjectType): class BrandType(DjangoObjectType):
categories = List(lambda: CategoryType, description=_("categories")) categories = List(lambda: CategoryType, description=_("categories"))
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot")) seo_meta = Field(SEOMetaType, description=_("SEO Meta snapshot"))
class Meta: class Meta:
model = Brand model = Brand
@ -204,7 +204,7 @@ class CategoryType(DjangoObjectType):
) )
tags = DjangoFilterConnectionField(lambda: CategoryTagType, description=_("tags for this category")) tags = DjangoFilterConnectionField(lambda: CategoryTagType, description=_("tags for this category"))
products = DjangoFilterConnectionField(lambda: ProductType, description=_("products in this category")) products = DjangoFilterConnectionField(lambda: ProductType, description=_("products in this category"))
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot")) seo_meta = Field(SEOMetaType, description=_("SEO Meta snapshot"))
class Meta: class Meta:
model = Category model = Category
@ -500,7 +500,7 @@ class ProductType(DjangoObjectType):
quantity = Float(description=_("quantity")) quantity = Float(description=_("quantity"))
feedbacks_count = Int(description=_("number of feedbacks")) feedbacks_count = Int(description=_("number of feedbacks"))
personal_orders_only = Boolean(description=_("only available for personal orders")) personal_orders_only = Boolean(description=_("only available for personal orders"))
seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot")) seo_meta = Field(SEOMetaType, description=_("SEO Meta snapshot"))
class Meta: class Meta:
model = Product model = Product

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,25 @@
# Generated by Django 5.2 on 2025-09-01 17:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("core", "0036_vendor_b2b_auth_token_vendor_users"),
]
operations = [
migrations.AddField(
model_name="product",
name="sku",
field=models.CharField(
blank=True,
db_index=True,
default=None,
help_text="stock keeping unit for this product",
max_length=8,
null=True,
verbose_name="SKU",
),
),
]

View file

@ -0,0 +1,44 @@
from django.db import migrations, transaction, IntegrityError
def generate_unique_sku(Product, make_candidate, taken):
while True:
candidate = make_candidate()
if candidate in taken:
continue
if not Product.objects.filter(sku=candidate).exists():
taken.add(candidate)
return candidate
def backfill_sku(apps, schema_editor):
Product = apps.get_model("core", "Product")
from core.utils import generate_human_readable_id as make_candidate
taken = set(Product.objects.exclude(sku__isnull=True).values_list("sku", flat=True))
qs = Product.objects.filter(sku__isnull=True)
BATCH = 500
start = 0
count = qs.count()
while start < count:
with transaction.atomic():
for product in qs.order_by("pk")[start : start + BATCH]:
product.sku = generate_unique_sku(Product, make_candidate, taken)
product.save(update_fields=["sku"])
start += BATCH
def noop(apps, schema_editor):
pass
class Migration(migrations.Migration):
dependencies = [
("core", "0037_product_sku"),
]
operations = [
migrations.RunPython(backfill_sku, reverse_code=noop),
]

View file

@ -0,0 +1,25 @@
# Generated by Django 5.2 on 2025-09-01 17:36
import core.utils
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("core", "0038_backfill_product_sku"),
]
operations = [
migrations.AlterField(
model_name="product",
name="sku",
field=models.CharField(
default=core.utils.generate_human_readable_id,
help_text="stock keeping unit for this product",
max_length=8,
unique=True,
verbose_name="SKU",
),
),
]

View file

@ -4,8 +4,6 @@ import logging
from typing import Any, Optional, Self from typing import Any, Optional, Self
from constance import config from constance import config
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.gis.db.models import PointField from django.contrib.gis.db.models import PointField
from django.contrib.postgres.indexes import GinIndex from django.contrib.postgres.indexes import GinIndex
from django.core.cache import cache from django.core.cache import cache
@ -32,8 +30,6 @@ from django.db.models import (
PositiveIntegerField, PositiveIntegerField,
QuerySet, QuerySet,
TextField, TextField,
UUIDField,
URLField,
) )
from django.db.models.indexes import Index from django.db.models.indexes import Index
from django.http import Http404 from django.http import Http404
@ -680,6 +676,13 @@ class Product(ExportModelOperationsMixin("product"), NiceModel): # type: ignore
null=True, null=True,
verbose_name=_("Slug"), verbose_name=_("Slug"),
) )
sku = CharField(
help_text=_("stock keeping unit for this product"),
verbose_name=_("SKU"),
max_length=8,
unique=True,
default=generate_human_readable_id,
)
objects: ProductManager = ProductManager() objects: ProductManager = ProductManager()
@ -2017,20 +2020,3 @@ class Feedback(ExportModelOperationsMixin("feedback"), NiceModel): # type: igno
class Meta: class Meta:
verbose_name = _("feedback") verbose_name = _("feedback")
verbose_name_plural = _("feedbacks") verbose_name_plural = _("feedbacks")
class SeoMeta(NiceModel):
uuid = None
content_type = ForeignKey(ContentType, on_delete=CASCADE)
object_id = UUIDField()
content_object = GenericForeignKey("content_type", "object_id")
meta_title = CharField(max_length=70, blank=True)
meta_description = CharField(max_length=180, blank=True)
canonical_override = URLField(blank=True)
robots = CharField(max_length=40, blank=True, default="index,follow")
social_image = ImageField(upload_to="seo/", blank=True, null=True)
extras = JSONField(blank=True, null=True)
class Meta:
unique_together = ("content_type", "object_id")

View file

@ -50,7 +50,7 @@ def send_order_created_email(order_pk: str) -> tuple[bool, str]:
except Order.DoesNotExist: except Order.DoesNotExist:
return False, f"Order not found with the given pk: {order_pk}" return False, f"Order not found with the given pk: {order_pk}"
if not order.user: if not any([order.user, order.attributes.get("email", None), order.attributes.get("customer_email", None)]):
return False, f"Order's user not found with the given pk: {order_pk}" return False, f"Order's user not found with the given pk: {order_pk}"
activate(order.user.language) activate(order.user.language)

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -113,23 +113,23 @@ msgstr "كيان لتخزين بيانات الإعلانات"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "كيان لتخزين بيانات التحليلات" msgstr "كيان لتخزين بيانات التحليلات"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "الخيارات العامة" msgstr "الخيارات العامة"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "خيارات البريد الإلكتروني" msgstr "خيارات البريد الإلكتروني"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "خيارات بوابة الدفع" msgstr "خيارات بوابة الدفع"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "خيارات الميزات" msgstr "خيارات الميزات"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "خيارات تحسين محركات البحث" msgstr "خيارات تحسين محركات البحث"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -113,23 +113,23 @@ msgstr "Subjekt pro ukládání dat inzerátů"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "Subjekt pro ukládání analytických dat" msgstr "Subjekt pro ukládání analytických dat"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "Obecné možnosti" msgstr "Obecné možnosti"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "Možnosti e-mailu" msgstr "Možnosti e-mailu"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "Možnosti platební brány" msgstr "Možnosti platební brány"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "Možnosti funkcí" msgstr "Možnosti funkcí"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "Možnosti SEO" msgstr "Možnosti SEO"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -113,23 +113,23 @@ msgstr "En enhed til lagring af annonceringsdata"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "En enhed til lagring af analysedata" msgstr "En enhed til lagring af analysedata"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "Generelle indstillinger" msgstr "Generelle indstillinger"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "Indstillinger for e-mail" msgstr "Indstillinger for e-mail"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "Muligheder for betalingsgateway" msgstr "Muligheder for betalingsgateway"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "Funktioner Indstillinger" msgstr "Funktioner Indstillinger"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "SEO-muligheder" msgstr "SEO-muligheder"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -113,23 +113,23 @@ msgstr "Eine Einheit zur Speicherung von Werbedaten"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "Eine Einheit zur Speicherung von Analysedaten" msgstr "Eine Einheit zur Speicherung von Analysedaten"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "Allgemeine Optionen" msgstr "Allgemeine Optionen"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "E-Mail-Optionen" msgstr "E-Mail-Optionen"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "Zahlungs-Gateway-Optionen" msgstr "Zahlungs-Gateway-Optionen"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "Merkmale Optionen" msgstr "Merkmale Optionen"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "SEO-Optionen" msgstr "SEO-Optionen"

View file

@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -117,23 +117,23 @@ msgstr "An entity for storing advertisiment data"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "An entity for storing analytics data" msgstr "An entity for storing analytics data"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "General Options" msgstr "General Options"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "Email Options" msgstr "Email Options"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "Payment Gateway Options" msgstr "Payment Gateway Options"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "Features Options" msgstr "Features Options"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "SEO Options" msgstr "SEO Options"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -113,23 +113,23 @@ msgstr "An entity for storing advertisiment data"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "An entity for storing analytics data" msgstr "An entity for storing analytics data"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "General Options" msgstr "General Options"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "Email Options" msgstr "Email Options"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "Payment Gateway Options" msgstr "Payment Gateway Options"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "Features Options" msgstr "Features Options"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "SEO Options" msgstr "SEO Options"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -113,23 +113,23 @@ msgstr "Una entidad para almacenar datos publicitarios"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "Una entidad para almacenar datos analíticos" msgstr "Una entidad para almacenar datos analíticos"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "Opciones generales" msgstr "Opciones generales"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "Opciones de correo electrónico" msgstr "Opciones de correo electrónico"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "Opciones de pasarela de pago" msgstr "Opciones de pasarela de pago"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "Características Opciones" msgstr "Características Opciones"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "Opciones SEO" msgstr "Opciones SEO"

View file

@ -1,9 +1,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -113,23 +113,23 @@ msgstr "Une entité pour stocker des données publicitaires"
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "Une entité pour stocker des données analytiques" msgstr "Une entité pour stocker des données analytiques"
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "Options générales" msgstr "Options générales"
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "Options de courrier électronique" msgstr "Options de courrier électronique"
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "Options de passerelle de paiement" msgstr "Options de passerelle de paiement"
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "Caractéristiques Options" msgstr "Caractéristiques Options"
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "Options de référencement" msgstr "Options de référencement"

View file

@ -5,9 +5,9 @@
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: EVIBES 2.9.2\n" "Project-Id-Version: EVIBES 2.9.3\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-07-18 08:39+0300\n" "POT-Creation-Date: 2025-09-01 20:37+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n" "PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n" "Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n" "Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
@ -116,23 +116,23 @@ msgstr ""
msgid "An entity for storing analytics data" msgid "An entity for storing analytics data"
msgstr "" msgstr ""
#: evibes/settings/constance.py:54 #: evibes/settings/constance.py:55
msgid "General Options" msgid "General Options"
msgstr "" msgstr ""
#: evibes/settings/constance.py:62 #: evibes/settings/constance.py:63
msgid "Email Options" msgid "Email Options"
msgstr "" msgstr ""
#: evibes/settings/constance.py:71 #: evibes/settings/constance.py:72
msgid "Payment Gateway Options" msgid "Payment Gateway Options"
msgstr "" msgstr ""
#: evibes/settings/constance.py:78 #: evibes/settings/constance.py:79
msgid "Features Options" msgid "Features Options"
msgstr "" msgstr ""
#: evibes/settings/constance.py:85 #: evibes/settings/constance.py:86
msgid "SEO Options" msgid "SEO Options"
msgstr "" msgstr ""

Some files were not shown because too many files have changed in this diff Show more