diff --git a/.dockerignore b/.dockerignore
index f5cb53a0..19f7e1bb 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -11,6 +11,7 @@ coverage.*
*.cover
*.py,cover
nosetests.xml
+desktop.ini
# Cache directories
__pycache__/
@@ -37,7 +38,6 @@ __pypackages__/
# Packaging and distribution
# ──────────────────────────────────────────────────────────────────────────
build/
-dist/
dist-ssr/
*.egg
*.egg-info/
diff --git a/.gitignore b/.gitignore
index 790c0656..9129c5e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,8 +64,9 @@ htmlcov/
.pybuilder/
# Storefronts
-.astro/
.nuxt/
+.next/
+next-env.d.ts
# Celery
celerybeat-schedule
@@ -141,6 +142,10 @@ cypress/screenshots/
# JetBrains
.idea/
+!.idea/icon.svg
+!.idea/externalDependencies.xml
+!.idea/evibes.iml
+!.idea/evibes.ico
# Microsoft
*.suo
diff --git a/.idea/evibes.ico b/.idea/evibes.ico
new file mode 100644
index 00000000..f3ba783b
Binary files /dev/null and b/.idea/evibes.ico differ
diff --git a/.idea/evibes.iml b/.idea/evibes.iml
new file mode 100644
index 00000000..307a37b8
--- /dev/null
+++ b/.idea/evibes.iml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/externalDependencies.xml b/.idea/externalDependencies.xml
new file mode 100644
index 00000000..66339880
--- /dev/null
+++ b/.idea/externalDependencies.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/icon.svg b/.idea/icon.svg
new file mode 100644
index 00000000..356c7ae0
--- /dev/null
+++ b/.idea/icon.svg
@@ -0,0 +1,25 @@
+
+
+
diff --git a/CODEOWNERS b/CODEOWNERS
index 2a23c894..047718e6 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -4,8 +4,7 @@ README.md @fureunoir contact@fureunoir.com
LICENSE @fureunoir contact@fureunoir.com
-Dockerfile.app @fureunoir contact@fureunoir.com
-Dockerfile.storefront @SaVBaD savbad@wiseless.xyz
+Dockerfiles @@maintainer
docker-compose.yml @@maintainer
.gitignore @@maintainer
.dockerignore @@maintainer
@@ -13,14 +12,6 @@ nginx @@maintainer
pyproject.toml @fureunoir contact@fureunoir.com
poetry.lock @fureunoir contact@fureunoir.com
-blog/ @fureunoir contact@fureunoir.com
-core/ @fureunoir contact@fureunoir.com
-evibes/ @fureunoir contact@fureunoir.com
-payments/ @fureunoir contact@fureunoir.com
-scripts/ @fureunoir contact@fureunoir.com
-vibes_auth/ @fureunoir contact@fureunoir.com
-storefront/ @SaVBaD savbad@wiseless.xyz
-
*.py @fureunoir contact@fureunoir.com
*.bat @fureunoir contact@fureunoir.com
*.sh @fureunoir contact@fureunoir.com
@@ -31,5 +22,13 @@ storefront/ @SaVBaD savbad@wiseless.xyz
*.mjs @SaVBaD savbad@wiseless.xyz
*.cjs @SaVBaD savbad@wiseless.xyz
*.vue @SaVBaD savbad@wiseless.xyz
-*.astro @SaVBaD savbad@wiseless.xyz
*.scss @SaVBaD savbad@wiseless.xyz
+
+blog/ @fureunoir contact@fureunoir.com
+core/ @fureunoir contact@fureunoir.com
+evibes/ @fureunoir contact@fureunoir.com
+payments/ @fureunoir contact@fureunoir.com
+scripts/ @fureunoir contact@fureunoir.com
+vibes_auth/ @fureunoir contact@fureunoir.com
+
+storefront/ @SaVBaD savbad@wiseless.xyz
\ No newline at end of file
diff --git a/Dockerfiles/Dockerfile.app b/Dockerfiles/Dockerfile.app
index 52042174..ef220880 100644
--- a/Dockerfiles/Dockerfile.app
+++ b/Dockerfiles/Dockerfile.app
@@ -26,6 +26,7 @@ RUN set -eux; \
graphviz-dev \
libgts-dev \
libpq5 \
+ chrony \
graphviz \
binutils \
libproj-dev \
@@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/app-entrypoint.sh
COPY . .
-ENTRYPOINT ["app-entrypoint.sh"]
\ No newline at end of file
+ENTRYPOINT ["/usr/bin/bash", "app-entrypoint.sh"]
\ No newline at end of file
diff --git a/Dockerfiles/Dockerfile.beat b/Dockerfiles/Dockerfile.beat
index 84410630..f2f8684f 100644
--- a/Dockerfiles/Dockerfile.beat
+++ b/Dockerfiles/Dockerfile.beat
@@ -26,6 +26,7 @@ RUN set -eux; \
graphviz-dev \
libgts-dev \
libpq5 \
+ chrony \
graphviz \
binutils \
libproj-dev \
@@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/beat-entrypoint.sh
COPY . .
-ENTRYPOINT ["beat-entrypoint.sh"]
\ No newline at end of file
+ENTRYPOINT ["/usr/bin/bash", "beat-entrypoint.sh"]
\ No newline at end of file
diff --git a/Dockerfiles/Dockerfile.stock_updater b/Dockerfiles/Dockerfile.stock_updater
new file mode 100644
index 00000000..39bbc5ba
--- /dev/null
+++ b/Dockerfiles/Dockerfile.stock_updater
@@ -0,0 +1,50 @@
+# syntax=docker/dockerfile:1
+FROM python:3.12-bookworm
+LABEL authors="fureunoir"
+
+ENV PYTHONDONTWRITEBYTECODE=1 \
+ PYTHONUNBUFFERED=1 \
+ LANG=C.UTF-8 \
+ DEBIAN_FRONTEND=noninteractive \
+ PATH="/root/.local/bin:$PATH"
+
+WORKDIR /app
+
+RUN set -eux; \
+ sed -i 's|https://deb.debian.org/debian|https://ftp.uk.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources; \
+ apt-get update; \
+ apt-get install -y --no-install-recommends wget gnupg; \
+ wget -qO - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -; \
+ echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \
+ > /etc/apt/sources.list.d/pgdg.list; \
+ apt-get update; \
+ apt-get install -y --no-install-recommends --fix-missing \
+ build-essential \
+ libpq-dev \
+ gettext \
+ libgettextpo-dev \
+ graphviz-dev \
+ libgts-dev \
+ libpq5 \
+ chrony \
+ graphviz \
+ binutils \
+ libproj-dev \
+ postgresql-client-17 \
+ gdal-bin; \
+ rm -rf /var/lib/apt/lists/*; \
+ pip install --upgrade pip; \
+ curl -sSL https://install.python-poetry.org | python3
+
+COPY pyproject.toml pyproject.toml
+COPY poetry.lock poetry.lock
+
+RUN poetry config virtualenvs.create false
+RUN poetry install --extras="worker openai" --no-interaction --no-ansi
+
+COPY ./scripts/Docker/stock-updater-entrypoint.sh /usr/local/bin/stock-updater-entrypoint.sh
+RUN chmod +x /usr/local/bin/stock-updater-entrypoint.sh
+
+COPY . .
+
+ENTRYPOINT ["/usr/bin/bash", "stock-updater-entrypoint.sh"]
\ No newline at end of file
diff --git a/Dockerfiles/Dockerfile.worker b/Dockerfiles/Dockerfile.worker
index b34fcaf3..cb5234a9 100644
--- a/Dockerfiles/Dockerfile.worker
+++ b/Dockerfiles/Dockerfile.worker
@@ -26,6 +26,7 @@ RUN set -eux; \
graphviz-dev \
libgts-dev \
libpq5 \
+ chrony \
graphviz \
binutils \
libproj-dev \
@@ -46,4 +47,4 @@ RUN chmod +x /usr/local/bin/worker-entrypoint.sh
COPY . .
-ENTRYPOINT ["worker-entrypoint.sh"]
\ No newline at end of file
+ENTRYPOINT ["/usr/bin/bash", "worker-entrypoint.sh"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 1c2d347e..5eacae06 100644
--- a/README.md
+++ b/README.md
@@ -44,10 +44,11 @@ extension.
cd eVibes
```
-2. Choose the storefront. By default, `main` branch has Astro one. Skip this step if you're OK with Astro.
+2. Choose the storefront. By default, `main` branch has no storefront included.
+Skip this step if you're OK with that and plan to only use API or develop your own storefront.
```bash
- git checkout storefront-
+ git checkout storefront-
```
3. Generate your .env file. Check and confirm the contents afterward.
diff --git a/blog/admin.py b/blog/admin.py
index afafd660..7c6bf974 100644
--- a/blog/admin.py
+++ b/blog/admin.py
@@ -1,37 +1,40 @@
-from django.contrib import admin
-from django_summernote.admin import SummernoteModelAdmin
+from django.contrib.admin import ModelAdmin, register
+from django_summernote.admin import SummernoteModelAdminMixin
+
+from core.admin import ActivationActionsMixin, FieldsetsMixin
from .models import Post, PostTag
-@admin.register(Post)
-class PostAdmin(SummernoteModelAdmin):
+@register(Post)
+class PostAdmin(SummernoteModelAdminMixin, FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
list_display = ("title", "author", "slug", "created", "modified")
list_filter = ("author", "tags", "created", "modified")
- search_fields = ("title", "content")
+ search_fields = ("title", "content", "slug")
filter_horizontal = ("tags",)
date_hierarchy = "created"
autocomplete_fields = ("author", "tags")
- summernote_fields = ("content",)
-
- fieldsets = (
- (
- None,
- {
- "fields": (
- "author",
- "title",
- "content",
- "file",
- "tags",
- )
- },
- ),
+ readonly_fields = (
+ "uuid",
+ "slug",
+ "modified",
+ "created",
)
+ summernote_fields = ("content",)
+ general_fields = [
+ "title",
+ "author",
+ "content",
+ "file",
+ ]
+ relation_fields = [
+ "tags",
+ ]
-@admin.register(PostTag)
-class PostTagAdmin(admin.ModelAdmin):
+
+@register(PostTag)
+class PostTagAdmin(ModelAdmin):
list_display = ("tag_name", "name")
search_fields = ("tag_name", "name")
ordering = ("tag_name",)
diff --git a/blog/locale/ar_AR/LC_MESSAGES/django.mo b/blog/locale/ar_AR/LC_MESSAGES/django.mo
index 5300dfa5..f313ef1e 100644
Binary files a/blog/locale/ar_AR/LC_MESSAGES/django.mo and b/blog/locale/ar_AR/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/ar_AR/LC_MESSAGES/django.po b/blog/locale/ar_AR/LC_MESSAGES/django.po
index f5a9d070..889822a7 100644
--- a/blog/locale/ar_AR/LC_MESSAGES/django.po
+++ b/blog/locale/ar_AR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,55 +17,52 @@ msgstr ""
msgid "blog"
msgstr "المدونة"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "عنوان المنشور"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "العنوان"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "المنشور"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "المنشورات"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "اسم العلامة"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "اسم سهل الاستخدام لعلامة المنشور"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "اسم عرض العلامة"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "علامة المشاركة"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "علامات المشاركة"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "محرك eVibes"
diff --git a/blog/locale/cs_CZ/LC_MESSAGES/django.mo b/blog/locale/cs_CZ/LC_MESSAGES/django.mo
index e10d7a66..c507d90f 100644
Binary files a/blog/locale/cs_CZ/LC_MESSAGES/django.mo and b/blog/locale/cs_CZ/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/cs_CZ/LC_MESSAGES/django.po b/blog/locale/cs_CZ/LC_MESSAGES/django.po
index e915c706..5ede773d 100644
--- a/blog/locale/cs_CZ/LC_MESSAGES/django.po
+++ b/blog/locale/cs_CZ/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,57 +17,54 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Název příspěvku"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Název"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Příspěvek"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Příspěvky"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Soubory Markdown nejsou podporovány - místo toho použijte obsah Markdown!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"musí být poskytnut soubor markdown nebo obsah markdown - vzájemně se "
"vylučují."
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "interní identifikátor tagu pro tag příspěvku"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Název štítku"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Uživatelsky přívětivý název pro značku příspěvku"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Zobrazení názvu štítku"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Označení příspěvku"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Štítky příspěvků"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Motor eVibes"
diff --git a/blog/locale/da_DK/LC_MESSAGES/django.mo b/blog/locale/da_DK/LC_MESSAGES/django.mo
index e5c1f73b..af1ba23a 100644
Binary files a/blog/locale/da_DK/LC_MESSAGES/django.mo and b/blog/locale/da_DK/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/da_DK/LC_MESSAGES/django.po b/blog/locale/da_DK/LC_MESSAGES/django.po
index 46d72f62..8b725448 100644
--- a/blog/locale/da_DK/LC_MESSAGES/django.po
+++ b/blog/locale/da_DK/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,55 +17,52 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Indlæggets titel"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Titel"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Indlæg"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Indlæg"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr "Markdown-filer understøttes ikke - brug markdown-indhold i stedet!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"en markdown-fil eller markdown-indhold skal leveres - gensidigt udelukkende"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "intern tag-identifikator for indlægs-tagget"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Tag-navn"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Brugervenligt navn til posttagget"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Navn på tag-visning"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Tag til indlæg"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Tags til indlæg"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibes-motor"
diff --git a/blog/locale/de_DE/LC_MESSAGES/django.mo b/blog/locale/de_DE/LC_MESSAGES/django.mo
index ca95544b..dc0b5861 100644
Binary files a/blog/locale/de_DE/LC_MESSAGES/django.mo and b/blog/locale/de_DE/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/de_DE/LC_MESSAGES/django.po b/blog/locale/de_DE/LC_MESSAGES/django.po
index dedd31ad..9774aacc 100644
--- a/blog/locale/de_DE/LC_MESSAGES/django.po
+++ b/blog/locale/de_DE/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,58 +17,55 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Titel des Beitrags"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Titel"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Beitrag"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Beiträge"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Markdown-Dateien werden nicht unterstützt - verwenden Sie stattdessen "
"Markdown-Inhalte!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"eine Markdown-Datei oder ein Markdown-Inhalt muss bereitgestellt werden - "
"beide schließen sich gegenseitig aus"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "interner Tag-Bezeichner für den Post-Tag"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Tag name"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Benutzerfreundlicher Name für das Post-Tag"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Tag-Anzeigename"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Tag eintragen"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Tags eintragen"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibes Motor"
diff --git a/blog/locale/en_GB/LC_MESSAGES/django.mo b/blog/locale/en_GB/LC_MESSAGES/django.mo
index 4a846ade..b3b2a30b 100644
Binary files a/blog/locale/en_GB/LC_MESSAGES/django.mo and b/blog/locale/en_GB/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/en_GB/LC_MESSAGES/django.po b/blog/locale/en_GB/LC_MESSAGES/django.po
index d7d73339..edb971dd 100644
--- a/blog/locale/en_GB/LC_MESSAGES/django.po
+++ b/blog/locale/en_GB/LC_MESSAGES/django.po
@@ -2,12 +2,12 @@
# Copyright (C) 2025 EGOR GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV , 2025.
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -21,61 +21,52 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Post's title"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Title"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Post"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Posts"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr "Markdown files are not supported yer - use markdown content instead!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"a markdown file or markdown content must be provided - mutually exclusive"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "internal tag identifier for the post tag"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Tag name"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "User-friendly name for the post tag"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Tag display name"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Post tag"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Post tags"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibes Engine"
-
-#~ msgid "(no content yet)"
-#~ msgstr "(no content yet)"
-
-#~ msgid "rendered HTML"
-#~ msgstr "Rendered HTML"
diff --git a/blog/locale/en_US/LC_MESSAGES/django.mo b/blog/locale/en_US/LC_MESSAGES/django.mo
index bf1dee8a..4f1d5f1f 100644
Binary files a/blog/locale/en_US/LC_MESSAGES/django.mo and b/blog/locale/en_US/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/en_US/LC_MESSAGES/django.po b/blog/locale/en_US/LC_MESSAGES/django.po
index 9272d2ef..7d0d3dae 100644
--- a/blog/locale/en_US/LC_MESSAGES/django.po
+++ b/blog/locale/en_US/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,55 +17,52 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Post's title"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Title"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Post"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Posts"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr "Markdown files are not supported yer - use markdown content instead!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"a markdown file or markdown content must be provided - mutually exclusive"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "internal tag identifier for the post tag"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Tag name"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "User-friendly name for the post tag"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Tag display name"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Post tag"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Post tags"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibes Engine"
diff --git a/blog/locale/es_ES/LC_MESSAGES/django.mo b/blog/locale/es_ES/LC_MESSAGES/django.mo
index 6f9496da..f993a3d2 100644
Binary files a/blog/locale/es_ES/LC_MESSAGES/django.mo and b/blog/locale/es_ES/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/es_ES/LC_MESSAGES/django.po b/blog/locale/es_ES/LC_MESSAGES/django.po
index 0949d9d5..a09ee410 100644
--- a/blog/locale/es_ES/LC_MESSAGES/django.po
+++ b/blog/locale/es_ES/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,57 +17,54 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Título del mensaje"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Título"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Publicar en"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Puestos"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"No se admiten archivos Markdown - ¡utiliza contenido Markdown en su lugar!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"se debe proporcionar un archivo markdown o contenido markdown - mutuamente "
"excluyentes"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "identificador interno de la etiqueta post"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Nombre de la etiqueta"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Nombre de la etiqueta"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Etiqueta postal"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Etiquetas"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Motor eVibes"
diff --git a/blog/locale/fr_FR/LC_MESSAGES/django.mo b/blog/locale/fr_FR/LC_MESSAGES/django.mo
index 64081a77..ffbc0cc0 100644
Binary files a/blog/locale/fr_FR/LC_MESSAGES/django.mo and b/blog/locale/fr_FR/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/fr_FR/LC_MESSAGES/django.po b/blog/locale/fr_FR/LC_MESSAGES/django.po
index f4d1c0df..6faa55df 100644
--- a/blog/locale/fr_FR/LC_MESSAGES/django.po
+++ b/blog/locale/fr_FR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,58 +17,55 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Titre du message"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Titre"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Poste"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Postes"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Les fichiers Markdown ne sont pas pris en charge - utilisez plutôt du "
"contenu Markdown !"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"un fichier markdown ou un contenu markdown doit être fourni - ils s'excluent "
"mutuellement"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "identifiant interne de la balise post"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Nom du jour"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Nom convivial pour la balise post"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Nom d'affichage de l'étiquette"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Tag de poste"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Tags de la poste"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Moteur eVibes"
diff --git a/blog/locale/hi_IN/LC_MESSAGES/django.mo b/blog/locale/hi_IN/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/blog/locale/hi_IN/LC_MESSAGES/django.mo and b/blog/locale/hi_IN/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/hi_IN/LC_MESSAGES/django.po b/blog/locale/hi_IN/LC_MESSAGES/django.po
index cde6b30e..6b340223 100644
--- a/blog/locale/hi_IN/LC_MESSAGES/django.po
+++ b/blog/locale/hi_IN/LC_MESSAGES/django.po
@@ -2,12 +2,12 @@
# Copyright (C) 2025 EGOR GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV , 2025.
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -20,51 +20,51 @@ msgstr ""
msgid "blog"
msgstr ""
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr ""
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr ""
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr ""
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr ""
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr ""
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr ""
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr ""
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr ""
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr ""
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr ""
diff --git a/blog/locale/it_IT/LC_MESSAGES/django.mo b/blog/locale/it_IT/LC_MESSAGES/django.mo
index 4fe49af5..beba2141 100644
Binary files a/blog/locale/it_IT/LC_MESSAGES/django.mo and b/blog/locale/it_IT/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/it_IT/LC_MESSAGES/django.po b/blog/locale/it_IT/LC_MESSAGES/django.po
index 33bc4952..214c3409 100644
--- a/blog/locale/it_IT/LC_MESSAGES/django.po
+++ b/blog/locale/it_IT/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,56 +17,53 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Titolo del post"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Titolo"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Posta"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Messaggi"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr "I file Markdown non sono supportati: usa invece i contenuti Markdown!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"deve essere fornito un file markdown o un contenuto markdown - si escludono "
"a vicenda"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "identificatore interno del tag post"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Nome del tag"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Nome intuitivo per il tag del post"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Nome del tag"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Post tag"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Tag dei post"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Motore eVibes"
diff --git a/blog/locale/ja_JP/LC_MESSAGES/django.mo b/blog/locale/ja_JP/LC_MESSAGES/django.mo
index b4077744..0bea06f8 100644
Binary files a/blog/locale/ja_JP/LC_MESSAGES/django.mo and b/blog/locale/ja_JP/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/ja_JP/LC_MESSAGES/django.po b/blog/locale/ja_JP/LC_MESSAGES/django.po
index 2963679c..21d9d5bc 100644
--- a/blog/locale/ja_JP/LC_MESSAGES/django.po
+++ b/blog/locale/ja_JP/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,58 +17,55 @@ msgstr ""
msgid "blog"
msgstr "ブログ"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "投稿タイトル"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "タイトル"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "ポスト"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "投稿"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
"ンツを使用してください!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
"い。"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "投稿タグの内部タグ識別子"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "タグ名"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "投稿タグのユーザーフレンドリーな名前"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "タグ表示名"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "投稿タグ"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "投稿タグ"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibesエンジン"
diff --git a/blog/locale/kk_KZ/LC_MESSAGES/django.mo b/blog/locale/kk_KZ/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/blog/locale/kk_KZ/LC_MESSAGES/django.mo and b/blog/locale/kk_KZ/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/kk_KZ/LC_MESSAGES/django.po b/blog/locale/kk_KZ/LC_MESSAGES/django.po
index cde6b30e..6b340223 100644
--- a/blog/locale/kk_KZ/LC_MESSAGES/django.po
+++ b/blog/locale/kk_KZ/LC_MESSAGES/django.po
@@ -2,12 +2,12 @@
# Copyright (C) 2025 EGOR GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV , 2025.
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -20,51 +20,51 @@ msgstr ""
msgid "blog"
msgstr ""
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr ""
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr ""
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr ""
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr ""
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr ""
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr ""
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr ""
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr ""
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr ""
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr ""
diff --git a/blog/locale/nl_NL/LC_MESSAGES/django.mo b/blog/locale/nl_NL/LC_MESSAGES/django.mo
index 479f9000..fad5266d 100644
Binary files a/blog/locale/nl_NL/LC_MESSAGES/django.mo and b/blog/locale/nl_NL/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/nl_NL/LC_MESSAGES/django.po b/blog/locale/nl_NL/LC_MESSAGES/django.po
index 1a2069d2..e14bcdc1 100644
--- a/blog/locale/nl_NL/LC_MESSAGES/django.po
+++ b/blog/locale/nl_NL/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,58 +17,55 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Titel van de post"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Titel"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Plaats"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Berichten"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Markdown-bestanden worden niet ondersteund - gebruik in plaats daarvan "
"markdown-inhoud!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"er moet een markdown-bestand of markdown-inhoud worden geleverd - wederzijds "
"exclusief"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "interne tagidentifier voor de posttag"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Tag naam"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Gebruiksvriendelijke naam voor de posttag"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Tag weergavenaam"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Post tag"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Post tags"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibes motor"
diff --git a/blog/locale/pl_PL/LC_MESSAGES/django.mo b/blog/locale/pl_PL/LC_MESSAGES/django.mo
index 726aa952..135950e8 100644
Binary files a/blog/locale/pl_PL/LC_MESSAGES/django.mo and b/blog/locale/pl_PL/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/pl_PL/LC_MESSAGES/django.po b/blog/locale/pl_PL/LC_MESSAGES/django.po
index 9c80ceda..3827d474 100644
--- a/blog/locale/pl_PL/LC_MESSAGES/django.po
+++ b/blog/locale/pl_PL/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,57 +17,54 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Tytuł postu"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Tytuł"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Post"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Posty"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Pliki Markdown nie są obsługiwane - zamiast tego użyj zawartości Markdown!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"należy dostarczyć plik markdown lub zawartość markdown - wzajemnie się "
"wykluczające"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "wewnętrzny identyfikator tagu posta"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Nazwa tagu"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Wyświetlana nazwa znacznika"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Tag posta"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Tagi postów"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Silnik eVibes"
diff --git a/blog/locale/pt_BR/LC_MESSAGES/django.mo b/blog/locale/pt_BR/LC_MESSAGES/django.mo
index 52b3f93d..b9b9daa1 100644
Binary files a/blog/locale/pt_BR/LC_MESSAGES/django.mo and b/blog/locale/pt_BR/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/pt_BR/LC_MESSAGES/django.po b/blog/locale/pt_BR/LC_MESSAGES/django.po
index efa85afe..4b1addfc 100644
--- a/blog/locale/pt_BR/LC_MESSAGES/django.po
+++ b/blog/locale/pt_BR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,56 +17,53 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Título da postagem"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Título"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Postar"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Publicações"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Os arquivos markdown não são suportados - use conteúdo markdown em vez disso!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"um arquivo ou conteúdo de markdown deve ser fornecido - mutuamente exclusivo"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "identificador de tag interno para a tag de postagem"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Nome da etiqueta"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Nome de fácil utilização para a tag de postagem"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Nome de exibição da tag"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Etiqueta de postagem"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Tags de postagem"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Motor eVibes"
diff --git a/blog/locale/ro_RO/LC_MESSAGES/django.mo b/blog/locale/ro_RO/LC_MESSAGES/django.mo
index 9df78c8a..1f2f9c95 100644
Binary files a/blog/locale/ro_RO/LC_MESSAGES/django.mo and b/blog/locale/ro_RO/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/ro_RO/LC_MESSAGES/django.po b/blog/locale/ro_RO/LC_MESSAGES/django.po
index 13146549..2e6dce42 100644
--- a/blog/locale/ro_RO/LC_MESSAGES/django.po
+++ b/blog/locale/ro_RO/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,57 +17,54 @@ msgstr ""
msgid "blog"
msgstr "Blog"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Titlul postului"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Titlul"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Post"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Mesaje"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Fișierele Markdown nu sunt acceptate - utilizați în schimb conținut Markdown!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"trebuie furnizat un fișier markdown sau conținut markdown - se exclud "
"reciproc"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "identificator intern de etichetă pentru eticheta postului"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Nume etichetă"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Nume ușor de utilizat pentru eticheta postului"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Nume afișare etichetă"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Etichetă post"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Etichete poștale"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Motorul eVibes"
diff --git a/blog/locale/ru_RU/LC_MESSAGES/django.mo b/blog/locale/ru_RU/LC_MESSAGES/django.mo
index 8220775b..c310a3b1 100644
Binary files a/blog/locale/ru_RU/LC_MESSAGES/django.mo and b/blog/locale/ru_RU/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/ru_RU/LC_MESSAGES/django.po b/blog/locale/ru_RU/LC_MESSAGES/django.po
index d1974a84..148f0d82 100644
--- a/blog/locale/ru_RU/LC_MESSAGES/django.po
+++ b/blog/locale/ru_RU/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,58 +17,55 @@ msgstr ""
msgid "blog"
msgstr "Блог"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "Заголовок сообщения"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "Название"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "Пост"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "Посты"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
"содержимое в формате Markdown!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"необходимо предоставить файл разметки или содержимое разметки - "
"взаимоисключающие варианты"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "внутренний идентификатор тега для тега post"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "Название тега"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "Удобное для пользователя название тега поста"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "Отображаемое имя тега"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "Тэг поста"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "Тэги постов"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "Движок eVibes"
diff --git a/blog/locale/zh_Hans/LC_MESSAGES/django.mo b/blog/locale/zh_Hans/LC_MESSAGES/django.mo
index 7824700f..d034c894 100644
Binary files a/blog/locale/zh_Hans/LC_MESSAGES/django.mo and b/blog/locale/zh_Hans/LC_MESSAGES/django.mo differ
diff --git a/blog/locale/zh_Hans/LC_MESSAGES/django.po b/blog/locale/zh_Hans/LC_MESSAGES/django.po
index addf9a90..22e73742 100644
--- a/blog/locale/zh_Hans/LC_MESSAGES/django.po
+++ b/blog/locale/zh_Hans/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,54 +17,51 @@ msgstr ""
msgid "blog"
msgstr "博客"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "post title"
msgstr "帖子标题"
-#: blog/models.py:17
+#: blog/models.py:36
msgid "title"
msgstr "标题"
-#: blog/models.py:64
+#: blog/models.py:83
msgid "post"
msgstr "职位"
-#: blog/models.py:65
+#: blog/models.py:84
msgid "posts"
msgstr "职位"
-#: blog/models.py:69
+#: blog/models.py:88
msgid "markdown files are not supported yet - use markdown content instead"
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
-#: blog/models.py:71
+#: blog/models.py:90
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
-#: blog/models.py:82
+#: blog/models.py:122
msgid "internal tag identifier for the post tag"
msgstr "职位标签的内部标签标识符"
-#: blog/models.py:83
+#: blog/models.py:123
msgid "tag name"
msgstr "标签名称"
-#: blog/models.py:87
+#: blog/models.py:127
msgid "user-friendly name for the post tag"
msgstr "方便用户使用的帖子标签名称"
-#: blog/models.py:88
+#: blog/models.py:128
msgid "tag display name"
msgstr "标签显示名称"
-#: blog/models.py:96
+#: blog/models.py:136
msgid "post tag"
msgstr "职位标签"
-#: blog/models.py:97
+#: blog/models.py:137
msgid "post tags"
msgstr "帖子标签"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibes 引擎"
diff --git a/blog/migrations/0001_initial.py b/blog/migrations/0001_initial.py
index d9f6c5ed..231105f3 100644
--- a/blog/migrations/0001_initial.py
+++ b/blog/migrations/0001_initial.py
@@ -18,56 +18,113 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
- name='PostTag',
+ name="PostTag",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('tag_name', models.CharField(help_text='internal tag identifier for the post tag', max_length=255,
- verbose_name='tag name')),
- ('name', models.CharField(help_text='user-friendly name for the post tag', max_length=255, unique=True,
- verbose_name='tag display name')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "tag_name",
+ models.CharField(
+ help_text="internal tag identifier for the post tag", max_length=255, verbose_name="tag name"
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="user-friendly name for the post tag",
+ max_length=255,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
],
options={
- 'verbose_name': 'post tag',
- 'verbose_name_plural': 'post tags',
+ "verbose_name": "post tag",
+ "verbose_name_plural": "post tags",
},
),
migrations.CreateModel(
- name='Post',
+ name="Post",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('title', models.CharField()),
- ('content', markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name='content')),
- ('file', models.FileField(blank=True, null=True, upload_to='posts/')),
- ('slug', models.SlugField(allow_unicode=True)),
- ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='posts',
- to=settings.AUTH_USER_MODEL)),
- ('tags', models.ManyToManyField(to='blog.posttag')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ ("title", models.CharField()),
+ ("content", markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content")),
+ ("file", models.FileField(blank=True, null=True, upload_to="posts/")),
+ ("slug", models.SlugField(allow_unicode=True)),
+ (
+ "author",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, related_name="posts", to=settings.AUTH_USER_MODEL
+ ),
+ ),
+ ("tags", models.ManyToManyField(to="blog.posttag")),
],
options={
- 'verbose_name': 'post',
- 'verbose_name_plural': 'posts',
+ "verbose_name": "post",
+ "verbose_name_plural": "posts",
},
),
]
diff --git a/blog/migrations/0002_alter_post_slug_alter_post_title.py b/blog/migrations/0002_alter_post_slug_alter_post_title.py
index fbaf535f..e247c9ea 100644
--- a/blog/migrations/0002_alter_post_slug_alter_post_title.py
+++ b/blog/migrations/0002_alter_post_slug_alter_post_title.py
@@ -5,20 +5,21 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('blog', '0001_initial'),
+ ("blog", "0001_initial"),
]
operations = [
migrations.AlterField(
- model_name='post',
- name='slug',
- field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, populate_from='title', unique=True),
+ model_name="post",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True, blank=True, editable=False, populate_from="title", unique=True
+ ),
),
migrations.AlterField(
- model_name='post',
- name='title',
- field=models.CharField(help_text='post title', max_length=128, unique=True, verbose_name='title'),
+ model_name="post",
+ name="title",
+ field=models.CharField(help_text="post title", max_length=128, unique=True, verbose_name="title"),
),
]
diff --git a/blog/migrations/0003_alter_post_tags.py b/blog/migrations/0003_alter_post_tags.py
index 1929216c..c514b15c 100644
--- a/blog/migrations/0003_alter_post_tags.py
+++ b/blog/migrations/0003_alter_post_tags.py
@@ -4,15 +4,14 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('blog', '0002_alter_post_slug_alter_post_title'),
+ ("blog", "0002_alter_post_slug_alter_post_title"),
]
operations = [
migrations.AlterField(
- model_name='post',
- name='tags',
- field=models.ManyToManyField(blank=True, related_name='posts', to='blog.posttag'),
+ model_name="post",
+ name="tags",
+ field=models.ManyToManyField(blank=True, related_name="posts", to="blog.posttag"),
),
]
diff --git a/blog/migrations/0004_post_content_ar_ar_post_content_cs_cz_and_more.py b/blog/migrations/0004_post_content_ar_ar_post_content_cs_cz_and_more.py
new file mode 100644
index 00000000..4ccfcaec
--- /dev/null
+++ b/blog/migrations/0004_post_content_ar_ar_post_content_cs_cz_and_more.py
@@ -0,0 +1,301 @@
+# Generated by Django 5.2 on 2025-06-29 13:09
+
+import markdown_field.fields
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("blog", "0003_alter_post_tags"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="post",
+ name="content_ar_ar",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_cs_cz",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_da_dk",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_de_de",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_en_gb",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_en_us",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_es_es",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_fr_fr",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_hi_in",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_it_it",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_ja_jp",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_kk_kz",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_nl_nl",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_pl_pl",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_pt_br",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_ro_ro",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_ru_ru",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="content_zh_hans",
+ field=markdown_field.fields.MarkdownField(blank=True, null=True, verbose_name="content"),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_ar_ar",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_cs_cz",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_da_dk",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_de_de",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_en_gb",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_en_us",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_es_es",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_fr_fr",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_hi_in",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_it_it",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_ja_jp",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_kk_kz",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_nl_nl",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_pl_pl",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_pt_br",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_ro_ro",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_ru_ru",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ migrations.AddField(
+ model_name="post",
+ name="title_zh_hans",
+ field=models.CharField(
+ help_text="post title",
+ max_length=128,
+ null=True,
+ unique=True,
+ verbose_name="title",
+ ),
+ ),
+ ]
diff --git a/blog/models.py b/blog/models.py
index d47853e8..18878a5a 100644
--- a/blog/models.py
+++ b/blog/models.py
@@ -7,13 +7,32 @@ from markdown_field import MarkdownField
from core.abstract import NiceModel
-class Post(NiceModel):
+class Post(NiceModel): # type: ignore [django-manager-missing]
+ """
+ Represents a blog post model extending NiceModel.
+
+ The Post class defines the structure and behavior of a blog post. It includes
+ attributes for author, title, content, optional file attachment, slug,
+ and associated tags. The class enforces constraints such as requiring either
+ content or a file attachment but not both simultaneously. It also supports
+ automatic slug generation based on the title. This model can be used in
+ a blogging platform to manage posts created by users.
+
+ Attributes:
+ is_publicly_visible (bool): Specifies whether the post is visible to the public.
+ author (ForeignKey): A reference to the user who authored the post.
+ title (CharField): The title of the post. Must be unique and non-empty.
+ content (MarkdownField): The content of the post written in Markdown format.
+ file (FileField): An optional file attachment for the post.
+ slug (AutoSlugField): A unique, automatically generated slug based on the title.
+ tags (ManyToManyField): Tags associated with the post for categorization.
+
+ """
+
is_publicly_visible = True
- author: ForeignKey = ForeignKey(
- to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts"
- )
- title: CharField = CharField(
+ author = ForeignKey(to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts")
+ title = CharField(
unique=True, max_length=128, blank=False, null=False, help_text=_("post title"), verbose_name=_("title")
)
content: MarkdownField = MarkdownField(
@@ -53,9 +72,9 @@ class Post(NiceModel):
blank=True,
null=True,
)
- file: FileField = FileField(upload_to="posts/", blank=True, null=True)
- slug: AutoSlugField = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
- tags: ManyToManyField = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
+ file = FileField(upload_to="posts/", blank=True, null=True)
+ slug = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
+ tags = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
def __str__(self):
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
@@ -73,16 +92,37 @@ class Post(NiceModel):
class PostTag(NiceModel):
- is_publicly_visible = True
+ """
+ Represents a tag associated with a post.
- tag_name: CharField = CharField(
+ The PostTag class is used to define and manage tags that can be assigned
+ to posts. These tags include an internal identifier and a user-friendly
+ display name. The class supports internationalization for both the internal
+ identifier and the display name.
+
+ Attributes:
+ is_publicly_visible (bool): Determines if the tag is visible publicly.
+ tag_name (CharField): An internal tag identifier for the post's tag. It is a required
+ field with a maximum length of 255 characters.
+ name (CharField): A user-friendly, unique display name for the post's tag
+ with a maximum length of 255 characters.
+
+ Meta:
+ verbose_name (str): Human-readable singular name of the PostTag model.
+ verbose_name_plural (str): Human-readable plural name of the PostTag model.
+ """
+
+ is_publicly_visible = True
+ posts: "Post"
+
+ tag_name = CharField(
blank=False,
null=False,
max_length=255,
help_text=_("internal tag identifier for the post tag"),
verbose_name=_("tag name"),
)
- name: CharField = CharField(
+ name = CharField(
max_length=255,
help_text=_("user-friendly name for the post tag"),
verbose_name=_("tag display name"),
diff --git a/blog/translation.py b/blog/translation.py
new file mode 100644
index 00000000..58f7ac02
--- /dev/null
+++ b/blog/translation.py
@@ -0,0 +1,9 @@
+from modeltranslation.decorators import register
+from modeltranslation.translator import TranslationOptions
+
+from blog.models import Post
+
+
+@register(Post)
+class PostOptions(TranslationOptions):
+ fields = ("title", "content")
diff --git a/blog/urls.py b/blog/urls.py
index 1a6c8b34..ac04560f 100644
--- a/blog/urls.py
+++ b/blog/urls.py
@@ -3,6 +3,8 @@ from rest_framework.routers import DefaultRouter
from blog.viewsets import PostViewSet
+app_name = "blog"
+
payment_router = DefaultRouter()
payment_router.register(prefix=r"posts", viewset=PostViewSet, basename="posts")
diff --git a/blog/views.py b/blog/views.py
index eea436a3..075719c8 100644
--- a/blog/views.py
+++ b/blog/views.py
@@ -1,3 +1,3 @@
import logging
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
diff --git a/blog/viewsets.py b/blog/viewsets.py
index 8c30214c..deb26f23 100644
--- a/blog/viewsets.py
+++ b/blog/viewsets.py
@@ -8,6 +8,22 @@ from core.permissions import EvibesPermission
class PostViewSet(ReadOnlyModelViewSet):
+ """
+ Encapsulates operations for managing and retrieving Post entities in a read-only model view set.
+
+ This class is tailored to handle Post objects that are active and allows filtration based on defined
+ filters. It integrates with Django's backend filtering system and ensures operations align with the
+ defined permissions. The view set also includes an additional "retrieve" permission configuration.
+
+ Attributes:
+ serializer_class: Specifies the serializer to be used for Post objects.
+ permission_classes: Defines the permissions required to interact with this view set.
+ queryset: Determines the initial queryset, filtered to include only active Post objects.
+ filter_backends: Lists the backends to be used for filtering querysets.
+ filterset_class: Defines the set of filters used for filtering Post objects.
+ additional: Contains additional configuration, such as specific action permissions.
+ """
+
serializer_class = PostSerializer
permission_classes = (EvibesPermission,)
queryset = Post.objects.filter(is_active=True)
diff --git a/core/abstract.py b/core/abstract.py
index 7ee83069..65f631e8 100644
--- a/core/abstract.py
+++ b/core/abstract.py
@@ -1,5 +1,4 @@
import uuid
-from datetime import datetime
from django.db.models import BooleanField, Model, UUIDField
from django.utils.translation import gettext_lazy as _
@@ -7,32 +6,24 @@ from django_extensions.db.fields import CreationDateTimeField, ModificationDateT
class NiceModel(Model):
- id = None
- uuid: uuid = UUIDField( # type: ignore
+ id: None = None
+ uuid = UUIDField(
verbose_name=_("unique id"),
help_text=_("unique id is used to surely identify any database object"),
primary_key=True,
default=uuid.uuid4,
editable=False,
)
- is_active: bool = BooleanField( # type: ignore
+ is_active = BooleanField(
default=True,
verbose_name=_("is active"),
- help_text=_(
- "if set to false, this object can't be seen by users without needed permission"
- ),
- )
- created: datetime = CreationDateTimeField( # type: ignore
- _("created"), help_text=_("when the object first appeared on the database")
- )
- modified: datetime = ModificationDateTimeField( # type: ignore
- _("modified"), help_text=_("when the object was last modified")
+ help_text=_("if set to false, this object can't be seen by users without needed permission"),
)
+ created = CreationDateTimeField(_("created"), help_text=_("when the object first appeared on the database"))
+ modified = ModificationDateTimeField(_("modified"), help_text=_("when the object was last modified"))
def save(self, **kwargs):
- self.update_modified = kwargs.pop(
- "update_modified", getattr(self, "update_modified", True)
- )
+ self.update_modified = kwargs.pop("update_modified", getattr(self, "update_modified", True))
super().save(**kwargs)
class Meta:
diff --git a/core/admin.py b/core/admin.py
index 74b499a6..d7bfbcf0 100644
--- a/core/admin.py
+++ b/core/admin.py
@@ -1,21 +1,20 @@
from contextlib import suppress
+from typing import ClassVar, Type
from constance.admin import Config
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
from django.apps import apps
-from django.contrib import admin
-from django.contrib.admin import ModelAdmin, TabularInline
+from django.contrib.admin import ModelAdmin, TabularInline, action, register, site
from django.contrib.gis.admin import GISModelAdmin
+from django.contrib.messages import constants as messages
from django.db.models import Model
from django.utils.translation import gettext_lazy as _
from modeltranslation.translator import NotRegistered, translator
from modeltranslation.utils import get_translation_fields
from mptt.admin import DraggableMPTTAdmin
-from evibes.settings import CONSTANCE_CONFIG
-
-from .forms import OrderForm, OrderProductForm, VendorForm
-from .models import (
+from core.forms import OrderForm, OrderProductForm, VendorForm
+from core.models import (
Address,
Attribute,
AttributeGroup,
@@ -35,14 +34,21 @@ from .models import (
Vendor,
Wishlist,
)
+from evibes.settings import CONSTANCE_CONFIG
class FieldsetsMixin:
general_fields: list = []
relation_fields: list = []
- model: Model
+ model: ClassVar[Type[Model]]
def get_fieldsets(self, request, obj=None):
+ if request:
+ pass
+
+ if obj:
+ pass
+
fieldsets = []
def add_translations_fieldset(fss):
@@ -52,9 +58,7 @@ class FieldsetsMixin:
for orig in transoptions.local_fields:
translation_fields += get_translation_fields(orig)
if translation_fields:
- fss = list(fss) + [
- (_("translations"), {"fields": translation_fields})
- ]
+ fss = list(fss) + [(_("translations"), {"fields": translation_fields})]
return fss
if self.general_fields:
@@ -79,34 +83,37 @@ class FieldsetsMixin:
return fieldsets
-class BasicModelAdmin(ModelAdmin):
- @admin.action(description=str(_("activate selected %(verbose_name_plural)s")))
- def activate_selected(self, request, queryset) -> str:
- if request:
- pass
- queryset.update(is_active=True)
- return str(_("%(verbose_name_plural)s activated successfully!"))
+# noinspection PyUnresolvedReferences
+class ActivationActionsMixin:
+ actions_on_top = True
+ actions_on_bottom = True
+ actions = [
+ "delete_selected",
+ "activate_selected",
+ "deactivate_selected",
+ ]
- @admin.action(description=str(_("deactivate selected %(verbose_name_plural)s")))
- def deactivate_selected(self, request, queryset) -> str:
- if request:
- pass
- queryset.update(is_active=False)
- return str(_("%(verbose_name_plural)s deactivated successfully."))
+ @action(description=_("activate selected %(verbose_name_plural)s").lower(), permissions=["change"])
+ def activate_selected(self, request, queryset):
+ try:
+ queryset.update(is_active=True)
+ self.message_user(
+ request=request, message=_("selected items have been activated.").lower(), level=messages.SUCCESS
+ )
- def get_actions(self, request):
- actions = super().get_actions(request)
- actions["activate_selected"] = (
- self.activate_selected,
- "activate_selected",
- str(_("activate selected %(verbose_name_plural)s")),
- )
- actions["deactivate_selected"] = (
- self.deactivate_selected,
- "deactivate_selected",
- str(_("deactivate selected %(verbose_name_plural)s")),
- )
- return actions
+ except Exception as e:
+ self.message_user(request=request, message=str(e), level=messages.ERROR)
+
+ @action(description=_("deactivate selected %(verbose_name_plural)s").lower(), permissions=["change"])
+ def deactivate_selected(self, request, queryset):
+ try:
+ queryset.update(is_active=False)
+ self.message_user(
+ request=request, message=_("selected items have been deactivated.").lower(), level=messages.SUCCESS
+ )
+
+ except Exception as e:
+ self.message_user(request=request, message=str(e), level=messages.ERROR)
class AttributeValueInline(TabularInline):
@@ -148,12 +155,7 @@ class OrderProductInline(TabularInline):
icon = "fa-solid fa-boxes-packing"
def get_queryset(self, request):
- return (
- super()
- .get_queryset(request)
- .select_related("product")
- .only("product__name")
- )
+ return super().get_queryset(request).select_related("product").only("product__name")
class CategoryChildrenInline(TabularInline):
@@ -167,9 +169,10 @@ class CategoryChildrenInline(TabularInline):
icon = "fa-solid fa-leaf"
-@admin.register(AttributeGroup)
-class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
- model = AttributeGroup # type: ignore
+@register(AttributeGroup)
+class AttributeGroupAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = AttributeGroup # type: ignore [misc]
list_display = ("name", "modified")
search_fields = ("uuid", "name")
readonly_fields = ("uuid", "modified", "created")
@@ -178,9 +181,10 @@ class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = []
-@admin.register(Attribute)
-class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Attribute # type: ignore
+@register(Attribute)
+class AttributeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Attribute # type: ignore [misc]
list_display = ("name", "group", "value_type", "modified")
list_filter = ("value_type", "group", "is_active")
search_fields = ("uuid", "name", "group__name")
@@ -191,9 +195,10 @@ class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["group", "categories"]
-@admin.register(AttributeValue)
-class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
- model = AttributeValue # type: ignore
+@register(AttributeValue)
+class AttributeValueAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = AttributeValue # type: ignore [misc]
list_display = ("attribute", "value", "modified")
list_filter = ("attribute__group", "is_active")
search_fields = ("uuid", "value", "attribute__name")
@@ -204,35 +209,39 @@ class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["attribute", "product"]
-@admin.register(Category)
-class CategoryAdmin(FieldsetsMixin, DraggableMPTTAdmin, BasicModelAdmin):
- model = Category # type: ignore
+@register(Category)
+class CategoryAdmin(FieldsetsMixin, ActivationActionsMixin, DraggableMPTTAdmin):
+ # noinspection PyClassVar
+ model = Category
list_display = ("indented_title", "parent", "is_active", "modified")
+ # noinspection PyUnresolvedReferences
list_filter = ("is_active", "level", "created", "modified")
search_fields = ("uuid", "name")
inlines = [CategoryChildrenInline]
autocomplete_fields = ["parent", "tags"]
readonly_fields = ("slug", "uuid", "modified", "created")
- general_fields = ["is_active", "name", "description", "image", "markup_percent"]
+ general_fields = ["is_active", "name", "description", "image", "markup_percent", "priority"]
relation_fields = ["parent", "tags"]
-@admin.register(Brand)
-class BrandAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Brand # type: ignore
+@register(Brand)
+class BrandAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Brand # type: ignore [misc]
list_display = ("name",)
list_filter = ("categories", "is_active")
search_fields = ("uuid", "name", "categories__name")
- readonly_fields = ("uuid", "modified", "created")
+ readonly_fields = ("uuid", "slug", "modified", "created")
- general_fields = ["is_active", "name", "description"]
+ general_fields = ["is_active", "name", "description", "priority"]
relation_fields = ["small_logo", "big_logo", "categories"]
-@admin.register(Product)
-class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Product # type: ignore
+@register(Product)
+class ProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Product # type: ignore [misc]
list_display = (
"name",
"partnumber",
@@ -246,8 +255,8 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
list_filter = (
"is_active",
"is_digital",
- ("tags", admin.RelatedOnlyFieldListFilter),
- ("stocks__vendor", admin.RelatedOnlyFieldListFilter),
+ "stocks__vendor",
+ "tags__name",
"created",
"modified",
)
@@ -255,7 +264,9 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
"name",
"partnumber",
"brand__name",
+ "brand__slug",
"category__name",
+ "category__slug",
"uuid",
"slug",
)
@@ -263,13 +274,14 @@ class ProductAdmin(FieldsetsMixin, BasicModelAdmin):
autocomplete_fields = ("category", "brand", "tags")
inlines = [AttributeValueInline, ProductImageInline, StockInline]
- general_fields = ["is_active", "name", "partnumber", "is_active", "is_digital"]
+ general_fields = ["is_active", "name", "partnumber", "is_digital"]
relation_fields = ["category", "brand", "tags"]
-@admin.register(ProductTag)
-class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
- model = ProductTag # type: ignore
+@register(ProductTag)
+class ProductTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = ProductTag # type: ignore [misc]
list_display = ("tag_name",)
search_fields = ("tag_name",)
readonly_fields = ("uuid", "modified", "created")
@@ -278,9 +290,10 @@ class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = []
-@admin.register(CategoryTag)
-class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
- model = CategoryTag # type: ignore
+@register(CategoryTag)
+class CategoryTagAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = CategoryTag # type: ignore [misc]
list_display = ("tag_name",)
search_fields = ("tag_name",)
readonly_fields = ("uuid", "modified", "created")
@@ -289,22 +302,24 @@ class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = []
-@admin.register(Vendor)
-class VendorAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Vendor # type: ignore
+@register(Vendor)
+class VendorAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Vendor # type: ignore [misc]
list_display = ("name", "markup_percent", "modified")
list_filter = ("markup_percent", "is_active")
search_fields = ("name",)
readonly_fields = ("uuid", "modified", "created")
form = VendorForm
- general_fields = ["is_active", "name", "markup_percent", "authentication"]
- relation_fields = []
+ general_fields = ["is_active", "name", "markup_percent", "authentication", "b2b_auth_token"]
+ relation_fields = ["users"]
-@admin.register(Feedback)
-class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Feedback # type: ignore
+@register(Feedback)
+class FeedbackAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Feedback # type: ignore [misc]
list_display = ("order_product", "rating", "comment", "modified")
list_filter = ("rating", "is_active")
search_fields = ("order_product__product__name", "comment")
@@ -314,9 +329,10 @@ class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["order_product"]
-@admin.register(Order)
-class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Order # type: ignore
+@register(Order)
+class OrderAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Order # type: ignore [misc]
list_display = (
"human_readable_id",
"user",
@@ -338,13 +354,14 @@ class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
inlines = [OrderProductInline]
form = OrderForm
- general_fields = ["is_active", "user", "status"]
+ general_fields = ["is_active", "user", "status", "notifications", "attributes", "buy_time"]
relation_fields = ["promo_code", "billing_address", "shipping_address"]
-@admin.register(OrderProduct)
-class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
- model = OrderProduct # type: ignore
+@register(OrderProduct)
+class OrderProductAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = OrderProduct # type: ignore [misc]
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
list_filter = ("status",)
search_fields = ("order__user__email", "product__name")
@@ -355,9 +372,10 @@ class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["order", "product"]
-@admin.register(PromoCode)
-class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
- model = PromoCode # type: ignore
+@register(PromoCode)
+class PromoCodeAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = PromoCode # type: ignore [misc]
list_display = (
"code",
"discount_percent",
@@ -383,9 +401,10 @@ class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["user"]
-@admin.register(Promotion)
-class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Promotion # type: ignore
+@register(Promotion)
+class PromotionAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Promotion # type: ignore [misc]
list_display = ("name", "discount_percent", "modified")
search_fields = ("name",)
readonly_fields = ("uuid", "modified", "created")
@@ -395,9 +414,10 @@ class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["products"]
-@admin.register(Stock)
-class StockAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Stock # type: ignore
+@register(Stock)
+class StockAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Stock # type: ignore [misc]
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
list_filter = ("vendor", "quantity")
search_fields = ("product__name", "vendor__name", "sku")
@@ -415,9 +435,10 @@ class StockAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["product", "vendor"]
-@admin.register(Wishlist)
-class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
- model = Wishlist # type: ignore
+@register(Wishlist)
+class WishlistAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = Wishlist # type: ignore [misc]
list_display = ("user", "modified")
search_fields = ("user__email",)
readonly_fields = ("uuid", "modified", "created")
@@ -426,9 +447,10 @@ class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["products"]
-@admin.register(ProductImage)
-class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
- model = ProductImage # type: ignore
+@register(ProductImage)
+class ProductImageAdmin(FieldsetsMixin, ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ # noinspection PyClassVar
+ model = ProductImage # type: ignore [misc]
list_display = ("alt", "product", "priority", "modified")
list_filter = ("priority",)
search_fields = ("alt", "product__name")
@@ -439,9 +461,10 @@ class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
relation_fields = ["product"]
-@admin.register(Address)
+@register(Address)
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
- model = Address # type: ignore
+ # noinspection PyClassVar
+ model = Address # type: ignore [misc]
list_display = ("street", "city", "region", "country", "user")
list_filter = ("country", "region")
search_fields = ("street", "city", "postal_code", "user__email")
@@ -501,8 +524,10 @@ class ConstanceConfig:
_meta = Meta()
-admin.site.unregister([Config]) # type: ignore
-admin.site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore
-admin.site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
-admin.site.site_header = "eVibes"
-admin.site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore
+# noinspection PyTypeChecker
+site.unregister([Config])
+# noinspection PyTypeChecker
+site.register([ConstanceConfig], BaseConstanceAdmin) # type: ignore [list-item]
+site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore [assignment]
+site.site_header = "eVibes"
+site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0] # type: ignore [assignment]
diff --git a/core/api_urls.py b/core/api_urls.py
index 3faadbc6..da873ef7 100644
--- a/core/api_urls.py
+++ b/core/api_urls.py
@@ -30,6 +30,8 @@ from core.viewsets import (
WishlistViewSet,
)
+app_name = "core"
+
core_router = DefaultRouter()
core_router.register(r"products", ProductViewSet, basename="products")
core_router.register(r"orders", OrderViewSet, basename="orders")
@@ -55,10 +57,26 @@ sitemaps = {
urlpatterns = [
path("core/", include(core_router.urls)),
path(
- "sitemap.xml", sitemap_index, {"sitemaps": sitemaps, "sitemap_url_name": "sitemap-detail"}, name="sitemap-index"
+ "sitemap.xml",
+ sitemap_index,
+ {
+ "sitemaps": sitemaps,
+ "sitemap_url_name": "core:sitemap-detail",
+ },
+ name="sitemap-index",
+ ),
+ path(
+ "sitemap-.xml",
+ sitemap_detail,
+ {"sitemaps": sitemaps},
+ name="sitemap-detail",
+ ),
+ path(
+ "sitemap--.xml",
+ sitemap_detail,
+ {"sitemaps": sitemaps},
+ name="sitemap-detail",
),
- path("sitemap-.xml", sitemap_detail, {"sitemaps": sitemaps}, name="sitemap-detail"),
- path("sitemap--.xml", sitemap_detail, {"sitemaps": sitemaps}, name="sitemap-detail"),
path("download//", download_digital_asset_view, name="download_digital_asset"),
path("search/", GlobalSearchView.as_view(), name="global_search"),
path("app/cache/", CacheOperatorView.as_view(), name="cache_operator"),
diff --git a/core/b2b_urls.py b/core/b2b_urls.py
index 7d4c5e60..53a4f04c 100644
--- a/core/b2b_urls.py
+++ b/core/b2b_urls.py
@@ -5,6 +5,8 @@ from core.views import (
GlobalSearchView,
)
+app_name = "core"
+
urlpatterns = [
path("search/", GlobalSearchView.as_view(), name="global_search"),
path("orders/buy_as_business/", BuyAsBusinessView.as_view(), name="request_cursed_url"),
diff --git a/core/docs/drf/viewsets.py b/core/docs/drf/viewsets.py
index 6a2dbfd1..2eeead63 100644
--- a/core/docs/drf/viewsets.py
+++ b/core/docs/drf/viewsets.py
@@ -35,6 +35,7 @@ from core.serializers import (
WishlistDetailSerializer,
WishlistSimpleSerializer,
)
+from core.serializers.seo import SeoSnapshotSerializer
from core.serializers.utility import AddressCreateSerializer, AddressSuggestionSerializer, DoFeedbackSerializer
from payments.serializers import TransactionProcessSerializer
@@ -122,28 +123,50 @@ ATTRIBUTE_VALUE_SCHEMA = {
CATEGORY_SCHEMA = {
"list": extend_schema(
summary=_("list all categories (simple view)"),
+ description=_("list all categories (simple view)"),
responses={status.HTTP_200_OK: CategorySimpleSerializer(many=True), **BASE_ERRORS},
),
"retrieve": extend_schema(
summary=_("retrieve a single category (detailed view)"),
+ description=_("retrieve a single category (detailed view)"),
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
),
"create": extend_schema(
summary=_("create a category"),
+ description=_("create a category"),
responses={status.HTTP_201_CREATED: CategoryDetailSerializer(), **BASE_ERRORS},
),
"destroy": extend_schema(
summary=_("delete a category"),
+ description=_("delete a category"),
responses={status.HTTP_204_NO_CONTENT: {}, **BASE_ERRORS},
),
"update": extend_schema(
summary=_("rewrite an existing category saving non-editables"),
+ description=_("rewrite an existing category saving non-editables"),
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
),
"partial_update": extend_schema(
summary=_("rewrite some fields of an existing category saving non-editables"),
+ description=_("rewrite some fields of an existing category saving non-editables"),
responses={status.HTTP_200_OK: CategoryDetailSerializer(), **BASE_ERRORS},
),
+ "seo": extend_schema(
+ summary=_("SEO Meta Snapshot"),
+ description=_("returns a snapshot of the category's SEO meta data"),
+ parameters=[
+ OpenApiParameter(
+ name="lookup",
+ location="path",
+ description=_("Category UUID or slug"),
+ type=str,
+ ),
+ ],
+ responses={
+ status.HTTP_200_OK: SeoSnapshotSerializer(),
+ **BASE_ERRORS,
+ },
+ ),
}
ORDER_SCHEMA = {
@@ -347,6 +370,7 @@ ATTRIBUTES_DESC = _(
PRODUCT_SCHEMA = {
"list": extend_schema(
summary=_("list all products (simple view)"),
+ description=_("list all products (simple view)"),
parameters=[
OpenApiParameter(
name="uuid",
@@ -439,6 +463,7 @@ PRODUCT_SCHEMA = {
),
"retrieve": extend_schema(
summary=_("retrieve a single product (detailed view)"),
+ description=_("retrieve a single product (detailed view)"),
parameters=[
OpenApiParameter(
name="lookup_value",
@@ -454,6 +479,7 @@ PRODUCT_SCHEMA = {
),
"create": extend_schema(
summary=_("create a product"),
+ description=_("create a product"),
responses={
status.HTTP_201_CREATED: ProductDetailSerializer(),
**BASE_ERRORS,
@@ -461,6 +487,7 @@ PRODUCT_SCHEMA = {
),
"update": extend_schema(
summary=_("rewrite an existing product, preserving non-editable fields"),
+ description=_("rewrite an existing product, preserving non-editable fields"),
parameters=[
OpenApiParameter(
name="lookup",
@@ -476,6 +503,7 @@ PRODUCT_SCHEMA = {
),
"partial_update": extend_schema(
summary=_("update some fields of an existing product, preserving non-editable fields"),
+ description=_("update some fields of an existing product, preserving non-editable fields"),
parameters=[
OpenApiParameter(
name="lookup",
@@ -491,6 +519,7 @@ PRODUCT_SCHEMA = {
),
"destroy": extend_schema(
summary=_("delete a product"),
+ description=_("delete a product"),
parameters=[
OpenApiParameter(
name="lookup",
@@ -506,6 +535,7 @@ PRODUCT_SCHEMA = {
),
"feedbacks": extend_schema(
summary=_("lists all permitted feedbacks for a product"),
+ description=_("lists all permitted feedbacks for a product"),
parameters=[
OpenApiParameter(
name="lookup",
@@ -519,6 +549,22 @@ PRODUCT_SCHEMA = {
**BASE_ERRORS,
},
),
+ "seo": extend_schema(
+ summary=_("SEO Meta Snapshot"),
+ description=_("returns a snapshot of the product's SEO meta data"),
+ parameters=[
+ OpenApiParameter(
+ name="lookup",
+ location="path",
+ description=_("Product UUID or slug"),
+ type=str,
+ ),
+ ],
+ responses={
+ status.HTTP_200_OK: SeoSnapshotSerializer(),
+ **BASE_ERRORS,
+ },
+ ),
}
ADDRESS_SCHEMA = {
diff --git a/core/elasticsearch/__init__.py b/core/elasticsearch/__init__.py
index 94df9650..cf6ebbfd 100644
--- a/core/elasticsearch/__init__.py
+++ b/core/elasticsearch/__init__.py
@@ -15,19 +15,15 @@ SMART_FIELDS = [
"name^6",
"name.ngram^5",
"name.phonetic",
-
"title^4",
"title.ngram^3",
"title.phonetic",
-
"description^2",
"description.ngram",
"description.phonetic",
-
"brand__name^3",
"brand__name.ngram",
"brand__name.auto",
-
"category__name^2",
"category__name.ngram",
"category__name.auto",
@@ -71,7 +67,6 @@ functions = [
"missing": 0,
},
},
-
# category-level boost when searching for categories
{
"filter": Q("term", **{"_index": "categories"}),
@@ -82,7 +77,6 @@ functions = [
"missing": 0,
},
},
-
# brand-level boost when searching for brands
{
"filter": Q("term", **{"_index": "brands"}),
@@ -191,8 +185,8 @@ def process_query(query: str = "", request: Request | None = None) -> dict[str,
results[idx].append(hit_result)
return results
- except NotFoundError:
- raise Http404
+ except NotFoundError as nfe:
+ raise Http404 from nfe
LANGUAGE_ANALYZER_MAP = {
diff --git a/core/elasticsearch/documents.py b/core/elasticsearch/documents.py
index dceadfe9..cb6af311 100644
--- a/core/elasticsearch/documents.py
+++ b/core/elasticsearch/documents.py
@@ -12,13 +12,9 @@ class _BaseDoc(ActiveOnlyMixin, Document):
analyzer="standard",
fields={
"raw": fields.KeywordField(ignore_above=256),
- "ngram": fields.TextField(
- analyzer="name_ngram", search_analyzer="query_lc"
- ),
+ "ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
"phonetic": fields.TextField(analyzer="name_phonetic"),
- "auto": fields.TextField(
- analyzer="autocomplete", search_analyzer="autocomplete_search"
- ),
+ "auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
},
)
description = fields.TextField(
@@ -26,13 +22,9 @@ class _BaseDoc(ActiveOnlyMixin, Document):
analyzer="standard",
fields={
"raw": fields.KeywordField(ignore_above=256),
- "ngram": fields.TextField(
- analyzer="name_ngram", search_analyzer="query_lc"
- ),
+ "ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
"phonetic": fields.TextField(analyzer="name_phonetic"),
- "auto": fields.TextField(
- analyzer="autocomplete", search_analyzer="autocomplete_search"
- ),
+ "auto": fields.TextField(analyzer="autocomplete", search_analyzer="autocomplete_search"),
},
)
slug = fields.KeywordField(attr="slug", index=False)
diff --git a/core/filters.py b/core/filters.py
index d2abb6bf..996a28a6 100644
--- a/core/filters.py
+++ b/core/filters.py
@@ -32,7 +32,7 @@ from django_filters import (
from core.elasticsearch import process_query
from core.models import Address, Brand, Category, Feedback, Order, Product, Wishlist
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
@@ -363,6 +363,7 @@ class CategoryFilter(FilterSet):
order_by = OrderingFilter(
fields=(
+ ("priority", "priority"),
("uuid", "uuid"),
("name", "name"),
("?", "random"),
@@ -430,6 +431,7 @@ class BrandFilter(FilterSet):
order_by = OrderingFilter(
fields=(
+ ("priority", "priority"),
("uuid", "uuid"),
("name", "name"),
("?", "random"),
diff --git a/core/graphene/__init__.py b/core/graphene/__init__.py
index d4f3b7db..1fe565b9 100644
--- a/core/graphene/__init__.py
+++ b/core/graphene/__init__.py
@@ -1,10 +1,10 @@
from graphene import Mutation
-class BaseMutation(Mutation):
- def __init__(self, *args, **kwargs):
+class BaseMutation(Mutation): # type: ignore [misc]
+ def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
@staticmethod
- def mutate(**kwargs):
+ def mutate(**kwargs) -> None:
pass
diff --git a/core/graphene/mutations.py b/core/graphene/mutations.py
index 462b5cf0..1ba0445e 100644
--- a/core/graphene/mutations.py
+++ b/core/graphene/mutations.py
@@ -13,13 +13,14 @@ from core.elasticsearch import process_query
from core.graphene import BaseMutation
from core.graphene.object_types import (
AddressType,
- BulkActionOrderProductInput,
+ BulkProductInput,
OrderType,
ProductType,
SearchResultsType,
WishlistType,
+ FeedbackType,
)
-from core.models import Address, Category, Order, Product, Wishlist
+from core.models import Address, Category, Order, Product, Wishlist, OrderProduct
from core.utils import format_attributes, is_url_safe
from core.utils.caching import web_cache
from core.utils.emailing import contact_us_email
@@ -27,7 +28,7 @@ from core.utils.messages import permission_denied_message
from core.utils.nominatim import fetch_address_suggestions
from payments.graphene.object_types import TransactionType
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
class CacheOperator(BaseMutation):
@@ -96,8 +97,8 @@ class AddOrderProduct(BaseMutation):
order = order.add_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
return AddOrderProduct(order=order)
- except Order.DoesNotExist:
- raise Http404(_(f"order {order_uuid} not found"))
+ except Order.DoesNotExist as dne:
+ raise Http404(_(f"order {order_uuid} not found")) from dne
class RemoveOrderProduct(BaseMutation):
@@ -122,8 +123,8 @@ class RemoveOrderProduct(BaseMutation):
order = order.remove_product(product_uuid=product_uuid, attributes=format_attributes(attributes))
return AddOrderProduct(order=order)
- except Order.DoesNotExist:
- raise Http404(_(f"order {order_uuid} not found"))
+ except Order.DoesNotExist as dne:
+ raise Http404(_(f"order {order_uuid} not found")) from dne
class RemoveAllOrderProducts(BaseMutation):
@@ -174,13 +175,14 @@ class BuyOrder(BaseMutation):
description = _("buy an order")
class Arguments:
- order_uuid = UUID(required=False)
+ order_uuid = String(required=False)
order_hr_id = String(required=False)
force_balance = Boolean(required=False)
force_payment = Boolean(required=False)
- promocode_uuid = UUID(required=False)
- shipping_address = UUID(required=False)
- billing_address = UUID(required=False)
+ promocode_uuid = String(required=False)
+ shipping_address = String(required=False)
+ billing_address = String(required=False)
+ chosen_products = List(BulkProductInput, required=False)
order = Field(OrderType, required=False)
transaction = Field(TransactionType, required=False)
@@ -196,6 +198,7 @@ class BuyOrder(BaseMutation):
promocode_uuid=None,
shipping_address=None,
billing_address=None,
+ chosen_products=None,
):
if not any([order_uuid, order_hr_id]) or all([order_uuid, order_hr_id]):
raise BadRequest(_("please provide either order_uuid or order_hr_id - mutually exclusive"))
@@ -214,6 +217,7 @@ class BuyOrder(BaseMutation):
promocode_uuid=promocode_uuid,
shipping_address=shipping_address,
billing_address=billing_address,
+ chosen_products=chosen_products,
)
match str(type(instance)):
@@ -224,8 +228,8 @@ class BuyOrder(BaseMutation):
case _:
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
- except Order.DoesNotExist:
- raise Http404(_(f"order {order_uuid} not found"))
+ except Order.DoesNotExist as dne:
+ raise Http404(_(f"order {order_uuid} not found")) from dne
class BulkOrderAction(BaseMutation):
@@ -236,7 +240,7 @@ class BulkOrderAction(BaseMutation):
order_uuid = UUID(required=False)
order_hr_id = String(required=False)
action = String(required=True, description=_("remove/add"))
- products = List(BulkActionOrderProductInput, required=True)
+ products = List(BulkProductInput, required=True)
order = Field(OrderType, required=False)
@@ -271,8 +275,48 @@ class BulkOrderAction(BaseMutation):
return BulkOrderAction(order=order)
- except Order.DoesNotExist:
- raise Http404(_(f"order {order_uuid} not found"))
+ except Order.DoesNotExist as dne:
+ raise Http404(_(f"order {order_uuid} not found")) from dne
+
+
+class BulkWishlistAction(BaseMutation):
+ class Meta:
+ description = _("perform an action on a list of products in the wishlist")
+
+ class Arguments:
+ wishlist_uuid = UUID(required=False)
+ action = String(required=True, description="remove/add")
+ products = List(BulkProductInput, required=True)
+
+ wishlist = Field(WishlistType, required=False)
+
+ @staticmethod
+ def mutate(
+ _parent,
+ info,
+ action,
+ products,
+ wishlist_uuid=None,
+ ):
+ if not wishlist_uuid:
+ raise BadRequest(_("please provide wishlist_uuid value"))
+ user = info.context.user
+ try:
+ wishlist = Wishlist.objects.get(user=user, uuid=wishlist_uuid)
+
+ # noinspection PyUnreachableCode
+ match action:
+ case "add":
+ wishlist = wishlist.bulk_add_products(products)
+ case "remove":
+ wishlist = wishlist.bulk_remove_products(products)
+ case _:
+ raise BadRequest(_("action must be either add or remove"))
+
+ return BulkWishlistAction(wishlist=wishlist)
+
+ except Wishlist.DoesNotExist as dne:
+ raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
class BuyUnregisteredOrder(BaseMutation):
@@ -344,8 +388,8 @@ class AddWishlistProduct(BaseMutation):
return AddWishlistProduct(wishlist=wishlist)
- except Wishlist.DoesNotExist:
- raise Http404(_(f"wishlist {wishlist_uuid} not found"))
+ except Wishlist.DoesNotExist as dne:
+ raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
class RemoveWishlistProduct(BaseMutation):
@@ -371,8 +415,8 @@ class RemoveWishlistProduct(BaseMutation):
return RemoveWishlistProduct(wishlist=wishlist)
- except Wishlist.DoesNotExist:
- raise Http404(_(f"wishlist {wishlist_uuid} not found"))
+ except Wishlist.DoesNotExist as dne:
+ raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
class RemoveAllWishlistProducts(BaseMutation):
@@ -398,8 +442,8 @@ class RemoveAllWishlistProducts(BaseMutation):
return RemoveAllWishlistProducts(wishlist=wishlist)
- except Wishlist.DoesNotExist:
- raise Http404(_(f"wishlist {wishlist_uuid} not found"))
+ except Wishlist.DoesNotExist as dne:
+ raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
class BuyWishlist(BaseMutation):
@@ -441,8 +485,8 @@ class BuyWishlist(BaseMutation):
case _:
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
- except Wishlist.DoesNotExist:
- raise Http404(_(f"wishlist {wishlist_uuid} not found"))
+ except Wishlist.DoesNotExist as dne:
+ raise Http404(_(f"wishlist {wishlist_uuid} not found")) from dne
class BuyProduct(BaseMutation):
@@ -483,6 +527,37 @@ class BuyProduct(BaseMutation):
raise TypeError(_(f"wrong type came from order.buy() method: {type(instance)!s}"))
+class FeedbackProductAction(BaseMutation):
+ class Meta:
+ description = _("add or delete a feedback for orderproduct")
+
+ class Arguments:
+ order_product_uuid = UUID(required=True)
+ action = String(required=True, description="add/remove")
+ comment = String(required=False)
+ rating = Int(required=False)
+
+ feedback = Field(FeedbackType, required=False)
+
+ @staticmethod
+ def mutate(_parent, info, order_product_uuid, action, comment=None, rating=None):
+ user = info.context.user
+ try:
+ order_product = OrderProduct.objects.get(uuid=order_product_uuid)
+ if user != order_product.order.user or not user.has_perm("core.change_orderproduct"):
+ raise PermissionDenied(permission_denied_message)
+ match action:
+ case "add":
+ feedback = order_product.do_feedback(comment=comment, rating=rating, action="add")
+ case "remove":
+ feedback = order_product.do_feedback(action="remove")
+ case _:
+ raise BadRequest(_("action must be either `add` or `remove`"))
+ return FeedbackProductAction(feedback=feedback)
+ except OrderProduct.DoesNotExist as dne:
+ raise Http404(_(f"order product {order_product_uuid} not found")) from dne
+
+
class CreateProduct(BaseMutation):
class Arguments:
name = String(required=True)
@@ -575,9 +650,9 @@ class DeleteAddress(BaseMutation):
raise PermissionDenied(permission_denied_message)
- except Address.DoesNotExist:
+ except Address.DoesNotExist as dne:
name = "Address"
- raise Http404(_(f"{name} does not exist: {uuid}"))
+ raise Http404(_(f"{name} does not exist: {uuid}")) from dne
class AutocompleteAddress(BaseMutation):
diff --git a/core/graphene/object_types.py b/core/graphene/object_types.py
index ef27b4b3..41d7566f 100644
--- a/core/graphene/object_types.py
+++ b/core/graphene/object_types.py
@@ -1,5 +1,8 @@
+import logging
+
+from constance import config
from django.core.cache import cache
-from django.db.models import Max, Min
+from django.db.models import Max, Min, QuerySet
from django.db.models.functions import Length
from django.utils.translation import gettext_lazy as _
from graphene import (
@@ -13,6 +16,7 @@ from graphene import (
ObjectType,
String,
relay,
+ Boolean,
)
from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType
@@ -40,8 +44,31 @@ from core.models import (
Vendor,
Wishlist,
)
+from core.utils import graphene_current_lang, graphene_abs
+from core.utils.seo_builders import (
+ org_schema,
+ breadcrumb_schema,
+ brand_schema,
+ website_schema,
+ category_schema,
+ item_list_schema,
+ product_schema,
+)
+from payments.graphene.object_types import TransactionType
+from payments.models import Transaction
-logger = __import__("logging").getLogger(__name__)
+logger = logging.getLogger("django")
+
+
+class SEOMetaType(ObjectType):
+ title = String()
+ description = String()
+ canonical = String()
+ robots = String()
+ open_graph = GenericScalar()
+ twitter = GenericScalar()
+ json_ld = List(GenericScalar)
+ hreflang = List(GenericScalar)
class AttributeType(DjangoObjectType):
@@ -87,6 +114,7 @@ class AttributeGroupType(DjangoObjectType):
class BrandType(DjangoObjectType):
categories = List(lambda: CategoryType, description=_("categories"))
+ seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
class Meta:
model = Brand
@@ -106,6 +134,48 @@ class BrandType(DjangoObjectType):
def resolve_small_logo(self: Brand, info):
return info.context.build_absolute_uri(self.small_logo.url) if self.small_logo else ""
+ def resolve_seo_meta(self: Brand, info):
+ lang = graphene_current_lang()
+ base = f"https://{config.BASE_DOMAIN}"
+ canonical = f"{base}/{lang}/brand/{self.slug}"
+ title = f"{self.name} | {config.PROJECT_NAME}"
+ description = (self.description or "")[:180]
+
+ logo_url = None
+ if getattr(self, "big_logo", None):
+ logo_url = graphene_abs(info.context, self.big_logo.url)
+ elif getattr(self, "small_logo", None):
+ logo_url = graphene_abs(info.context, self.small_logo.url)
+
+ og = {
+ "title": title,
+ "description": description,
+ "type": "website",
+ "url": canonical,
+ "image": logo_url or "",
+ }
+ tw = {"card": "summary_large_image", "title": title, "description": description, "image": logo_url or ""}
+
+ crumbs = [("Home", f"{base}/"), (self.name, canonical)]
+
+ json_ld = [
+ org_schema(),
+ website_schema(),
+ breadcrumb_schema(crumbs),
+ brand_schema(self, canonical, logo_url=logo_url),
+ ]
+
+ return {
+ "title": title,
+ "description": description,
+ "canonical": canonical,
+ "robots": "index,follow",
+ "open_graph": og,
+ "twitter": tw,
+ "json_ld": json_ld,
+ "hreflang": [],
+ }
+
class FilterableAttributeType(ObjectType):
attribute_name = String(required=True)
@@ -134,6 +204,7 @@ class CategoryType(DjangoObjectType):
)
tags = DjangoFilterConnectionField(lambda: CategoryTagType, description=_("tags for this category"))
products = DjangoFilterConnectionField(lambda: ProductType, description=_("products in this category"))
+ seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
class Meta:
model = Category
@@ -216,6 +287,58 @@ class CategoryType(DjangoObjectType):
"max_price": min_max_prices["max_price"],
}
+ def resolve_seo_meta(self: Category, info):
+ lang = graphene_current_lang()
+ base = f"https://{config.BASE_DOMAIN}"
+ canonical = f"{base}/{lang}/catalog/{self.slug}"
+ title = f"{self.name} | {config.PROJECT_NAME}"
+ description = (self.description or "")[:180]
+
+ og_image = graphene_abs(info.context, self.image.url) if getattr(self, "image", None) else ""
+
+ og = {
+ "title": title,
+ "description": description,
+ "type": "website",
+ "url": canonical,
+ "image": og_image,
+ }
+ tw = {"card": "summary_large_image", "title": title, "description": description, "image": og_image}
+
+ crumbs = [("Home", f"{base}/")]
+ for c in self.get_ancestors():
+ crumbs.append((c.name, f"{base}/{lang}/catalog/{c.slug}"))
+ crumbs.append((self.name, canonical))
+
+ json_ld = [org_schema(), website_schema(), breadcrumb_schema(crumbs), category_schema(self, canonical)]
+
+ product_urls = []
+ qs = (
+ Product.objects.filter(
+ is_active=True,
+ category=self,
+ brand__is_active=True,
+ stocks__vendor__is_active=True,
+ )
+ .only("slug")
+ .distinct()[:24]
+ )
+ for p in qs:
+ product_urls.append(f"{base}/{lang}/product/{p.slug}")
+ if product_urls:
+ json_ld.append(item_list_schema(product_urls))
+
+ return {
+ "title": title,
+ "description": description,
+ "canonical": canonical,
+ "robots": "index,follow",
+ "open_graph": og,
+ "twitter": tw,
+ "json_ld": json_ld,
+ "hreflang": [],
+ }
+
class VendorType(DjangoObjectType):
markup_percent = Float(description=_("markup percentage"))
@@ -234,6 +357,7 @@ class AddressType(DjangoObjectType):
class Meta:
model = Address
+ interfaces = (relay.Node,)
fields = (
"uuid",
"street",
@@ -313,6 +437,7 @@ class OrderType(DjangoObjectType):
is_whole_digital = Float(description=_("are all products in the order digital"))
attributes = GenericScalar(description=_("attributes"))
notifications = GenericScalar(description=_("notifications"))
+ payments_transactions = Field(TransactionType, description=_("transactions for this order"))
class Meta:
model = Order
@@ -329,21 +454,27 @@ class OrderType(DjangoObjectType):
"total_quantity",
"is_whole_digital",
"human_readable_id",
+ "payments_transactions",
)
description = _("orders")
- def resolve_total_price(self, _info):
+ def resolve_total_price(self: Order, _info):
return self.total_price
- def resolve_total_quantity(self, _info):
+ def resolve_total_quantity(self: Order, _info):
return self.total_quantity
- def resolve_notifications(self, _info):
+ def resolve_notifications(self: Order, _info):
return camelize(self.notifications)
- def resolve_attributes(self, _info):
+ def resolve_attributes(self: Order, _info):
return camelize(self.attributes)
+ def resolve_payments_transactions(self: Order, _info) -> QuerySet[Transaction] | None:
+ if self.payments_transactions:
+ return self.payments_transactions.all()
+ return None
+
class ProductImageType(DjangoObjectType):
image = String(description=_("image url"))
@@ -368,6 +499,8 @@ class ProductType(DjangoObjectType):
price = Float(description=_("price"))
quantity = Float(description=_("quantity"))
feedbacks_count = Int(description=_("number of feedbacks"))
+ personal_orders_only = Boolean(description=_("only available for personal orders"))
+ seo_meta = Field(SEOMetaType, description=_("SEO meta snapshot"))
class Meta:
model = Product
@@ -381,13 +514,17 @@ class ProductType(DjangoObjectType):
"slug",
"description",
"feedbacks",
+ "feedbacks_count",
+ "personal_orders_only",
+ "quantity",
+ "attribute_groups",
"images",
"price",
)
filter_fields = ["uuid", "name"]
description = _("products")
- def resolve_price(self, _info) -> float:
+ def resolve_price(self: Product, _info) -> float:
return self.price or 0.0
def resolve_feedbacks(self: Product, _info):
@@ -395,7 +532,7 @@ class ProductType(DjangoObjectType):
return Feedback.objects.filter(order_product__product=self)
return Feedback.objects.filter(order_product__product=self, is_active=True)
- def resolve_feedbacks_count(self, _info) -> int:
+ def resolve_feedbacks_count(self: Product, _info) -> int:
return self.feedbacks_count or 0
def resolve_attribute_groups(self: Product, info):
@@ -403,9 +540,58 @@ class ProductType(DjangoObjectType):
return AttributeGroup.objects.filter(attributes__values__product=self).distinct()
- def resolve_quantity(self, _info) -> int:
+ def resolve_quantity(self: Product, _info) -> int:
return self.quantity or 0
+ def resolve_personal_orders_only(self: Product, _info) -> bool:
+ return False or self.personal_orders_only
+
+ def resolve_seo_meta(self: Product, info):
+ lang = graphene_current_lang()
+ base = f"https://{config.BASE_DOMAIN}"
+ canonical = f"{base}/{lang}/product/{self.slug}"
+ title = f"{self.name} | {config.PROJECT_NAME}"
+ description = (self.description or "")[:180]
+
+ first_img = self.images.order_by("priority").first()
+ og_image = graphene_abs(info.context, first_img.image.url) if first_img else ""
+
+ og = {
+ "title": title,
+ "description": description,
+ "type": "product",
+ "url": canonical,
+ "image": og_image,
+ }
+ tw = {"card": "summary_large_image", "title": title, "description": description, "image": og_image}
+
+ crumbs = [("Home", f"{base}/")]
+ if self.category:
+ for c in self.category.get_ancestors(include_self=True):
+ crumbs.append((c.name, f"{base}/{lang}/catalog/{c.slug}"))
+ crumbs.append((self.name, canonical))
+
+ images = list(self.images.all()[:6])
+ rating = {"value": self.rating, "count": self.feedbacks_count}
+
+ json_ld = [
+ org_schema(),
+ website_schema(),
+ breadcrumb_schema(crumbs),
+ product_schema(self, images, rating=rating),
+ ]
+
+ return {
+ "title": title,
+ "description": description,
+ "canonical": canonical,
+ "robots": "index,follow",
+ "open_graph": og,
+ "twitter": tw,
+ "json_ld": json_ld,
+ "hreflang": [],
+ }
+
class AttributeValueType(DjangoObjectType):
value = String(description=_("attribute value"))
@@ -436,7 +622,7 @@ class PromoCodeType(DjangoObjectType):
description = _("promocodes")
def resolve_discount(self: PromoCode, _info) -> float:
- return float(self.discount_percent) if self.discount_percent else float(self.discount_amount)
+ return float(self.discount_percent) if self.discount_percent else float(self.discount_amount) # type: ignore [arg-type]
def resolve_discount_type(self: PromoCode, _info) -> str:
return "percent" if self.discount_percent else "amount"
@@ -557,6 +743,6 @@ class SearchResultsType(ObjectType):
posts = List(description=_("posts search results"), of_type=SearchPostsResultsType)
-class BulkActionOrderProductInput(InputObjectType):
+class BulkProductInput(InputObjectType):
uuid = UUID(required=True)
attributes = GenericScalar(required=False)
diff --git a/core/graphene/schema.py b/core/graphene/schema.py
index 29ff0fd6..f7f6eab8 100644
--- a/core/graphene/schema.py
+++ b/core/graphene/schema.py
@@ -1,6 +1,7 @@
import logging
from django.core.cache import cache
+from django.utils import timezone
from django.core.exceptions import PermissionDenied
from graphene import Field, List, ObjectType, Schema
from graphene_django.filter import DjangoFilterConnectionField
@@ -14,12 +15,14 @@ from core.filters import (
OrderFilter,
ProductFilter,
WishlistFilter,
+ AddressFilter,
)
from core.graphene.mutations import (
AddOrderProduct,
AddWishlistProduct,
AutocompleteAddress,
BulkOrderAction,
+ BulkWishlistAction,
BuyOrder,
BuyProduct,
BuyWishlist,
@@ -29,6 +32,7 @@ from core.graphene.mutations import (
CreateProduct,
DeleteAddress,
DeleteProduct,
+ FeedbackProductAction,
RemoveAllOrderProducts,
RemoveAllWishlistProducts,
RemoveOrderProduct,
@@ -56,6 +60,7 @@ from core.graphene.object_types import (
StockType,
VendorType,
WishlistType,
+ AddressType,
)
from core.models import (
AttributeGroup,
@@ -73,6 +78,7 @@ from core.models import (
Stock,
Vendor,
Wishlist,
+ Address,
)
from core.utils import get_project_parameters
from core.utils.languages import get_flag_by_language
@@ -95,7 +101,7 @@ from vibes_auth.graphene.mutations import (
from vibes_auth.graphene.object_types import UserType
from vibes_auth.models import User
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
class Query(ObjectType):
@@ -104,6 +110,7 @@ class Query(ObjectType):
products = DjangoFilterConnectionField(ProductType, filterset_class=ProductFilter)
orders = DjangoFilterConnectionField(OrderType, filterset_class=OrderFilter)
users = DjangoFilterConnectionField(UserType, filterset_class=UserFilter)
+ addresses = DjangoFilterConnectionField(AddressType, filterset_class=AddressFilter)
attribute_groups = DjangoFilterConnectionField(AttributeGroupType)
categories = DjangoFilterConnectionField(CategoryType, filterset_class=CategoryFilter)
vendors = DjangoFilterConnectionField(VendorType)
@@ -145,7 +152,10 @@ class Query(ObjectType):
Product.objects.all().select_related("brand", "category").prefetch_related("images", "stocks")
if info.context.user.has_perm("core.view_product")
else Product.objects.filter(
- is_active=True, brand__is_active=True, category__is_active=True, stocks__isnull=False
+ is_active=True,
+ brand__is_active=True,
+ category__is_active=True,
+ stocks__vendor__is_active=True,
)
.select_related("brand", "category")
.prefetch_related("images", "stocks")
@@ -284,7 +294,12 @@ class Query(ObjectType):
promocodes = PromoCode.objects
if info.context.user.has_perm("core.view_promocode"):
return promocodes.filter(user__uuid=kwargs.get("user_uuid")) or promocodes.all()
- return promocodes.filter(is_active=True, user=info.context.user)
+ return promocodes.filter(
+ is_active=True,
+ user=info.context.user,
+ used_on__isnull=True,
+ start_time__lte=timezone.now(),
+ )
@staticmethod
def resolve_product_tags(_parent, info, **_kwargs):
@@ -298,6 +313,12 @@ class Query(ObjectType):
return CategoryTag.objects.all()
return CategoryTag.objects.filter(is_active=True)
+ @staticmethod
+ def resolve_addresses(_parent, info, **_kwargs):
+ if info.context.user.has_perm("core.view_address"):
+ return Address.objects.all()
+ return Address.objects.filter(is_active=True, user=info.context.user)
+
class Mutation(ObjectType):
search = Search.Field()
@@ -314,6 +335,8 @@ class Mutation(ObjectType):
remove_order_products_of_a_kind = RemoveOrderProductsOfAKind.Field()
buy_order = BuyOrder.Field()
bulk_order_action = BulkOrderAction.Field()
+ bulk_wishlist_action = BulkWishlistAction.Field()
+ feedback_product_action = FeedbackProductAction.Field()
deposit = Deposit.Field()
obtain_jwt_token = ObtainJSONWebToken.Field()
refresh_jwt_token = RefreshJSONWebToken.Field()
diff --git a/core/locale/ar_AR/LC_MESSAGES/django.mo b/core/locale/ar_AR/LC_MESSAGES/django.mo
index 7b6f17c5..c51e2f9e 100644
Binary files a/core/locale/ar_AR/LC_MESSAGES/django.mo and b/core/locale/ar_AR/LC_MESSAGES/django.mo differ
diff --git a/core/locale/ar_AR/LC_MESSAGES/django.po b/core/locale/ar_AR/LC_MESSAGES/django.po
index 3438c4df..3203c1fe 100644
--- a/core/locale/ar_AR/LC_MESSAGES/django.po
+++ b/core/locale/ar_AR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,119 +13,116 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "المعرف الفريد"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr "يستخدم المعرف الفريد لتحديد أي كائن قاعدة بيانات بالتأكيد"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "نشط"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"إذا تم تعيينه على خطأ، لا يمكن للمستخدمين رؤية هذا الكائن دون الحاجة إلى إذن"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "تم إنشاؤها"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "عندما ظهر الكائن لأول مرة في قاعدة البيانات"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "تم التعديل"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "متى تم تحرير الكائن آخر مرة"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "الترجمات"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "جنرال لواء"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "العلاقات"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "البيانات الوصفية"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "الطوابع الزمنية"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "تنشيط المحدد %(verbose_name_plural)s"
+msgstr "تنشيط المحدد _PH_0__%(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s تم تفعيله بنجاح!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "تم تفعيل العناصر المختارة!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "إلغاء تنشيط %(verbose_name_plural)s المحددة"
+msgstr "إلغاء التنشيط المحدد _PH_0_%(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s تم إلغاء تنشيطه بنجاح."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "تم إلغاء تنشيط العناصر المحددة!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "قيمة السمة"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "قيم السمات"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "الصورة"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "الصور"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "المخزون"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "الأسهم"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "طلب المنتج"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "اطلب المنتجات"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "الأطفال"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "التكوين"
@@ -177,7 +174,7 @@ msgstr "مومنتال"
msgid "successful"
msgstr "ناجح"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "ذاكرة التخزين المؤقت للإدخال/الإخراج"
@@ -187,7 +184,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"تطبيق مفتاح فقط لقراءة البيانات المسموح بها من ذاكرة التخزين المؤقت.\n"
-"تطبيق مفتاح وبيانات ومهلة مع المصادقة لكتابة البيانات إلى ذاكرة التخزين المؤقت."
+"تطبيق مفتاح وبيانات ومهلة مع المصادقة لكتابة البيانات إلى ذاكرة التخزين "
+"المؤقت."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -201,7 +199,7 @@ msgstr "الحصول على معلمات التطبيق القابلة للكش
msgid "send a message to the support team"
msgstr "إرسال رسالة إلى فريق الدعم"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "طلب عنوان URL مرتبط بـ CORSed. مسموح بـ https فقط."
@@ -242,8 +240,7 @@ msgid "rewrite an existing attribute group saving non-editables"
msgstr "إعادة كتابة مجموعة سمات موجودة تحفظ غير القابلة للتعديل"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr "إعادة كتابة بعض حقول مجموعة سمات موجودة تحفظ غير القابلة للتعديل"
#: core/docs/drf/viewsets.py:70
@@ -291,8 +288,7 @@ msgid "rewrite an existing attribute value saving non-editables"
msgstr "إعادة كتابة قيمة سمة موجودة تحفظ غير القابلة للتعديل"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr "إعادة كتابة بعض حقول قيمة سمة موجودة حفظ غير قابل للتعديل"
#: core/docs/drf/viewsets.py:124
@@ -329,8 +325,8 @@ msgstr "بالنسبة للمستخدمين من غير الموظفين، يت
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"البحث في سلسلة فرعية غير حساسة لحالة الأحرف عبر human_readable_id و "
"order_products.product.name و order_products.product.partnumber"
@@ -366,9 +362,9 @@ msgstr "تصفية حسب حالة الطلب (مطابقة سلسلة فرعي
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"الترتيب حسب واحد من: uuid، معرف_بشري_مقروء، بريد_إلكتروني_مستخدم، مستخدم، "
"حالة، إنشاء، تعديل، وقت_الشراء، عشوائي. البادئة بحرف \"-\" للترتيب التنازلي "
@@ -411,7 +407,7 @@ msgstr ""
"ينهي أمر الشراء. إذا تم استخدام \"فرض_الرصيد\"، يتم إكمال عملية الشراء "
"باستخدام رصيد المستخدم؛ إذا تم استخدام \"فرض_الدفع\"، يتم بدء المعاملة."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "شراء طلب شراء بدون إنشاء حساب"
@@ -438,8 +434,7 @@ msgid ""
"adds a list of products to an order using the provided `product_uuid` and "
"`attributes`."
msgstr ""
-"يضيف قائمة من المنتجات إلى طلب باستخدام \"معرّف_المنتج\" و\"السمات\" "
-"المتوفرة."
+"يضيف قائمة من المنتجات إلى طلب باستخدام \"معرّف_المنتج\" و\"السمات\" المتوفرة."
#: core/docs/drf/viewsets.py:266
msgid "remove product from order"
@@ -449,7 +444,8 @@ msgstr "إزالة منتج من الطلب"
msgid ""
"removes a product from an order using the provided `product_uuid` and "
"`attributes`."
-msgstr "يزيل منتجًا من أحد الطلبات باستخدام \"معرّف_المنتج\" و\"السمات\" المتوفرة."
+msgstr ""
+"يزيل منتجًا من أحد الطلبات باستخدام \"معرّف_المنتج\" و\"السمات\" المتوفرة."
#: core/docs/drf/viewsets.py:272
msgid "remove product from order, quantities will not count"
@@ -535,20 +531,32 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"تصفية حسب زوج واحد أو أكثر من أسماء/قيم السمات. \n"
"- **صيغة**: `attr_name=الطريقة-القيمة[ ؛ attr2=الطريقة2-القيمة2]...`\n"
-"- **الأساليب** (افتراضيًا إلى \"يحتوي على\" إذا تم حذفها): \"بالضبط\"، \"بالضبط\"، \"بالضبط\"، \"يحتوي\"، \"يحتوي\"، \"لاغية\"، \"يبدأ ب\"، \"يبدأ ب\"، \"يبدأ ب\"، \"ينتهي ب\"، \"ينتهي ب\"، \"regex\"، \"iregex\"، \"lt\"، \"lte\"، \"gt\"، \"gte\"، \"in\n"
-"- **كتابة القيمة**: تتم تجربة JSON أولًا (حتى تتمكن من تمرير القوائم/المجادلات)، \"صحيح\"/\"خطأ\" للمنطقيين والأعداد الصحيحة والعوامات؛ وإلا يتم التعامل معها كسلسلة. \n"
-"- **القاعدة 64**: البادئة ب \"b64-\" لتشفير القيمة الخام بأمان لقاعدة 64- لتشفير القيمة الخام. \n"
+"- **الأساليب** (افتراضيًا إلى \"يحتوي على\" إذا تم حذفها): \"بالضبط\"، "
+"\"بالضبط\"، \"بالضبط\"، \"يحتوي\"، \"يحتوي\"، \"لاغية\"، \"يبدأ ب\"، \"يبدأ "
+"ب\"، \"يبدأ ب\"، \"ينتهي ب\"، \"ينتهي ب\"، \"regex\"، \"iregex\"، \"lt\"، "
+"\"lte\"، \"gt\"، \"gte\"، \"in\n"
+"- **كتابة القيمة**: تتم تجربة JSON أولًا (حتى تتمكن من تمرير القوائم/"
+"المجادلات)، \"صحيح\"/\"خطأ\" للمنطقيين والأعداد الصحيحة والعوامات؛ وإلا يتم "
+"التعامل معها كسلسلة. \n"
+"- **القاعدة 64**: البادئة ب \"b64-\" لتشفير القيمة الخام بأمان لقاعدة 64- "
+"لتشفير القيمة الخام. \n"
"أمثلة: \n"
-"'color=exact-red'، 'size=gt-10'، 'features=in-[\"wifi\"،\"bluetooth\"]، 'fatures=in-[\"wifi\",\"bluetooth\"],\n"
+"'color=exact-red'، 'size=gt-10'، 'features=in-[\"wifi\"،\"bluetooth\"]، "
+"'fatures=in-[\"wifi\",\"bluetooth\"],\n"
"\"b64-description=icontains-aGVhdC1jb2xk"
#: core/docs/drf/viewsets.py:349
@@ -601,7 +609,8 @@ msgstr "(بالضبط) الرقمية مقابل المادية"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
"قائمة مفصولة بفواصل من الحقول للفرز حسب. البادئة بـ \"-\" للفرز التنازلي. \n"
@@ -731,7 +740,7 @@ msgstr "حذف علاقة الطلب-المنتج"
msgid "add or remove feedback on an order–product relation"
msgstr "إضافة أو إزالة الملاحظات على العلاقة بين الطلب والمنتج"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "لم يتم توفير مصطلح بحث."
@@ -779,8 +788,8 @@ msgstr "السمات"
msgid "Quantity"
msgstr "الكمية"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "سبيكة"
@@ -841,214 +850,237 @@ msgstr "المستوى"
msgid "Product UUID"
msgstr "UUID المنتج"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr ""
"مفتاح للبحث عنه في ذاكرة التخزين المؤقت أو تعيينه في ذاكرة التخزين المؤقت"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "البيانات المراد تخزينها في ذاكرة التخزين المؤقت"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "المهلة بالثواني لتعيين البيانات في ذاكرة التخزين المؤقت"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "البيانات المخزنة مؤقتاً"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "بيانات JSON مجمّلة من عنوان URL المطلوب"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "يُسمح فقط بعناوين URL التي تبدأ ب http(s)://"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "إضافة منتج إلى الطلب"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "الطلب {order_uuid} غير موجود"
+msgstr "الطلب {order_uuid} غير موجود!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "إزالة منتج من الطلب"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "إزالة جميع المنتجات من الطلب"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "شراء طلبية"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "يرجى تقديم إما Order_uuid أو order_uid_hr_hr_id - متنافيان!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "جاء نوع خاطئ من طريقة order.buy(): {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "تنفيذ إجراء على قائمة من المنتجات بالترتيب"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "إزالة/إضافة"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "يجب أن يكون الإجراء إما \"إضافة\" أو \"إزالة\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "تنفيذ إجراء على قائمة المنتجات في قائمة الأمنيات"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "يُرجى تقديم قيمة \"wishlist_uid\"."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "قائمة الرغبات {wishlist_uuid} غير موجودة!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "إضافة منتج إلى الطلب"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "قائمة الأمنيات {wishlist_uuid} غير موجودة"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "إزالة منتج من الطلب"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "إزالة منتج من الطلب"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "إزالة منتج من الطلب"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "شراء طلبية"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr "الرجاء إرسال السمات كسلسلة منسقة مثل attr1=قيمة1، attr2=قيمة2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "إضافة أو حذف تعليق على طلبالمنتج"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "يجب أن يكون الإجراء إما \"إضافة\" أو \"إزالة\"!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "طلب المنتج {order_product_uuid} غير موجود!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "سلسلة العنوان الأصلي المقدمة من المستخدم"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} غير موجود: {uuid}"
+msgstr "{name} غير موجود: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "يجب أن يكون الحد بين 1 و10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - يعمل مثل السحر"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "السمات"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "السمات المجمعة"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "مجموعات السمات"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "الفئات"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "العلامات التجارية"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "الفئات"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "النسبة المئوية للترميز"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr "ما هي السمات والقيم التي يمكن استخدامها لتصفية هذه الفئة."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"الحد الأدنى والحد الأقصى لأسعار المنتجات في هذه الفئة، إذا كانت متوفرة."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "العلامات الخاصة بهذه الفئة"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "المنتجات في هذه الفئة"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "البائعون"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "خط العرض (الإحداثي Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "خط الطول (الإحداثي X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "كيفية"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "قيمة التصنيف من 1 إلى 10، شاملة، أو 0 إذا لم يتم تعيينها."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "يمثل ملاحظات من المستخدم."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "الإشعارات"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "تحميل الرابط الخاص بمنتج الطلب هذا إن أمكن"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "قائمة بطلب المنتجات بهذا الترتيب"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "عنوان إرسال الفواتير"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1056,986 +1088,993 @@ msgstr ""
"عنوان الشحن لهذا الطلب، اترك العنوان فارغًا إذا كان هو نفسه عنوان إرسال "
"الفواتير أو إذا لم يكن منطبقًا"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "السعر الإجمالي لهذا الطلب"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "إجمالي كمية المنتجات بالترتيب"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "هل جميع المنتجات في الطلب رقمي"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "المعاملات الخاصة بهذا الطلب"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "الطلبات"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "رابط الصورة"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "صور المنتج"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "الفئة"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "الملاحظات"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "العلامة التجارية"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "مجموعات السمات"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "السعر"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "الكمية"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "عدد الملاحظات"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "المنتجات"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "الرموز الترويجية"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "المنتجات المعروضة للبيع"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "العروض الترويجية"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "البائع"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "المنتج"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "المنتجات المفضلة"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "قوائم التمنيات"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "المنتجات الموسومة"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "علامات المنتج"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "الفئات الموسومة"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "علامات الفئات"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "اسم المشروع"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "البريد الإلكتروني للشركة"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "اسم الشركة"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "عنوان الشركة"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "رقم هاتف الشركة"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
-"\"البريد الإلكتروني من\"، في بعض الأحيان يجب استخدامه بدلاً من قيمة المستخدم"
-" المضيف"
+"\"البريد الإلكتروني من\"، في بعض الأحيان يجب استخدامه بدلاً من قيمة المستخدم "
+"المضيف"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "مستخدم البريد الإلكتروني المضيف"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "الحد الأقصى لمبلغ السداد"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "الحد الأدنى لمبلغ السداد"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "بيانات التحليلات"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "بيانات الإعلانات"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "التكوين"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "رمز اللغة"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "اسم اللغة"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "علم اللغة، إذا كان موجوداً :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "الحصول على قائمة باللغات المدعومة"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "نتائج البحث عن المنتجات"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "نتائج البحث عن المنتجات"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "والد هذه المجموعة"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "مجموعة السمات الرئيسية"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "اسم مجموعة السمات"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "مجموعة السمات"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"تخزين بيانات الاعتماد ونقاط النهاية المطلوبة لاتصالات واجهة برمجة التطبيقات "
"الخاصة بالمورّد"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "معلومات المصادقة"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "تحديد الترميز للمنتجات المسترجعة من هذا البائع"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "نسبة هامش الربح للبائع"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "اسم هذا البائع"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "اسم البائع"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "معرّف العلامة الداخلي لعلامة المنتج"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "اسم العلامة"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "اسم سهل الاستخدام لعلامة المنتج"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "اسم عرض العلامة"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "علامة المنتج"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "علامة الفئة"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "علامات الفئة"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "تحميل صورة تمثل هذه الفئة"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "صورة الفئة"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "تحديد نسبة ترميز للمنتجات في هذه الفئة"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "أصل هذه الفئة لتكوين بنية هرمية"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "الفئة الرئيسية"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "اسم الفئة"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "تقديم اسم لهذه الفئة"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "إضافة وصف تفصيلي لهذه الفئة"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "وصف الفئة"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "العلامات التي تساعد في وصف هذه الفئة أو تجميعها"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "الأولوية"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "اسم هذه العلامة التجارية"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "اسم العلامة التجارية"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "تحميل شعار يمثل هذه العلامة التجارية"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "صورة العلامة التجارية الصغيرة"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "رفع شعار كبير يمثل هذه العلامة التجارية"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "صورة كبيرة للعلامة التجارية"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "إضافة وصف تفصيلي للعلامة التجارية"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "وصف العلامة التجارية"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "الفئات الاختيارية التي ترتبط بها هذه العلامة التجارية"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "الفئات"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "الفئة التي ينتمي إليها هذا المنتج"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "ربط هذا المنتج اختياريًا بعلامة تجارية"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "العلامات التي تساعد في وصف أو تجميع هذا المنتج"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "يشير إلى ما إذا كان هذا المنتج يتم تسليمه رقميًا أم لا"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "هل المنتج رقمي"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "توفير اسم تعريفي واضح للمنتج"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "اسم المنتج"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "إضافة وصف تفصيلي للمنتج"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "وصف المنتج"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "رقم الجزء لهذا المنتج"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "رقم الجزء"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "فئة هذه السمة"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "مجموعة هذه السمة"
-
-#: core/models.py:465
-msgid "string"
-msgstr "الخيط"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "عدد صحيح"
-
-#: core/models.py:467
-msgid "float"
-msgstr "تعويم"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "منطقية"
-
-#: core/models.py:469
-msgid "array"
-msgstr "المصفوفة"
-
-#: core/models.py:470
-msgid "object"
-msgstr "الكائن"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "نوع قيمة السمة"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "نوع القيمة"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "اسم هذه السمة"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "اسم السمة"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "السمة"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "سمة هذه القيمة"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "المنتج المحدد المرتبط بقيمة هذه السمة"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "المنتج المرتبط"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "القيمة المحددة لهذه السمة"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "توفير نص بديل للصورة لإمكانية الوصول"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "النص البديل للصورة"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "تحميل ملف الصورة لهذا المنتج"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "صورة المنتج"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "يحدد الترتيب الذي يتم عرض الصور به"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "أولوية العرض"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "المنتج الذي تمثله هذه الصورة"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "صور المنتج"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "النسبة المئوية للخصم على المنتجات المختارة"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "نسبة الخصم"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "تقديم اسم فريد لهذا العرض الترويجي"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "اسم الترقية"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "وصف الترقية"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "حدد المنتجات المشمولة في هذا العرض الترويجي"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "المنتجات المشمولة"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "الترقية"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "البائع الذي يورد هذا المنتج المخزون"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "البائع المرتبط"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "السعر النهائي للعميل بعد هوامش الربح"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "سعر البيع"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "المنتج المرتبط بإدخال المخزون هذا"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "المنتج المرتبط"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "السعر المدفوع للبائع مقابل هذا المنتج"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "سعر الشراء من البائع"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "الكمية المتوفرة من المنتج في المخزون"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "الكمية في المخزون"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "SKU المعين من قبل البائع لتحديد المنتج"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "وحدة تخزين البائع"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "الملف الرقمي المرتبط بهذا المخزون إن أمكن"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "ملف رقمي"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "إدخالات المخزون"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "الفئة التي ينتمي إليها هذا المنتج"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "ربط هذا المنتج اختياريًا بعلامة تجارية"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "العلامات التي تساعد في وصف أو تجميع هذا المنتج"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "يشير إلى ما إذا كان هذا المنتج يتم تسليمه رقميًا أم لا"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "هل المنتج رقمي"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "توفير اسم تعريفي واضح للمنتج"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "اسم المنتج"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "إضافة وصف تفصيلي للمنتج"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "وصف المنتج"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "رقم الجزء لهذا المنتج"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "رقم الجزء"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "فئة هذه السمة"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "مجموعة هذه السمة"
+
+#: core/models.py:767
+msgid "string"
+msgstr "الخيط"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "عدد صحيح"
+
+#: core/models.py:769
+msgid "float"
+msgstr "تعويم"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "منطقية"
+
+#: core/models.py:771
+msgid "array"
+msgstr "المصفوفة"
+
+#: core/models.py:772
+msgid "object"
+msgstr "الكائن"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "نوع قيمة السمة"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "نوع القيمة"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "اسم هذه السمة"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "اسم السمة"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "السمة"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "سمة هذه القيمة"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "المنتج المحدد المرتبط بقيمة هذه السمة"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "القيمة المحددة لهذه السمة"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "توفير نص بديل للصورة لإمكانية الوصول"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "النص البديل للصورة"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "تحميل ملف الصورة لهذا المنتج"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "صورة المنتج"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "يحدد الترتيب الذي يتم عرض الصور به"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "أولوية العرض"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "المنتج الذي تمثله هذه الصورة"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "صور المنتج"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "النسبة المئوية للخصم على المنتجات المختارة"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "نسبة الخصم"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "تقديم اسم فريد لهذا العرض الترويجي"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "اسم الترقية"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "وصف الترقية"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "حدد المنتجات المشمولة في هذا العرض الترويجي"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "المنتجات المشمولة"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "الترقية"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "المنتجات التي حددها المستخدم على أنها مطلوبة"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "المستخدم الذي يمتلك قائمة الرغبات هذه"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "مالك قائمة الرغبات"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "قائمة الرغبات"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} غير موجود: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "فيلم وثائقي"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "الأفلام الوثائقية"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "لم يتم حلها"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "سطر العنوان للعميل"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "سطر العنوان"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "الشارع"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "المنطقة"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "المدينة"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "المنطقة"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "الرمز البريدي"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "البلد"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "نقطة تحديد الموقع الجغرافي(خط الطول، خط العرض)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "استجابة JSON كاملة من أداة التشفير الجغرافي لهذا العنوان"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "استجابة JSON مخزّنة من خدمة الترميز الجغرافي"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "العنوان"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "العناوين"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "الرمز الفريد الذي يستخدمه المستخدم لاسترداد قيمة الخصم"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "معرّف الرمز الترويجي"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "مبلغ الخصم الثابت المطبق في حالة عدم استخدام النسبة المئوية"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "مبلغ الخصم الثابت"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "النسبة المئوية للخصم المطبق في حالة عدم استخدام مبلغ ثابت"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "النسبة المئوية للخصم"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "الطابع الزمني عند انتهاء صلاحية الرمز الترويجي"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "وقت انتهاء الصلاحية"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "الطابع الزمني الذي يكون هذا الرمز الترويجي صالحاً منه"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "وقت بدء الصلاحية"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
-msgstr ""
-"الطابع الزمني عند استخدام الرمز الترويجي، فارغ إذا لم يتم استخدامه بعد"
+msgstr "الطابع الزمني عند استخدام الرمز الترويجي، فارغ إذا لم يتم استخدامه بعد"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "الطابع الزمني للاستخدام"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "المستخدم المعين لهذا الرمز الترويجي إن أمكن"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "المستخدم المعين"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "الرمز الترويجي"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "الرموز الترويجية"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
msgstr ""
-"يجب تحديد نوع واحد فقط من الخصم (المبلغ أو النسبة المئوية)، وليس كلا النوعين"
-" أو لا هذا ولا ذاك."
+"يجب تحديد نوع واحد فقط من الخصم (المبلغ أو النسبة المئوية)، وليس كلا النوعين "
+"أو لا هذا ولا ذاك."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "تم استخدام الرمز الترويجي بالفعل"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
msgstr "نوع الخصم غير صالح للرمز الترويجي {self.uuid}"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "عنوان إرسال الفواتير المستخدم لهذا الطلب"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "الرمز الترويجي الاختياري المطبق على هذا الطلب"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "الرمز الترويجي المطبق"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "عنوان الشحن المستخدم لهذا الطلب"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "عنوان الشحن"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "الحالة الحالية للطلب في دورة حياته"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "حالة الطلب"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"بنية JSON للإشعارات التي سيتم عرضها للمستخدمين، في واجهة مستخدم المشرف، يتم "
"استخدام عرض الجدول"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "تمثيل JSON لسمات الطلب لهذا الطلب"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "المستخدم الذي قدم الطلب"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "المستخدم"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "الطابع الزمني عند الانتهاء من الطلب"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "وقت الشراء"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "معرّف يمكن قراءته بواسطة البشر للطلب"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "معرّف يمكن قراءته من قبل البشر"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "الطلب"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "يجب أن يكون لدى المستخدم طلب واحد فقط معلق في كل مرة!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "لا يمكنك إضافة منتجات إلى طلب غير معلق إلى طلب غير معلق"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "لا يمكنك إضافة منتجات غير نشطة للطلب"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "لا يمكنك إضافة منتجات أكثر من المتوفرة في المخزون"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "لا يمكنك إزالة المنتجات من طلب غير معلق من طلب غير معلق"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} غير موجود مع الاستعلام <{query}>"
+msgstr "{name} غير موجود مع الاستعلام <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "الرمز الترويجي غير موجود"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "يمكنك فقط شراء المنتجات المادية مع تحديد عنوان الشحن فقط!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "العنوان غير موجود"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr "لا يمكنك الشراء في هذه اللحظة، يرجى المحاولة مرة أخرى بعد بضع دقائق."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "قيمة القوة غير صالحة"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "لا يمكنك شراء طلبية فارغة!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "لا يمكنك شراء طلب بدون مستخدم!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "المستخدم بدون رصيد لا يمكنه الشراء بالرصيد!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "عدم كفاية الأموال لإكمال الطلب"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
msgstr ""
-"لا يمكنك الشراء بدون تسجيل، يرجى تقديم المعلومات التالية: اسم العميل، البريد"
-" الإلكتروني للعميل، رقم هاتف العميل"
+"لا يمكنك الشراء بدون تسجيل، يرجى تقديم المعلومات التالية: اسم العميل، البريد "
+"الإلكتروني للعميل، رقم هاتف العميل"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"طريقة الدفع غير صالحة: {payment_method} من {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "السعر الذي دفعه العميل لهذا المنتج وقت الشراء"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "سعر الشراء وقت الطلب"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "تعليقات داخلية للمسؤولين حول هذا المنتج المطلوب"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "التعليقات الداخلية"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "إشعارات المستخدم"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "تمثيل JSON لسمات هذا العنصر"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "سمات المنتج المطلوبة"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "الإشارة إلى الطلب الأصلي الذي يحتوي على هذا المنتج"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "ترتيب الوالدين"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "المنتج المحدد المرتبط بخط الطلب هذا"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "كمية هذا المنتج المحدد في الطلب"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "كمية المنتج"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "الحالة الحالية لهذا المنتج بالترتيب"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "حالة خط الإنتاج"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "يجب أن يكون لـ Orderproduct طلب مرتبط به!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "إجراء خاطئ محدد للتغذية الراجعة: {action}"
+msgstr "تم تحديد إجراء خاطئ للتغذية الراجعة: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "لا يمكنك التعليق على طلب لم يتم استلامه"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "تنزيل"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "التنزيلات"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "لا يمكنك تنزيل أصل رقمي لطلب غير مكتمل"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "التعليقات المقدمة من المستخدمين حول تجربتهم مع المنتج"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "تعليقات على الملاحظات"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr "الإشارة إلى المنتج المحدد في الطلب الذي تدور حوله هذه الملاحظات"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "منتجات الطلبات ذات الصلة"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "التصنيف المعين من قبل المستخدم للمنتج"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "تصنيف المنتج"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "الملاحظات"
@@ -2044,13 +2083,13 @@ msgid ""
"you must provide a comment, rating, and order product uuid to add feedback."
msgstr "يجب عليك تقديم تعليق، وتقييم، وطلب المنتج uuid لإضافة ملاحظاتك."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "خطأ أثناء إنشاء الرمز الترويجي: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2059,7 +2098,7 @@ msgid "order confirmation"
msgstr "تأكيد الطلب"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2070,27 +2109,28 @@ msgstr "الشعار"
#: core/templates/shipped_order_delivered_email.html:100
#, python-format
msgid "hello %(order.user.first_name)s,"
-msgstr "مرحبًا %(order.user.first_name)s,"
+msgstr "مرحباً %(order.user.first_name)s,"
#: core/templates/digital_order_created_email.html:102
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
-"شكرًا لك على طلبك #%(order.pk)s! يسعدنا إبلاغك بأننا قد أخذنا طلبك في العمل."
-" فيما يلي تفاصيل طلبك:"
+"شكرًا لك على طلبك #%(order.pk)s! يسعدنا إبلاغك بأننا قد أخذنا طلبك في العمل. "
+"فيما يلي تفاصيل طلبك:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "الإجمالي"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2110,30 +2150,30 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "مع أطيب التحيات، فريق عمل %(config.PROJECT_NAME)s"
+msgstr "مع أطيب تحياتي،
فريق %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "جميع الحقوق محفوظة"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "تم تسليم الطلب"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "مرحباً %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
" details of your order:"
-msgstr "لقد قمنا بمعالجة طلبك بنجاح №%(order_uuid)s__! فيما يلي تفاصيل طلبك:"
+msgstr "لقد قمنا بمعالجة طلبك بنجاح №%(order_uuid)s! فيما يلي تفاصيل طلبك:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2141,12 +2181,12 @@ msgstr ""
"معلومات إضافية\n"
" معلومات إضافية"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "القيمة"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2154,10 +2194,10 @@ msgid ""
msgstr ""
"إذا كانت لديك أي أسئلة، فلا تتردد في الاتصال بدعمنا على %(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "مع أطيب التحيات، فريق عمل %(project_name)s"
+msgstr "مع أطيب تحياتي،
فريق %(project_name)s"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2166,7 +2206,8 @@ msgstr "المفتاح"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr "شكرًا لك على طلبك! يسعدنا تأكيد طلبك. فيما يلي تفاصيل طلبك:"
@@ -2184,7 +2225,7 @@ msgstr "سيتم توصيل طلبك إلى العنوان التالي:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "مع أطيب تحياتي،
فريق عمل %(config.PROJECT_NAME)s"
+msgstr "مع أطيب تحياتي،
فريق %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2203,30 +2244,20 @@ msgstr "كل من البيانات والمهلة مطلوبة"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "قيمة المهلة غير صالحة، يجب أن تكون بين 0 و216000 ثانية"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "يجب أن يكون {model} نموذجًا"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "يجب أن تكون {data} كائن قائمة"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | بدء الاتصال بنا"
+msgstr "{config.PROJECT_NAME} | بادر بالاتصال بنا"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | تأكيد الطلب"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME} | تم تسليم الطلب"
+msgstr "{config.PROJECT_NAME} | طلبية تم تسليمها"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2239,21 +2270,21 @@ msgstr "يجب تكوين معلمة NOMINATIM_URL!"
#: core/validators.py:16
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
-msgstr "يجب ألا تتجاوز أبعاد الصورة w{max_width} x h{max_height} بكسل"
+msgstr "يجب ألا تتجاوز أبعاد الصورة w{max_width} x h{max_height} بكسل!"
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "تنسيق رقم الهاتف غير صالح"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "يمكنك تنزيل الأصل الرقمي مرة واحدة فقط"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "الرمز المفضل غير موجود"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "خطأ في الترميز الجغرافي: {e}"
diff --git a/core/locale/cs_CZ/LC_MESSAGES/django.mo b/core/locale/cs_CZ/LC_MESSAGES/django.mo
index a6208ad4..7afca15f 100644
Binary files a/core/locale/cs_CZ/LC_MESSAGES/django.mo and b/core/locale/cs_CZ/LC_MESSAGES/django.mo differ
diff --git a/core/locale/cs_CZ/LC_MESSAGES/django.po b/core/locale/cs_CZ/LC_MESSAGES/django.po
index ae574cb7..1712b0dd 100644
--- a/core/locale/cs_CZ/LC_MESSAGES/django.po
+++ b/core/locale/cs_CZ/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,121 +13,118 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Jedinečné ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"Jedinečné ID slouží k jisté identifikaci jakéhokoli databázového objektu."
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Je aktivní"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Pokud je nastaveno na false, nemohou tento objekt vidět uživatelé bez "
"potřebného oprávnění."
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Vytvořeno"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Kdy se objekt poprvé objevil v databázi"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Upraveno"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Kdy byl objekt naposledy upraven"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Překlady"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Obecné"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Vztahy"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadata"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Časová razítka"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "Aktivovat vybrané %(verbose_name_plural)s"
+msgstr "Aktivace vybraného %(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s úspěšně aktivován!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Vybrané položky byly aktivovány!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Deaktivovat vybrané %(verbose_name_plural)s"
+msgstr "Deaktivace vybraných %(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s byl úspěšně deaktivován."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Vybrané položky byly deaktivovány!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Hodnota atributu"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Hodnoty atributů"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Obrázek"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Obrázky"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stock"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Zásoby"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Objednat produkt"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Objednat produkty"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Děti"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Konfigurace"
@@ -179,7 +176,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Úspěšné"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Vstup/výstup mezipaměti"
@@ -203,7 +200,7 @@ msgstr "Získání vystavitelných parametrů aplikace"
msgid "send a message to the support team"
msgstr "Odeslání zprávy týmu podpory"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Vyžádejte si adresu URL s protokolem CORS. Povoleno pouze https."
@@ -246,8 +243,7 @@ msgstr ""
"Přepsání existující skupiny atributů s uložením neupravitelných položek"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Přepsání některých polí existující skupiny atributů s uložením "
"neupravitelných položek"
@@ -299,8 +295,7 @@ msgid "rewrite an existing attribute value saving non-editables"
msgstr "Přepsání existující hodnoty atributu uložením neupravitelných položek"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Přepsání některých polí existující hodnoty atributu s uložením "
"neupravitelných položek"
@@ -342,12 +337,12 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"Vyhledávání podřetězců bez ohledu na velikost písmen v položkách "
-"human_readable_id, order_products.product.name a "
-"order_products.product.partnumber"
+"human_readable_id, order_products.product.name a order_products.product."
+"partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -383,9 +378,9 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Řazení podle jedné z následujících možností: uuid, human_readable_id, "
"user_email, user, status, created, modified, buy_time, random. Pro sestupné "
@@ -426,11 +421,11 @@ msgid ""
"completed using the user's balance; if `force_payment` is used, a "
"transaction is initiated."
msgstr ""
-"Dokončí nákup objednávky. Pokud je použito `force_balance`, nákup se dokončí"
-" s použitím zůstatku uživatele; pokud je použito `force_payment`, zahájí se "
+"Dokončí nákup objednávky. Pokud je použito `force_balance`, nákup se dokončí "
+"s použitím zůstatku uživatele; pokud je použito `force_payment`, zahájí se "
"transakce."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "zakoupení objednávky bez vytvoření účtu"
@@ -542,8 +537,7 @@ msgstr "Přidání mnoha produktů do seznamu přání"
#: core/docs/drf/viewsets.py:320
msgid "adds many products to an wishlist using the provided `product_uuids`"
-msgstr ""
-"Přidá mnoho produktů do seznamu přání pomocí zadaných `product_uuids`."
+msgstr "Přidá mnoho produktů do seznamu přání pomocí zadaných `product_uuids`."
#: core/docs/drf/viewsets.py:325
msgid "remove many products from wishlist"
@@ -559,18 +553,28 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtrování podle jedné nebo více dvojic název/hodnota atributu. \n"
"- **Syntaxe**: `attr_name=method-value[;attr2=method2-value2]...`\n"
-"- **Metody** (pokud je vynecháno, výchozí hodnota je `obsahuje`): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
-"- **Typování hodnot**: Pro booleany, celá čísla, floaty se nejprve zkouší JSON (takže můžete předávat seznamy/dicty), `true`/`false`; jinak se s nimi zachází jako s řetězci. \n"
-"- **Base64**: předpona `b64-` pro bezpečné zakódování surové hodnoty do URL base64. \n"
+"- **Metody** (pokud je vynecháno, výchozí hodnota je `obsahuje`): `iexact`, "
+"`exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, "
+"`endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
+"- **Typování hodnot**: Pro booleany, celá čísla, floaty se nejprve zkouší "
+"JSON (takže můžete předávat seznamy/dicty), `true`/`false`; jinak se s nimi "
+"zachází jako s řetězci. \n"
+"- **Base64**: předpona `b64-` pro bezpečné zakódování surové hodnoty do URL "
+"base64. \n"
"Příklady: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\", \"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`"
@@ -625,10 +629,12 @@ msgstr "(přesně) Digitální vs. fyzické"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Seznam polí oddělených čárkou, podle kterých se má třídit. Pro sestupné řazení použijte předponu `-`. \n"
+"Seznam polí oddělených čárkou, podle kterých se má třídit. Pro sestupné "
+"řazení použijte předponu `-`. \n"
"**Povolené:** uuid, rating, name, slug, created, modified, price, random"
#: core/docs/drf/viewsets.py:441
@@ -756,7 +762,7 @@ msgstr "odstranit vztah objednávka-produkt"
msgid "add or remove feedback on an order–product relation"
msgstr "přidat nebo odebrat zpětnou vazbu na vztah objednávka-produkt."
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Nebyl zadán žádný vyhledávací termín."
@@ -804,8 +810,8 @@ msgstr "Atributy"
msgid "Quantity"
msgstr "Množství"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Slug"
@@ -867,216 +873,238 @@ msgstr "Úroveň"
msgid "Product UUID"
msgstr "UUID produktu"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Klíč k vyhledání v keši nebo nastavení do keše"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Data k uložení do mezipaměti"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Časový limit v sekundách pro nastavení dat do mezipaměti"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Data uložená v mezipaměti"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Kamelizovaná data JSON z požadované adresy URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Povoleny jsou pouze adresy URL začínající http(s)://."
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Přidání produktu do objednávky"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Objednávka {order_uuid} nebyla nalezena"
+msgstr "Objednávka {order_uuid} nebyla nalezena!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Odstranění produktu z objednávky"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Odstranění všech produktů z objednávky"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Koupit objednávku"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Zadejte prosím order_uuid nebo order_hr_id - vzájemně se vylučují!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Z metody order.buy() pochází nesprávný typ: {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Provedení akce na seznamu produktů v objednávce"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Odebrat/přidat"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Akce musí být buď \"přidat\", nebo \"odebrat\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Provedení akce na seznamu produktů v seznamu přání"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Zadejte prosím hodnotu `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Seznam přání {wishlist_uuid} nenalezen!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Přidání produktu do objednávky"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Seznam přání {wishlist_uuid} nebyl nalezen"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Odstranění produktu z objednávky"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Odstranění produktu z objednávky"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Odstranění produktu z objednávky"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Koupit objednávku"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
-"Prosím, pošlete atributy jako řetězec ve formátu "
-"attr1=hodnota1,attr2=hodnota2."
+"Prosím, pošlete atributy jako řetězec ve formátu attr1=hodnota1,"
+"attr2=hodnota2."
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Přidání nebo odstranění zpětné vazby pro objednávkuprodukt"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Akce musí být buď `add` nebo `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Orderproduct {order_product_uuid} nenalezen!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Původní řetězec adresy zadaný uživatelem"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} neexistuje: {uuid}"
+msgstr "{name} neexistuje: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Limit musí být mezi 1 a 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - funguje jako kouzlo"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Atributy"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Seskupené atributy"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Skupiny atributů"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Kategorie"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Značky"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Kategorie"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Procento přirážky"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr "Které atributy a hodnoty lze použít pro filtrování této kategorie."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
-msgstr ""
-"Minimální a maximální ceny produktů v této kategorii, pokud jsou k "
-"dispozici."
-
#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
+msgstr ""
+"Minimální a maximální ceny produktů v této kategorii, pokud jsou k dispozici."
+
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Štítky pro tuto kategorii"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Produkty v této kategorii"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Prodejci"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Zeměpisná šířka (souřadnice Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Zeměpisná délka (souřadnice X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Jak na to"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Hodnota hodnocení od 1 do 10 včetně nebo 0, pokud není nastaveno."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Představuje zpětnou vazbu od uživatele."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Oznámení"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Stáhněte si url adresu pro tento objednaný produkt, pokud je to možné"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Seznam objednaných produktů v tomto pořadí"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Fakturační adresa"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1084,731 +1112,728 @@ msgstr ""
"Dodací adresa pro tuto objednávku, pokud je stejná jako fakturační adresa "
"nebo pokud není použitelná, ponechte prázdné."
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Celková cena této objednávky"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Celkové množství objednaných produktů"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Jsou všechny produkty v objednávce digitální"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transakce pro tuto objednávku"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Objednávky"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Adresa URL obrázku"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Obrázky produktu"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Kategorie"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Zpětná vazba"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Značka"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Skupiny atributů"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Cena"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Množství"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Počet zpětných vazeb"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Produkty"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Propagační kódy"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Produkty v prodeji"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Propagační akce"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Prodejce"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Produkt"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Produkty uvedené na seznamu přání"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Seznamy přání"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Produkty s příznakem"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Štítky produktu"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Kategorie s příznakem"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Štítky kategorií"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Název projektu"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "E-mail společnosti"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Název společnosti"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Adresa společnosti"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Telefonní číslo společnosti"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"'email from', někdy se musí použít místo hodnoty hostitelského uživatele."
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Uživatel hostitelského e-mailu"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Maximální částka pro platbu"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Minimální částka pro platbu"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Analytická data"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Reklamní údaje"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Konfigurace"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Kód jazyka"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Název jazyka"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Příznak jazyka, pokud existuje :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Získat seznam podporovaných jazyků"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Výsledky vyhledávání produktů"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Výsledky vyhledávání produktů"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Rodič této skupiny"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Nadřazená skupina atributů"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Název skupiny atributů"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Skupina atributů"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Ukládá pověření a koncové body potřebné pro komunikaci s rozhraním API "
"dodavatele."
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Informace o ověřování"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Definice přirážky pro produkty získané od tohoto dodavatele"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Procento přirážky prodejce"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Název tohoto prodejce"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Název prodejce"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Interní identifikátor značky produktu"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Název štítku"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Uživatelsky přívětivý název pro značku produktu"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Zobrazení názvu štítku"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Štítek produktu"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "značka kategorie"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "štítky kategorií"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Nahrát obrázek reprezentující tuto kategorii"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Obrázek kategorie"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Definovat procento přirážky pro produkty v této kategorii."
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Nadřízený této kategorie, který tvoří hierarchickou strukturu."
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Nadřazená kategorie"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Název kategorie"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Uveďte název této kategorie"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Přidejte podrobný popis této kategorie"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Popis kategorie"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "značky, které pomáhají popsat nebo seskupit tuto kategorii"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Priorita"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Název této značky"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Název značky"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Nahrát logo reprezentující tuto značku"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Malý obrázek značky"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Nahrát velké logo reprezentující tuto značku"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Velká image značky"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Přidejte podrobný popis značky"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Popis značky"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Volitelné kategorie, se kterými je tato značka spojena"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Kategorie"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Kategorie, do které tento produkt patří"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Volitelně přiřadit tento produkt ke značce"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Značky, které pomáhají popsat nebo seskupit tento produkt"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Označuje, zda je tento produkt dodáván digitálně"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Je produkt digitální"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Uveďte jasný identifikační název výrobku"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Název produktu"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Přidejte podrobný popis produktu"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Popis produktu"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Číslo dílu pro tento produkt"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Číslo dílu"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Kategorie tohoto atributu"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Skupina tohoto atributu"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Řetězec"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Celé číslo"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Float"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Boolean"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Pole"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Objekt"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Typ hodnoty atributu"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Typ hodnoty"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Název tohoto atributu"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Název atributu"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Atribut"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Atribut této hodnoty"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Konkrétní produkt spojený s hodnotou tohoto atributu"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Související produkt"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "Konkrétní hodnota tohoto atributu"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "Poskytněte alternativní text k obrázku kvůli přístupnosti."
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Text alt obrázku"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Nahrát soubor s obrázkem tohoto produktu"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Obrázek produktu"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Určuje pořadí, v jakém se obrázky zobrazují."
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Priorita zobrazení"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "Výrobek, který tento obrázek představuje"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Obrázky produktů"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Procentuální sleva na vybrané produkty"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Procento slevy"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Uveďte jedinečný název této propagační akce"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Název akce"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Popis propagace"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Vyberte, které produkty jsou zahrnuty do této akce"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Zahrnuté produkty"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Propagace"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "Prodejce dodávající tento výrobek na sklad"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Přidružený prodejce"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Konečná cena pro zákazníka po přirážkách"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Prodejní cena"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "Produkt spojený s touto skladovou položkou"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Související produkt"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "Cena zaplacená prodejci za tento výrobek"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Kupní cena prodejce"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Dostupné množství produktu na skladě"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Množství na skladě"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "SKU přidělený prodejcem pro identifikaci výrobku"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "SKU prodejce"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Digitální soubor spojený s touto zásobou, je-li to vhodné"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Digitální soubor"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Zápisy do zásob"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Kategorie, do které tento produkt patří"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Volitelně přiřadit tento produkt ke značce"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Značky, které pomáhají popsat nebo seskupit tento produkt"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Označuje, zda je tento produkt dodáván digitálně"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Je produkt digitální"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Uveďte jasný identifikační název výrobku"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Název produktu"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Přidejte podrobný popis produktu"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Popis produktu"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Číslo dílu pro tento produkt"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Číslo dílu"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Kategorie tohoto atributu"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Skupina tohoto atributu"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Řetězec"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Celé číslo"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Float"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Boolean"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Pole"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Objekt"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Typ hodnoty atributu"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Typ hodnoty"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Název tohoto atributu"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Název atributu"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Atribut"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Atribut této hodnoty"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Konkrétní produkt spojený s hodnotou tohoto atributu"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "Konkrétní hodnota tohoto atributu"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Poskytněte alternativní text k obrázku kvůli přístupnosti."
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Text alt obrázku"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Nahrát soubor s obrázkem tohoto produktu"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Obrázek produktu"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Určuje pořadí, v jakém se obrázky zobrazují."
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Priorita zobrazení"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "Výrobek, který tento obrázek představuje"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Obrázky produktů"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Procentuální sleva na vybrané produkty"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Procento slevy"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Uveďte jedinečný název této propagační akce"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Název akce"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Popis propagace"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Vyberte, které produkty jsou zahrnuty do této akce"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Zahrnuté produkty"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Propagace"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Výrobky, které uživatel označil jako požadované"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Uživatel, který vlastní tento seznam přání"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Majitel seznamu přání"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Seznam přání"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} neexistuje: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Dokumentární film"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Dokumentární filmy"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Nevyřešené"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Adresní řádek pro zákazníka"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Adresní řádek"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Ulice"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Okres"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Město"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Region"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Poštovní směrovací číslo"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Země"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolokace Bod(Zeměpisná délka, Zeměpisná šířka)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Úplná odpověď JSON z geokodéru pro tuto adresu"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Uložená odpověď JSON ze služby geokódování"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Adresa"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adresy"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Jedinečný kód, který uživatel použije k uplatnění slevy."
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Identifikátor propagačního kódu"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Pevná výše slevy, pokud není použito procento"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Pevná výše slevy"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Procentuální sleva uplatněná v případě nevyužití pevné částky"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Procentuální sleva"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Časové razítko ukončení platnosti promokódu"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Doba ukončení platnosti"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Časové razítko, od kterého je tento promokód platný"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Čas zahájení platnosti"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr "Časové razítko použití promokódu, prázdné, pokud ještě nebyl použit."
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Časové razítko použití"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Uživatel přiřazený k tomuto promokódu, je-li to relevantní"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Přiřazený uživatel"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Propagační kód"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Propagační kódy"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1816,137 +1841,144 @@ msgstr ""
"Měl by být definován pouze jeden typ slevy (částka nebo procento), nikoli "
"však oba typy slev nebo žádný z nich."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Promo kód byl již použit"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Neplatný typ slevy pro promocode {self.uuid}"
+msgstr "Neplatný typ slevy pro promokód {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "Fakturační adresa použitá pro tuto objednávku"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Volitelný promo kód použitý na tuto objednávku"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Použitý promo kód"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "Dodací adresa použitá pro tuto objednávku"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Dodací adresa"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Aktuální stav zakázky v jejím životním cyklu"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Stav objednávky"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"JSON struktura oznámení pro zobrazení uživatelům, v uživatelském rozhraní "
"administrátora se používá tabulkové zobrazení."
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "JSON reprezentace atributů objednávky pro tuto objednávku"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "Uživatel, který zadal objednávku"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Uživatel"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Časové razítko, kdy byla objednávka dokončena."
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Kupte si čas"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Lidsky čitelný identifikátor objednávky"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "lidsky čitelné ID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Objednávka"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Uživatel smí mít vždy pouze jednu čekající objednávku!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
-msgstr ""
-"Do objednávky, která není v procesu vyřizování, nelze přidat produkty."
+msgstr "Do objednávky, která není v procesu vyřizování, nelze přidat produkty."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Do objednávky nelze přidat neaktivní produkty"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "Nelze přidat více produktů, než je dostupné na skladě"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "Nelze odebrat produkty z objednávky, která není nevyřízená."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} neexistuje s dotazem <{query}>"
+msgstr "{name} neexistuje s dotazem <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Promo kód neexistuje"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "Fyzické produkty můžete zakoupit pouze se zadanou dodací adresou!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Adresa neexistuje"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"V tuto chvíli nemůžete nakupovat, zkuste to prosím znovu za několik minut."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Neplatná hodnota síly"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Nelze zakoupit prázdnou objednávku!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "Bez uživatele nelze objednávku zakoupit!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Uživatel bez zůstatku nemůže nakupovat se zůstatkem!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Nedostatek finančních prostředků na dokončení objednávky"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1954,118 +1986,121 @@ msgstr ""
"bez registrace nelze nakupovat, uveďte prosím následující údaje: jméno "
"zákazníka, e-mail zákazníka, telefonní číslo zákazníka."
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"Neplatný způsob platby: {payment_method} z {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "Cena, kterou zákazník zaplatil za tento produkt v době nákupu."
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Nákupní cena v době objednávky"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "Interní komentáře pro administrátory k tomuto objednanému produktu"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Interní připomínky"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Oznámení uživatele"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "JSON reprezentace atributů této položky"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Objednané atributy produktu"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Odkaz na nadřazenou objednávku, která obsahuje tento produkt"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Objednávka rodičů"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Konkrétní produkt spojený s touto objednávkou"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Množství tohoto konkrétního produktu v objednávce"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Množství produktu"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Aktuální stav tohoto produktu v objednávce"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Stav produktové řady"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Orderproduct musí mít přiřazenou objednávku!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "špatně zadaná akce pro zpětnou vazbu: {action}"
+msgstr "Špatně zadaná akce pro zpětnou vazbu: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "nelze poskytnout zpětnou vazbu na objednávku, která nebyla přijata"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Stáhnout"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Ke stažení na"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "Digitální aktivum pro nedokončenou objednávku nelze stáhnout."
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Komentáře uživatelů o jejich zkušenostech s produktem"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Zpětná vazba"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"Odkazuje na konkrétní produkt v objednávce, kterého se tato zpětná vazba "
"týká."
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Související objednávka produktu"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Hodnocení produktu přidělené uživatelem"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Hodnocení produktu"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Zpětná vazba"
@@ -2075,13 +2110,13 @@ msgid ""
msgstr ""
"pro přidání zpětné vazby musíte uvést komentář, hodnocení a uuid produktu."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Chyba při vytváření promokódu: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2090,7 +2125,7 @@ msgid "order confirmation"
msgstr "Potvrzení objednávky"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2101,13 +2136,14 @@ msgstr "Logo"
#: core/templates/shipped_order_delivered_email.html:100
#, python-format
msgid "hello %(order.user.first_name)s,"
-msgstr "Hello %(order.user.first_name)s,"
+msgstr "Ahoj %(order.user.first_name)s,"
#: core/templates/digital_order_created_email.html:102
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Děkujeme vám za vaši objednávku #%(order.pk)s! S potěšením Vám oznamujeme, "
@@ -2115,14 +2151,14 @@ msgstr ""
"objednávce:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Celkem"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2145,20 +2181,20 @@ msgid "best regards,
the %(config.PROJECT_NAME)s team"
msgstr "S pozdravem,
tým %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Všechna práva vyhrazena"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Dodaná objednávka"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Ahoj %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2167,7 +2203,7 @@ msgstr ""
"Úspěšně jsme zpracovali vaši objednávku №%(order_uuid)s! Níže jsou uvedeny "
"podrobnosti vaší objednávky:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2175,12 +2211,12 @@ msgstr ""
"další\n"
" informace"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Hodnota"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2189,7 +2225,7 @@ msgstr ""
"V případě dotazů se můžete obrátit na naši podporu na adrese "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "S pozdravem,
tým %(project_name)s"
@@ -2201,7 +2237,8 @@ msgstr "Klíč"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Děkujeme vám za vaši objednávku! S potěšením potvrzujeme váš nákup. Níže "
@@ -2221,7 +2258,7 @@ msgstr "Vaše objednávka bude doručena na následující adresu:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "S pozdravem,
tým %(config.PROJECT_NAME)s"
+msgstr "S pozdravem,
Tým %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2240,30 +2277,20 @@ msgstr "Jsou vyžadována data i časový limit"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "Nesprávná hodnota timeoutu, musí být v rozmezí 0 až 216000 sekund."
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} musí být model"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} musí být objekt seznamu"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Kontakt iniciován"
+msgstr "{config.PROJECT_NAME} | kontaktujte nás inicioval"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Potvrzení objednávky"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME} | Dodaná objednávka"
+msgstr "{config.PROJECT_NAME} | Objednávka doručena"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2283,15 +2310,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Nesprávný formát telefonního čísla"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Digitální aktivum můžete stáhnout pouze jednou"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon nebyl nalezen"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Chyba v zeměpisném kódování: {e}"
diff --git a/core/locale/da_DK/LC_MESSAGES/django.mo b/core/locale/da_DK/LC_MESSAGES/django.mo
index 3364a06b..1a540d7e 100644
Binary files a/core/locale/da_DK/LC_MESSAGES/django.mo and b/core/locale/da_DK/LC_MESSAGES/django.mo differ
diff --git a/core/locale/da_DK/LC_MESSAGES/django.po b/core/locale/da_DK/LC_MESSAGES/django.po
index 1ed0e4c7..e185395c 100644
--- a/core/locale/da_DK/LC_MESSAGES/django.po
+++ b/core/locale/da_DK/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,120 +13,117 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Unikt ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr "Unikt ID bruges til sikkert at identificere ethvert databaseobjekt"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Er aktiv"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Hvis det er sat til false, kan dette objekt ikke ses af brugere uden den "
"nødvendige tilladelse."
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Oprettet"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Da objektet første gang dukkede op i databasen"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modificeret"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Hvornår objektet sidst blev redigeret"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Oversættelser"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Generelt"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relationer"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadata"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Tidsstempler"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "Aktivér udvalgte %(verbose_name_plural)s"
+msgstr "Aktivér valgt %(verbose_name_plural)s."
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s aktiveret med succes!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Udvalgte varer er blevet aktiveret!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Deaktiver udvalgte %(verbose_name_plural)s"
+msgstr "Deaktiver valgte %(verbose_name_plural)s."
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s deaktiveret med succes."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Udvalgte varer er blevet deaktiveret!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Attributværdi"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Attributværdier"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Billede"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Billeder"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Lager"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Aktier"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Bestil produkt"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Bestil produkter"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Børn"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Konfig"
@@ -178,7 +175,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Succesfuld"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Cache-I/O"
@@ -188,7 +185,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"Anvend kun en nøgle til at læse tilladte data fra cachen.\n"
-"Anvend nøgle, data og timeout med autentificering for at skrive data til cachen."
+"Anvend nøgle, data og timeout med autentificering for at skrive data til "
+"cachen."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -202,7 +200,7 @@ msgstr "Hent applikationens eksponerbare parametre"
msgid "send a message to the support team"
msgstr "Send en besked til supportteamet"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Anmod om en CORSed URL. Kun https er tilladt."
@@ -245,8 +243,7 @@ msgstr ""
"attributter"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Omskriv nogle felter i en eksisterende attributgruppe og gem ikke-"
"redigerbare felter"
@@ -299,11 +296,10 @@ msgstr ""
"Omskriv en eksisterende attributværdi, der gemmer ikke-redigerbare filer"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
-"Omskriv nogle felter i en eksisterende attributværdi og gem ikke-redigerbare"
-" felter"
+"Omskriv nogle felter i en eksisterende attributværdi og gem ikke-redigerbare "
+"felter"
#: core/docs/drf/viewsets.py:124
msgid "list all categories (simple view)"
@@ -337,17 +333,16 @@ msgstr "Liste over alle kategorier (enkel visning)"
#: core/docs/drf/viewsets.py:152
msgid "for non-staff users, only their own orders are returned."
-msgstr ""
-"For ikke-ansatte brugere er det kun deres egne ordrer, der returneres."
+msgstr "For ikke-ansatte brugere er det kun deres egne ordrer, der returneres."
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"Substringsøgning uden brug af store og små bogstaver på tværs af "
-"human_readable_id, order_products.product.name og "
-"order_products.product.partnumber"
+"human_readable_id, order_products.product.name og order_products.product."
+"partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -379,13 +374,13 @@ msgstr "Filtrer efter ordrestatus (case-insensitive substring match)"
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Bestil efter en af: uuid, human_readable_id, user_email, user, status, "
-"created, modified, buy_time, random. Præfiks med '-' for faldende rækkefølge"
-" (f.eks. '-buy_time')."
+"created, modified, buy_time, random. Præfiks med '-' for faldende rækkefølge "
+"(f.eks. '-buy_time')."
#: core/docs/drf/viewsets.py:210
msgid "retrieve a single order (detailed view)"
@@ -427,7 +422,7 @@ msgstr ""
"ved hjælp af brugerens saldo; hvis `force_payment` bruges, igangsættes en "
"transaktion."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "Køb en ordre uden at oprette en konto"
@@ -535,8 +530,7 @@ msgstr "Fjern et produkt fra ønskelisten"
#: core/docs/drf/viewsets.py:314
msgid "removes a product from an wishlist using the provided `product_uuid`"
msgstr ""
-"Fjerner et produkt fra en ønskeliste ved hjælp af den angivne "
-"`product_uuid`."
+"Fjerner et produkt fra en ønskeliste ved hjælp af den angivne `product_uuid`."
#: core/docs/drf/viewsets.py:319
msgid "add many products to wishlist"
@@ -563,18 +557,28 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtrer efter et eller flere attributnavn/værdipar. \n"
"- **Syntaks**: `attr_name=method-value[;attr2=method2-value2]...`.\n"
-"- **Metoder** (standard er `icontains`, hvis udeladt): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
-"- Værdiindtastning**: JSON forsøges først (så du kan sende lister/dikter), `true`/`false` for booleans, heltal, floats; ellers behandles de som strenge. \n"
-"- **Base64**: præfiks med `b64-` for URL-sikker base64-kodning af den rå værdi. \n"
+"- **Metoder** (standard er `icontains`, hvis udeladt): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
+"- Værdiindtastning**: JSON forsøges først (så du kan sende lister/dikter), "
+"`true`/`false` for booleans, heltal, floats; ellers behandles de som "
+"strenge. \n"
+"- **Base64**: præfiks med `b64-` for URL-sikker base64-kodning af den rå "
+"værdi. \n"
"Eksempler på dette: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`."
@@ -629,10 +633,12 @@ msgstr "(præcis) Digital vs. fysisk"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Kommasepareret liste over felter, der skal sorteres efter. Præfiks med `-` for faldende. \n"
+"Kommasepareret liste over felter, der skal sorteres efter. Præfiks med `-` "
+"for faldende. \n"
"**Tilladt:** uuid, vurdering, navn, slug, oprettet, ændret, pris, tilfældig"
#: core/docs/drf/viewsets.py:441
@@ -758,7 +764,7 @@ msgstr "slette en ordre-produkt-relation"
msgid "add or remove feedback on an order–product relation"
msgstr "tilføje eller fjerne feedback på en ordre-produkt-relation"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Der er ikke angivet noget søgeord."
@@ -806,8 +812,8 @@ msgstr "Egenskaber"
msgid "Quantity"
msgstr "Mængde"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Snegl"
@@ -869,220 +875,242 @@ msgstr "Niveau"
msgid "Product UUID"
msgstr "Produkt UUID"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Nøgle til at lede efter i eller lægge i cachen"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Data, der skal gemmes i cachen"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Timeout i sekunder for at lægge data i cachen"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Cachelagrede data"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Cameliserede JSON-data fra den ønskede URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Kun URL'er, der starter med http(s)://, er tilladt."
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Tilføj et produkt til ordren"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Ordre {order_uuid} ikke fundet"
+msgstr "Ordre {order_uuid} ikke fundet!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Fjern et produkt fra ordren"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Fjern alle produkter fra ordren"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Køb en ordre"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Angiv enten order_uuid eller order_hr_id - det udelukker hinanden!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Forkert type kom fra metoden order.buy(): {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Udfør en handling på en liste af produkter i ordren"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Fjern/tilføj"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Handlingen skal være enten \"tilføj\" eller \"fjern\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Udfør en handling på en liste af produkter i ønskelisten"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Angiv venligst værdien `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Ønskeliste {wishlist_uuid} ikke fundet!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Tilføj et produkt til ordren"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Ønskeliste {wishlist_uuid} ikke fundet"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Fjern et produkt fra ordren"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Fjern et produkt fra ordren"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Fjern et produkt fra ordren"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Køb en ordre"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
-"Send venligst attributterne som en streng formateret som "
-"attr1=værdi1,attr2=værdi2"
+"Send venligst attributterne som en streng formateret som attr1=værdi1,"
+"attr2=værdi2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Tilføj eller slet en feedback til ordreproduktet"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Handlingen skal være enten `add` eller `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Ordreprodukt {order_product_uuid} ikke fundet!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Original adressestreng leveret af brugeren"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} findes ikke: {uuid}"
+msgstr "{name} findes ikke: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Grænsen skal være mellem 1 og 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - fungerer som en charme"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Egenskaber"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Grupperede attributter"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Grupper af attributter"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Kategorier"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Mærker"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Kategorier"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Markup-procentdel"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
-"Hvilke attributter og værdier, der kan bruges til at filtrere denne "
-"kategori."
+"Hvilke attributter og værdier, der kan bruges til at filtrere denne kategori."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Minimums- og maksimumspriser for produkter i denne kategori, hvis de er "
"tilgængelige."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tags for denne kategori"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Produkter i denne kategori"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Leverandører"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Breddegrad (Y-koordinat)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Længdegrad (X-koordinat)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Sådan gør du"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr ""
"Vurderingsværdi fra 1 til 10, inklusive, eller 0, hvis den ikke er "
"indstillet."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Repræsenterer feedback fra en bruger."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Meddelelser"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Download url for dette ordreprodukt, hvis det er relevant"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "En liste over bestillingsprodukter i denne ordre"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Faktureringsadresse"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1090,732 +1118,729 @@ msgstr ""
"Leveringsadresse for denne ordre, lad den være tom, hvis den er den samme "
"som faktureringsadressen, eller hvis den ikke er relevant"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Samlet pris for denne ordre"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Samlet antal produkter i ordren"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Er alle produkterne i ordren digitale?"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transaktioner for denne ordre"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Bestillinger"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Billed-URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Produktets billeder"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Kategori"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Tilbagemeldinger"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Brand"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Attributgrupper"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Pris"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Mængde"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Antal tilbagemeldinger"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Produkter"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Promokoder"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Produkter til salg"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Kampagner"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Leverandør"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Produkt"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Produkter på ønskelisten"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Ønskelister"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Mærkede produkter"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Produktmærker"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Tagged kategorier"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Kategoriernes tags"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Projektets navn"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Virksomhedens e-mail"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Virksomhedens navn"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Virksomhedens adresse"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Virksomhedens telefonnummer"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"'e-mail fra', nogle gange skal den bruges i stedet for værtsbrugerværdien"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "E-mail-værtsbruger"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Maksimalt beløb til betaling"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Minimumsbeløb for betaling"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Analytiske data"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Data om reklamer"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Konfiguration"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Sprogkode"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Sprogets navn"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Sprogflag, hvis det findes :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Få en liste over understøttede sprog"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Søgeresultater for produkter"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Søgeresultater for produkter"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Forælder til denne gruppe"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Overordnet attributgruppe"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Attributgruppens navn"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Attributgruppe"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Gemmer legitimationsoplysninger og slutpunkter, der er nødvendige for "
"leverandørens API-kommunikation"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Oplysninger om godkendelse"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Definer markeringen for produkter, der hentes fra denne leverandør"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Sælgerens markup-procentdel"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Navn på denne leverandør"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Leverandørens navn"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Intern tag-identifikator for produkttagget"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Tag-navn"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Brugervenligt navn til produktmærket"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Navn på tag-visning"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Produktmærke"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "Kategori-tag"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "Kategori-tags"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Upload et billede, der repræsenterer denne kategori"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Kategori billede"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Definer en markup-procentdel for produkter i denne kategori"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Forælder til denne kategori for at danne en hierarkisk struktur"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Overordnet kategori"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Navn på kategori"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Giv et navn til denne kategori"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Tilføj en detaljeret beskrivelse af denne kategori"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Beskrivelse af kategori"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "tags, der hjælper med at beskrive eller gruppere denne kategori"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Prioritet"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Navnet på dette mærke"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Varemærke"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Upload et logo, der repræsenterer dette brand"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Brandets lille image"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Upload et stort logo, der repræsenterer dette brand"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Brandets store image"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Tilføj en detaljeret beskrivelse af brandet"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Varemærkebeskrivelse"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Valgfrie kategorier, som dette brand er forbundet med"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Kategorier"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Kategori, som dette produkt tilhører"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Tilknyt eventuelt dette produkt til et brand"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Tags, der hjælper med at beskrive eller gruppere dette produkt"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Angiver, om dette produkt leveres digitalt"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Er produktet digitalt?"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Giv produktet et klart identificerende navn"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Produktets navn"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Tilføj en detaljeret beskrivelse af produktet"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Produktbeskrivelse"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Reservedelsnummer for dette produkt"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Varenummer"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Kategori for denne attribut"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Gruppe af denne attribut"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Streng"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Heltal"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Flyder"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Boolsk"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Array"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Objekt"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Type af attributtens værdi"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Værditype"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Navn på denne attribut"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Attributtens navn"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Attribut"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Attribut for denne værdi"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Det specifikke produkt, der er knyttet til denne attributs værdi"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Tilknyttet produkt"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "Den specifikke værdi for denne attribut"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "Giv alternativ tekst til billedet af hensyn til tilgængeligheden"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Billedets alt-tekst"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Upload billedfilen til dette produkt"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Produktbillede"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Bestemmer den rækkefølge, billederne vises i"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Skærm-prioritet"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "Det produkt, som dette billede repræsenterer"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Produktbilleder"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Procentvis rabat for de valgte produkter"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Rabatprocent"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Giv et unikt navn til denne kampagne"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Navn på kampagne"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Beskrivelse af kampagnen"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Vælg, hvilke produkter der er inkluderet i denne kampagne"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Inkluderede produkter"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Forfremmelse"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "Den leverandør, der leverer dette produkt, lagerfører"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Tilknyttet leverandør"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Endelig pris til kunden efter tillæg"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Salgspris"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "Det produkt, der er knyttet til denne lagerpost"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Tilknyttet produkt"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "Den pris, der er betalt til sælgeren for dette produkt"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Leverandørens købspris"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Tilgængelig mængde af produktet på lager"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Antal på lager"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "Leverandørtildelt SKU til identifikation af produktet"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "Leverandørens SKU"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Digital fil knyttet til dette lager, hvis relevant"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Digital fil"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Lagerposteringer"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Kategori, som dette produkt tilhører"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Tilknyt eventuelt dette produkt til et brand"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Tags, der hjælper med at beskrive eller gruppere dette produkt"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Angiver, om dette produkt leveres digitalt"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Er produktet digitalt?"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Giv produktet et klart identificerende navn"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Produktets navn"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Tilføj en detaljeret beskrivelse af produktet"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Produktbeskrivelse"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Reservedelsnummer for dette produkt"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Varenummer"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Kategori for denne attribut"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Gruppe af denne attribut"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Streng"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Heltal"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Flyder"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Boolsk"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Array"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Objekt"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Type af attributtens værdi"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Værditype"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Navn på denne attribut"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Attributtens navn"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Attribut"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Attribut for denne værdi"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Det specifikke produkt, der er knyttet til denne attributs værdi"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "Den specifikke værdi for denne attribut"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Giv alternativ tekst til billedet af hensyn til tilgængeligheden"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Billedets alt-tekst"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Upload billedfilen til dette produkt"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Produktbillede"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Bestemmer den rækkefølge, billederne vises i"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Skærm-prioritet"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "Det produkt, som dette billede repræsenterer"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Produktbilleder"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Procentvis rabat for de valgte produkter"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Rabatprocent"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Giv et unikt navn til denne kampagne"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Navn på kampagne"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Beskrivelse af kampagnen"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Vælg, hvilke produkter der er inkluderet i denne kampagne"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Inkluderede produkter"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Forfremmelse"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Produkter, som brugeren har markeret som ønskede"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Bruger, der ejer denne ønskeliste"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Ønskelistens ejer"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Ønskeliste"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} findes ikke: {product_uuid}."
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Dokumentarfilm"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Dokumentarfilm"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Uafklaret"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Adresselinje til kunden"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Adresselinje"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Gade"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Distrikt"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "By"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Region"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Postnummer"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Land"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolokaliseringspunkt (længdegrad, breddegrad)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Fuldt JSON-svar fra geokoderen for denne adresse"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Gemt JSON-svar fra geokodningstjenesten"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Adresse"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adresser"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Unik kode, der bruges af en bruger til at indløse en rabat"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Identifikator for kampagnekode"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Fast rabatbeløb anvendes, hvis procent ikke bruges"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Fast rabatbeløb"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Procentvis rabat, hvis det faste beløb ikke bruges"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Procentvis rabat"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Tidsstempel, når promokoden udløber"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Slut gyldighedstid"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Tidsstempel, hvorfra denne promokode er gyldig"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Start gyldighedstid"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Tidsstempel, hvor promokoden blev brugt, blank, hvis den ikke er brugt endnu"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Tidsstempel for brug"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Bruger tildelt denne promokode, hvis relevant"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Tildelt bruger"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Kampagnekode"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Kampagnekoder"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1823,137 +1848,145 @@ msgstr ""
"Der skal kun defineres én type rabat (beløb eller procent), men ikke begge "
"eller ingen af dem."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Promokoden er allerede blevet brugt"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Ugyldig rabattype for promokode {self.uuid}."
+msgstr "Ugyldig rabattype for promokode {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "Den faktureringsadresse, der bruges til denne ordre"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Valgfri kampagnekode anvendt på denne ordre"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Anvendt kampagnekode"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "Den leveringsadresse, der er brugt til denne ordre"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Leveringsadresse"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Ordrens aktuelle status i dens livscyklus"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Bestillingsstatus"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
-"JSON-struktur af meddelelser, der skal vises til brugerne, i admin UI bruges"
-" tabelvisningen"
+"JSON-struktur af meddelelser, der skal vises til brugerne, i admin UI bruges "
+"tabelvisningen"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "JSON-repræsentation af ordreattributter for denne ordre"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "Den bruger, der har afgivet ordren"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Bruger"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Tidsstemplet for, hvornår ordren blev afsluttet"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Køb tid"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "En menneskeligt læsbar identifikator for ordren"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "menneskeligt læsbart ID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Bestil"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "En bruger må kun have én afventende ordre ad gangen!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "Du kan ikke tilføje produkter til en ordre, der ikke er i gang."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Du kan ikke tilføje inaktive produkter til en ordre"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "Du kan ikke tilføje flere produkter, end der er på lager"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
-"Du kan ikke fjerne produkter fra en ordre, der ikke er en igangværende "
-"ordre."
+"Du kan ikke fjerne produkter fra en ordre, der ikke er en igangværende ordre."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} findes ikke med forespørgsel <{query}>."
+msgstr "{name} findes ikke med forespørgslen <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Promokode findes ikke"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "Du kan kun købe fysiske produkter med angivet leveringsadresse!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Adressen findes ikke"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr "Du kan ikke købe i øjeblikket, prøv venligst igen om et par minutter."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Ugyldig kraftværdi"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Du kan ikke købe en tom ordre!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+"Du kan ikke fjerne produkter fra en ordre, der ikke er en igangværende ordre."
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "En bruger uden saldo kan ikke købe med saldo!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Utilstrækkelige midler til at gennemføre ordren"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1961,120 +1994,121 @@ msgstr ""
"du kan ikke købe uden registrering, angiv venligst følgende oplysninger: "
"kundens navn, kundens e-mail, kundens telefonnummer"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"Ugyldig betalingsmetode: {payment_method} fra {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "Den pris, som kunden har betalt for dette produkt på købstidspunktet"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Købspris på bestillingstidspunktet"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "Interne kommentarer til administratorer om dette bestilte produkt"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Interne kommentarer"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Notifikationer til brugere"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "JSON-repræsentation af dette elements attributter"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Bestilte produktattributter"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Henvisning til den overordnede ordre, der indeholder dette produkt"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Forældreordre"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Det specifikke produkt, der er knyttet til denne ordrelinje"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Mængde af dette specifikke produkt i ordren"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Produktmængde"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Aktuel status for dette produkt i bestillingen"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Status for produktlinje"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Orderproduct skal have en tilknyttet ordre!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "forkert handling angivet for feedback: {action}."
+msgstr "Forkert handling angivet for feedback: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
-"Du kan ikke fjerne produkter fra en ordre, der ikke er en igangværende "
-"ordre."
+"Du kan ikke fjerne produkter fra en ordre, der ikke er en igangværende ordre."
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Download"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Downloads"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "Du kan ikke downloade et digitalt aktiv for en ikke-færdiggjort ordre"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Brugernes kommentarer om deres oplevelse med produktet"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Kommentarer til feedback"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
-"Henviser til det specifikke produkt i en ordre, som denne feedback handler "
-"om"
+"Henviser til det specifikke produkt i en ordre, som denne feedback handler om"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Relateret ordreprodukt"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Brugertildelt vurdering af produktet"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Produktvurdering"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Feedback"
@@ -2085,13 +2119,13 @@ msgstr ""
"Du skal angive en kommentar, en vurdering og et produkt-uid for at tilføje "
"feedback."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Fejl under oprettelse af promokode: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2100,7 +2134,7 @@ msgid "order confirmation"
msgstr "Ordrebekræftelse"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2117,21 +2151,22 @@ msgstr "Hej %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Tak for din ordre #%(order.pk)s! Vi er glade for at kunne informere dig om, "
"at vi har taget din ordre i brug. Nedenfor er detaljerne om din ordre:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "I alt"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2151,23 +2186,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Med venlig hilsen,
%(config.PROJECT_NAME)s team"
+msgstr "Med venlig hilsen,
teamet %(config.PROJECT_NAME)s."
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Alle rettigheder forbeholdes"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Order Delivered"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hej %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2176,7 +2211,7 @@ msgstr ""
"Vi har behandlet din ordre №%(order_uuid)s! Nedenfor er detaljerne om din "
"ordre:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2184,12 +2219,12 @@ msgstr ""
"yderligere\n"
" oplysninger"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Værdi"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2198,10 +2233,10 @@ msgstr ""
"Hvis du har spørgsmål, er du velkommen til at kontakte vores support på "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Med venlig hilsen,
%(project_name)s team"
+msgstr "Med venlig hilsen,
teamet %(project_name)s."
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2210,7 +2245,8 @@ msgstr "Nøgle"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Tak for din bestilling! Vi er glade for at kunne bekræfte dit køb. Nedenfor "
@@ -2230,7 +2266,7 @@ msgstr "Din ordre vil blive leveret til følgende adresse:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Med venlig hilsen %(config.PROJECT_NAME)s team"
+msgstr "De bedste hilsner,
The %(config.PROJECT_NAME)s team"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2249,30 +2285,20 @@ msgstr "Både data og timeout er påkrævet"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "Ugyldig timeout-værdi, den skal være mellem 0 og 216000 sekunder"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} skal være model"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} skal være et listeobjekt"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Kontakt os indledt"
+msgstr "{config.PROJECT_NAME} | kontakt os påbegyndt"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Ordrebekræftelse"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME} | Ordre leveret"
+msgstr "{config.PROJECT_NAME} | Order Delivered"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2286,22 +2312,21 @@ msgstr "Parameteren NOMINATIM_URL skal være konfigureret!"
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
msgstr ""
-"Billedets dimensioner bør ikke overstige w{max_width} x h{max_height} "
-"pixels."
+"Billedets dimensioner bør ikke overstige w{max_width} x h{max_height} pixels."
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "Ugyldigt telefonnummerformat"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Du kan kun downloade det digitale aktiv én gang"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "Favicon ikke fundet"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Fejl i geokodning: {e}"
diff --git a/core/locale/de_DE/LC_MESSAGES/django.mo b/core/locale/de_DE/LC_MESSAGES/django.mo
index 394ab449..fe91eb6e 100644
Binary files a/core/locale/de_DE/LC_MESSAGES/django.mo and b/core/locale/de_DE/LC_MESSAGES/django.mo differ
diff --git a/core/locale/de_DE/LC_MESSAGES/django.po b/core/locale/de_DE/LC_MESSAGES/django.po
index c3c5f7b7..51822d39 100644
--- a/core/locale/de_DE/LC_MESSAGES/django.po
+++ b/core/locale/de_DE/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,122 +13,119 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Eindeutige ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"Eindeutige ID wird zur sicheren Identifizierung jedes Datenbankobjekts "
"verwendet"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Ist aktiv"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Wenn auf false gesetzt, kann dieses Objekt von Benutzern ohne die "
"erforderliche Berechtigung nicht gesehen werden."
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Erstellt"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Wann das Objekt zum ersten Mal in der Datenbank erschienen ist"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Geändert"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Wann das Objekt zuletzt bearbeitet wurde"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Übersetzungen"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Allgemein"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Beziehungen"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadaten"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Zeitstempel"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr "Ausgewählte %(verbose_name_plural)s aktivieren"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s erfolgreich aktiviert!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Ausgewählte Artikel wurden aktiviert!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
msgstr "Ausgewählte %(verbose_name_plural)s deaktivieren"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s wurde erfolgreich deaktiviert."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Ausgewählte Artikel wurden deaktiviert!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Attribut Wert"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Attribut Werte"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Bild"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Bilder"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Lagerbestand"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Bestände"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Produkt bestellen"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Produkte bestellen"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Kinder"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Konfigurieren Sie"
@@ -180,7 +177,7 @@ msgstr "Momente"
msgid "successful"
msgstr "Erfolgreich"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Cache I/O"
@@ -189,8 +186,10 @@ msgid ""
"apply only a key to read permitted data from cache.\n"
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
-"Wenden Sie nur einen Schlüssel an, um erlaubte Daten aus dem Cache zu lesen.\n"
-"Schlüssel, Daten und Timeout mit Authentifizierung anwenden, um Daten in den Cache zu schreiben."
+"Wenden Sie nur einen Schlüssel an, um erlaubte Daten aus dem Cache zu "
+"lesen.\n"
+"Schlüssel, Daten und Timeout mit Authentifizierung anwenden, um Daten in den "
+"Cache zu schreiben."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -204,7 +203,7 @@ msgstr "Abrufen der exponierbaren Parameter der Anwendung"
msgid "send a message to the support team"
msgstr "Senden Sie eine Nachricht an das Support-Team"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Fordern Sie eine CORS-gesicherte URL an. Nur https erlaubt."
@@ -247,8 +246,7 @@ msgstr ""
"Editierbarkeit"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Umschreiben einiger Felder einer bestehenden Attributgruppe, wobei nicht "
"editierbare Felder gespeichert werden"
@@ -278,8 +276,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:90
msgid "rewrite some fields of an existing attribute saving non-editables"
msgstr ""
-"Umschreiben einiger Felder eines vorhandenen Attributs, um nicht editierbare"
-" Daten zu speichern"
+"Umschreiben einiger Felder eines vorhandenen Attributs, um nicht editierbare "
+"Daten zu speichern"
#: core/docs/drf/viewsets.py:97
msgid "list all attribute values (simple view)"
@@ -304,8 +302,7 @@ msgstr ""
"Editierbarkeit"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Umschreiben einiger Felder eines vorhandenen Attributwerts, wobei nicht "
"bearbeitbare Daten gespeichert werden"
@@ -334,8 +331,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:144
msgid "rewrite some fields of an existing category saving non-editables"
msgstr ""
-"Umschreiben einiger Felder einer bestehenden Kategorie, um nicht editierbare"
-" Daten zu speichern"
+"Umschreiben einiger Felder einer bestehenden Kategorie, um nicht editierbare "
+"Daten zu speichern"
#: core/docs/drf/viewsets.py:151
msgid "list all orders (simple view)"
@@ -348,12 +345,12 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"Groß- und Kleinschreibung unempfindliche Teilstringsuche über "
-"human_readable_id, order_products.product.name und "
-"order_products.product.partnumber"
+"human_readable_id, order_products.product.name und order_products.product."
+"partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -389,9 +386,9 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Sortierung nach einem von: uuid, human_readable_id, user_email, user, "
"status, created, modified, buy_time, random. Präfix mit '-' für absteigend "
@@ -421,8 +418,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:227
msgid "rewrite some fields of an existing order saving non-editables"
msgstr ""
-"Umschreiben einiger Felder einer bestehenden Kategorie, um nicht editierbare"
-" Daten zu speichern"
+"Umschreiben einiger Felder einer bestehenden Kategorie, um nicht editierbare "
+"Daten zu speichern"
#: core/docs/drf/viewsets.py:231
msgid "purchase an order"
@@ -438,15 +435,14 @@ msgstr ""
"wird der Kauf mit dem Guthaben des Benutzers abgeschlossen; bei Verwendung "
"von \"force_payment\" wird eine Transaktion ausgelöst."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "eine Bestellung kaufen, ohne ein Konto anzulegen"
#: core/docs/drf/viewsets.py:246
msgid "finalizes the order purchase for a non-registered user."
msgstr ""
-"schließt den Kauf einer Bestellung für einen nicht registrierten Benutzer "
-"ab."
+"schließt den Kauf einer Bestellung für einen nicht registrierten Benutzer ab."
#: core/docs/drf/viewsets.py:254
msgid "add product to order"
@@ -463,8 +459,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:260
msgid "add a list of products to order, quantities will not count"
msgstr ""
-"Fügen Sie eine Liste der zu bestellenden Produkte hinzu, Mengen werden nicht"
-" gezählt"
+"Fügen Sie eine Liste der zu bestellenden Produkte hinzu, Mengen werden nicht "
+"gezählt"
#: core/docs/drf/viewsets.py:261
msgid ""
@@ -533,8 +529,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:303
msgid "rewrite some fields of an existing wishlist saving non-editables"
msgstr ""
-"Umschreiben einiger Felder eines vorhandenen Attributs, um nicht editierbare"
-" Daten zu speichern"
+"Umschreiben einiger Felder eines vorhandenen Attributs, um nicht editierbare "
+"Daten zu speichern"
#: core/docs/drf/viewsets.py:307
msgid "add product to wishlist"
@@ -581,18 +577,29 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtern Sie nach einem oder mehreren Attributnamen/Wertpaaren. \n"
"- **Syntax**: `attr_name=Methode-Wert[;attr2=Methode2-Wert2]...`\n"
-"- **Methoden** (Standardwert ist \"icontains\", wenn nicht angegeben): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
-"- **Wert-Typisierung**: JSON wird zuerst versucht (damit man Listen/Dicts übergeben kann), `true`/`false` für Booleans, Integers, Floats; ansonsten als String behandelt. \n"
-"- Base64**: Präfix \"b64-\" für URL-sichere Base64-Kodierung des Rohwertes. \n"
+"- **Methoden** (Standardwert ist \"icontains\", wenn nicht angegeben): "
+"`iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, "
+"`istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, "
+"`gt`, `gte`, `in`\n"
+"- **Wert-Typisierung**: JSON wird zuerst versucht (damit man Listen/Dicts "
+"übergeben kann), `true`/`false` für Booleans, Integers, Floats; ansonsten "
+"als String behandelt. \n"
+"- Base64**: Präfix \"b64-\" für URL-sichere Base64-Kodierung des "
+"Rohwertes. \n"
"Beispiele: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\", \"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`"
@@ -620,8 +627,7 @@ msgstr "(genau) Kategorie UUID"
#: core/docs/drf/viewsets.py:378
msgid "(list) Tag names, case-insensitive"
-msgstr ""
-"(Liste) Tag-Namen, Groß- und Kleinschreibung wird nicht berücksichtigt"
+msgstr "(Liste) Tag-Namen, Groß- und Kleinschreibung wird nicht berücksichtigt"
#: core/docs/drf/viewsets.py:384
msgid "(gte) Minimum stock price"
@@ -649,10 +655,12 @@ msgstr "(genau) Digital vs. physisch"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Durch Kommata getrennte Liste der Felder, nach denen sortiert werden soll. Präfix mit \"-\" für absteigend. \n"
+"Durch Kommata getrennte Liste der Felder, nach denen sortiert werden soll. "
+"Präfix mit \"-\" für absteigend. \n"
"**Erlaubt:** uuid, rating, name, slug, created, modified, price, random"
#: core/docs/drf/viewsets.py:441
@@ -672,8 +680,8 @@ msgstr "Ein Produkt erstellen"
#: core/docs/drf/viewsets.py:463
msgid "rewrite an existing product, preserving non-editable fields"
msgstr ""
-"Umschreiben eines bestehenden Produkts unter Beibehaltung nicht editierbarer"
-" Felder"
+"Umschreiben eines bestehenden Produkts unter Beibehaltung nicht editierbarer "
+"Felder"
#: core/docs/drf/viewsets.py:478
msgid ""
@@ -721,10 +729,10 @@ msgstr "Autovervollständigung der Adresseingabe"
#: core/docs/drf/viewsets.py:576
msgid "raw data query string, please append with data from geo-IP endpoint"
msgstr ""
-"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
-" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
-"it-it -l ja-jp -l kk-kz -l nl-nl -l pl -l pt-br -l ro-ro -l ru-ru -l zh-hans"
-" -a core -a geo -a payments -a vibes_auth -a blog"
+"docker compose exec app poetry run python manage.py deepl_translate -l en-gb "
+"-l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
+"it-it -l ja-jp -l kk-kz -l nl-nl -l pl -l pt-br -l ro-ro -l ru-ru -l zh-hans "
+"-a core -a geo -a payments -a vibes_auth -a blog"
#: core/docs/drf/viewsets.py:582
msgid "limit the results amount, 1 < limit < 10, default: 5"
@@ -754,8 +762,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:615
msgid "rewrite some fields of an existing feedback saving non-editables"
msgstr ""
-"Umschreiben einiger Felder einer bestehenden Kategorie, um nicht editierbare"
-" Daten zu speichern"
+"Umschreiben einiger Felder einer bestehenden Kategorie, um nicht editierbare "
+"Daten zu speichern"
#: core/docs/drf/viewsets.py:622
msgid "list all order–product relations (simple view)"
@@ -786,7 +794,7 @@ msgid "add or remove feedback on an order–product relation"
msgstr ""
"Feedback zu einer Bestellung-Produkt-Beziehung hinzufügen oder entfernen"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Kein Suchbegriff angegeben."
@@ -834,8 +842,8 @@ msgstr "Attribute"
msgid "Quantity"
msgstr "Menge"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Schnecke"
@@ -850,8 +858,8 @@ msgstr "Unterkategorien einbeziehen"
#: core/filters.py:147
msgid "there must be a category_uuid to use include_subcategories flag"
msgstr ""
-"Es muss eine category_uuid vorhanden sein, um das Flag include_subcategories"
-" zu verwenden"
+"Es muss eine category_uuid vorhanden sein, um das Flag include_subcategories "
+"zu verwenden"
#: core/filters.py:280
msgid "Search (ID, product name or part number)"
@@ -898,220 +906,243 @@ msgstr "Ebene"
msgid "Product UUID"
msgstr "Produkt UUID"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Schlüssel, der im Cache zu suchen oder in den Cache zu legen ist"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Im Cache zu speichernde Daten"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Timeout in Sekunden, um die Daten in den Cache zu stellen"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Zwischengespeicherte Daten"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Camelized JSON-Daten aus der angeforderten URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Nur URLs, die mit http(s):// beginnen, sind zulässig"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Ein Produkt zur Bestellung hinzufügen"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Bestellung {order_uuid} nicht gefunden"
+msgstr "Auftrag {order_uuid} nicht gefunden!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Ein Produkt aus der Bestellung entfernen"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Alle Produkte aus der Bestellung entfernen"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Eine Bestellung kaufen"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr ""
"Bitte geben Sie entweder order_uuid oder order_hr_id an - beide schließen "
"sich gegenseitig aus!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Von der Methode order.buy() kam der falsche Typ: {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Eine Aktion für eine Liste von Produkten in der Bestellung ausführen"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Entfernen/Hinzufügen"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Aktion muss entweder \"Hinzufügen\" oder \"Entfernen\" sein!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Ausführen einer Aktion für eine Liste von Produkten in der Wunschliste"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Bitte geben Sie den Wert `wishlist_uuid` an."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Wishlist {wishlist_uuid} nicht gefunden!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Ein Produkt zur Bestellung hinzufügen"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Wunschzettel {wishlist_uuid} nicht gefunden"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Ein Produkt aus der Bestellung entfernen"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Ein Produkt aus der Bestellung entfernen"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Ein Produkt aus der Bestellung entfernen"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Eine Bestellung kaufen"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
"Bitte senden Sie die Attribute als String im Format attr1=wert1,attr2=wert2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr ""
+"Feedback zu einer Bestellung-Produkt-Beziehung hinzufügen oder entfernen"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Aktion muss entweder `Add` oder `remove` sein!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Bestellprodukt {order_product_uuid} nicht gefunden!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Vom Benutzer angegebene Originaladresse"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} existiert nicht: {uuid}"
+msgstr "{name} existiert nicht: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Der Grenzwert muss zwischen 1 und 10 liegen."
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - funktioniert wie ein Zauber"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Attribute"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Gruppierte Attribute"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Gruppen von Attributen"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Kategorien"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Marken"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Kategorien"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Markup Percentage"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Welche Attribute und Werte können für die Filterung dieser Kategorie "
"verwendet werden."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
-msgstr ""
-"Mindest- und Höchstpreise für Produkte in dieser Kategorie, sofern "
-"verfügbar."
-
#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
+msgstr ""
+"Mindest- und Höchstpreise für Produkte in dieser Kategorie, sofern verfügbar."
+
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tags für diese Kategorie"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Produkte in dieser Kategorie"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Anbieter"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Breitengrad (Y-Koordinate)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Längengrad (X-Koordinate)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Wie"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr ""
"Bewertungswert von 1 bis einschließlich 10 oder 0, wenn nicht festgelegt."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Stellt das Feedback eines Benutzers dar."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Benachrichtigungen"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Download-Url für dieses Bestellprodukt, falls zutreffend"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Eine Liste der bestellten Produkte in dieser Reihenfolge"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Rechnungsadresse"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1119,746 +1150,740 @@ msgstr ""
"Lieferadresse für diese Bestellung, leer lassen, wenn sie mit der "
"Rechnungsadresse übereinstimmt oder nicht zutrifft"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Gesamtpreis für diese Bestellung"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Gesamtmenge der bestellten Produkte"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Sind alle Produkte in der Bestellung digital"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Vorgänge für diesen Auftrag"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Bestellungen"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Bild URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Bilder des Produkts"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Kategorie"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Rückmeldungen"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Marke"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Attribut-Gruppen"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Preis"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Menge"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Anzahl der Rückmeldungen"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Produkte"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Promocodes"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Zum Verkauf stehende Produkte"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Werbeaktionen"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Anbieter"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Produkt"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Auf dem Wunschzettel stehende Produkte"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Wunschzettel"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Markierte Produkte"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Produkt-Tags"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Markierte Kategorien"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Kategorien'-Tags"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Name des Projekts"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Unternehmen E-Mail"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Name des Unternehmens"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Adresse des Unternehmens"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Telefonnummer des Unternehmens"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"E-Mail von\", muss manchmal anstelle des Host-Benutzerwerts verwendet werden"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "E-Mail-Host-Benutzer"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Höchstbetrag für die Zahlung"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Mindestbetrag für die Zahlung"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Analytische Daten"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Advertisement data"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Konfiguration"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Sprachcode"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Name der Sprache"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Sprachflagge, falls vorhanden :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Eine Liste der unterstützten Sprachen abrufen"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Suchergebnisse für Produkte"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Suchergebnisse für Produkte"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Elternteil dieser Gruppe"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Übergeordnete Attributgruppe"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Name der Attributgruppe"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Attribut-Gruppe"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Speichert Anmeldeinformationen und Endpunkte, die für die API-Kommunikation "
"des Anbieters erforderlich sind"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Informationen zur Authentifizierung"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr ""
"Definieren Sie den Aufschlag für Produkte, die von diesem Lieferanten "
"bezogen werden"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Prozentualer Aufschlag des Lieferanten"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Name dieses Anbieters"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Name des Anbieters"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Interner Tag-Identifikator für das Produkt-Tag"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Tag name"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Benutzerfreundlicher Name für den Produktanhänger"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Tag-Anzeigename"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Produkt-Tag"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "Kategorie-Tag"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "Kategorie-Tags"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Laden Sie ein Bild hoch, das diese Kategorie repräsentiert"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Kategorie Bild"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr ""
"Definieren Sie einen prozentualen Aufschlag für Produkte in dieser Kategorie"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr ""
"Übergeordneter dieser Kategorie, um eine hierarchische Struktur zu bilden"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Übergeordnete Kategorie"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Name der Kategorie"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Geben Sie einen Namen für diese Kategorie an"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Fügen Sie eine detaillierte Beschreibung für diese Kategorie hinzu"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Beschreibung der Kategorie"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "Tags, die helfen, diese Kategorie zu beschreiben oder zu gruppieren"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Priorität"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Name dieser Marke"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Markenname"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Laden Sie ein Logo hoch, das diese Marke repräsentiert"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Marke kleines Bild"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Laden Sie ein großes Logo hoch, das diese Marke repräsentiert"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Großes Image der Marke"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Fügen Sie eine detaillierte Beschreibung der Marke hinzu"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Beschreibung der Marke"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr ""
"Optionale Kategorien, mit denen diese Marke in Verbindung gebracht wird"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Kategorien"
-#: core/models.py:330
+#: core/models.py:515
+msgid "the vendor supplying this product stock"
+msgstr "Der Verkäufer, der dieses Produkt liefert, hat folgende Bestände"
+
+#: core/models.py:516
+msgid "associated vendor"
+msgstr "Zugehöriger Anbieter"
+
+#: core/models.py:520
+msgid "final price to the customer after markups"
+msgstr "Endpreis für den Kunden nach Aufschlägen"
+
+#: core/models.py:521
+msgid "selling price"
+msgstr "Verkaufspreis"
+
+#: core/models.py:526
+msgid "the product associated with this stock entry"
+msgstr "Das mit diesem Bestandseintrag verbundene Produkt"
+
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Zugehöriges Produkt"
+
+#: core/models.py:534
+msgid "the price paid to the vendor for this product"
+msgstr "Der an den Verkäufer gezahlte Preis für dieses Produkt"
+
+#: core/models.py:535
+msgid "vendor purchase price"
+msgstr "Einkaufspreis des Verkäufers"
+
+#: core/models.py:539
+msgid "available quantity of the product in stock"
+msgstr "Verfügbare Menge des Produkts auf Lager"
+
+#: core/models.py:540
+msgid "quantity in stock"
+msgstr "Vorrätige Menge"
+
+#: core/models.py:544
+msgid "vendor-assigned SKU for identifying the product"
+msgstr "Vom Hersteller zugewiesene SKU zur Identifizierung des Produkts"
+
+#: core/models.py:545
+msgid "vendor sku"
+msgstr "SKU des Verkäufers"
+
+#: core/models.py:551
+msgid "digital file associated with this stock if applicable"
+msgstr "Digitale Datei, die mit diesem Bestand verbunden ist, falls zutreffend"
+
+#: core/models.py:552
+msgid "digital file"
+msgstr "Digitale Datei"
+
+#: core/models.py:561
+msgid "stock entries"
+msgstr "Bestandseinträge"
+
+#: core/models.py:605
msgid "category this product belongs to"
msgstr "Kategorie, zu der dieses Produkt gehört"
-#: core/models.py:339
+#: core/models.py:614
msgid "optionally associate this product with a brand"
msgstr "Optional können Sie dieses Produkt mit einer Marke verknüpfen"
-#: core/models.py:345
+#: core/models.py:620
msgid "tags that help describe or group this product"
msgstr "Tags, die helfen, dieses Produkt zu beschreiben oder zu gruppieren"
-#: core/models.py:350
+#: core/models.py:625
msgid "indicates whether this product is digitally delivered"
msgstr "Gibt an, ob dieses Produkt digital geliefert wird"
-#: core/models.py:351
+#: core/models.py:626
msgid "is product digital"
msgstr "Ist das Produkt digital"
-#: core/models.py:357
+#: core/models.py:632
msgid "provide a clear identifying name for the product"
-msgstr ""
-"Geben Sie einen eindeutigen Namen zur Identifizierung des Produkts an."
+msgstr "Geben Sie einen eindeutigen Namen zur Identifizierung des Produkts an."
-#: core/models.py:358
+#: core/models.py:633
msgid "product name"
msgstr "Name des Produkts"
-#: core/models.py:363 core/models.py:579
+#: core/models.py:638 core/models.py:955
msgid "add a detailed description of the product"
msgstr "Fügen Sie eine detaillierte Beschreibung des Produkts hinzu"
-#: core/models.py:364
+#: core/models.py:639
msgid "product description"
msgstr "Beschreibung des Produkts"
-#: core/models.py:371
+#: core/models.py:646
msgid "part number for this product"
msgstr "Teilenummer für dieses Produkt"
-#: core/models.py:372
+#: core/models.py:647
msgid "part number"
msgstr "Teilnummer"
-#: core/models.py:451
+#: core/models.py:753
msgid "category of this attribute"
msgstr "Kategorie dieses Attributs"
-#: core/models.py:459
+#: core/models.py:761
msgid "group of this attribute"
msgstr "Gruppe dieses Attributs"
-#: core/models.py:465
+#: core/models.py:767
msgid "string"
msgstr "Zeichenfolge"
-#: core/models.py:466
+#: core/models.py:768
msgid "integer"
msgstr "Integer"
-#: core/models.py:467
+#: core/models.py:769
msgid "float"
msgstr "Schwimmer"
-#: core/models.py:468
+#: core/models.py:770
msgid "boolean"
msgstr "Boolesche"
-#: core/models.py:469
+#: core/models.py:771
msgid "array"
msgstr "Array"
-#: core/models.py:470
+#: core/models.py:772
msgid "object"
msgstr "Objekt"
-#: core/models.py:472
+#: core/models.py:774
msgid "type of the attribute's value"
msgstr "Typ des Attributwerts"
-#: core/models.py:473
+#: core/models.py:775
msgid "value type"
msgstr "Werttyp"
-#: core/models.py:478
+#: core/models.py:780
msgid "name of this attribute"
msgstr "Name dieses Attributs"
-#: core/models.py:479
+#: core/models.py:781
msgid "attribute's name"
msgstr "Name des Attributs"
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
msgid "attribute"
msgstr "Attribut"
-#: core/models.py:498
+#: core/models.py:823
msgid "attribute of this value"
msgstr "Attribut dieses Wertes"
-#: core/models.py:506
+#: core/models.py:831
msgid "the specific product associated with this attribute's value"
msgstr ""
"Das spezifische Produkt, das mit dem Wert dieses Attributs verbunden ist"
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Zugehöriges Produkt"
-
-#: core/models.py:512
+#: core/models.py:837
msgid "the specific value for this attribute"
msgstr "Der spezifische Wert für dieses Attribut"
-#: core/models.py:528
+#: core/models.py:871
msgid "provide alternative text for the image for accessibility"
msgstr ""
"Geben Sie einen alternativen Text für das Bild an, um die Barrierefreiheit "
"zu gewährleisten."
-#: core/models.py:529
+#: core/models.py:872
msgid "image alt text"
msgstr "Bild-Alt-Text"
-#: core/models.py:532
+#: core/models.py:875
msgid "upload the image file for this product"
msgstr "Laden Sie die Bilddatei für dieses Produkt hoch"
-#: core/models.py:533 core/models.py:558
+#: core/models.py:876 core/models.py:901
msgid "product image"
msgstr "Produktbild"
-#: core/models.py:539
+#: core/models.py:882
msgid "determines the order in which images are displayed"
msgstr "Legt die Reihenfolge fest, in der die Bilder angezeigt werden"
-#: core/models.py:540
+#: core/models.py:883
msgid "display priority"
msgstr "Priorität anzeigen"
-#: core/models.py:545
+#: core/models.py:888
msgid "the product that this image represents"
msgstr "Das Produkt, das dieses Bild darstellt"
-#: core/models.py:559
+#: core/models.py:902
msgid "product images"
msgstr "Produktbilder"
-#: core/models.py:567
+#: core/models.py:943
msgid "percentage discount for the selected products"
msgstr "Prozentualer Rabatt für die ausgewählten Produkte"
-#: core/models.py:568
+#: core/models.py:944
msgid "discount percentage"
msgstr "Prozentsatz der Ermäßigung"
-#: core/models.py:573
+#: core/models.py:949
msgid "provide a unique name for this promotion"
msgstr "Geben Sie einen eindeutigen Namen für diese Aktion an"
-#: core/models.py:574
+#: core/models.py:950
msgid "promotion name"
msgstr "Name der Aktion"
-#: core/models.py:580
+#: core/models.py:956
msgid "promotion description"
msgstr "Promotion description"
-#: core/models.py:585
+#: core/models.py:961
msgid "select which products are included in this promotion"
msgstr "Wählen Sie aus, welche Produkte in dieser Aktion enthalten sind"
-#: core/models.py:586
+#: core/models.py:962
msgid "included products"
msgstr "Enthaltene Produkte"
-#: core/models.py:590
+#: core/models.py:966
msgid "promotion"
msgstr "Förderung"
-#: core/models.py:605
-msgid "the vendor supplying this product stock"
-msgstr "Der Verkäufer, der dieses Produkt liefert, hat folgende Bestände"
-
-#: core/models.py:606
-msgid "associated vendor"
-msgstr "Zugehöriger Anbieter"
-
-#: core/models.py:610
-msgid "final price to the customer after markups"
-msgstr "Endpreis für den Kunden nach Aufschlägen"
-
-#: core/models.py:611
-msgid "selling price"
-msgstr "Verkaufspreis"
-
-#: core/models.py:616
-msgid "the product associated with this stock entry"
-msgstr "Das mit diesem Bestandseintrag verbundene Produkt"
-
-#: core/models.py:624
-msgid "the price paid to the vendor for this product"
-msgstr "Der an den Verkäufer gezahlte Preis für dieses Produkt"
-
-#: core/models.py:625
-msgid "vendor purchase price"
-msgstr "Einkaufspreis des Verkäufers"
-
-#: core/models.py:629
-msgid "available quantity of the product in stock"
-msgstr "Verfügbare Menge des Produkts auf Lager"
-
-#: core/models.py:630
-msgid "quantity in stock"
-msgstr "Vorrätige Menge"
-
-#: core/models.py:634
-msgid "vendor-assigned SKU for identifying the product"
-msgstr "Vom Hersteller zugewiesene SKU zur Identifizierung des Produkts"
-
-#: core/models.py:635
-msgid "vendor sku"
-msgstr "SKU des Verkäufers"
-
-#: core/models.py:641
-msgid "digital file associated with this stock if applicable"
-msgstr ""
-"Digitale Datei, die mit diesem Bestand verbunden ist, falls zutreffend"
-
-#: core/models.py:642
-msgid "digital file"
-msgstr "Digitale Datei"
-
-#: core/models.py:651
-msgid "stock entries"
-msgstr "Bestandseinträge"
-
-#: core/models.py:660
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Produkte, die der Benutzer als gewünscht markiert hat"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Benutzer, dem diese Wunschliste gehört"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Besitzer der Wishlist"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Wunschzettel"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} existiert nicht: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Dokumentarfilm"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Dokumentarfilme"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Ungelöst"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Adresszeile für den Kunden"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Adresszeile"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Straße"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Bezirk"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Stadt"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Region"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Postleitzahl"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Land"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolocation Point(Längengrad, Breitengrad)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Vollständige JSON-Antwort vom Geocoder für diese Adresse"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Gespeicherte JSON-Antwort vom Geokodierungsdienst"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Adresse"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adressen"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr ""
"Einzigartiger Code, den ein Nutzer zum Einlösen eines Rabatts verwendet"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Kennung des Promo-Codes"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr ""
-"Fester Rabattbetrag, der angewandt wird, wenn kein Prozentsatz verwendet "
-"wird"
+"Fester Rabattbetrag, der angewandt wird, wenn kein Prozentsatz verwendet wird"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Fester Rabattbetrag"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Prozentualer Rabatt, wenn der Festbetrag nicht verwendet wird"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Prozentualer Rabatt"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Zeitstempel, wann der Promocode abläuft"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Ende der Gültigkeitsdauer"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Zeitstempel, ab dem dieser Promocode gültig ist"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Beginn der Gültigkeitsdauer"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Zeitstempel, wann der Promocode verwendet wurde, leer, wenn noch nicht "
"verwendet"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Zeitstempel der Verwendung"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Diesem Promocode zugewiesener Benutzer, falls zutreffend"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Zugewiesener Benutzer"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Promo-Code"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Promo-Codes"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1866,142 +1891,152 @@ msgstr ""
"Es sollte nur eine Art von Rabatt definiert werden (Betrag oder "
"Prozentsatz), aber nicht beides oder keines von beiden."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Promocode wurde bereits verwendet"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Ungültiger Rabatttyp für Promocode {self.uuid}"
+msgstr "Ungültiger Rabatttyp für den Promocode {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "Die für diese Bestellung verwendete Rechnungsadresse"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Optionaler Promo-Code für diese Bestellung"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Angewandter Promo-Code"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "Die für diese Bestellung verwendete Lieferadresse"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Lieferadresse"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Aktueller Status des Auftrags in seinem Lebenszyklus"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Status der Bestellung"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"JSON-Struktur der Benachrichtigungen, die den Benutzern angezeigt werden "
"sollen; in der Admin-UI wird die Tabellenansicht verwendet"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "JSON-Darstellung der Auftragsattribute für diesen Auftrag"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "Der Benutzer, der die Bestellung aufgegeben hat"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Benutzer"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Der Zeitstempel, zu dem der Auftrag abgeschlossen wurde"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Zeit kaufen"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Ein von Menschen lesbarer Identifikator für den Auftrag"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "menschenlesbare ID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Bestellung"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Ein Benutzer darf immer nur einen schwebenden Auftrag haben!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr ""
"Sie können keine Produkte zu einem Auftrag hinzufügen, der nicht in "
"Bearbeitung ist."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Sie können keine inaktiven Produkte zur Bestellung hinzufügen"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "Sie können nicht mehr Produkte hinzufügen, als auf Lager sind"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
"Sie können keine Produkte aus einer Bestellung entfernen, die nicht in "
"Bearbeitung ist."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} existiert nicht mit Abfrage <{query}>"
+msgstr "{name} existiert nicht mit Abfrage <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Promocode existiert nicht"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
"Sie können nur physische Produkte mit angegebener Lieferadresse kaufen!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Adresse ist nicht vorhanden"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"Sie können im Moment nicht kaufen, bitte versuchen Sie es in ein paar "
"Minuten erneut."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Ungültiger Force-Wert"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Sie können keine leere Bestellung kaufen!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+"Sie können keine Produkte aus einer Bestellung entfernen, die nicht in "
+"Bearbeitung ist."
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Ein Benutzer ohne Guthaben kann nicht mit Guthaben kaufen!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Unzureichende Mittel für die Ausführung des Auftrags"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -2009,124 +2044,127 @@ msgstr ""
"Sie können nicht ohne Registrierung kaufen, bitte geben Sie die folgenden "
"Informationen an: Kundenname, Kunden-E-Mail, Kunden-Telefonnummer"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"Ungültige Zahlungsmethode: {payment_method} von {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr ""
"Der Preis, den der Kunde zum Zeitpunkt des Kaufs für dieses Produkt bezahlt "
"hat"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Einkaufspreis zum Zeitpunkt der Bestellung"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "Interne Kommentare für Administratoren zu diesem bestellten Produkt"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Interne Kommentare"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Benutzerbenachrichtigungen"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "JSON-Darstellung der Attribute dieses Artikels"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Bestellte Produktattribute"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Verweis auf den übergeordneten Auftrag, der dieses Produkt enthält"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Übergeordneter Auftrag"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Das spezifische Produkt, das mit dieser Auftragszeile verbunden ist"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Menge dieses spezifischen Produkts in der Bestellung"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Produktmenge"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Aktueller Status dieses Produkts im Auftrag"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Status der Produktlinie"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Das Bestellprodukt muss eine zugehörige Bestellung haben!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "falsche Aktion für die Rückmeldung angegeben: {action}"
+msgstr "Falsche Aktion für Feedback angegeben: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
"Sie können keine Produkte aus einer Bestellung entfernen, die nicht in "
"Bearbeitung ist."
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Herunterladen"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Herunterladen"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr ""
"Sie können kein digitales Asset für eine nicht abgeschlossene Bestellung "
"herunterladen"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Kommentare der Nutzer über ihre Erfahrungen mit dem Produkt"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Kommentare zum Feedback"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
-"Verweist auf das spezifische Produkt in einer Bestellung, auf das sich diese"
-" Rückmeldung bezieht"
+"Verweist auf das spezifische Produkt in einer Bestellung, auf das sich diese "
+"Rückmeldung bezieht"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Produkt zur Bestellung"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Vom Benutzer zugewiesene Bewertung für das Produkt"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Produktbewertung"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Rückmeldung"
@@ -2137,13 +2175,13 @@ msgstr ""
"Sie müssen einen Kommentar, eine Bewertung und eine Produktnummer angeben, "
"um eine Bewertung abzugeben."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Fehler bei der Erstellung des Promocodes: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2152,7 +2190,7 @@ msgid "order confirmation"
msgstr "Bestätigung der Bestellung"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2169,7 +2207,8 @@ msgstr "Hallo %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Vielen Dank für Ihre Bestellung #%(order.pk)s! Wir freuen uns, Ihnen "
@@ -2177,14 +2216,14 @@ msgstr ""
"Nachfolgend finden Sie die Details Ihrer Bestellung:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Insgesamt"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2204,23 +2243,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Mit freundlichen Grüßen,
das %(config.PROJECT_NAME)s Team"
+msgstr "Mit freundlichen Grüßen,
das %(config.PROJECT_NAME)s-Team"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Alle Rechte vorbehalten"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Bestellung Geliefert"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hallo %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2229,7 +2268,7 @@ msgstr ""
"Wir haben Ihre Bestellung erfolgreich bearbeitet №%(order_uuid)s! "
"Nachstehend finden Sie die Details Ihrer Bestellung:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2237,12 +2276,12 @@ msgstr ""
"zusätzliche\n"
" Informationen"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Wert"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2251,10 +2290,10 @@ msgstr ""
"Wenn Sie Fragen haben, wenden Sie sich bitte an unseren Support unter "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Mit freundlichen Grüßen,
das %(project_name)s Team"
+msgstr "Mit freundlichen Grüßen,
das %(project_name)s-Team"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2263,7 +2302,8 @@ msgstr "Schlüssel"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Vielen Dank für Ihre Bestellung! Wir freuen uns, Ihren Kauf zu bestätigen. "
@@ -2283,7 +2323,7 @@ msgstr "Ihre Bestellung wird an die folgende Adresse geliefert:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Mit freundlichen Grüßen,
das %(config.PROJECT_NAME)s Team"
+msgstr "Mit freundlichen Grüßen,
Das %(config.PROJECT_NAME)s-Team"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2300,33 +2340,22 @@ msgstr "Sowohl Daten als auch Timeout sind erforderlich"
#: core/utils/caching.py:43
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
-msgstr ""
-"Ungültiger Timeout-Wert, er muss zwischen 0 und 216000 Sekunden liegen"
-
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} muss Modell sein"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} muss ein Listenobjekt sein"
+msgstr "Ungültiger Timeout-Wert, er muss zwischen 0 und 216000 Sekunden liegen"
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Kontakt initiiert"
+msgstr "{config.PROJECT_NAME} | Kontakt eingeleitet"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Auftragsbestätigung"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME} | Auftrag ausgeliefert"
+msgstr "{config.PROJECT_NAME} | Bestellung ausgeliefert"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2347,15 +2376,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Ungültiges Rufnummernformat"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Sie können das digitale Asset nur einmal herunterladen"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "Favicon nicht gefunden"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
-msgstr "Geokodierungsfehler: {e}"
+msgstr "Geocodierungsfehler: {e}"
diff --git a/core/locale/en_GB/LC_MESSAGES/django.mo b/core/locale/en_GB/LC_MESSAGES/django.mo
index 5b92c417..ad23a4ca 100644
Binary files a/core/locale/en_GB/LC_MESSAGES/django.mo and b/core/locale/en_GB/LC_MESSAGES/django.mo differ
diff --git a/core/locale/en_GB/LC_MESSAGES/django.po b/core/locale/en_GB/LC_MESSAGES/django.po
index f745b8ec..fde33fa9 100644
--- a/core/locale/en_GB/LC_MESSAGES/django.po
+++ b/core/locale/en_GB/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -17,118 +17,116 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Unique ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr "Unique ID is used to surely identify any database object"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Is Active"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"If set to false, this object can't be seen by users without needed permission"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Created"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "When the object first appeared on the database"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modified"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "When the object was last edited"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Translations"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "General"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relations"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadata"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Timestamps"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr "Activate selected %(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s activated successfully!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Selected items have been activated!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
msgstr "Deactivate selected %(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s deactivated successfully."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Selected items have been deactivated!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Attribute Value"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Attribute Values"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Image"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Images"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stock"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Stocks"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Order Product"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Order Products"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Children"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Config"
@@ -180,7 +178,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Successful"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Cache I/O"
@@ -204,7 +202,7 @@ msgstr "Get application's exposable parameters"
msgid "send a message to the support team"
msgstr "Send a message to the support team"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Request a CORSed URL. Only https allowed."
@@ -414,7 +412,7 @@ msgstr ""
"completed using the user's balance; If `force_payment` is used, a "
"transaction is initiated."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "purchase an order without account creation"
@@ -744,7 +742,7 @@ msgstr "delete an order–product relation"
msgid "add or remove feedback on an order–product relation"
msgstr "add or remove feedback on an order–product relation"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "No search term provided."
@@ -792,8 +790,8 @@ msgstr "Attributes"
msgid "Quantity"
msgstr "Quantity"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229 core/models.py:307
-#: core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Slug"
@@ -854,100 +852,109 @@ msgstr "Level"
msgid "Product UUID"
msgstr "Product UUID"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Key to look for in or set into the cache"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Data to store in cache"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Timeout in seconds to set the data for into the cache"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Cached data"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Camelized JSON data from the requested URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Only URLs starting with http(s):// are allowed"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Add a product to the order"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Order {order_uuid} not found"
+msgstr "Order {order_uuid} not found!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Remove all products from the order"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Buy an order"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Please provide either order_uuid or order_hr_id - mutually exclusive!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Wrong type came from order.buy() method: {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Perform an action on a list of products in the order"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Remove/Add"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Action must be either \"add\" or \"remove\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Perform an action on a list of products in the wishlist"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Please provide `wishlist_uuid` value."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Wishlist {wishlist_uuid} not found!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Add a product to the order"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Wishlist {wishlist_uuid} not found"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Buy an order"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
"please send the attributes as the string formatted like attr1=value1,"
"attr2=value2"
@@ -955,113 +962,128 @@ msgstr ""
"Please send the attributes as the string formatted like attr1=value1,"
"attr2=value2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Add or delete a feedback for the orderproduct"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Action must be either `add` or `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Orderproduct {order_product_uuid} not found!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Original address string provided by the user"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} does not exist: {uuid}"
+msgstr "{name} does not exist: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Limit must be between 1 and 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - works like a charm"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Attributes"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Grouped attributes"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Groups of attributes"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Categories"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Brands"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Categories"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Markup Percentage"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr "Which attributes and values can be used for filtering this category."
-#: core/graphene/object_types.py:133
+#: core/graphene/object_types.py:135
msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Minimum and maximum prices for products in this category, if available."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tags for this category"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Products in this category"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Vendors"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Latitude (Y coordinate)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Longitude (X coordinate)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Comment"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Rating value from 1 to 10, inclusive, or 0 if not set."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Represents feedback from a user."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Notifications"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Download url for this order product if applicable"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "A list of order products in this order"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Billing address"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1069,728 +1091,726 @@ msgstr ""
"Shipping address for this order, leave blank if same as billing address or "
"if not applicable"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Total price of this order"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Total quantity of products in order"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Are all of the products in the order digital"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transactions for this order"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Orders"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Image URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Product's images"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Category"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Feedbacks"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Brand"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Attribute groups"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Price"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Quantity"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Number of feedbacks"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Products"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Promocodes"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Products on sale"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promotions"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Vendor"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Product"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Wishlisted products"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Wishlists"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Tagged products"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Product tags"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Tagged categories"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Categories' tags"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Project name"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Company Email"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Company Name"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Company Address"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Company Phone Number"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr "'email from', sometimes it must be used instead of host user value"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Email host user"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Maximum amount for payment"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Minimum amount for payment"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Analytics data"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Advertisement data"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configuration"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Language code"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Language name"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Language flag, if exists :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Get a list of supported languages"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Products search results"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Products search results"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Parent of this group"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Parent attribute group"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Attribute group's name"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Attribute group"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Stores credentials and endpoints required for vendor's API communication"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Authentication info"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Define the markup for products retrieved from this vendor"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Vendor markup percentage"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Name of this vendor"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Vendor name"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Internal tag identifier for the product tag"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Tag name"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "User-friendly name for the product tag"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Tag display name"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Product tag"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "category tag"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "category tags"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Upload an image representing this category"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Category image"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Define a markup percentage for products in this category"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Parent of this category to form a hierarchical structure"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Parent category"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Category name"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Provide a name for this category"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Add a detailed description for this category"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Category description"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "tags that help describe or group this category"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Priority"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Name of this brand"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Brand name"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Upload a logo representing this brand"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Brand small image"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Upload a big logo representing this brand"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Brand big image"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Add a detailed description of the brand"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Brand description"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Optional categories that this brand is associated with"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Categories"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Category this product belongs to"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Optionally associate this product with a brand"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Tags that help describe or group this product"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Indicates whether this product is digitally delivered"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Is product digital"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Provide a clear identifying name for the product"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Product name"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Add a detailed description of the product"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Product description"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Part number for this product"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Part number"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Category of this attribute"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Group of this attribute"
-
-#: core/models.py:465
-msgid "string"
-msgstr "String"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Integer"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Float"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Boolean"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Array"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Object"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Type of the attribute's value"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Value type"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Name of this attribute"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Attribute's name"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Attribute"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Attribute of this value"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "The specific product associated with this attribute's value"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617 core/models.py:1361
-msgid "associated product"
-msgstr "Associated product"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "The specific value for this attribute"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "Provide alternative text for the image for accessibility"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Image alt text"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Upload the image file for this product"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Product image"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Determines the order in which images are displayed"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Display priority"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "The product that this image represents"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Product images"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Percentage discount for the selected products"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Discount percentage"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Provide a unique name for this promotion"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Promotion name"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Promotion description"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Select which products are included in this promotion"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Included products"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Promotion"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "The vendor supplying this product stock"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Associated vendor"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Final price to the customer after markups"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Selling price"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "The product associated with this stock entry"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Associated product"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "The price paid to the vendor for this product"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Vendor purchase price"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Available quantity of the product in stock"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Quantity in stock"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "Vendor-assigned SKU for identifying the product"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "Vendor's SKU"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Digital file associated with this stock if applicable"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Digital file"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Stock entries"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Category this product belongs to"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Optionally associate this product with a brand"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Tags that help describe or group this product"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Indicates whether this product is digitally delivered"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Is product digital"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Provide a clear identifying name for the product"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Product name"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Add a detailed description of the product"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Product description"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Part number for this product"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Part number"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Category of this attribute"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Group of this attribute"
+
+#: core/models.py:767
+msgid "string"
+msgstr "String"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Integer"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Float"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Boolean"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Array"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Object"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Type of the attribute's value"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Value type"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Name of this attribute"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Attribute's name"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Attribute"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Attribute of this value"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "The specific product associated with this attribute's value"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "The specific value for this attribute"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Provide alternative text for the image for accessibility"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Image alt text"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Upload the image file for this product"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Product image"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Determines the order in which images are displayed"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Display priority"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "The product that this image represents"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Product images"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Percentage discount for the selected products"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Discount percentage"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Provide a unique name for this promotion"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Promotion name"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Promotion description"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Select which products are included in this promotion"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Included products"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Promotion"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Products that the user has marked as wanted"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "User who owns this wishlist"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Wishlist's Owner"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Wishlist"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} does not exist: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documentary"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentaries"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Unresolved"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Address line for the customer"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Address line"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Street"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "District"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "City"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Region"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Postal code"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Country"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolocation Point(Longitude, Latitude)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Full JSON response from geocoder for this address"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Stored JSON response from the geocoding service"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Address"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adresses"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Unique code used by a user to redeem a discount"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Promo code identifier"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Fixed discount amount applied if percent is not used"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Fixed discount amount"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Percentage discount applied if fixed amount is not used"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Percentage discount"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Timestamp when the promocode expires"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "End validity time"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Timestamp from which this promocode is valid"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Start validity time"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr "Timestamp when the promocode was used, blank if not used yet"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Usage timestamp"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "User assigned to this promocode if applicable"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Assigned user"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Promo code"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Promo codes"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1798,136 +1818,144 @@ msgstr ""
"Only one type of discount should be defined (amount or percent), but not "
"both or neither."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Promocode has been used already"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Invalid discount type for promocode {self.uuid}"
+msgstr "Invalid discount type for promocode {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "The billing address used for this order"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Optional promo code applied to this order"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Applied promo code"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "The shipping address used for this order"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Shipping address"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Current status of the order in its lifecycle"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Order status"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"JSON structure of notifications to display to users, in admin UI the table-"
"view is used"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "JSON representation of order attributes for this order"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "The user who placed the order"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "User"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "The timestamp when the order was finalized"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Buy time"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "A human-readable identifier for the order"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "human-readable ID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Order"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "A user must have only one pending order at a time!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "You cannot add products to an order that is not a pending one"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "You cannot add inactive products to order"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "You cannot add more products than available in stock"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "You cannot remove products from an order that is not a pending one"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} does not exist with query <{query}>"
+msgstr "{name} does not exist with query <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Promocode does not exist"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "You can only buy physical products with shipping address specified!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Address does not exist"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"You can not purchase at this moment, please try again in a few minutes."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Invalid force value"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "You cannot purchase an empty order!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "You cannot buy an order without a user!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "A user without a balance cannot buy with balance!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Insufficient funds to complete the order"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1935,116 +1963,120 @@ msgstr ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"Invalid payment method: {payment_method} from {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "The price paid by the customer for this product at purchase time"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Purchase price at order time"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "Internal comments for admins about this ordered product"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Internal comments"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "User notifications"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "JSON representation of this item's attributes"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Ordered product attributes"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Reference to the parent order that contains this product"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Parent order"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "The specific product associated with this order line"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Quantity of this specific product in the order"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Product quantity"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Current status of this product in the order"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Product line status"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Orderproduct must have an associated order!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "wrong action specified for feedback: {action}"
+msgstr "Wrong action specified for feedback: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "you cannot feedback an order which is not received"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Download"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Downloads"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "You can not download a digital asset for a non-finished order"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "User-provided comments about their experience with the product"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Feedback comments"
-#: core/models.py:1490
+#: core/models.py:1970
msgid "references the specific product in an order that this feedback is about"
msgstr ""
"References the specific product in an order that this feedback is about"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Related order product"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "User-assigned rating for the product"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Product rating"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Feedback"
@@ -2054,13 +2086,13 @@ msgid ""
msgstr ""
"you must provide a comment, rating, and order product uuid to add feedback."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Error during promocode creation: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2069,7 +2101,7 @@ msgid "order confirmation"
msgstr "Order Confirmation"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2094,14 +2126,14 @@ msgstr ""
"have taken your order into work. Below are the details of your order:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Total"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2124,20 +2156,20 @@ msgid "best regards,
the %(config.PROJECT_NAME)s team"
msgstr "Best regards,
the %(config.PROJECT_NAME)s team"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "All rights reserved"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Order Delivered"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hello %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2146,7 +2178,7 @@ msgstr ""
"We have successfully processed your order №%(order_uuid)s! Below are the "
"details of your order:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2154,12 +2186,12 @@ msgstr ""
"additional\n"
" information"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Value"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2168,7 +2200,7 @@ msgstr ""
"If you have any questions, feel free to contact our support at "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Best regards,
the %(project_name)s team"
@@ -2201,7 +2233,7 @@ msgstr "Your order will be delivered to the following address:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Best regards,
the %(config.PROJECT_NAME)s team"
+msgstr "Best regards,
The %(config.PROJECT_NAME)s team"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2220,27 +2252,17 @@ msgstr "Both data and timeout are required"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "Invalid timeout value, it must be between 0 and 216000 seconds"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} must be model"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} must be list object"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Contact Us initiated"
+msgstr "{config.PROJECT_NAME} | contact us initiated"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Order Confirmation"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr "{config.PROJECT_NAME} | Order Delivered"
@@ -2256,45 +2278,22 @@ msgstr "NOMINATIM_URL parameter must be configured!"
#: core/validators.py:16
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
-msgstr "Image dimensions should not exceed w{max_width} x h{max_height} pixels"
+msgstr ""
+"Image dimensions should not exceed w{max_width} x h{max_height} pixels!"
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "Invalid phone number format"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "You can only download the digital asset once"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon not found"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Geocoding error: {e}"
-
-#~ msgid "I18N"
-#~ msgstr "Internationalization"
-
-#~ msgid "name"
-#~ msgstr "Name"
-
-#~ msgid "rating"
-#~ msgstr "Rating"
-
-#~ msgid "is business"
-#~ msgstr "Is Business"
-
-#~ msgid "brand slug"
-#~ msgstr "Brand's slug"
-
-#~ msgid "basic info"
-#~ msgstr "Basic Info"
-
-#~ msgid "important dates"
-#~ msgstr "Important Dates"
-
-#~ msgid "eVibes Engine"
-#~ msgstr "eVibes Engine"
diff --git a/core/locale/en_US/LC_MESSAGES/django.mo b/core/locale/en_US/LC_MESSAGES/django.mo
index fb9ef2f3..76bb51d8 100644
Binary files a/core/locale/en_US/LC_MESSAGES/django.mo and b/core/locale/en_US/LC_MESSAGES/django.mo differ
diff --git a/core/locale/en_US/LC_MESSAGES/django.po b/core/locale/en_US/LC_MESSAGES/django.po
index 640e7f77..9e0a2164 100644
--- a/core/locale/en_US/LC_MESSAGES/django.po
+++ b/core/locale/en_US/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,120 +13,116 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Unique ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr "Unique ID is used to surely identify any database object"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Is Active"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
-"If set to false, this object can't be seen by users without needed "
-"permission"
+"If set to false, this object can't be seen by users without needed permission"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Created"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "When the object first appeared on the database"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modified"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "When the object was last edited"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Translations"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "General"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relations"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadata"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Timestamps"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr "Activate selected %(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s activated successfully!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Selected items have been activated!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
msgstr "Deactivate selected %(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s deactivated successfully."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Selected items have been deactivated!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Attribute Value"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Attribute Values"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Image"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Images"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stock"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Stocks"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Order Product"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Order Products"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Children"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Config"
@@ -178,7 +174,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Successful"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Cache I/O"
@@ -202,7 +198,7 @@ msgstr "Get application's exposable parameters"
msgid "send a message to the support team"
msgstr "Send a message to the support team"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Request a CORSed URL. Only https allowed."
@@ -243,8 +239,7 @@ msgid "rewrite an existing attribute group saving non-editables"
msgstr "Rewrite an existing attribute group saving non-editables"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Rewrite some fields of an existing attribute group saving non-editables"
@@ -293,8 +288,7 @@ msgid "rewrite an existing attribute value saving non-editables"
msgstr "Rewrite an existing attribute value saving non-editables"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Rewrite some fields of an existing attribute value saving non-editables"
@@ -332,11 +326,11 @@ msgstr "For non-staff users, only their own orders are returned."
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -368,13 +362,13 @@ msgstr "Filter by order status (case-insensitive substring match)"
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
#: core/docs/drf/viewsets.py:210
msgid "retrieve a single order (detailed view)"
@@ -414,7 +408,7 @@ msgstr ""
"completed using the user's balance; If `force_payment` is used, a "
"transaction is initiated."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "purchase an order without account creation"
@@ -540,17 +534,26 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…`\n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`,\n"
@@ -606,10 +609,12 @@ msgstr "(exact) Digital vs. physical"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
#: core/docs/drf/viewsets.py:441
@@ -732,7 +737,7 @@ msgstr "delete an order–product relation"
msgid "add or remove feedback on an order–product relation"
msgstr "add or remove feedback on an order–product relation"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "No search term provided."
@@ -780,8 +785,8 @@ msgstr "Attributes"
msgid "Quantity"
msgstr "Quantity"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Slug"
@@ -842,215 +847,238 @@ msgstr "Level"
msgid "Product UUID"
msgstr "Product UUID"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Key to look for in or set into the cache"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Data to store in cache"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Timeout in seconds to set the data for into the cache"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Cached data"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Camelized JSON data from the requested URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Only URLs starting with http(s):// are allowed"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Add a product to the order"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Order {order_uuid} not found"
+msgstr "Order {order_uuid} not found!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Remove all products from the order"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Buy an order"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Please provide either order_uuid or order_hr_id - mutually exclusive!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Wrong type came from order.buy() method: {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Perform an action on a list of products in the order"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Remove/Add"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Action must be either \"add\" or \"remove\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Perform an action on a list of products in the wishlist"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Please provide `wishlist_uuid` value."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Wishlist {wishlist_uuid} not found!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Add a product to the order"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Wishlist {wishlist_uuid} not found"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Remove a product from the order"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Buy an order"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
-"Please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"Please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Add or delete a feedback for the orderproduct"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Action must be either `add` or `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Orderproduct {order_product_uuid} not found!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Original address string provided by the user"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} does not exist: {uuid}"
+msgstr "{name} does not exist: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Limit must be between 1 and 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - works like a charm"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Attributes"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Grouped attributes"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Groups of attributes"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Categories"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Brands"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Categories"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Markup Percentage"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr "Which attributes and values can be used for filtering this category."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Minimum and maximum prices for products in this category, if available."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tags for this category"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Products in this category"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Vendors"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Latitude (Y coordinate)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Longitude (X coordinate)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "How to"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Rating value from 1 to 10, inclusive, or 0 if not set."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Represents feedback from a user."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Notifications"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Download url for this order product if applicable"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "A list of order products in this order"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Billing address"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1058,729 +1086,726 @@ msgstr ""
"Shipping address for this order, leave blank if same as billing address or "
"if not applicable"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Total price of this order"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Total quantity of products in order"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Are all of the products in the order digital"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transactions for this order"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Orders"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Image URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Product's images"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Category"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Feedbacks"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Brand"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Attribute groups"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Price"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Quantity"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Number of feedbacks"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Products"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Promocodes"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Products on sale"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promotions"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Vendor"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Product"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Wishlisted products"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Wishlists"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Tagged products"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Product tags"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Tagged categories"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Categories' tags"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Project name"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Company Email"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Company Name"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Company Address"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Company Phone Number"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr "'email from', sometimes it must be used instead of host user value"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Email host user"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Maximum amount for payment"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Minimum amount for payment"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Analytics data"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Advertisement data"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configuration"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Language code"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Language name"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Language flag, if exists :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Get a list of supported languages"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Products search results"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Products search results"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Parent of this group"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Parent attribute group"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Attribute group's name"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Attribute group"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Stores credentials and endpoints required for vendor's API communication"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Authentication info"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Define the markup for products retrieved from this vendor"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Vendor markup percentage"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Name of this vendor"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Vendor name"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Internal tag identifier for the product tag"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Tag name"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "User-friendly name for the product tag"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Tag display name"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Product tag"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "category tag"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "category tags"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Upload an image representing this category"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Category image"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Define a markup percentage for products in this category"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Parent of this category to form a hierarchical structure"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Parent category"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Category name"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Provide a name for this category"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Add a detailed description for this category"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Category description"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "tags that help describe or group this category"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Priority"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Name of this brand"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Brand name"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Upload a logo representing this brand"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Brand small image"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Upload a big logo representing this brand"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Brand big image"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Add a detailed description of the brand"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Brand description"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Optional categories that this brand is associated with"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Categories"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Category this product belongs to"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Optionally associate this product with a brand"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Tags that help describe or group this product"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Indicates whether this product is digitally delivered"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Is product digital"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Provide a clear identifying name for the product"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Product name"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Add a detailed description of the product"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Product description"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Part number for this product"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Part number"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Category of this attribute"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Group of this attribute"
-
-#: core/models.py:465
-msgid "string"
-msgstr "String"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Integer"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Float"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Boolean"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Array"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Object"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Type of the attribute's value"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Value type"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Name of this attribute"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Attribute's name"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Attribute"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Attribute of this value"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "The specific product associated with this attribute's value"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Associated product"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "The specific value for this attribute"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "Provide alternative text for the image for accessibility"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Image alt text"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Upload the image file for this product"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Product image"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Determines the order in which images are displayed"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Display priority"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "The product that this image represents"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Product images"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Percentage discount for the selected products"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Discount percentage"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Provide a unique name for this promotion"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Promotion name"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Promotion description"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Select which products are included in this promotion"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Included products"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Promotion"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "The vendor supplying this product stock"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Associated vendor"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Final price to the customer after markups"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Selling price"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "The product associated with this stock entry"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Associated product"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "The price paid to the vendor for this product"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Vendor purchase price"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Available quantity of the product in stock"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Quantity in stock"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "Vendor-assigned SKU for identifying the product"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "Vendor's SKU"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Digital file associated with this stock if applicable"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Digital file"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Stock entries"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Category this product belongs to"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Optionally associate this product with a brand"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Tags that help describe or group this product"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Indicates whether this product is digitally delivered"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Is product digital"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Provide a clear identifying name for the product"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Product name"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Add a detailed description of the product"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Product description"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Part number for this product"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Part number"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Category of this attribute"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Group of this attribute"
+
+#: core/models.py:767
+msgid "string"
+msgstr "String"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Integer"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Float"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Boolean"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Array"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Object"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Type of the attribute's value"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Value type"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Name of this attribute"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Attribute's name"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Attribute"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Attribute of this value"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "The specific product associated with this attribute's value"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "The specific value for this attribute"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Provide alternative text for the image for accessibility"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Image alt text"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Upload the image file for this product"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Product image"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Determines the order in which images are displayed"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Display priority"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "The product that this image represents"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Product images"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Percentage discount for the selected products"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Discount percentage"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Provide a unique name for this promotion"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Promotion name"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Promotion description"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Select which products are included in this promotion"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Included products"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Promotion"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Products that the user has marked as wanted"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "User who owns this wishlist"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Wishlist's Owner"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Wishlist"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} does not exist: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documentary"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentaries"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Unresolved"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Address line for the customer"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Address line"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Street"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "District"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "City"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Region"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Postal code"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Country"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolocation Point(Longitude, Latitude)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Full JSON response from geocoder for this address"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Stored JSON response from the geocoding service"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Address"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adresses"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Unique code used by a user to redeem a discount"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Promo code identifier"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Fixed discount amount applied if percent is not used"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Fixed discount amount"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Percentage discount applied if fixed amount is not used"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Percentage discount"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Timestamp when the promocode expires"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "End validity time"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Timestamp from which this promocode is valid"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Start validity time"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr "Timestamp when the promocode was used, blank if not used yet"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Usage timestamp"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "User assigned to this promocode if applicable"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Assigned user"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Promo code"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Promo codes"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1788,136 +1813,144 @@ msgstr ""
"Only one type of discount should be defined (amount or percent), but not "
"both or neither."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Promocode has been used already"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Invalid discount type for promocode {self.uuid}"
+msgstr "Invalid discount type for promocode {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "The billing address used for this order"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Optional promo code applied to this order"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Applied promo code"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "The shipping address used for this order"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Shipping address"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Current status of the order in its lifecycle"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Order status"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"JSON structure of notifications to display to users, in admin UI the table-"
"view is used"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "JSON representation of order attributes for this order"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "The user who placed the order"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "User"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "The timestamp when the order was finalized"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Buy time"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "A human-readable identifier for the order"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "human-readable ID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Order"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "A user must have only one pending order at a time!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "You cannot add products to an order that is not a pending one"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "You cannot add inactive products to order"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "You cannot add more products than available in stock"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "You cannot remove products from an order that is not a pending one"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} does not exist with query <{query}>"
+msgstr "{name} does not exist with query <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Promocode does not exist"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "You can only buy physical products with shipping address specified!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Address does not exist"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"You can not purchase at this moment, please try again in a few minutes."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Invalid force value"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "You cannot purchase an empty order!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "You cannot buy an order without a user!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "A user without a balance cannot buy with balance!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Insufficient funds to complete the order"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1925,117 +1958,120 @@ msgstr ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"Invalid payment method: {payment_method} from {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "The price paid by the customer for this product at purchase time"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Purchase price at order time"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "Internal comments for admins about this ordered product"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Internal comments"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "User notifications"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "JSON representation of this item's attributes"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Ordered product attributes"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Reference to the parent order that contains this product"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Parent order"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "The specific product associated with this order line"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Quantity of this specific product in the order"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Product quantity"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Current status of this product in the order"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Product line status"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Orderproduct must have an associated order!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "wrong action specified for feedback: {action}"
+msgstr "Wrong action specified for feedback: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "you cannot feedback an order which is not received"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Download"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Downloads"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "You can not download a digital asset for a non-finished order"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "User-provided comments about their experience with the product"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Feedback comments"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"References the specific product in an order that this feedback is about"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Related order product"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "User-assigned rating for the product"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Product rating"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Feedback"
@@ -2045,13 +2081,13 @@ msgid ""
msgstr ""
"you must provide a comment, rating, and order product uuid to add feedback."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Error during promocode creation: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2060,7 +2096,7 @@ msgid "order confirmation"
msgstr "Order Confirmation"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2077,21 +2113,22 @@ msgstr "Hello %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
-"Thank you for your order #%(order.pk)s! We are pleased to inform you that we"
-" have taken your order into work. Below are the details of your order:"
+"Thank you for your order #%(order.pk)s! We are pleased to inform you that we "
+"have taken your order into work. Below are the details of your order:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Total"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2114,20 +2151,20 @@ msgid "best regards,
the %(config.PROJECT_NAME)s team"
msgstr "Best regards,
the %(config.PROJECT_NAME)s team"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "All rights reserved"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Order Delivered"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hello %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2136,7 +2173,7 @@ msgstr ""
"We have successfully processed your order №%(order_uuid)s! Below are the "
"details of your order:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2144,12 +2181,12 @@ msgstr ""
"additional\n"
" information"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Value"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2158,7 +2195,7 @@ msgstr ""
"If you have any questions, feel free to contact our support at "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Best regards,
the %(project_name)s team"
@@ -2170,11 +2207,12 @@ msgstr "Key"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
-"Thank you for your order! We are pleased to confirm your purchase. Below are"
-" the details of your order:"
+"Thank you for your order! We are pleased to confirm your purchase. Below are "
+"the details of your order:"
#: core/templates/shipped_order_created_email.html:123
#: core/templates/shipped_order_delivered_email.html:123
@@ -2190,7 +2228,7 @@ msgstr "Your order will be delivered to the following address:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Best regards,
the %(config.PROJECT_NAME)s team"
+msgstr "Best regards,
The %(config.PROJECT_NAME)s team"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2209,27 +2247,17 @@ msgstr "Both data and timeout are required"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "Invalid timeout value, it must be between 0 and 216000 seconds"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} must be model"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} must be list object"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Contact Us initiated"
+msgstr "{config.PROJECT_NAME} | contact us initiated"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Order Confirmation"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr "{config.PROJECT_NAME} | Order Delivered"
@@ -2246,21 +2274,21 @@ msgstr "NOMINATIM_URL parameter must be configured!"
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
msgstr ""
-"Image dimensions should not exceed w{max_width} x h{max_height} pixels"
+"Image dimensions should not exceed w{max_width} x h{max_height} pixels!"
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "Invalid phone number format"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "You can only download the digital asset once"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon not found"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Geocoding error: {e}"
diff --git a/core/locale/es_ES/LC_MESSAGES/django.mo b/core/locale/es_ES/LC_MESSAGES/django.mo
index 85c222c7..6347fe2c 100644
Binary files a/core/locale/es_ES/LC_MESSAGES/django.mo and b/core/locale/es_ES/LC_MESSAGES/django.mo differ
diff --git a/core/locale/es_ES/LC_MESSAGES/django.po b/core/locale/es_ES/LC_MESSAGES/django.po
index 4bd2f4e6..ea18d7c6 100644
--- a/core/locale/es_ES/LC_MESSAGES/django.po
+++ b/core/locale/es_ES/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,122 +13,119 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Identificación única"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"El identificador único se utiliza para identificar con seguridad cualquier "
"objeto de la base de datos"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Está activo"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Si se establece en false, este objeto no puede ser visto por los usuarios "
"sin el permiso necesario"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Creado"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Cuando el objeto apareció por primera vez en la base de datos"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modificado"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Cuándo se editó el objeto por última vez"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Traducciones"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "General"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relaciones"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadatos"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Marcas de tiempo"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "Activar %(verbose_name_plural)s seleccionados"
+msgstr "Activar %(verbose_name_plural)s seleccionado"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "¡%(verbose_name_plural)s activado con éxito!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Los artículos seleccionados se han activado."
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Desactivar %(verbose_name_plural)s seleccionados"
+msgstr "Desactivar %(verbose_name_plural)s seleccionado"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s desactivado con éxito."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Los artículos seleccionados se han desactivado."
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Atributo Valor"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Valores de los atributos"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Imagen"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Imágenes"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stock"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Acciones"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Pedir un producto"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Pedir productos"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Niños"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Configurar"
@@ -180,7 +177,7 @@ msgstr "Momento"
msgid "successful"
msgstr "Éxito"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "E/S de caché"
@@ -190,7 +187,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"Aplicar sólo una clave para leer datos permitidos de la caché.\n"
-"Aplicar clave, datos y tiempo de espera con autenticación para escribir datos en la caché."
+"Aplicar clave, datos y tiempo de espera con autenticación para escribir "
+"datos en la caché."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -204,7 +202,7 @@ msgstr "Obtener los parámetros exponibles de la aplicación"
msgid "send a message to the support team"
msgstr "Enviar un mensaje al equipo de asistencia"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Solicitar una URL CORSed. Solo se permite https."
@@ -222,8 +220,8 @@ msgid ""
"purchase an order as a business, using the provided `products` with "
"`product_uuid` and `attributes`."
msgstr ""
-"Compra un pedido como empresa, utilizando los `productos` proporcionados con"
-" `product_uuid` y `attributes`."
+"Compra un pedido como empresa, utilizando los `productos` proporcionados con "
+"`product_uuid` y `attributes`."
#: core/docs/drf/viewsets.py:43
msgid "list all attribute groups (simple view)"
@@ -246,8 +244,7 @@ msgid "rewrite an existing attribute group saving non-editables"
msgstr "Reescribir un grupo de atributos existente guardando los no editables"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Reescribir algunos campos de un grupo de atributos existente guardando los "
"no editables"
@@ -275,8 +272,7 @@ msgstr "Reescribir un atributo existente guardando los no editables"
#: core/docs/drf/viewsets.py:90
msgid "rewrite some fields of an existing attribute saving non-editables"
msgstr ""
-"Reescribir algunos campos de un atributo existente guardando los no "
-"editables"
+"Reescribir algunos campos de un atributo existente guardando los no editables"
#: core/docs/drf/viewsets.py:97
msgid "list all attribute values (simple view)"
@@ -299,11 +295,10 @@ msgid "rewrite an existing attribute value saving non-editables"
msgstr "Reescribir un valor de atributo existente guardando los no editables"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
-"Reescribir algunos campos de un valor de atributo existente guardando los no"
-" editables"
+"Reescribir algunos campos de un valor de atributo existente guardando los no "
+"editables"
#: core/docs/drf/viewsets.py:124
msgid "list all categories (simple view)"
@@ -343,12 +338,12 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"Búsqueda de subcadenas sin distinción entre mayúsculas y minúsculas en "
-"human_readable_id, order_products.product.name y "
-"order_products.product.partnumber"
+"human_readable_id, order_products.product.name y order_products.product."
+"partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -369,8 +364,8 @@ msgstr "Filtrar por ID de pedido exacto legible por el ser humano"
#: core/docs/drf/viewsets.py:185
msgid "Filter by user's email (case-insensitive exact match)"
msgstr ""
-"Filtrar por correo electrónico del usuario (coincidencia exacta insensible a"
-" mayúsculas y minúsculas)"
+"Filtrar por correo electrónico del usuario (coincidencia exacta insensible a "
+"mayúsculas y minúsculas)"
#: core/docs/drf/viewsets.py:190
msgid "Filter by user's UUID"
@@ -384,9 +379,9 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Ordenar por: uuid, human_readable_id, user_email, user, status, created, "
"modified, buy_time, random. Utilice el prefijo '-' para orden descendente "
@@ -432,7 +427,7 @@ msgstr ""
"finaliza utilizando el saldo del usuario; Si se utiliza `force_payment`, se "
"inicia una transacción."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "comprar un pedido sin crear una cuenta"
@@ -521,8 +516,7 @@ msgstr "Reescribir un atributo existente guardando los no editables"
#: core/docs/drf/viewsets.py:303
msgid "rewrite some fields of an existing wishlist saving non-editables"
msgstr ""
-"Reescribir algunos campos de un atributo existente guardando los no "
-"editables"
+"Reescribir algunos campos de un atributo existente guardando los no editables"
#: core/docs/drf/viewsets.py:307
msgid "add product to wishlist"
@@ -569,20 +563,31 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtrar por uno o varios pares nombre/valor de atributo. \n"
"- Sintaxis**: `nombre_attr=método-valor[;attr2=método2-valor2]...`.\n"
-"- Métodos** (por defecto `icontiene` si se omite): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
-"- Tipificación de valores**: Se intenta primero JSON (para poder pasar listas/dictos), `true`/`false` para booleanos, enteros, flotantes; en caso contrario se trata como cadena. \n"
-"- Base64**: prefiérelo con `b64-` para codificar en base64 el valor sin procesar. \n"
+"- Métodos** (por defecto `icontiene` si se omite): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
+"- Tipificación de valores**: Se intenta primero JSON (para poder pasar "
+"listas/dictos), `true`/`false` para booleanos, enteros, flotantes; en caso "
+"contrario se trata como cadena. \n"
+"- Base64**: prefiérelo con `b64-` para codificar en base64 el valor sin "
+"procesar. \n"
"Ejemplos: \n"
-"`color=rojo exacto`, `tamaño=gt-10`, `características=en-[\"wifi\", \"bluetooth\"]`,\n"
+"`color=rojo exacto`, `tamaño=gt-10`, `características=en-[\"wifi\", "
+"\"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`."
#: core/docs/drf/viewsets.py:349
@@ -637,10 +642,12 @@ msgstr "(exacto) Digital frente a físico"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Lista separada por comas de campos por los que ordenar. Prefiérela con `-` para que sea descendente. \n"
+"Lista separada por comas de campos por los que ordenar. Prefiérela con `-` "
+"para que sea descendente. \n"
"**Permitido:** uuid, rating, name, slug, created, modified, price, random"
#: core/docs/drf/viewsets.py:441
@@ -768,7 +775,7 @@ msgstr "suprimir una relación pedido-producto"
msgid "add or remove feedback on an order–product relation"
msgstr "añadir o eliminar comentarios en una relación pedido-producto"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "No se proporciona ningún término de búsqueda."
@@ -816,8 +823,8 @@ msgstr "Atributos"
msgid "Quantity"
msgstr "Cantidad"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Babosa"
@@ -831,8 +838,7 @@ msgstr "Incluir subcategorías"
#: core/filters.py:147
msgid "there must be a category_uuid to use include_subcategories flag"
-msgstr ""
-"Debe haber un category_uuid para usar la bandera include_subcategories"
+msgstr "Debe haber un category_uuid para usar la bandera include_subcategories"
#: core/filters.py:280
msgid "Search (ID, product name or part number)"
@@ -879,220 +885,241 @@ msgstr "Nivel"
msgid "Product UUID"
msgstr "UUID del producto"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Clave que hay que buscar o introducir en la caché"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Datos a almacenar en caché"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Tiempo de espera en segundos para poner los datos en la caché"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Datos en caché"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Datos JSON camelizados de la URL solicitada"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Sólo se permiten URL que empiecen por http(s)://."
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Añadir un producto al pedido"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Pedido {order_uuid} no encontrado"
+msgstr "Pedido {order_uuid} ¡no encontrado!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Eliminar un producto del pedido"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Eliminar todos los productos del pedido"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Comprar un pedido"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Indique order_uuid o order_hr_id, ¡se excluyen mutuamente!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
-msgstr ""
-"Tipo incorrecto proveniente del método order.buy(): {type(instance)!s}"
+msgstr "Tipo incorrecto proveniente del método order.buy(): {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Realizar una acción en una lista de productos del pedido"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Quitar/Agregar"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "La acción debe ser \"añadir\" o \"eliminar\"."
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Realizar una acción en una lista de productos de la lista de deseos"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Por favor, proporcione el valor `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Lista de deseos {wishlist_uuid} ¡no encontrada!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Añadir un producto al pedido"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Lista de deseos {wishlist_uuid} no encontrada"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Eliminar un producto del pedido"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Eliminar un producto del pedido"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Eliminar un producto del pedido"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Comprar un pedido"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
-"Por favor, envíe los atributos como una cadena formateada como "
-"attr1=valor1,attr2=valor2"
+"Por favor, envíe los atributos como una cadena formateada como attr1=valor1,"
+"attr2=valor2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Añadir o eliminar un comentario para el pedido-producto"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "La acción debe ser \"añadir\" o \"eliminar\"."
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "No se ha encontrado el producto {order_product_uuid}."
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Cadena de dirección original proporcionada por el usuario"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} no existe: {uuid}"
+msgstr "{name} no existe: ¡{uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "El límite debe estar entre 1 y 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - funciona a las mil maravillas"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Atributos"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Atributos agrupados"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Grupos de atributos"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Categorías"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Marcas"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Categorías"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Porcentaje de recargo"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Qué atributos y valores se pueden utilizar para filtrar esta categoría."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Precios mínimo y máximo de los productos de esta categoría, si están "
"disponibles."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Etiquetas para esta categoría"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Productos de esta categoría"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Vendedores"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Latitud (coordenada Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Longitud (coordenada X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Cómo"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr ""
-"Valor de calificación de 1 a 10, ambos inclusive, o 0 si no está "
-"configurado."
+"Valor de calificación de 1 a 10, ambos inclusive, o 0 si no está configurado."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Representa la opinión de un usuario."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Notificaciones"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Descargar url para este producto de pedido si procede"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Una lista de los productos del pedido"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Dirección de facturación"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1100,735 +1127,732 @@ msgstr ""
"Dirección de envío para este pedido, dejar en blanco si es la misma que la "
"de facturación o si no procede"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Precio total de este pedido"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Cantidad total de productos del pedido"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "¿Están todos los productos en el pedido digital"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transacciones para este pedido"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Pedidos"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "URL de la imagen"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Imágenes del producto"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Categoría"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Comentarios"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Marca"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Grupos de atributos"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Precio"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Cantidad"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Número de reacciones"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Productos"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Códigos promocionales"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Productos a la venta"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promociones"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Vendedor"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Producto"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Productos deseados"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Listas de deseos"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Productos con etiqueta"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Etiquetas del producto"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Categorías"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Etiquetas de las categorías"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Nombre del proyecto"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Correo electrónico de la empresa"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Nombre de la empresa"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Dirección de la empresa"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Teléfono de la empresa"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"'email from', a veces debe utilizarse en lugar del valor del usuario host"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Correo electrónico del usuario anfitrión"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Importe máximo de pago"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Importe mínimo de pago"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Datos analíticos"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Datos publicitarios"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configuración"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Código de idioma"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Nombre de la lengua"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Bandera de idioma, si existe :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Obtener una lista de los idiomas admitidos"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Resultados de la búsqueda de productos"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Resultados de la búsqueda de productos"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Padre de este grupo"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Grupo de atributos padre"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Nombre del grupo de atributos"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Grupo de atributos"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Almacena las credenciales y los puntos finales necesarios para la "
"comunicación API del proveedor"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Información de autenticación"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr ""
"Definir el margen de beneficio para los productos recuperados de este "
"proveedor"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Porcentaje de margen del vendedor"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Nombre de este vendedor"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Nombre del vendedor"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Identificador interno de la etiqueta del producto"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Nombre de la etiqueta"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Nombre fácil de usar para la etiqueta del producto"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Nombre de la etiqueta"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Etiqueta del producto"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "etiqueta de categoría"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "etiquetas de categoría"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Cargar una imagen que represente esta categoría"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Categoría imagen"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Definir un porcentaje de recargo para los productos de esta categoría"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Padre de esta categoría para formar una estructura jerárquica"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Categoría de padres"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Nombre de la categoría"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Indique un nombre para esta categoría"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Añadir una descripción detallada para esta categoría"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Descripción de la categoría"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "etiquetas que ayudan a describir o agrupar esta categoría"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Prioridad"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Nombre de esta marca"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Marca"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Cargar un logotipo que represente a esta marca"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Marca pequeña imagen"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Sube un logotipo grande que represente a esta marca"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Gran imagen de marca"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Añadir una descripción detallada de la marca"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Descripción de la marca"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Categorías opcionales a las que se asocia esta marca"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Categorías"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Categoría a la que pertenece este producto"
+#: core/models.py:515
+msgid "the vendor supplying this product stock"
+msgstr "El vendedor que suministra este producto dispone de"
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Si lo desea, puede asociar este producto a una marca"
+#: core/models.py:516
+msgid "associated vendor"
+msgstr "Proveedor asociado"
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Etiquetas que ayudan a describir o agrupar este producto"
+#: core/models.py:520
+msgid "final price to the customer after markups"
+msgstr "Precio final al cliente después de márgenes"
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Indica si este producto se entrega digitalmente"
+#: core/models.py:521
+msgid "selling price"
+msgstr "Precio de venta"
-#: core/models.py:351
-msgid "is product digital"
-msgstr "¿Es digital el producto?"
+#: core/models.py:526
+msgid "the product associated with this stock entry"
+msgstr "El producto asociado a esta entrada en stock"
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Proporcionar un nombre que identifique claramente el producto"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Nombre del producto"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Añada una descripción detallada del producto"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Descripción del producto"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Número de pieza de este producto"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Número de pieza"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Categoría de este atributo"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Grupo de este atributo"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Cadena"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Entero"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Flotador"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Booleano"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Matriz"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Objeto"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Tipo del valor del atributo"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Tipo de valor"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Nombre de este atributo"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Nombre del atributo"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Atributo"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Atributo de este valor"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "El producto específico asociado al valor de este atributo"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
msgid "associated product"
msgstr "Producto asociado"
-#: core/models.py:512
+#: core/models.py:534
+msgid "the price paid to the vendor for this product"
+msgstr "El precio pagado al vendedor por este producto"
+
+#: core/models.py:535
+msgid "vendor purchase price"
+msgstr "Precio de compra al vendedor"
+
+#: core/models.py:539
+msgid "available quantity of the product in stock"
+msgstr "Cantidad disponible del producto en stock"
+
+#: core/models.py:540
+msgid "quantity in stock"
+msgstr "Cantidad en stock"
+
+#: core/models.py:544
+msgid "vendor-assigned SKU for identifying the product"
+msgstr "SKU asignada por el proveedor para identificar el producto"
+
+#: core/models.py:545
+msgid "vendor sku"
+msgstr "SKU del vendedor"
+
+#: core/models.py:551
+msgid "digital file associated with this stock if applicable"
+msgstr "Archivo digital asociado a esta acción, si procede"
+
+#: core/models.py:552
+msgid "digital file"
+msgstr "Archivo digital"
+
+#: core/models.py:561
+msgid "stock entries"
+msgstr "Entradas en existencias"
+
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Categoría a la que pertenece este producto"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Si lo desea, puede asociar este producto a una marca"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Etiquetas que ayudan a describir o agrupar este producto"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Indica si este producto se entrega digitalmente"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "¿Es digital el producto?"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Proporcionar un nombre que identifique claramente el producto"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Nombre del producto"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Añada una descripción detallada del producto"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Descripción del producto"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Número de pieza de este producto"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Número de pieza"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Categoría de este atributo"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Grupo de este atributo"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Cadena"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Entero"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Flotador"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Booleano"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Matriz"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Objeto"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Tipo del valor del atributo"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Tipo de valor"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Nombre de este atributo"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Nombre del atributo"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Atributo"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Atributo de este valor"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "El producto específico asociado al valor de este atributo"
+
+#: core/models.py:837
msgid "the specific value for this attribute"
msgstr "El valor específico de este atributo"
-#: core/models.py:528
+#: core/models.py:871
msgid "provide alternative text for the image for accessibility"
msgstr ""
"Proporcione un texto alternativo para la imagen en aras de la accesibilidad"
-#: core/models.py:529
+#: core/models.py:872
msgid "image alt text"
msgstr "Texto alternativo de la imagen"
-#: core/models.py:532
+#: core/models.py:875
msgid "upload the image file for this product"
msgstr "Cargar el archivo de imagen para este producto"
-#: core/models.py:533 core/models.py:558
+#: core/models.py:876 core/models.py:901
msgid "product image"
msgstr "Imagen del producto"
-#: core/models.py:539
+#: core/models.py:882
msgid "determines the order in which images are displayed"
msgstr "Determina el orden de visualización de las imágenes"
-#: core/models.py:540
+#: core/models.py:883
msgid "display priority"
msgstr "Prioridad de visualización"
-#: core/models.py:545
+#: core/models.py:888
msgid "the product that this image represents"
msgstr "El producto que representa esta imagen"
-#: core/models.py:559
+#: core/models.py:902
msgid "product images"
msgstr "Imágenes de productos"
-#: core/models.py:567
+#: core/models.py:943
msgid "percentage discount for the selected products"
msgstr "Porcentaje de descuento para los productos seleccionados"
-#: core/models.py:568
+#: core/models.py:944
msgid "discount percentage"
msgstr "Porcentaje de descuento"
-#: core/models.py:573
+#: core/models.py:949
msgid "provide a unique name for this promotion"
msgstr "Proporcione un nombre único para esta promoción"
-#: core/models.py:574
+#: core/models.py:950
msgid "promotion name"
msgstr "Nombre de la promoción"
-#: core/models.py:580
+#: core/models.py:956
msgid "promotion description"
msgstr "Descripción de la promoción"
-#: core/models.py:585
+#: core/models.py:961
msgid "select which products are included in this promotion"
msgstr "Seleccione los productos incluidos en esta promoción"
-#: core/models.py:586
+#: core/models.py:962
msgid "included products"
msgstr "Productos incluidos"
-#: core/models.py:590
+#: core/models.py:966
msgid "promotion"
msgstr "Promoción"
-#: core/models.py:605
-msgid "the vendor supplying this product stock"
-msgstr "El vendedor que suministra este producto dispone de"
-
-#: core/models.py:606
-msgid "associated vendor"
-msgstr "Proveedor asociado"
-
-#: core/models.py:610
-msgid "final price to the customer after markups"
-msgstr "Precio final al cliente después de márgenes"
-
-#: core/models.py:611
-msgid "selling price"
-msgstr "Precio de venta"
-
-#: core/models.py:616
-msgid "the product associated with this stock entry"
-msgstr "El producto asociado a esta entrada en stock"
-
-#: core/models.py:624
-msgid "the price paid to the vendor for this product"
-msgstr "El precio pagado al vendedor por este producto"
-
-#: core/models.py:625
-msgid "vendor purchase price"
-msgstr "Precio de compra al vendedor"
-
-#: core/models.py:629
-msgid "available quantity of the product in stock"
-msgstr "Cantidad disponible del producto en stock"
-
-#: core/models.py:630
-msgid "quantity in stock"
-msgstr "Cantidad en stock"
-
-#: core/models.py:634
-msgid "vendor-assigned SKU for identifying the product"
-msgstr "SKU asignada por el proveedor para identificar el producto"
-
-#: core/models.py:635
-msgid "vendor sku"
-msgstr "SKU del vendedor"
-
-#: core/models.py:641
-msgid "digital file associated with this stock if applicable"
-msgstr "Archivo digital asociado a esta acción, si procede"
-
-#: core/models.py:642
-msgid "digital file"
-msgstr "Archivo digital"
-
-#: core/models.py:651
-msgid "stock entries"
-msgstr "Entradas en existencias"
-
-#: core/models.py:660
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Productos que el usuario ha marcado como deseados"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Usuario propietario de esta lista de deseos"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Propietario de Wishlist"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Lista de deseos"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} no existe: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documental"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentaries"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Sin resolver"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Dirección del cliente"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Dirección"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Calle"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Distrito"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Ciudad"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Región"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Promo code"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "País"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolocalización Punto(Longitud, Latitud)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Respuesta JSON completa del geocodificador para esta dirección"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Respuesta JSON almacenada del servicio de geocodificación"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Dirección"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Direcciones"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Código único utilizado por un usuario para canjear un descuento"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Promo code identifier"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Se aplica un descuento fijo si no se utiliza el porcentaje"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Importe fijo del descuento"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Porcentaje de descuento aplicado si no se utiliza el importe fijo"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Porcentaje de descuento"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Fecha de caducidad del promocode"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Hora de fin de validez"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Fecha a partir de la cual es válido este promocode"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Hora de inicio de validez"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Fecha en la que se utilizó el promocode, en blanco si aún no se ha utilizado"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Marca de tiempo de uso"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Usuario asignado a este promocode si procede"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Usuario asignado"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Promo code"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Promo codes"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1836,138 +1860,146 @@ msgstr ""
"Sólo debe definirse un tipo de descuento (importe o porcentaje), pero no "
"ambos ni ninguno."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "El código promocional ya ha sido utilizado"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Tipo de descuento no válido para promocode {self.uuid}"
+msgstr "¡Tipo de descuento no válido para el código promocional {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "La dirección de facturación utilizada para este pedido"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Código promocional opcional aplicado a este pedido"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Código promocional aplicado"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "La dirección de envío utilizada para este pedido"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Dirección de envío"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Estado actual del pedido en su ciclo de vida"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Estado del pedido"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"Estructura JSON de las notificaciones para mostrar a los usuarios, en la "
"interfaz de administración se utiliza la vista de tabla."
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "Representación JSON de los atributos de la orden para esta orden"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "El usuario que realizó el pedido"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Usuario"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Fecha de finalización de la orden"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Comprar tiempo"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Un identificador legible por el ser humano para la orden"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "ID legible por humanos"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Pida"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Un usuario sólo puede tener una orden pendiente a la vez."
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "No puede añadir productos a un pedido que no esté pendiente"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "No se pueden añadir productos inactivos al pedido"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "No puede añadir más productos de los disponibles en stock"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "No puede eliminar productos de un pedido que no esté pendiente"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} no existe con la consulta <{query}>"
+msgstr "{name} ¡no existe con la consulta <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Promocode no existe"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
"Sólo puede comprar productos físicos con la dirección de envío especificada."
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "La dirección no existe"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"No puede comprar en este momento, por favor inténtelo de nuevo en unos "
"minutos."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Valor de fuerza no válido"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "No se puede comprar un pedido vacío."
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "No se puede comprar un pedido sin un usuario."
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "¡Un usuario sin saldo no puede comprar con saldo!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Fondos insuficientes para completar el pedido"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1975,120 +2007,123 @@ msgstr ""
"no puede comprar sin registrarse, facilite la siguiente información: nombre "
"del cliente, correo electrónico del cliente, número de teléfono del cliente"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"Forma de pago no válida: ¡{payment_method} de {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr ""
"El precio pagado por el cliente por este producto en el momento de la compra"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Precio de compra en el momento del pedido"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr ""
"Comentarios internos para los administradores sobre este producto solicitado"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Comentarios internos"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Notificaciones a los usuarios"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "Representación JSON de los atributos de este elemento"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Atributos ordenados del producto"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Referencia al pedido principal que contiene este producto"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Orden de los padres"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "El producto específico asociado a esta línea de pedido"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Cantidad de este producto específico en el pedido"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Cantidad de productos"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Estado actual de este producto en el pedido"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Estado de la línea de productos"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "El pedido-producto debe tener un pedido asociado."
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "acción incorrecta especificada para la retroalimentación: {action}"
+msgstr "Acción incorrecta especificada para la retroalimentación: ¡{action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "no se puede comentar un pedido no recibido"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Descargar"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Descargas"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "No puede descargar un activo digital para un pedido no finalizado"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Comentarios de los usuarios sobre su experiencia con el producto"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Comentarios"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"Hace referencia al producto específico de un pedido sobre el que trata esta "
"opinión"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Producto relacionado con el pedido"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Valoración del producto asignada por el usuario"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Valoración del producto"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Comentarios"
@@ -2099,13 +2134,13 @@ msgstr ""
"debe proporcionar un comentario, una valoración y el uuid del producto "
"solicitado para añadir comentarios."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Error durante la creación del promocode: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2114,7 +2149,7 @@ msgid "order confirmation"
msgstr "Confirmación de pedido"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2131,21 +2166,22 @@ msgstr "Hola %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"¡Gracias por su pedido #%(order.pk)s! Nos complace informarle de que hemos "
"recibido su pedido. A continuación encontrará los detalles de su pedido:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Total"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2165,23 +2201,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Saludos cordiales,
el equipo de %(config.PROJECT_NAME)s"
+msgstr "Saludos cordiales,
el equipo %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Todos los derechos reservados"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Pedido entregado"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hola %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2190,7 +2226,7 @@ msgstr ""
"¡Hemos procesado correctamente su pedido №%(order_uuid)s! A continuación "
"encontrará los detalles de su pedido:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2198,12 +2234,12 @@ msgstr ""
"información adicional\n"
" información adicional"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Valor"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2212,10 +2248,10 @@ msgstr ""
"Si tiene alguna pregunta, no dude en ponerse en contacto con nuestro "
"servicio de asistencia en %(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Saludos cordiales,
el equipo de %(project_name)s"
+msgstr "Saludos cordiales,
el equipo %(project_name)s"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2224,7 +2260,8 @@ msgstr "Clave"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Gracias por su pedido. Nos complace confirmarle su compra. A continuación "
@@ -2244,7 +2281,7 @@ msgstr "Su pedido se entregará en la siguiente dirección:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Saludos cordiales,
el equipo de %(config.PROJECT_NAME)s"
+msgstr "Saludos cordiales,
El equipo %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2264,27 +2301,17 @@ msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr ""
"Valor de tiempo de espera no válido, debe estar entre 0 y 216000 segundos."
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} debe ser modelo"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} debe ser un objeto de lista"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Contacto iniciado"
+msgstr "{config.PROJECT_NAME} | contacto iniciado"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Confirmación de pedido"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr "{config.PROJECT_NAME} | Pedido entregado"
@@ -2308,15 +2335,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Formato de número de teléfono no válido"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Sólo puede descargar el activo digital una vez"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon no encontrado"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Error de geocodificación: {e}"
diff --git a/core/locale/fr_FR/LC_MESSAGES/django.mo b/core/locale/fr_FR/LC_MESSAGES/django.mo
index 7efaee64..bc856c1c 100644
Binary files a/core/locale/fr_FR/LC_MESSAGES/django.mo and b/core/locale/fr_FR/LC_MESSAGES/django.mo differ
diff --git a/core/locale/fr_FR/LC_MESSAGES/django.po b/core/locale/fr_FR/LC_MESSAGES/django.po
index 20b653a6..1ca76be8 100644
--- a/core/locale/fr_FR/LC_MESSAGES/django.po
+++ b/core/locale/fr_FR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,122 +13,119 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Unique ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"L'identifiant unique est utilisé pour identifier de manière sûre tout objet "
"de la base de données."
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Est actif"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Si la valeur est fixée à false, cet objet ne peut pas être vu par les "
"utilisateurs qui n'ont pas l'autorisation nécessaire."
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Créée"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Date de la première apparition de l'objet dans la base de données"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modifié"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Date de la dernière modification de l'objet"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Traductions"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Général"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relations"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Métadonnées"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Horodatage"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "Activer les %(verbose_name_plural)s sélectionnés"
+msgstr "Activer la %(verbose_name_plural)s sélectionnée"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s activé avec succès !"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Les articles sélectionnés ont été activés !"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Désactiver les %(verbose_name_plural)s sélectionnés"
+msgstr "Désactiver la %(verbose_name_plural)s sélectionnée"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "Désactivation réussie de %(verbose_name_plural)s."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Les articles sélectionnés ont été désactivés !"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Valeur de l'attribut"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Valeurs des attributs"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Image"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Images"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stock"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Stocks"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Commander un produit"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Commander des produits"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Les enfants"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Config"
@@ -180,7 +177,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Réussite"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Cache I/O"
@@ -189,8 +186,10 @@ msgid ""
"apply only a key to read permitted data from cache.\n"
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
-"Appliquer uniquement une clé pour lire les données autorisées dans la mémoire cache.\n"
-"Appliquer une clé, des données et un délai d'attente avec authentification pour écrire des données dans la mémoire cache."
+"Appliquer uniquement une clé pour lire les données autorisées dans la "
+"mémoire cache.\n"
+"Appliquer une clé, des données et un délai d'attente avec authentification "
+"pour écrire des données dans la mémoire cache."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -204,7 +203,7 @@ msgstr "Obtenir les paramètres exposables de l'application"
msgid "send a message to the support team"
msgstr "Envoyer un message à l'équipe d'assistance"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Demander une URL CORSée. Seul https est autorisé."
@@ -248,8 +247,7 @@ msgstr ""
"modifiables"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Réécrire certains champs d'un groupe d'attributs existant en sauvegardant "
"les non-éditables"
@@ -278,8 +276,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:90
msgid "rewrite some fields of an existing attribute saving non-editables"
msgstr ""
-"Réécrire certains champs d'un attribut existant en sauvegardant les éléments"
-" non modifiables"
+"Réécrire certains champs d'un attribut existant en sauvegardant les éléments "
+"non modifiables"
#: core/docs/drf/viewsets.py:97
msgid "list all attribute values (simple view)"
@@ -304,8 +302,7 @@ msgstr ""
"modifiables"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Réécrire certains champs d'une valeur d'attribut existante en sauvegardant "
"les éléments non modifiables"
@@ -348,11 +345,11 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
-"Recherche insensible à la casse dans human_readable_id, "
-"order_products.product.name, et order_products.product.partnumber"
+"Recherche insensible à la casse dans human_readable_id, order_products."
+"product.name, et order_products.product.partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -388,13 +385,13 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Ordonner par l'un des éléments suivants : uuid, human_readable_id, "
-"user_email, user, status, created, modified, buy_time, random. Préfixer avec"
-" '-' pour l'ordre décroissant (par exemple '-buy_time')."
+"user_email, user, status, created, modified, buy_time, random. Préfixer avec "
+"'-' pour l'ordre décroissant (par exemple '-buy_time')."
#: core/docs/drf/viewsets.py:210
msgid "retrieve a single order (detailed view)"
@@ -432,11 +429,11 @@ msgid ""
"completed using the user's balance; if `force_payment` is used, a "
"transaction is initiated."
msgstr ""
-"Finalise l'achat de la commande. Si `force_balance` est utilisé, l'achat est"
-" complété en utilisant le solde de l'utilisateur ; Si `force_payment` est "
+"Finalise l'achat de la commande. Si `force_balance` est utilisé, l'achat est "
+"complété en utilisant le solde de l'utilisateur ; Si `force_payment` est "
"utilisé, une transaction est initiée."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "acheter une commande sans créer de compte"
@@ -493,8 +490,8 @@ msgid ""
"removes a list of products from an order using the provided `product_uuid` "
"and `attributes`"
msgstr ""
-"Supprime une liste de produits d'une commande en utilisant le `product_uuid`"
-" et les `attributs` fournis."
+"Supprime une liste de produits d'une commande en utilisant le `product_uuid` "
+"et les `attributs` fournis."
#: core/docs/drf/viewsets.py:281
msgid "list all wishlists (simple view)"
@@ -530,8 +527,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:303
msgid "rewrite some fields of an existing wishlist saving non-editables"
msgstr ""
-"Réécrire certains champs d'un attribut existant en sauvegardant les éléments"
-" non modifiables"
+"Réécrire certains champs d'un attribut existant en sauvegardant les éléments "
+"non modifiables"
#: core/docs/drf/viewsets.py:307
msgid "add product to wishlist"
@@ -578,18 +575,29 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtre sur une ou plusieurs paires nom/valeur d'attribut. \n"
"- **Syntaxe** : `nom_attr=méthode-valeur[;attr2=méthode2-valeur2]...`\n"
-"- **Méthodes** (la valeur par défaut est `icontains` si elle est omise) : `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
-"- **Type de valeur** : JSON est essayé en premier (pour que vous puissiez passer des listes/dicts), `true`/`false` pour les booléens, les entiers, les flottants ; sinon traité comme une chaîne de caractères. \n"
-"- **Base64** : préfixe avec `b64-` pour encoder la valeur brute en base64 de manière sûre pour l'URL. \n"
+"- **Méthodes** (la valeur par défaut est `icontains` si elle est omise) : "
+"`iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, "
+"`istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, "
+"`gt`, `gte`, `in`\n"
+"- **Type de valeur** : JSON est essayé en premier (pour que vous puissiez "
+"passer des listes/dicts), `true`/`false` pour les booléens, les entiers, les "
+"flottants ; sinon traité comme une chaîne de caractères. \n"
+"- **Base64** : préfixe avec `b64-` pour encoder la valeur brute en base64 de "
+"manière sûre pour l'URL. \n"
"Exemples : \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\", \"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`"
@@ -644,10 +652,12 @@ msgstr "(exact) Numérique ou physique"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Liste de champs séparés par des virgules à trier. Préfixer avec `-` pour un tri descendant. \n"
+"Liste de champs séparés par des virgules à trier. Préfixer avec `-` pour un "
+"tri descendant. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
#: core/docs/drf/viewsets.py:441
@@ -778,7 +788,7 @@ msgstr ""
"ajouter ou supprimer un retour d'information sur une relation commande-"
"produit"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Aucun terme de recherche n'est fourni."
@@ -826,8 +836,8 @@ msgstr "Attributs"
msgid "Quantity"
msgstr "Quantité"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Limace"
@@ -890,961 +900,981 @@ msgstr "Niveau"
msgid "Product UUID"
msgstr "UUID du produit"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Clé à rechercher ou à insérer dans la cache"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Données à stocker dans la mémoire cache"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Délai d'attente en secondes pour placer les données dans le cache"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Données mises en cache"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Données JSON camélisées provenant de l'URL demandée"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Seuls les URL commençant par http(s):// sont autorisés."
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Ajouter un produit à la commande"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "L'ordre {order_uuid} n'a pas été trouvé"
+msgstr "Ordre {order_uuid} introuvable !"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Supprimer un produit de la commande"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Supprimer tous les produits de la commande"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Acheter une commande"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr ""
"Veuillez fournir soit order_uuid, soit order_hr_id - les deux s'excluent "
"mutuellement !"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr ""
"Le mauvais type provient de la méthode order.buy() : {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Effectuer une action sur une liste de produits dans la commande"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Supprimer/Ajouter"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "L'action doit être soit \"ajouter\", soit \"supprimer\" !"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr ""
+"Effectuer une action sur une liste de produits dans la liste de souhaits"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Veuillez indiquer la valeur de `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Wishlist {wishlist_uuid} introuvable !"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Ajouter un produit à la commande"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Wishlist {wishlist_uuid} introuvable"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Supprimer un produit de la commande"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Supprimer un produit de la commande"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Supprimer un produit de la commande"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Acheter une commande"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
"Veuillez envoyer les attributs sous la forme d'une chaîne formatée comme "
"attr1=valeur1,attr2=valeur2."
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr ""
+"ajouter ou supprimer un retour d'information sur une relation commande-"
+"produit"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "L'action doit être soit `add` soit `remove` !"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Le produit {order_product_uuid} n'a pas été trouvé !"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Chaîne d'adresse originale fournie par l'utilisateur"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} n'existe pas : {uuid}"
+msgstr "{name} n'existe pas : {uuid} !"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "La limite doit être comprise entre 1 et 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - fonctionne comme un charme"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Attributs"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Attributs groupés"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Groupes d'attributs"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Catégories"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Marques"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Catégories"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Markup Percentage"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Quels attributs et valeurs peuvent être utilisés pour filtrer cette "
"catégorie."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Prix minimum et maximum pour les produits de cette catégorie, s'ils sont "
"disponibles."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tags pour cette catégorie"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Produits dans cette catégorie"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Vendeurs"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Latitude (coordonnée Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Longitude (coordonnée X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Comment"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Valeur d'évaluation de 1 à 10 inclus, ou 0 si elle n'est pas définie."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Représente le retour d'information d'un utilisateur."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Notifications"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "URL de téléchargement pour ce produit de la commande, le cas échéant"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Une liste des produits commandés dans cette commande"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Adresse de facturation"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
msgstr ""
-"Adresse d'expédition pour cette commande, laisser vide si elle est identique"
-" à l'adresse de facturation ou si elle n'est pas applicable"
+"Adresse d'expédition pour cette commande, laisser vide si elle est identique "
+"à l'adresse de facturation ou si elle n'est pas applicable"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Prix total de la commande"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Quantité totale de produits dans la commande"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Tous les produits de la commande sont-ils numériques ?"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transactions pour cette commande"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Commandes"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Image URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Images du produit"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Catégorie"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Retour d'information"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Marque"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Groupes d'attributs"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Prix"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Quantité"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Nombre de retours d'information"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Produits"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Promocodes"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Produits en vente"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promotions"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Vendeur"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Produit"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Produits en liste de souhaits"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Liste de souhaits"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Produits marqués"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Étiquettes du produit"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Catégories marquées"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Tags des catégories"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Nom du projet"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Courriel de l'entreprise"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Nom de l'entreprise"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Adresse de l'entreprise"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Numéro de téléphone de l'entreprise"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"'email from', parfois il doit être utilisé à la place de la valeur de "
"l'utilisateur de l'hôte"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Utilisateur de l'hôte de messagerie"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Montant maximum du paiement"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Montant minimum pour le paiement"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Données analytiques"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Advertisement data"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configuration"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Code langue"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Nom de la langue"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Drapeau linguistique, s'il existe :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Obtenir la liste des langues prises en charge"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Résultats de la recherche de produits"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Résultats de la recherche de produits"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Parent de ce groupe"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Groupe d'attributs parent"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Nom du groupe d'attributs"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Groupe d'attributs"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Stocke les informations d'identification et les points d'extrémité "
"nécessaires à la communication avec l'API du fournisseur."
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Informations sur l'authentification"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr ""
"Définir la majoration pour les produits récupérés auprès de ce fournisseur"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Pourcentage de marge du vendeur"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Nom de ce vendeur"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Nom du vendeur"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Identifiant interne de l'étiquette du produit"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Nom du jour"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Nom convivial pour l'étiquette du produit"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Nom d'affichage de l'étiquette"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Étiquette du produit"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "étiquette de catégorie"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "balises de catégorie"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Télécharger une image représentant cette catégorie"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Image de catégorie"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr ""
"Définir un pourcentage de majoration pour les produits de cette catégorie"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Parent de cette catégorie pour former une structure hiérarchique"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Catégorie de parents"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Nom de la catégorie"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Donnez un nom à cette catégorie"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Ajouter une description détaillée pour cette catégorie"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Description de la catégorie"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "les étiquettes qui aident à décrire ou à regrouper cette catégorie"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Priorité"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Nom de cette marque"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Nom de marque"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Télécharger un logo représentant cette marque"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Petite image de marque"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Télécharger un grand logo représentant cette marque"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Une grande image de marque"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Ajouter une description détaillée de la marque"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Description de la marque"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Catégories facultatives auxquelles cette marque est associée"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Catégories"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Catégorie à laquelle appartient ce produit"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Possibilité d'associer ce produit à une marque"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Étiquettes permettant de décrire ou de regrouper ce produit"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Indique si ce produit est livré numériquement"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Le produit est-il numérique ?"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Fournir un nom d'identification clair pour le produit"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Nom du produit"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Ajouter une description détaillée du produit"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Description du produit"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Numéro de pièce pour ce produit"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Numéro de pièce"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Catégorie de cet attribut"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Groupe de cet attribut"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Chaîne"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Entier"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Flotteur"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Booléen"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Tableau"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Objet"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Type de la valeur de l'attribut"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Type de valeur"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Nom de cet attribut"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Nom de l'attribut"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Attribut"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Attribut de cette valeur"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Le produit spécifique associé à la valeur de cet attribut"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Produit associé"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "La valeur spécifique de cet attribut"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "Fournir un texte alternatif pour l'image afin d'en faciliter l'accès"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Texte alt de l'image"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Télécharger le fichier image pour ce produit"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Image du produit"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Détermine l'ordre d'affichage des images"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Priorité à l'affichage"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "Le produit que cette image représente"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Images du produit"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Pourcentage de réduction pour les produits sélectionnés"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Pourcentage de réduction"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Donnez un nom unique à cette promotion"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Nom de la promotion"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Promotion description"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Sélectionnez les produits inclus dans cette promotion"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Produits inclus"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Promotion"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "Le vendeur qui fournit ce stock de produits"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Vendeur associé"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Prix final pour le client après majoration"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Prix de vente"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "Le produit associé à cette entrée de stock"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Produit associé"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "Le prix payé au vendeur pour ce produit"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Prix d'achat du vendeur"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Quantité disponible du produit en stock"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Quantité en stock"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "SKU attribué par le fournisseur pour identifier le produit"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "UGS du vendeur"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Fichier numérique associé à ce stock, le cas échéant"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Fichier numérique"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Entrées de stock"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Catégorie à laquelle appartient ce produit"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Possibilité d'associer ce produit à une marque"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Étiquettes permettant de décrire ou de regrouper ce produit"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Indique si ce produit est livré numériquement"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Le produit est-il numérique ?"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Fournir un nom d'identification clair pour le produit"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Nom du produit"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Ajouter une description détaillée du produit"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Description du produit"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Numéro de pièce pour ce produit"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Numéro de pièce"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Catégorie de cet attribut"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Groupe de cet attribut"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Chaîne"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Entier"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Flotteur"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Booléen"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Tableau"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Objet"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Type de la valeur de l'attribut"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Type de valeur"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Nom de cet attribut"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Nom de l'attribut"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Attribut"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Attribut de cette valeur"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Le produit spécifique associé à la valeur de cet attribut"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "La valeur spécifique de cet attribut"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Fournir un texte alternatif pour l'image afin d'en faciliter l'accès"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Texte alt de l'image"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Télécharger le fichier image pour ce produit"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Image du produit"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Détermine l'ordre d'affichage des images"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Priorité à l'affichage"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "Le produit que cette image représente"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Images du produit"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Pourcentage de réduction pour les produits sélectionnés"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Pourcentage de réduction"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Donnez un nom unique à cette promotion"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Nom de la promotion"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Promotion description"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Sélectionnez les produits inclus dans cette promotion"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Produits inclus"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Promotion"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Produits que l'utilisateur a marqués comme souhaités"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Utilisateur qui possède cette liste de souhaits"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Propriétaire de la liste de souhaits"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Liste de souhaits"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} n'existe pas : {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documentaire"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentaires"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Non résolu"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Ligne d'adresse du client"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Ligne d'adresse"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Rue"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "District"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Ville"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Région"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Code postal"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Pays"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Point de géolocalisation (longitude, latitude)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Réponse JSON complète du géocodeur pour cette adresse"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Réponse JSON stockée du service de géocodage"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Adresse"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adresses"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
-msgstr ""
-"Code unique utilisé par un utilisateur pour bénéficier d'une réduction"
+msgstr "Code unique utilisé par un utilisateur pour bénéficier d'une réduction"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Identifiant du code promotionnel"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
-msgstr ""
-"Montant fixe de la remise appliqué si le pourcentage n'est pas utilisé"
+msgstr "Montant fixe de la remise appliqué si le pourcentage n'est pas utilisé"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Montant de l'escompte fixe"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
-msgstr ""
-"Pourcentage de réduction appliqué si le montant fixe n'est pas utilisé"
+msgstr "Pourcentage de réduction appliqué si le montant fixe n'est pas utilisé"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Pourcentage de réduction"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Date d'expiration du code promotionnel"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Heure de fin de validité"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Date à partir de laquelle ce code promotionnel est valable"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Heure de début de validité"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
-"Date à laquelle le code promotionnel a été utilisé, vide s'il n'a pas encore"
-" été utilisé."
+"Date à laquelle le code promotionnel a été utilisé, vide s'il n'a pas encore "
+"été utilisé."
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Horodatage de l'utilisation"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Utilisateur assigné à ce code promo, le cas échéant"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Utilisateur assigné"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Code promo"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Codes promotionnels"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1852,144 +1882,153 @@ msgstr ""
"Un seul type de remise doit être défini (montant ou pourcentage), mais pas "
"les deux ni aucun des deux."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Le code promotionnel a déjà été utilisé"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Type de réduction non valide pour le code promo {self.uuid}"
+msgstr "Type de réduction non valide pour le code promo {self.uuid} !"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "L'adresse de facturation utilisée pour cette commande"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Code promo optionnel appliqué à cette commande"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Code promo appliqué"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "L'adresse de livraison utilisée pour cette commande"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Adresse de livraison"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Statut actuel de la commande dans son cycle de vie"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Statut de la commande"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"Structure JSON des notifications à afficher aux utilisateurs ; dans "
"l'interface d'administration, la vue en tableau est utilisée."
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "Représentation JSON des attributs de cette commande"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "L'utilisateur qui a passé la commande"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Utilisateur"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "L'heure à laquelle la commande a été finalisée."
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Temps d'achat"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Un identifiant lisible par l'homme pour la commande"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "ID lisible par l'homme"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Commande"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Un utilisateur ne peut avoir qu'un seul ordre en cours à la fois !"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr ""
-"Vous ne pouvez pas ajouter de produits à une commande qui n'est pas en "
-"cours."
+"Vous ne pouvez pas ajouter de produits à une commande qui n'est pas en cours."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Vous ne pouvez pas ajouter des produits inactifs à la commande"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr ""
"Vous ne pouvez pas ajouter plus de produits que ceux disponibles en stock"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
"Vous ne pouvez pas retirer des produits d'une commande qui n'est pas en "
"cours."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} n'existe pas avec la requête <{query}>"
+msgstr "{name} n'existe pas avec la requête <{query}> !"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Le code promotionnel n'existe pas"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
"Vous ne pouvez acheter que des produits physiques dont l'adresse de "
"livraison est spécifiée !"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "L'adresse n'existe pas"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"Vous ne pouvez pas acheter en ce moment, veuillez réessayer dans quelques "
"minutes."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Valeur de force non valide"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Vous ne pouvez pas acheter une commande vide !"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+"Vous ne pouvez pas retirer des produits d'une commande qui n'est pas en "
+"cours."
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Un utilisateur sans solde ne peut pas acheter avec un solde !"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Insuffisance de fonds pour compléter la commande"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1998,7 +2037,7 @@ msgstr ""
"informations suivantes : nom du client, courriel du client, numéro de "
"téléphone du client"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
@@ -2006,116 +2045,118 @@ msgstr ""
"Méthode de paiement non valide : {payment_method} de "
"{available_payment_methods} !"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "Le prix payé par le client pour ce produit au moment de l'achat"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Prix d'achat au moment de la commande"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
-msgstr ""
-"Commentaires internes pour les administrateurs sur ce produit commandé"
+msgstr "Commentaires internes pour les administrateurs sur ce produit commandé"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Commentaires internes"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Notifications aux utilisateurs"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "Représentation JSON des attributs de cet élément"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Attributs du produit ordonnés"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Référence à l'ordre parent qui contient ce produit"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Ordonnance parentale"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Le produit spécifique associé à cette ligne de commande"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Quantité de ce produit spécifique dans la commande"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Quantité de produits"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Statut actuel de ce produit dans la commande"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Statut de la ligne de produits"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Le produit doit être associé à une commande !"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "mauvaise action spécifiée pour le retour d'information : {action}"
+msgstr "Mauvaise action spécifiée pour le retour d'information : {action} !"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
"Vous ne pouvez pas retirer des produits d'une commande qui n'est pas en "
"cours."
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Télécharger"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Téléchargements"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr ""
"Vous ne pouvez pas télécharger un bien numérique pour une commande non "
"terminée."
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Commentaires des utilisateurs sur leur expérience du produit"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Commentaires"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"Fait référence au produit spécifique d'une commande sur lequel porte le "
"retour d'information."
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Produit de commande apparenté"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Note attribuée par l'utilisateur au produit"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Evaluation du produit"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Retour d'information"
@@ -2126,13 +2167,13 @@ msgstr ""
"vous devez fournir un commentaire, une note et l'uuid du produit commandé "
"pour ajouter un commentaire."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Erreur lors de la création du promocode : {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2141,7 +2182,7 @@ msgid "order confirmation"
msgstr "Confirmation de commande"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2158,7 +2199,8 @@ msgstr "Bonjour %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Merci pour votre commande #%(order.pk)s ! Nous avons le plaisir de vous "
@@ -2166,14 +2208,14 @@ msgstr ""
"dessous les détails de votre commande :"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Total"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2193,23 +2235,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Meilleures salutations,
l'équipe de %(config.PROJECT_NAME)s"
+msgstr "Meilleures salutations,
l'équipe %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Tous droits réservés"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Commande livrée"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Bonjour %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2218,7 +2260,7 @@ msgstr ""
"Nous avons traité avec succès votre commande №%(order_uuid)s ! Vous "
"trouverez ci-dessous les détails de votre commande :"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2226,12 +2268,12 @@ msgstr ""
"informations\n"
" complémentaires"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Valeur"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2240,10 +2282,10 @@ msgstr ""
"Si vous avez des questions, n'hésitez pas à contacter notre service "
"d'assistance à %(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Meilleures salutations,
l'équipe de %(project_name)s"
+msgstr "Meilleures salutations,
l'équipe %(project_name)s"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2252,7 +2294,8 @@ msgstr "Clé"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Nous vous remercions pour votre commande ! Nous avons le plaisir de "
@@ -2273,7 +2316,7 @@ msgstr "Votre commande sera livrée à l'adresse suivante :"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Meilleures salutations,
l'équipe de %(config.PROJECT_NAME)s"
+msgstr "Meilleures salutations,
L'équipe %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2291,30 +2334,20 @@ msgstr "Les données et le délai d'attente sont tous deux nécessaires"
#: core/utils/caching.py:43
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr ""
-"La valeur du délai d'attente n'est pas valide, elle doit être comprise entre"
-" 0 et 216000 secondes."
-
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} doit être le modèle"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} doit être un objet de liste"
+"La valeur du délai d'attente n'est pas valide, elle doit être comprise entre "
+"0 et 216000 secondes."
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Nous contacter initié"
+msgstr "{config.PROJECT_NAME} | nous contacter initié"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Confirmation de commande"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr "{config.PROJECT_NAME} | Commande livrée"
@@ -2338,15 +2371,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Format de numéro de téléphone non valide"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Vous ne pouvez télécharger le bien numérique qu'une seule fois"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon introuvable"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Erreur de géocodage : {e}"
diff --git a/core/locale/hi_IN/LC_MESSAGES/django.mo b/core/locale/hi_IN/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/core/locale/hi_IN/LC_MESSAGES/django.mo and b/core/locale/hi_IN/LC_MESSAGES/django.mo differ
diff --git a/core/locale/hi_IN/LC_MESSAGES/django.po b/core/locale/hi_IN/LC_MESSAGES/django.po
index 8a0441eb..f4aec1bb 100644
--- a/core/locale/hi_IN/LC_MESSAGES/django.po
+++ b/core/locale/hi_IN/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -16,117 +16,115 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr ""
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr ""
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
"if set to false, this object can't be seen by users without needed permission"
msgstr ""
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr ""
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr ""
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr ""
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr ""
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr ""
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr ""
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr ""
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr ""
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr ""
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr ""
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
+#: core/admin.py:101
+msgid "selected items have been activated."
msgstr ""
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
msgstr ""
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
msgstr ""
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr ""
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr ""
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr ""
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr ""
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr ""
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr ""
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr ""
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr ""
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr ""
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr ""
@@ -178,7 +176,7 @@ msgstr ""
msgid "successful"
msgstr ""
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr ""
@@ -200,7 +198,7 @@ msgstr ""
msgid "send a message to the support team"
msgstr ""
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr ""
@@ -398,7 +396,7 @@ msgid ""
"transaction is initiated."
msgstr ""
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr ""
@@ -702,7 +700,7 @@ msgstr ""
msgid "add or remove feedback on an order–product relation"
msgstr ""
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr ""
@@ -750,8 +748,8 @@ msgstr ""
msgid "Quantity"
msgstr ""
-#: core/filters.py:73 core/filters.py:355 core/models.py:229 core/models.py:307
-#: core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr ""
@@ -812,1182 +810,1216 @@ msgstr ""
msgid "Product UUID"
msgstr ""
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr ""
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr ""
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr ""
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr ""
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr ""
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr ""
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr ""
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
msgstr ""
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr ""
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr ""
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr ""
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr ""
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr ""
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr ""
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr ""
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr ""
-#: core/graphene/mutations.py:326
-msgid "add a product to the wishlist"
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
msgstr ""
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr ""
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
#, python-brace-format
msgid "wishlist {wishlist_uuid} not found"
msgstr ""
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:370
+msgid "add a product to the wishlist"
+msgstr ""
+
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr ""
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr ""
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr ""
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr ""
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
"please send the attributes as the string formatted like attr1=value1,"
"attr2=value2"
msgstr ""
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr ""
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr ""
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr ""
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr ""
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
msgstr ""
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr ""
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr ""
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr ""
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr ""
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr ""
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr ""
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr ""
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr ""
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr ""
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
-#: core/graphene/object_types.py:133
+#: core/graphene/object_types.py:135
msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr ""
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr ""
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr ""
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr ""
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr ""
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr ""
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr ""
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr ""
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr ""
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr ""
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr ""
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr ""
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
msgstr ""
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr ""
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr ""
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr ""
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr ""
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr ""
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr ""
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr ""
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr ""
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr ""
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr ""
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr ""
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr ""
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr ""
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr ""
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr ""
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr ""
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr ""
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr ""
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr ""
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr ""
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr ""
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr ""
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr ""
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr ""
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr ""
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr ""
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr ""
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr ""
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr ""
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr ""
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr ""
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr ""
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr ""
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr ""
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr ""
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr ""
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr ""
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr ""
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr ""
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr ""
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr ""
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr ""
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr ""
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr ""
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr ""
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr ""
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr ""
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr ""
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr ""
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr ""
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr ""
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr ""
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr ""
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr ""
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr ""
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr ""
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr ""
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr ""
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr ""
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr ""
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr ""
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr ""
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr ""
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr ""
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr ""
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr ""
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr ""
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr ""
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr ""
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr ""
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr ""
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr ""
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr ""
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr ""
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr ""
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr ""
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr ""
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr ""
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr ""
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr ""
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr ""
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr ""
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr ""
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr ""
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr ""
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr ""
-
-#: core/models.py:358
-msgid "product name"
-msgstr ""
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr ""
-
-#: core/models.py:364
-msgid "product description"
-msgstr ""
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr ""
-
-#: core/models.py:372
-msgid "part number"
-msgstr ""
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr ""
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr ""
-
-#: core/models.py:465
-msgid "string"
-msgstr ""
-
-#: core/models.py:466
-msgid "integer"
-msgstr ""
-
-#: core/models.py:467
-msgid "float"
-msgstr ""
-
-#: core/models.py:468
-msgid "boolean"
-msgstr ""
-
-#: core/models.py:469
-msgid "array"
-msgstr ""
-
-#: core/models.py:470
-msgid "object"
-msgstr ""
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr ""
-
-#: core/models.py:473
-msgid "value type"
-msgstr ""
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr ""
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr ""
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr ""
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr ""
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr ""
-
-#: core/models.py:507 core/models.py:546 core/models.py:617 core/models.py:1361
-msgid "associated product"
-msgstr ""
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr ""
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr ""
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr ""
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr ""
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr ""
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr ""
-
-#: core/models.py:540
-msgid "display priority"
-msgstr ""
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr ""
-
-#: core/models.py:559
-msgid "product images"
-msgstr ""
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr ""
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr ""
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr ""
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr ""
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr ""
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr ""
-
-#: core/models.py:586
-msgid "included products"
-msgstr ""
-
-#: core/models.py:590
-msgid "promotion"
-msgstr ""
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr ""
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr ""
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr ""
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr ""
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr ""
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr ""
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr ""
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr ""
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr ""
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr ""
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr ""
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr ""
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr ""
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr ""
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr ""
-#: core/models.py:660
-msgid "products that the user has marked as wanted"
+#: core/models.py:605
+msgid "category this product belongs to"
msgstr ""
-#: core/models.py:668
-msgid "user who owns this wishlist"
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
msgstr ""
-#: core/models.py:669
-msgid "wishlist owner"
+#: core/models.py:620
+msgid "tags that help describe or group this product"
msgstr ""
-#: core/models.py:677
-msgid "wishlist"
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
msgstr ""
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
+#: core/models.py:626
+msgid "is product digital"
msgstr ""
-#: core/models.py:724
-msgid "documentary"
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
msgstr ""
-#: core/models.py:725
-msgid "documentaries"
+#: core/models.py:633
+msgid "product name"
msgstr ""
-#: core/models.py:735
-msgid "unresolved"
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
msgstr ""
-#: core/models.py:744
-msgid "address line for the customer"
+#: core/models.py:639
+msgid "product description"
msgstr ""
-#: core/models.py:745
-msgid "address line"
+#: core/models.py:646
+msgid "part number for this product"
msgstr ""
-#: core/models.py:747
-msgid "street"
+#: core/models.py:647
+msgid "part number"
msgstr ""
-#: core/models.py:748
-msgid "district"
+#: core/models.py:753
+msgid "category of this attribute"
msgstr ""
-#: core/models.py:749
-msgid "city"
-msgstr ""
-
-#: core/models.py:750
-msgid "region"
-msgstr ""
-
-#: core/models.py:751
-msgid "postal code"
-msgstr ""
-
-#: core/models.py:752
-msgid "country"
-msgstr ""
-
-#: core/models.py:759
-msgid "geolocation point: (longitude, latitude)"
-msgstr ""
-
-#: core/models.py:762
-msgid "full JSON response from geocoder for this address"
+#: core/models.py:761
+msgid "group of this attribute"
msgstr ""
#: core/models.py:767
-msgid "stored JSON response from the geocoding service"
+msgid "string"
+msgstr ""
+
+#: core/models.py:768
+msgid "integer"
+msgstr ""
+
+#: core/models.py:769
+msgid "float"
+msgstr ""
+
+#: core/models.py:770
+msgid "boolean"
+msgstr ""
+
+#: core/models.py:771
+msgid "array"
+msgstr ""
+
+#: core/models.py:772
+msgid "object"
+msgstr ""
+
+#: core/models.py:774
+msgid "type of the attribute's value"
msgstr ""
#: core/models.py:775
+msgid "value type"
+msgstr ""
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr ""
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr ""
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr ""
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr ""
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr ""
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr ""
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr ""
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr ""
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr ""
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr ""
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr ""
+
+#: core/models.py:883
+msgid "display priority"
+msgstr ""
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr ""
+
+#: core/models.py:902
+msgid "product images"
+msgstr ""
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr ""
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr ""
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr ""
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr ""
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr ""
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr ""
+
+#: core/models.py:962
+msgid "included products"
+msgstr ""
+
+#: core/models.py:966
+msgid "promotion"
+msgstr ""
+
+#: core/models.py:991
+msgid "products that the user has marked as wanted"
+msgstr ""
+
+#: core/models.py:999
+msgid "user who owns this wishlist"
+msgstr ""
+
+#: core/models.py:1000
+msgid "wishlist owner"
+msgstr ""
+
+#: core/models.py:1008
+msgid "wishlist"
+msgstr ""
+
+#: core/models.py:1075
+msgid "documentary"
+msgstr ""
+
+#: core/models.py:1076
+msgid "documentaries"
+msgstr ""
+
+#: core/models.py:1086
+msgid "unresolved"
+msgstr ""
+
+#: core/models.py:1132
+msgid "address line for the customer"
+msgstr ""
+
+#: core/models.py:1133
+msgid "address line"
+msgstr ""
+
+#: core/models.py:1135
+msgid "street"
+msgstr ""
+
+#: core/models.py:1136
+msgid "district"
+msgstr ""
+
+#: core/models.py:1137
+msgid "city"
+msgstr ""
+
+#: core/models.py:1138
+msgid "region"
+msgstr ""
+
+#: core/models.py:1139
+msgid "postal code"
+msgstr ""
+
+#: core/models.py:1140
+msgid "country"
+msgstr ""
+
+#: core/models.py:1147
+msgid "geolocation point: (longitude, latitude)"
+msgstr ""
+
+#: core/models.py:1150
+msgid "full JSON response from geocoder for this address"
+msgstr ""
+
+#: core/models.py:1155
+msgid "stored JSON response from the geocoding service"
+msgstr ""
+
+#: core/models.py:1163
msgid "address"
msgstr ""
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr ""
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr ""
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr ""
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr ""
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr ""
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr ""
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr ""
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr ""
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr ""
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr ""
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr ""
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr ""
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr ""
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr ""
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr ""
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr ""
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
msgstr ""
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr ""
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
msgstr ""
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr ""
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr ""
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr ""
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr ""
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr ""
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr ""
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr ""
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr ""
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr ""
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr ""
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr ""
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr ""
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr ""
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr ""
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr ""
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr ""
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr ""
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr ""
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr ""
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
msgstr ""
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr ""
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr ""
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr ""
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr ""
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr ""
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr ""
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
msgstr ""
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr ""
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr ""
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr ""
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr ""
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr ""
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr ""
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr ""
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr ""
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr ""
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr ""
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr ""
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr ""
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr ""
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr ""
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr ""
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
msgstr ""
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr ""
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr ""
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr ""
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr ""
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr ""
-#: core/models.py:1490
+#: core/models.py:1970
msgid "references the specific product in an order that this feedback is about"
msgstr ""
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr ""
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr ""
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr ""
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr ""
@@ -1996,13 +2028,13 @@ msgid ""
"you must provide a comment, rating, and order product uuid to add feedback."
msgstr ""
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr ""
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2011,7 +2043,7 @@ msgid "order confirmation"
msgstr ""
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2034,14 +2066,14 @@ msgid ""
msgstr ""
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr ""
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2062,45 +2094,45 @@ msgid "best regards,
the %(config.PROJECT_NAME)s team"
msgstr ""
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
" details of your order:"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
msgstr ""
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr ""
@@ -2148,27 +2180,17 @@ msgstr ""
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr ""
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr ""
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr ""
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
msgstr ""
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr ""
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr ""
@@ -2190,15 +2212,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr ""
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr ""
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr ""
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr ""
diff --git a/core/locale/it_IT/LC_MESSAGES/django.mo b/core/locale/it_IT/LC_MESSAGES/django.mo
index ee9a0fc6..67caf431 100644
Binary files a/core/locale/it_IT/LC_MESSAGES/django.mo and b/core/locale/it_IT/LC_MESSAGES/django.mo differ
diff --git a/core/locale/it_IT/LC_MESSAGES/django.po b/core/locale/it_IT/LC_MESSAGES/django.po
index 262e790d..8283b927 100644
--- a/core/locale/it_IT/LC_MESSAGES/django.po
+++ b/core/locale/it_IT/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,122 +13,119 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "ID univoco"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"L'ID univoco viene utilizzato per identificare con certezza qualsiasi "
"oggetto del database."
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "È attivo"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
-"Se impostato a false, questo oggetto non può essere visto dagli utenti senza"
-" i necessari permessi."
+"Se impostato a false, questo oggetto non può essere visto dagli utenti senza "
+"i necessari permessi."
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Creato"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Quando l'oggetto è apparso per la prima volta nel database"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modificato"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Quando l'oggetto è stato modificato per l'ultima volta"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Traduzioni"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Generale"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relazioni"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadati"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Timestamp"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr "Attivare il %(verbose_name_plural)s selezionato"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s attivato con successo!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Gli articoli selezionati sono stati attivati!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
msgstr "Disattivare il %(verbose_name_plural)s selezionato"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s disattivato con successo."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Gli articoli selezionati sono stati disattivati!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Valore dell'attributo"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Valori degli attributi"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Immagine"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Immagini"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stock"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Le scorte"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Ordina il prodotto"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Ordinare i prodotti"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "I bambini"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Configurazione"
@@ -180,7 +177,7 @@ msgstr "Momentale"
msgid "successful"
msgstr "Successo"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "I/O della cache"
@@ -190,7 +187,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"Applicare solo una chiave per leggere i dati consentiti dalla cache.\n"
-"Applicare chiave, dati e timeout con autenticazione per scrivere dati nella cache."
+"Applicare chiave, dati e timeout con autenticazione per scrivere dati nella "
+"cache."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -204,7 +202,7 @@ msgstr "Ottenere i parametri esponibili dell'applicazione"
msgid "send a message to the support team"
msgstr "Inviate un messaggio al team di assistenza"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Richiedere un URL CORSed. È consentito solo https."
@@ -247,8 +245,7 @@ msgstr ""
"Riscrivere un gruppo di attributi esistente salvando i non modificabili"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Riscrivere alcuni campi di un gruppo di attributi esistente salvando quelli "
"non modificabili"
@@ -303,8 +300,7 @@ msgstr ""
"modificabili"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Riscrivere alcuni campi di un valore di attributo esistente salvando i "
"valori non modificabili"
@@ -333,8 +329,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:144
msgid "rewrite some fields of an existing category saving non-editables"
msgstr ""
-"Riscrivere alcuni campi di una categoria esistente salvando gli elementi non"
-" modificabili"
+"Riscrivere alcuni campi di una categoria esistente salvando gli elementi non "
+"modificabili"
#: core/docs/drf/viewsets.py:151
msgid "list all orders (simple view)"
@@ -348,12 +344,12 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"Ricerca di sottostringhe senza distinzione di maiuscole e minuscole tra "
-"human_readable_id, order_products.product.name e "
-"order_products.product.partnumber"
+"human_readable_id, order_products.product.name e order_products.product."
+"partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -389,9 +385,9 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Ordinare per uno dei seguenti criteri: uuid, human_readable_id, user_email, "
"user, status, created, modified, buy_time, random. Prefisso con '-' per la "
@@ -421,8 +417,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:227
msgid "rewrite some fields of an existing order saving non-editables"
msgstr ""
-"Riscrivere alcuni campi di una categoria esistente salvando gli elementi non"
-" modificabili"
+"Riscrivere alcuni campi di una categoria esistente salvando gli elementi non "
+"modificabili"
#: core/docs/drf/viewsets.py:231
msgid "purchase an order"
@@ -435,10 +431,10 @@ msgid ""
"transaction is initiated."
msgstr ""
"Finalizza l'acquisto dell'ordine. Se si utilizza `forza_bilancio`, "
-"l'acquisto viene completato utilizzando il saldo dell'utente; se si utilizza"
-" `forza_pagamento`, viene avviata una transazione."
+"l'acquisto viene completato utilizzando il saldo dell'utente; se si utilizza "
+"`forza_pagamento`, viene avviata una transazione."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "acquistare un ordine senza creare un account"
@@ -504,8 +500,8 @@ msgstr "Elenco di tutti gli attributi (vista semplice)"
#: core/docs/drf/viewsets.py:282
msgid "for non-staff users, only their own wishlists are returned."
msgstr ""
-"Per gli utenti che non fanno parte del personale, vengono restituite solo le"
-" loro liste dei desideri."
+"Per gli utenti che non fanno parte del personale, vengono restituite solo le "
+"loro liste dei desideri."
#: core/docs/drf/viewsets.py:286
msgid "retrieve a single wishlist (detailed view)"
@@ -578,18 +574,28 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtrare in base a una o più coppie nome/valore dell'attributo. \n"
"- **Sintassi**: `nome_attraverso=metodo-valore[;attr2=metodo2-valore2]...`\n"
-"- **Metodi** (predefiniti a `icontains` se omessi): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
-"- **Tipo di valore**: JSON viene tentato per primo (in modo da poter passare liste/dict), `true`/`false` per booleani, interi, float; altrimenti viene trattato come stringa. \n"
-"- **Base64**: prefisso con `b64-` per codificare in base64 il valore grezzo. \n"
+"- **Metodi** (predefiniti a `icontains` se omessi): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
+"- **Tipo di valore**: JSON viene tentato per primo (in modo da poter passare "
+"liste/dict), `true`/`false` per booleani, interi, float; altrimenti viene "
+"trattato come stringa. \n"
+"- **Base64**: prefisso con `b64-` per codificare in base64 il valore "
+"grezzo. \n"
"Esempi: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\", \"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`"
@@ -645,10 +651,12 @@ msgstr "(esatto) Digitale e fisico"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Elenco separato da virgole dei campi da ordinare. Prefisso con `-` per l'ordinamento discendente. \n"
+"Elenco separato da virgole dei campi da ordinare. Prefisso con `-` per "
+"l'ordinamento discendente. \n"
"**Consentito:** uuid, rating, nome, slug, creato, modificato, prezzo, casuale"
#: core/docs/drf/viewsets.py:441
@@ -667,8 +675,7 @@ msgstr "Creare un prodotto"
#: core/docs/drf/viewsets.py:463
msgid "rewrite an existing product, preserving non-editable fields"
-msgstr ""
-"Riscrivere un prodotto esistente, preservando i campi non modificabili"
+msgstr "Riscrivere un prodotto esistente, preservando i campi non modificabili"
#: core/docs/drf/viewsets.py:478
msgid ""
@@ -746,8 +753,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:615
msgid "rewrite some fields of an existing feedback saving non-editables"
msgstr ""
-"Riscrivere alcuni campi di una categoria esistente salvando gli elementi non"
-" modificabili"
+"Riscrivere alcuni campi di una categoria esistente salvando gli elementi non "
+"modificabili"
#: core/docs/drf/viewsets.py:622
msgid "list all order–product relations (simple view)"
@@ -777,7 +784,7 @@ msgstr "eliminare una relazione ordine-prodotto"
msgid "add or remove feedback on an order–product relation"
msgstr "aggiungere o rimuovere un feedback su una relazione ordine-prodotto"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Non è stato fornito alcun termine di ricerca."
@@ -825,8 +832,8 @@ msgstr "Attributi"
msgid "Quantity"
msgstr "Quantità"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Lumaca"
@@ -888,219 +895,241 @@ msgstr "Livello"
msgid "Product UUID"
msgstr "UUID del prodotto"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Chiave da cercare o da inserire nella cache"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Data to store in cache"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Timeout in secondi per l'inserimento dei dati nella cache"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Dati in cache"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Dati JSON camelizzati dall'URL richiesto"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Sono consentiti solo gli URL che iniziano con http(s)://"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Aggiungere un prodotto all'ordine"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Ordine {order_uuid} non trovato"
+msgstr "Ordine {order_uuid} non trovato!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Rimuovere un prodotto dall'ordine"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Rimuovere tutti i prodotti dall'ordine"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Acquistare un ordine"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr ""
"Si prega di fornire order_uuid o order_hr_id, che si escludono a vicenda!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
-msgstr ""
-"Il metodo order.buy() ha fornito un tipo sbagliato: {type(instance)!s}"
+msgstr "Il metodo order.buy() ha fornito un tipo sbagliato: {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Eseguire un'azione su un elenco di prodotti nell'ordine"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Rimuovi/Aggiungi"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "L'azione deve essere \"aggiungere\" o \"rimuovere\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Eseguire un'azione su un elenco di prodotti nella wishlist"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Fornire il valore `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Lista dei desideri {wishlist_uuid} non trovata!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Aggiungere un prodotto all'ordine"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Lista dei desideri {wishlist_uuid} non trovata"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Rimuovere un prodotto dall'ordine"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Rimuovere un prodotto dall'ordine"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Rimuovere un prodotto dall'ordine"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Acquistare un ordine"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
-"Inviare gli attributi come stringa formattata come "
-"attr1=valore1,attr2=valore2"
+"Inviare gli attributi come stringa formattata come attr1=valore1,"
+"attr2=valore2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Aggiungere o eliminare un feedback per l'ordine-prodotto"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "L'azione deve essere `add` o `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Prodotto dell'ordine {order_product_uuid} non trovato!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Stringa di indirizzo originale fornita dall'utente"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} non esiste: {uuid}"
+msgstr "{name} non esiste: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Il limite deve essere compreso tra 1 e 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch: funziona a meraviglia"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Attributi"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Attributi raggruppati"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Gruppi di attributi"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Categorie"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Marche"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Categorie"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Percentuale di markup"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Quali attributi e valori possono essere utilizzati per filtrare questa "
"categoria."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Prezzi minimi e massimi per i prodotti di questa categoria, se disponibili."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tag per questa categoria"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Prodotti in questa categoria"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Venditori"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Latitudine (coordinata Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Longitudine (coordinata X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Come"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Valore di valutazione da 1 a 10, incluso, o 0 se non impostato."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Rappresenta il feedback di un utente."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Notifiche"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "URL di download per il prodotto dell'ordine, se applicabile"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Un elenco di prodotti ordinati in questo ordine"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Indirizzo di fatturazione"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1108,877 +1137,881 @@ msgstr ""
"Indirizzo di spedizione per questo ordine, lasciare in bianco se è uguale "
"all'indirizzo di fatturazione o se non è applicabile"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Prezzo totale dell'ordine"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Quantità totale di prodotti in ordine"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Tutti i prodotti sono presenti nell'ordine digitale"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transazioni per questo ordine"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Ordini"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "URL immagine"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Immagini del prodotto"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Categoria"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Feedback"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Marchio"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Gruppi di attributi"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Prezzo"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Quantità"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Numero di feedback"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Prodotti"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Codici promozionali"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Prodotti in vendita"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promozioni"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Venditore"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Prodotto"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Prodotti desiderati"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Liste dei desideri"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Prodotti contrassegnati"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Tag del prodotto"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Contrassegnato dalle categorie"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Tag delle categorie"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Nome del progetto"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Email aziendale"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Nome della società"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Indirizzo dell'azienda"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Numero di telefono dell'azienda"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"'email from', a volte deve essere usato al posto del valore dell'utente host"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Utente host dell'e-mail"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Importo massimo per il pagamento"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Importo minimo per il pagamento"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Dati analitici"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Dati pubblicitari"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configurazione"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Codice lingua"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Nome della lingua"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Bandiera della lingua, se esiste :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Ottenere un elenco delle lingue supportate"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Risultati della ricerca dei prodotti"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Risultati della ricerca dei prodotti"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Genitore di questo gruppo"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Gruppo di attributi padre"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Nome del gruppo di attributi"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Gruppo di attributi"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Memorizza le credenziali e gli endpoint necessari per la comunicazione API "
"del fornitore."
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Informazioni sull'autenticazione"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Definire il markup per i prodotti recuperati da questo fornitore"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Percentuale di ricarico del fornitore"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Nome del fornitore"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Nome del fornitore"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Identificatore interno dell'etichetta del prodotto"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Nome del tag"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Nome intuitivo per l'etichetta del prodotto"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Nome del tag"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Etichetta del prodotto"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "tag categoria"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "tag di categoria"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Caricare un'immagine che rappresenti questa categoria"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Categoria immagine"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr ""
"Definire una percentuale di ricarico per i prodotti di questa categoria"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Genitore di questa categoria per formare una struttura gerarchica"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Categoria di genitori"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Nome della categoria"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Indicare un nome per questa categoria"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Aggiungere una descrizione dettagliata per questa categoria"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Descrizione della categoria"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "tag che aiutano a descrivere o raggruppare questa categoria"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Priorità"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Nome del marchio"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Nome del marchio"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Caricare un logo che rappresenti questo marchio"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Immagine piccola del marchio"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Caricare un grande logo che rappresenti questo marchio"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Grande immagine del marchio"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Aggiungere una descrizione dettagliata del marchio"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Descrizione del marchio"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Categorie opzionali a cui questo marchio è associato"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Categorie"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Categoria a cui appartiene questo prodotto"
+#: core/models.py:515
+msgid "the vendor supplying this product stock"
+msgstr "Il venditore che fornisce questo stock di prodotti"
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Associare facoltativamente questo prodotto a un marchio"
+#: core/models.py:516
+msgid "associated vendor"
+msgstr "Venditore associato"
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Tag che aiutano a descrivere o raggruppare questo prodotto"
+#: core/models.py:520
+msgid "final price to the customer after markups"
+msgstr "Prezzo finale al cliente dopo i ricarichi"
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Indica se il prodotto è consegnato in formato digitale"
+#: core/models.py:521
+msgid "selling price"
+msgstr "Prezzo di vendita"
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Il prodotto è digitale"
+#: core/models.py:526
+msgid "the product associated with this stock entry"
+msgstr "Il prodotto associato a questa voce di magazzino"
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Fornire un nome identificativo chiaro per il prodotto"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Nome del prodotto"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Aggiungere una descrizione dettagliata del prodotto"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Descrizione del prodotto"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Numero di parte per questo prodotto"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Numero di parte"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Categoria di questo attributo"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Gruppo di questo attributo"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Stringa"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Intero"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Galleggiante"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Booleano"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Array"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Oggetto"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Tipo di valore dell'attributo"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Tipo di valore"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Nome dell'attributo"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Nome dell'attributo"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Attributo"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Attributo di questo valore"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Il prodotto specifico associato al valore di questo attributo"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
msgid "associated product"
msgstr "Prodotto associato"
-#: core/models.py:512
+#: core/models.py:534
+msgid "the price paid to the vendor for this product"
+msgstr "Il prezzo pagato al venditore per questo prodotto"
+
+#: core/models.py:535
+msgid "vendor purchase price"
+msgstr "Prezzo di acquisto del fornitore"
+
+#: core/models.py:539
+msgid "available quantity of the product in stock"
+msgstr "Quantità disponibile del prodotto in magazzino"
+
+#: core/models.py:540
+msgid "quantity in stock"
+msgstr "Quantità in magazzino"
+
+#: core/models.py:544
+msgid "vendor-assigned SKU for identifying the product"
+msgstr "SKU assegnato dal fornitore per identificare il prodotto"
+
+#: core/models.py:545
+msgid "vendor sku"
+msgstr "SKU del venditore"
+
+#: core/models.py:551
+msgid "digital file associated with this stock if applicable"
+msgstr "File digitale associato a questo stock, se applicabile"
+
+#: core/models.py:552
+msgid "digital file"
+msgstr "File digitale"
+
+#: core/models.py:561
+msgid "stock entries"
+msgstr "Voci di magazzino"
+
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Categoria a cui appartiene questo prodotto"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Associare facoltativamente questo prodotto a un marchio"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Tag che aiutano a descrivere o raggruppare questo prodotto"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Indica se il prodotto è consegnato in formato digitale"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Il prodotto è digitale"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Fornire un nome identificativo chiaro per il prodotto"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Nome del prodotto"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Aggiungere una descrizione dettagliata del prodotto"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Descrizione del prodotto"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Numero di parte per questo prodotto"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Numero di parte"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Categoria di questo attributo"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Gruppo di questo attributo"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Stringa"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Intero"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Galleggiante"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Booleano"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Array"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Oggetto"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Tipo di valore dell'attributo"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Tipo di valore"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Nome dell'attributo"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Nome dell'attributo"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Attributo"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Attributo di questo valore"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Il prodotto specifico associato al valore di questo attributo"
+
+#: core/models.py:837
msgid "the specific value for this attribute"
msgstr "Il valore specifico per questo attributo"
-#: core/models.py:528
+#: core/models.py:871
msgid "provide alternative text for the image for accessibility"
msgstr ""
"Fornire un testo alternativo per l'immagine ai fini dell'accessibilità."
-#: core/models.py:529
+#: core/models.py:872
msgid "image alt text"
msgstr "Testo alt dell'immagine"
-#: core/models.py:532
+#: core/models.py:875
msgid "upload the image file for this product"
msgstr "Caricare il file immagine per questo prodotto"
-#: core/models.py:533 core/models.py:558
+#: core/models.py:876 core/models.py:901
msgid "product image"
msgstr "Immagine del prodotto"
-#: core/models.py:539
+#: core/models.py:882
msgid "determines the order in which images are displayed"
msgstr "Determina l'ordine di visualizzazione delle immagini"
-#: core/models.py:540
+#: core/models.py:883
msgid "display priority"
msgstr "Priorità del display"
-#: core/models.py:545
+#: core/models.py:888
msgid "the product that this image represents"
msgstr "Il prodotto che questa immagine rappresenta"
-#: core/models.py:559
+#: core/models.py:902
msgid "product images"
msgstr "Immagini del prodotto"
-#: core/models.py:567
+#: core/models.py:943
msgid "percentage discount for the selected products"
msgstr "Percentuale di sconto per i prodotti selezionati"
-#: core/models.py:568
+#: core/models.py:944
msgid "discount percentage"
msgstr "Percentuale di sconto"
-#: core/models.py:573
+#: core/models.py:949
msgid "provide a unique name for this promotion"
msgstr "Fornite un nome unico per questa promozione"
-#: core/models.py:574
+#: core/models.py:950
msgid "promotion name"
msgstr "Nome della promozione"
-#: core/models.py:580
+#: core/models.py:956
msgid "promotion description"
msgstr "Descrizione della promozione"
-#: core/models.py:585
+#: core/models.py:961
msgid "select which products are included in this promotion"
msgstr "Selezionare i prodotti inclusi in questa promozione"
-#: core/models.py:586
+#: core/models.py:962
msgid "included products"
msgstr "Prodotti inclusi"
-#: core/models.py:590
+#: core/models.py:966
msgid "promotion"
msgstr "Promozione"
-#: core/models.py:605
-msgid "the vendor supplying this product stock"
-msgstr "Il venditore che fornisce questo stock di prodotti"
-
-#: core/models.py:606
-msgid "associated vendor"
-msgstr "Venditore associato"
-
-#: core/models.py:610
-msgid "final price to the customer after markups"
-msgstr "Prezzo finale al cliente dopo i ricarichi"
-
-#: core/models.py:611
-msgid "selling price"
-msgstr "Prezzo di vendita"
-
-#: core/models.py:616
-msgid "the product associated with this stock entry"
-msgstr "Il prodotto associato a questa voce di magazzino"
-
-#: core/models.py:624
-msgid "the price paid to the vendor for this product"
-msgstr "Il prezzo pagato al venditore per questo prodotto"
-
-#: core/models.py:625
-msgid "vendor purchase price"
-msgstr "Prezzo di acquisto del fornitore"
-
-#: core/models.py:629
-msgid "available quantity of the product in stock"
-msgstr "Quantità disponibile del prodotto in magazzino"
-
-#: core/models.py:630
-msgid "quantity in stock"
-msgstr "Quantità in magazzino"
-
-#: core/models.py:634
-msgid "vendor-assigned SKU for identifying the product"
-msgstr "SKU assegnato dal fornitore per identificare il prodotto"
-
-#: core/models.py:635
-msgid "vendor sku"
-msgstr "SKU del venditore"
-
-#: core/models.py:641
-msgid "digital file associated with this stock if applicable"
-msgstr "File digitale associato a questo stock, se applicabile"
-
-#: core/models.py:642
-msgid "digital file"
-msgstr "File digitale"
-
-#: core/models.py:651
-msgid "stock entries"
-msgstr "Voci di magazzino"
-
-#: core/models.py:660
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Prodotti che l'utente ha contrassegnato come desiderati"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Utente che possiede questa wishlist"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Proprietario della lista dei desideri"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Lista dei desideri"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} non esiste: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documentario"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentari"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Non risolto"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Indirizzo del cliente"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Linea di indirizzo"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Via"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Distretto"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Città"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Regione"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Codice postale"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Paese"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Punto di geolocalizzazione(Longitudine, Latitudine)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Risposta JSON completa di geocoder per questo indirizzo"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Risposta JSON memorizzata dal servizio di geocodifica"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Indirizzo"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Indirizzi"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Codice univoco utilizzato da un utente per riscattare uno sconto"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Identificatore del codice promozionale"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
-msgstr ""
-"Importo fisso dello sconto applicato se non si utilizza la percentuale"
+msgstr "Importo fisso dello sconto applicato se non si utilizza la percentuale"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Importo fisso dello sconto"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Sconto percentuale applicato se l'importo fisso non viene utilizzato"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Sconto percentuale"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Data di scadenza del codice promozionale"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Tempo di validità finale"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Data a partire dalla quale il codice promozionale è valido"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Ora di inizio validità"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Timestamp in cui è stato utilizzato il codice promozionale, vuoto se non "
"ancora utilizzato"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Timestamp d'uso"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Utente assegnato a questo codice promozionale, se applicabile"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Utente assegnato"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Codice promozionale"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Codici promozionali"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
msgstr ""
-"È necessario definire un solo tipo di sconto (importo o percentuale), ma non"
-" entrambi o nessuno."
+"È necessario definire un solo tipo di sconto (importo o percentuale), ma non "
+"entrambi o nessuno."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Il codice promozionale è già stato utilizzato"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Tipo di sconto non valido per il codice promozionale {self.uuid}"
+msgstr "Tipo di sconto non valido per il codice promozionale {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "L'indirizzo di fatturazione utilizzato per questo ordine"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Codice promozionale opzionale applicato a questo ordine"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Codice promozionale applicato"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "L'indirizzo di spedizione utilizzato per questo ordine"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Indirizzo di spedizione"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Stato attuale dell'ordine nel suo ciclo di vita"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Stato dell'ordine"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"Struttura JSON delle notifiche da mostrare agli utenti; nell'interfaccia "
"utente dell'amministratore viene utilizzata la visualizzazione a tabella."
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "Rappresentazione JSON degli attributi dell'ordine per questo ordine"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "L'utente che ha effettuato l'ordine"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Utente"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Il timestamp del momento in cui l'ordine è stato finalizzato"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Acquista tempo"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Un identificatore leggibile dall'uomo per l'ordine"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "ID leggibile dall'uomo"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Ordine"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Un utente può avere un solo ordine pendente alla volta!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr ""
"Non è possibile aggiungere prodotti a un ordine che non sia in sospeso."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Non è possibile aggiungere all'ordine prodotti inattivi"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr ""
"Non è possibile aggiungere più prodotti di quelli disponibili in magazzino"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "Non è possibile rimuovere i prodotti da un ordine che non è in corso."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} non esiste con la query <{query}>."
+msgstr "{name} non esiste con la query <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Il codice promozionale non esiste"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
"È possibile acquistare solo prodotti fisici con indirizzo di spedizione "
"specificato!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "L'indirizzo non esiste"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"In questo momento non è possibile acquistare, riprovare tra qualche minuto."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Valore di forza non valido"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Non è possibile acquistare un ordine vuoto!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "Non è possibile acquistare un ordine senza un utente!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Un utente senza saldo non può acquistare con il saldo!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Fondi insufficienti per completare l'ordine"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1987,7 +2020,7 @@ msgstr ""
"seguenti informazioni: nome del cliente, e-mail del cliente, numero di "
"telefono del cliente"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
@@ -1995,111 +2028,114 @@ msgstr ""
"Metodo di pagamento non valido: {payment_method} da "
"{available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr ""
"Il prezzo pagato dal cliente per questo prodotto al momento dell'acquisto."
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Prezzo di acquisto al momento dell'ordine"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "Commenti interni per gli amministratori su questo prodotto ordinato"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Commenti interni"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Notifiche degli utenti"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "Rappresentazione JSON degli attributi di questo elemento"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Attributi del prodotto ordinati"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Riferimento all'ordine padre che contiene questo prodotto"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Ordine dei genitori"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Il prodotto specifico associato a questa riga d'ordine"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Quantità di questo prodotto specifico nell'ordine"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Quantità di prodotto"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Stato attuale di questo prodotto nell'ordine"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Stato della linea di prodotti"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "L'ordine-prodotto deve avere un ordine associato!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "azione errata specificata per il feedback: {action}"
+msgstr "Azione errata specificata per il feedback: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "non è possibile dare un riscontro a un ordine non ricevuto"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Scaricare"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Scaricamento"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "Non è possibile scaricare un bene digitale per un ordine non finito."
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Commenti degli utenti sulla loro esperienza con il prodotto"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Commenti di feedback"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"Riferisce il prodotto specifico in un ordine di cui si tratta il feedback."
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Prodotto correlato all'ordine"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Valutazione del prodotto assegnata dall'utente"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Valutazione del prodotto"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Feedback"
@@ -2107,16 +2143,16 @@ msgstr "Feedback"
msgid ""
"you must provide a comment, rating, and order product uuid to add feedback."
msgstr ""
-"per aggiungere un feedback è necessario fornire un commento, una valutazione"
-" e l'uuid del prodotto dell'ordine."
+"per aggiungere un feedback è necessario fornire un commento, una valutazione "
+"e l'uuid del prodotto dell'ordine."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Errore durante la creazione del codice promozionale: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2125,7 +2161,7 @@ msgid "order confirmation"
msgstr "Conferma dell'ordine"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2142,7 +2178,8 @@ msgstr "Hello %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Grazie per il vostro ordine #%(order.pk)s! Siamo lieti di informarla che "
@@ -2150,14 +2187,14 @@ msgstr ""
"del vostro ordine:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Totale"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2171,8 +2208,8 @@ msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(config.EMAIL_HOST_USER)s."
msgstr ""
-"Per qualsiasi domanda, non esitate a contattare il nostro supporto al numero"
-" %(config.EMAIL_HOST_USER)s."
+"Per qualsiasi domanda, non esitate a contattare il nostro supporto al numero "
+"%(config.EMAIL_HOST_USER)s."
#: core/templates/digital_order_created_email.html:133
#, python-format
@@ -2180,20 +2217,20 @@ msgid "best regards,
the %(config.PROJECT_NAME)s team"
msgstr "Cordiali saluti,
il team %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Tutti i diritti riservati"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Ordine consegnato"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hello %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2202,7 +2239,7 @@ msgstr ""
"Abbiamo elaborato con successo il suo ordine №%(order_uuid)s! Di seguito "
"sono riportati i dettagli del suo ordine:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2210,21 +2247,21 @@ msgstr ""
"ulteriori\n"
" informazioni"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Valore"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
msgstr ""
-"Per qualsiasi domanda, non esitate a contattare il nostro supporto al numero"
-" %(contact_email)s."
+"Per qualsiasi domanda, non esitate a contattare il nostro supporto al numero "
+"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Cordiali saluti,
il team %(project_name)s"
@@ -2236,7 +2273,8 @@ msgstr "Chiave"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Grazie per il vostro ordine! Siamo lieti di confermare il suo acquisto. Di "
@@ -2276,27 +2314,17 @@ msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr ""
"Valore di timeout non valido, deve essere compreso tra 0 e 216000 secondi."
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} deve essere un modello"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} deve essere un oggetto elenco"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Contatti avviati"
+msgstr "{config.PROJECT_NAME} | contattaci iniziato"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Conferma d'ordine"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr "{config.PROJECT_NAME} | Ordine consegnato"
@@ -2313,22 +2341,22 @@ msgstr "Il parametro NOMINATIM_URL deve essere configurato!"
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
msgstr ""
-"Le dimensioni dell'immagine non devono superare w{max_width} x h{max_height}"
-" pixel"
+"Le dimensioni dell'immagine non devono superare w{max_width} x h{max_height} "
+"pixel"
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "Formato del numero di telefono non valido"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "È possibile scaricare l'asset digitale una sola volta"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon non trovata"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Errore di geocodifica: {e}"
diff --git a/core/locale/ja_JP/LC_MESSAGES/django.mo b/core/locale/ja_JP/LC_MESSAGES/django.mo
index 683bc591..2244ee80 100644
Binary files a/core/locale/ja_JP/LC_MESSAGES/django.mo and b/core/locale/ja_JP/LC_MESSAGES/django.mo differ
diff --git a/core/locale/ja_JP/LC_MESSAGES/django.po b/core/locale/ja_JP/LC_MESSAGES/django.po
index 98076e69..cfec51a6 100644
--- a/core/locale/ja_JP/LC_MESSAGES/django.po
+++ b/core/locale/ja_JP/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,118 +13,118 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "ユニークID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
-msgstr "ユニークIDは、データベースオブジェクトを確実に識別するために使用されます。"
+msgstr ""
+"ユニークIDは、データベースオブジェクトを確実に識別するために使用されます。"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "アクティブ"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
-msgstr "falseに設定された場合、このオブジェクトは必要なパーミッションのないユーザーには見えない。"
+"if set to false, this object can't be seen by users without needed permission"
+msgstr ""
+"falseに設定された場合、このオブジェクトは必要なパーミッションのないユーザーに"
+"は見えない。"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "作成"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "そのオブジェクトが初めてデータベースに登場した時"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "変形"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "オブジェクトの最終編集日時"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "翻訳"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "一般"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "関係"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "メタデータ"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "タイムスタンプ"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "選択した %(verbose_name_plural)s をアクティブにする。"
+msgstr "選択した%(verbose_name_plural)sをアクティブにする"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)sは正常に起動しました!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "選択した項目がアクティブになりました!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "選択された %(verbose_name_plural)s を非アクティブにする。"
+msgstr "選択された%(verbose_name_plural)sを非アクティブにする"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)sは正常に停止しました。"
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "選択されたアイテムは無効化されました!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "属性値"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "属性値"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "画像"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "画像"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "在庫"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "株式"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "商品のご注文"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "商品のご注文"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "子供たち"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "コンフィグ"
@@ -176,7 +176,7 @@ msgstr "モメンタル"
msgid "successful"
msgstr "成功"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "キャッシュI/O"
@@ -186,7 +186,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"許可されたデータをキャッシュから読み出すには、キーのみを適用する。\n"
-"キャッシュにデータを書き込むには、認証付きのキー、データ、タイムアウトを適用する。"
+"キャッシュにデータを書き込むには、認証付きのキー、データ、タイムアウトを適用"
+"する。"
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -200,7 +201,7 @@ msgstr "アプリケーションの公開可能なパラメータを取得する
msgid "send a message to the support team"
msgstr "サポートチームにメッセージを送る"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "CORSされたURLを要求する。httpsのみ許可。"
@@ -216,7 +217,9 @@ msgstr "ビジネスとして注文を購入する"
msgid ""
"purchase an order as a business, using the provided `products` with "
"`product_uuid` and `attributes`."
-msgstr "提供された `product` と `product_uuid` と `attributes` を使用して、ビジネスとして注文を購入する。"
+msgstr ""
+"提供された `product` と `product_uuid` と `attributes` を使用して、ビジネスと"
+"して注文を購入する。"
#: core/docs/drf/viewsets.py:43
msgid "list all attribute groups (simple view)"
@@ -239,9 +242,10 @@ msgid "rewrite an existing attribute group saving non-editables"
msgstr "既存の属性グループを書き換えて、編集不可能なものを保存する。"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
-msgstr "既存の属性グループのいくつかのフィールドを書き換え、編集不可能なものを保存する。"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
+msgstr ""
+"既存の属性グループのいくつかのフィールドを書き換え、編集不可能なものを保存す"
+"る。"
#: core/docs/drf/viewsets.py:70
msgid "list all attributes (simple view)"
@@ -265,7 +269,8 @@ msgstr "既存の属性を書き換える。"
#: core/docs/drf/viewsets.py:90
msgid "rewrite some fields of an existing attribute saving non-editables"
-msgstr "既存の属性のいくつかのフィールドを書き換え、編集不可能なものを保存する。"
+msgstr ""
+"既存の属性のいくつかのフィールドを書き換え、編集不可能なものを保存する。"
#: core/docs/drf/viewsets.py:97
msgid "list all attribute values (simple view)"
@@ -288,9 +293,9 @@ msgid "rewrite an existing attribute value saving non-editables"
msgstr "既存の属性値を書き換える。"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
-msgstr "既存の属性値のいくつかのフィールドを書き換え、編集不可能な値を保存する。"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
+msgstr ""
+"既存の属性値のいくつかのフィールドを書き換え、編集不可能な値を保存する。"
#: core/docs/drf/viewsets.py:124
msgid "list all categories (simple view)"
@@ -326,10 +331,11 @@ msgstr "スタッフ以外のユーザーについては、自分の注文のみ
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
-"human_readable_id、order_products.product.name、order_products.product.partnumberの大文字小文字を区別しない部分文字列検索"
+"human_readable_id、order_products.product.name、order_products.product."
+"partnumberの大文字小文字を区別しない部分文字列検索"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -349,7 +355,8 @@ msgstr "人間が読み取れる正確な注文IDによるフィルタリング"
#: core/docs/drf/viewsets.py:185
msgid "Filter by user's email (case-insensitive exact match)"
-msgstr "ユーザーのEメールによるフィルタリング(大文字・小文字を区別しない完全一致)"
+msgstr ""
+"ユーザーのEメールによるフィルタリング(大文字・小文字を区別しない完全一致)"
#: core/docs/drf/viewsets.py:190
msgid "Filter by user's UUID"
@@ -357,15 +364,19 @@ msgstr "ユーザーのUUIDによるフィルタリング"
#: core/docs/drf/viewsets.py:195
msgid "Filter by order status (case-insensitive substring match)"
-msgstr "注文ステータスによるフィルタリング(大文字と小文字を区別しない部分文字列マッチ)"
+msgstr ""
+"注文ステータスによるフィルタリング(大文字と小文字を区別しない部分文字列マッ"
+"チ)"
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
-"uuid、human_readable_id、user_email、user、status、created、modified、buy_time、randomのいずれかによる順序。降順の場合は'-'をプレフィックスとしてつける(例:'-buy_time')。"
+"uuid、human_readable_id、user_email、user、status、created、modified、"
+"buy_time、randomのいずれかによる順序。降順の場合は'-'をプレフィックスとしてつ"
+"ける(例:'-buy_time')。"
#: core/docs/drf/viewsets.py:210
msgid "retrieve a single order (detailed view)"
@@ -401,10 +412,11 @@ msgid ""
"completed using the user's balance; if `force_payment` is used, a "
"transaction is initiated."
msgstr ""
-"注文の購入を確定する。force_balance` が使用された場合、ユーザーの残高を使用して購入が完了します。 `force_payment` "
-"が使用された場合、トランザクションが開始されます。"
+"注文の購入を確定する。force_balance` が使用された場合、ユーザーの残高を使用し"
+"て購入が完了します。 `force_payment` が使用された場合、トランザクションが開始"
+"されます。"
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "アカウントを作成せずに注文を購入する"
@@ -420,7 +432,8 @@ msgstr "注文に商品を追加する"
msgid ""
"adds a product to an order using the provided `product_uuid` and "
"`attributes`."
-msgstr "指定した `product_uuid` と `attributes` を使用して、商品を注文に追加する。"
+msgstr ""
+"指定した `product_uuid` と `attributes` を使用して、商品を注文に追加する。"
#: core/docs/drf/viewsets.py:260
msgid "add a list of products to order, quantities will not count"
@@ -430,7 +443,9 @@ msgstr "数量はカウントされません。"
msgid ""
"adds a list of products to an order using the provided `product_uuid` and "
"`attributes`."
-msgstr "指定された `product_uuid` と `attributes` を使用して、注文に商品のリストを追加する。"
+msgstr ""
+"指定された `product_uuid` と `attributes` を使用して、注文に商品のリストを追"
+"加する。"
#: core/docs/drf/viewsets.py:266
msgid "remove product from order"
@@ -440,7 +455,9 @@ msgstr "注文から商品を削除する"
msgid ""
"removes a product from an order using the provided `product_uuid` and "
"`attributes`."
-msgstr "指定された `product_uuid` と `attributes` を使用して、注文から商品を削除する。"
+msgstr ""
+"指定された `product_uuid` と `attributes` を使用して、注文から商品を削除す"
+"る。"
#: core/docs/drf/viewsets.py:272
msgid "remove product from order, quantities will not count"
@@ -450,7 +467,9 @@ msgstr "注文から商品を削除すると、数量はカウントされませ
msgid ""
"removes a list of products from an order using the provided `product_uuid` "
"and `attributes`"
-msgstr "指定された `product_uuid` と `attributes` を用いて、注文から商品のリストを削除する。"
+msgstr ""
+"指定された `product_uuid` と `attributes` を用いて、注文から商品のリストを削"
+"除する。"
#: core/docs/drf/viewsets.py:281
msgid "list all wishlists (simple view)"
@@ -482,7 +501,8 @@ msgstr "既存の属性を書き換える。"
#: core/docs/drf/viewsets.py:303
msgid "rewrite some fields of an existing wishlist saving non-editables"
-msgstr "既存の属性のいくつかのフィールドを書き換え、編集不可能なものを保存する。"
+msgstr ""
+"既存の属性のいくつかのフィールドを書き換え、編集不可能なものを保存する。"
#: core/docs/drf/viewsets.py:307
msgid "add product to wishlist"
@@ -498,7 +518,8 @@ msgstr "ウィッシュリストから商品を削除する"
#: core/docs/drf/viewsets.py:314
msgid "removes a product from an wishlist using the provided `product_uuid`"
-msgstr "指定された `product_uuid` を使ってウィッシュリストから商品を削除します。"
+msgstr ""
+"指定された `product_uuid` を使ってウィッシュリストから商品を削除します。"
#: core/docs/drf/viewsets.py:319
msgid "add many products to wishlist"
@@ -506,7 +527,8 @@ msgstr "ウィッシュリストに多くの商品を追加する"
#: core/docs/drf/viewsets.py:320
msgid "adds many products to an wishlist using the provided `product_uuids`"
-msgstr "指定された `product_uuids` を使ってウィッシュリストに多くの商品を追加する。"
+msgstr ""
+"指定された `product_uuids` を使ってウィッシュリストに多くの商品を追加する。"
#: core/docs/drf/viewsets.py:325
msgid "remove many products from wishlist"
@@ -515,24 +537,34 @@ msgstr "注文から商品を削除する"
#: core/docs/drf/viewsets.py:326
msgid ""
"removes many products from an wishlist using the provided `product_uuids`"
-msgstr "指定された `product_uuids` を使ってウィッシュリストから多くの商品を削除する。"
+msgstr ""
+"指定された `product_uuids` を使ってウィッシュリストから多くの商品を削除する。"
#: core/docs/drf/viewsets.py:333
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"1つまたは複数の属性名/値のペアでフィルタリングします。 \n"
"- シンタックス**:attr_name=method-value[;attr2=method2-value2]...`。\n"
-"- メソッド** (省略された場合のデフォルトは `icontains`):`iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
-"- 値の型付け**:boolean, integer, float の場合は `true`/`false`; それ以外の場合は文字列として扱う。 \n"
-"- それ以外は文字列として扱われる。 **Base64**: `b64-` をプレフィックスとしてつけると、生の値を URL-safe base64-encode することができる。 \n"
+"- メソッド** (省略された場合のデフォルトは `icontains`):`iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
+"- 値の型付け**:boolean, integer, float の場合は `true`/`false`; それ以外の場"
+"合は文字列として扱う。 \n"
+"- それ以外は文字列として扱われる。 **Base64**: `b64-` をプレフィックスとして"
+"つけると、生の値を URL-safe base64-encode することができる。 \n"
"例 \n"
"color=exact-red`、`size=gt-10`、`features=in-[\"wifi\", \"bluetooth\"]`、\n"
"b64-description=icontains-aGVhdC1jb2xk`。"
@@ -587,10 +619,12 @@ msgstr "(正確には)デジタルとフィジカル"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"カンマ区切りの並べ替えフィールドのリスト。降順の場合は `-` をプレフィックスとしてつける。 \n"
+"カンマ区切りの並べ替えフィールドのリスト。降順の場合は `-` をプレフィックスと"
+"してつける。 \n"
"**許可:** uuid, rating, name, slug, created, modified, price, random"
#: core/docs/drf/viewsets.py:441
@@ -614,7 +648,9 @@ msgstr "編集不可能なフィールドを保持したまま、既存の製品
#: core/docs/drf/viewsets.py:478
msgid ""
"update some fields of an existing product, preserving non-editable fields"
-msgstr "編集不可能なフィールドを保持したまま、既存の製品の一部のフィールドを更新する。"
+msgstr ""
+"編集不可能なフィールドを保持したまま、既存の製品の一部のフィールドを更新す"
+"る。"
#: core/docs/drf/viewsets.py:493
msgid "delete a product"
@@ -655,8 +691,8 @@ msgstr "オートコンプリート住所入力"
#: core/docs/drf/viewsets.py:576
msgid "raw data query string, please append with data from geo-IP endpoint"
msgstr ""
-"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
-" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
+"docker compose exec app poetry run python manage.py deepl_translate -l en-gb "
+"-l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
"it-it -l ja-jp -l kk-kz -l n-nl -l pl-pl -l pt-br -l ro-ro -l ru-ru -l zh-"
"hans -a core -a geo -a payments -a vibes_auth -a blog"
@@ -686,7 +722,9 @@ msgstr "既存のフィードバックを書き換える。"
#: core/docs/drf/viewsets.py:615
msgid "rewrite some fields of an existing feedback saving non-editables"
-msgstr "既存のフィードバックのいくつかのフィールドを書き換えて、編集不可能なものを保存する。"
+msgstr ""
+"既存のフィードバックのいくつかのフィールドを書き換えて、編集不可能なものを保"
+"存する。"
#: core/docs/drf/viewsets.py:622
msgid "list all order–product relations (simple view)"
@@ -716,7 +754,7 @@ msgstr "注文と商品の関係を削除する"
msgid "add or remove feedback on an order–product relation"
msgstr "注文と商品の関係に関するフィードバックを追加または削除する。"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "検索語はありません。"
@@ -764,8 +802,8 @@ msgstr "属性"
msgid "Quantity"
msgstr "数量"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "スラッグ"
@@ -779,7 +817,8 @@ msgstr "サブカテゴリーを含む"
#: core/filters.py:147
msgid "there must be a category_uuid to use include_subcategories flag"
-msgstr "include_subcategoriesフラグを使うには、category_uuidがなければならない。"
+msgstr ""
+"include_subcategoriesフラグを使うには、category_uuidがなければならない。"
#: core/filters.py:280
msgid "Search (ID, product name or part number)"
@@ -826,1200 +865,1241 @@ msgstr "レベル"
msgid "Product UUID"
msgstr "製品UUID"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "キャッシュを探すキー、またはキャッシュにセットするキー"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "キャッシュに保存するデータ"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "キャッシュにデータをセットするタイムアウト時間(秒"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "キャッシュ・データ"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "リクエストされたURLからキャメル化されたJSONデータ"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "http(s)://で始まるURLのみが許可されます。"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "注文に商品を追加する"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "注文{order_uuid}が見つかりません"
+msgstr "注文 {order_uuid} が見つかりません!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "注文から商品を削除する"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "注文からすべての商品を削除する"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "注文する"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "order_uuidまたはorder_hr_idを入力してください!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "order.buy()メソッドから間違った型が来た:{type(instance)!s}。"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "注文商品のリストに対してアクションを実行する"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "削除/追加"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "アクションは \"add \"か \"remove \"のどちらかでなければならない!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "ウィッシュリストの商品リストに対してアクションを実行する"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "wishlist_uuid`の値を指定してください。"
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "ウィッシュリスト {wishlist_uuid} が見つかりません!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "注文に商品を追加する"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "ウィッシュリスト{wishlist_uuid}が見つかりません。"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "注文から商品を削除する"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "注文から商品を削除する"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "注文から商品を削除する"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "注文する"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
-msgstr "属性は、attr1=value1,attr2=value2のような形式の文字列として送信してください。"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
+msgstr ""
+"属性は、attr1=value1,attr2=value2のような形式の文字列として送信してください。"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "orderproductに対するフィードバックを追加または削除する。"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "アクションは `add` または `remove` のいずれかでなければならない!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Orderproduct {order_product_uuid} が見つかりません!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "ユーザーが提供したオリジナルのアドレス文字列"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} は存在しません:{uuid} は存在しません。"
+msgstr "{name}は存在しません:{uuid}が存在しません!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "上限は1から10の間でなければならない"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - 魅力のように動作"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "属性"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "グループ化された属性"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "属性のグループ"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "カテゴリー"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "ブランド"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "カテゴリー"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "マークアップ率"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr "このカテゴリのフィルタリングに使用できる属性と値。"
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr "このカテゴリーの商品の最低価格と最高価格がある場合。"
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "このカテゴリのタグ"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "このカテゴリの製品"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "ベンダー"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "緯度(Y座標)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "経度(X座標)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "どのように"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "1から10までの評価値(設定されていない場合は0)。"
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "ユーザーからのフィードバックを表す。"
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "お知らせ"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "該当する場合は、この注文商品のダウンロードURLを入力してください。"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "注文商品のリスト"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "請求先住所"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
msgstr "請求先住所と同じ場合、または該当しない場合は空白にしてください。"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "この注文の合計金額"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "注文商品の総数量"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "ご注文の商品はすべてデジタルですか?"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "この注文の取引"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "受注状況"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "画像URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "製品画像"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "カテゴリー"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "フィードバック"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "ブランド"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "属性グループ"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "価格"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "数量"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "フィードバック数"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "製品紹介"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "プロモコード"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "販売商品"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "プロモーション"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "ベンダー"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "製品"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "ウィッシュリスト掲載商品"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "ウィッシュリスト"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "タグ別アーカイブ"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "商品タグ"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "タグ別アーカイブ"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "カテゴリー' タグ"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "プロジェクト名"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "会社Eメール"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "会社名"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "会社住所"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "会社電話番号"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr "'email from' は、ホストユーザの値の代わりに使用されることがあります。"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "メールホストユーザー"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "支払限度額"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "最低支払額"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "分析データ"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "広告データ"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "構成"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "言語コード"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "言語名"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "言語フラグがある場合 :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "サポートされている言語のリストを取得する"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "製品検索結果"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "製品検索結果"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "このグループの親"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "親属性グループ"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "属性グループ名"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "属性グループ"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr "ベンダーのAPI通信に必要な認証情報とエンドポイントを保存する。"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "認証情報"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "このベンダーから取得した商品のマークアップを定義する。"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "ベンダーのマークアップ率"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "このベンダーの名前"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "ベンダー名"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "商品タグの内部タグ識別子"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "タグ名"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "商品タグのユーザーフレンドリーな名前"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "タグ表示名"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "商品タグ"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "カテゴリタグ"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "カテゴリータグ"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "このカテゴリーを表す画像をアップロードする"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "カテゴリーイメージ"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "このカテゴリの商品のマークアップ率を定義する"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "階層構造を形成するこのカテゴリの親"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "親カテゴリー"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "カテゴリー名"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "このカテゴリの名前を入力してください。"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "このカテゴリの詳細説明を追加する"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "カテゴリー説明"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "このカテゴリーを説明またはグループ化するのに役立つタグ"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "優先順位"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "ブランド名"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "ブランド名"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "このブランドを代表するロゴをアップロードする"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "小さなブランドイメージ"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "このブランドを象徴する大きなロゴをアップロードする"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "大きなブランドイメージ"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "ブランドの詳細な説明を加える"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "ブランド説明"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "このブランドが関連するオプション・カテゴリー"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "カテゴリー"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "この製品が属するカテゴリ"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "オプションでこの製品をブランドと関連付ける"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "この商品の説明やグループ分けに役立つタグ"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "この製品がデジタル配信されるかどうかを示す"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "製品はデジタルか"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "製品の明確な識別名を提供する"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "商品名"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "商品の詳細説明を追加する"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "商品説明"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "この製品の品番"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "品番"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "この属性のカテゴリー"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "この属性のグループ"
-
-#: core/models.py:465
-msgid "string"
-msgstr "ストリング"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "整数"
-
-#: core/models.py:467
-msgid "float"
-msgstr "フロート"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "ブーリアン"
-
-#: core/models.py:469
-msgid "array"
-msgstr "配列"
-
-#: core/models.py:470
-msgid "object"
-msgstr "対象"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "属性値のタイプ"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "値の種類"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "この属性の名前"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "属性名"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "属性"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "この値の属性"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "この属性の値に関連する特定の製品"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "関連製品"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "この属性の具体的な値"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "アクセシビリティのために、画像に代替テキストを提供する。"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "画像のaltテキスト"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "この商品の画像ファイルをアップロードする"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "商品画像"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "画像の表示順を決める"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "表示優先度"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "この画像が表す製品"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "商品画像"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "選択した商品の割引率"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "割引率"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "このプロモーションのユニークな名前を入力してください。"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "プロモーション名"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "プロモーション内容"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "キャンペーン対象商品をお選びください。"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "含まれる製品"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "プロモーション"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "この製品の在庫を供給しているベンダー"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "関連ベンダー"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "マークアップ後の顧客への最終価格"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "販売価格"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "このストックエントリーに関連する製品"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "関連製品"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "この製品に対してベンダーに支払われた価格"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "ベンダーの購入価格"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "在庫数"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "在庫数"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "製品を識別するためにベンダーが割り当てたSKU"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "ベンダーのSKU"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "この銘柄に関連するデジタルファイル(該当する場合"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "デジタルファイル"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "ストックエントリー"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "この製品が属するカテゴリ"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "オプションでこの製品をブランドと関連付ける"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "この商品の説明やグループ分けに役立つタグ"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "この製品がデジタル配信されるかどうかを示す"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "製品はデジタルか"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "製品の明確な識別名を提供する"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "商品名"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "商品の詳細説明を追加する"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "商品説明"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "この製品の品番"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "品番"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "この属性のカテゴリー"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "この属性のグループ"
+
+#: core/models.py:767
+msgid "string"
+msgstr "ストリング"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "整数"
+
+#: core/models.py:769
+msgid "float"
+msgstr "フロート"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "ブーリアン"
+
+#: core/models.py:771
+msgid "array"
+msgstr "配列"
+
+#: core/models.py:772
+msgid "object"
+msgstr "対象"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "属性値のタイプ"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "値の種類"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "この属性の名前"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "属性名"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "属性"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "この値の属性"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "この属性の値に関連する特定の製品"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "この属性の具体的な値"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "アクセシビリティのために、画像に代替テキストを提供する。"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "画像のaltテキスト"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "この商品の画像ファイルをアップロードする"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "商品画像"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "画像の表示順を決める"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "表示優先度"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "この画像が表す製品"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "商品画像"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "選択した商品の割引率"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "割引率"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "このプロモーションのユニークな名前を入力してください。"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "プロモーション名"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "プロモーション内容"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "キャンペーン対象商品をお選びください。"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "含まれる製品"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "プロモーション"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "ユーザーが欲しいとマークした商品"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "このウィッシュリストを所有しているユーザー"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "ウィッシュリストのオーナー"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "ウィッシュリスト"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name}が存在しません:{product_uuid}が存在しません。"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "ドキュメンタリー"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "ドキュメンタリー"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "未解決"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "お客様の住所"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "住所"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "ストリート"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "地区"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "都市"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "地域"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "郵便番号"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "国名"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "ジオロケーションポイント(経度、緯度)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "この住所に対するジオコーダーからの完全なJSON応答"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "ジオコーディング・サービスからの保存されたJSONレスポンス"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "住所"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "住所"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "ユーザーが割引を利用する際に使用する固有のコード"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "プロモコード識別子"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "パーセントを使用しない場合に適用される固定割引額"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "固定割引額"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "定額を使用しない場合に適用される割引率"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "割引率"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "プロモコードの有効期限が切れるタイムスタンプ"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "終了有効時間"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "このプロモコードが有効なタイムスタンプ"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "開始有効時間"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr "プロモコードが使用されたタイムスタンプ、未使用の場合は空白"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "使用タイムスタンプ"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "該当する場合、このプロモコードに割り当てられたユーザー"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "担当ユーザー"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "プロモコード"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "プロモコード"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
-msgstr "割引の種類は1つだけ(金額またはパーセント)定義されるべきで、両方またはどちらも定義してはならない。"
+msgstr ""
+"割引の種類は1つだけ(金額またはパーセント)定義されるべきで、両方またはどちら"
+"も定義してはならない。"
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "プロモコードはすでに使用されています"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "プロモコード {self.uuid} の割引タイプが無効です。"
+msgstr "プロモコード {self.uuid} の割引タイプが無効です!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "この注文に使用される請求先住所"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "この注文に適用されるプロモコード"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "プロモーションコード適用"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "この注文に使用された配送先住所"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "配送先住所"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "ライフサイクルにおける現在の注文状況"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "注文状況"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
-msgstr "ユーザーに表示する通知のJSON構造、管理UIではテーブルビューが使用されます。"
+msgstr ""
+"ユーザーに表示する通知のJSON構造、管理UIではテーブルビューが使用されます。"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "この注文の注文属性のJSON表現"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "注文を行ったユーザー"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "ユーザー"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "注文が確定したタイムスタンプ"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "時間を買う"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "オーダーの人間が読み取り可能な識別子。"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "人間が読めるID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "オーダー"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "ユーザーは一度に1つの未決注文しか持つことができません!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "保留中の注文以外の注文に商品を追加することはできません。"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "アクティブでない商品を注文に追加することはできません。"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "在庫以上の商品を追加することはできません。"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "保留中の注文以外の注文から商品を削除することはできません。"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "クエリ<{query}>で{name}が存在しません。"
+msgstr "{name}はクエリ<{query}と一緒に存在しません!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "プロモコードが存在しない"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "配送先住所が指定された現物商品のみ購入可能!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "アドレスが存在しない"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr "現在ご購入いただけません。数分後にもう一度お試しください。"
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "無効なフォース値"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "空注文はできません!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "ユーザーがいない注文は購入できない!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "残高のないユーザーは、残高で購入することはできない!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "注文を完了するための資金不足"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
-msgstr "ご登録がない場合はご購入いただけませんので、以下の情報をお知らせください:お客様のお名前、お客様のEメール、お客様の電話番号"
+msgstr ""
+"ご登録がない場合はご購入いただけませんので、以下の情報をお知らせください:お"
+"客様のお名前、お客様のEメール、お客様の電話番号"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
-msgstr "支払方法が無効です:{available_payment_methods}からの{payment_method}が無効です!"
+msgstr ""
+"支払方法が無効です:{available_payment_methods}からの{payment_method}が無効で"
+"す!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "この商品の購入時に顧客が支払った価格"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "注文時の購入価格"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "この注文商品に関する管理者への内部コメント"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "社内コメント"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "ユーザー通知"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "このアイテムの属性のJSON表現"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "製品属性の順序"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "この商品を含む親注文への参照"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "親注文"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "この注文ラインに関連する特定の製品"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "注文に含まれる特定の商品の数量"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "製品数量"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "この商品の現在のご注文状況"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "製品ラインの状況"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Orderproductには関連する注文がなければならない!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "フィードバックに指定されたアクションが間違っています:{action}"
+msgstr "フィードバックに指定されたアクションが間違っています:{action}です!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "受信していない注文をフィードバックすることはできません。"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "ダウンロード"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "ダウンロード"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "未完成の注文のデジタル資産をダウンロードすることはできません。"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "ユーザーから寄せられた製品使用体験に関するコメント"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "フィードバック・コメント"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr "このフィードバックが対象としている注文の特定の製品を参照する。"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "関連注文商品"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "ユーザーによる製品の評価"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "製品評価"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "フィードバック"
#: core/serializers/utility.py:87
msgid ""
"you must provide a comment, rating, and order product uuid to add feedback."
-msgstr "フィードバックを追加するには、コメント、評価、および注文商品の uuid を入力する必要があります。"
+msgstr ""
+"フィードバックを追加するには、コメント、評価、および注文商品の uuid を入力す"
+"る必要があります。"
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "プロモコード作成中にエラーが発生しました:{e!s}です。"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2028,7 +2108,7 @@ msgid "order confirmation"
msgstr "ご注文の確認"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2039,25 +2119,28 @@ msgstr "ロゴ"
#: core/templates/shipped_order_delivered_email.html:100
#, python-format
msgid "hello %(order.user.first_name)s,"
-msgstr "こんにちは、%(order.user.first_name)sです、"
+msgstr "こんにちは%(order.user.first_name)s、"
#: core/templates/digital_order_created_email.html:102
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
-msgstr "ご注文ありがとうございます#%(order.pk)s!ご注文を承りましたことをお知らせいたします。以下、ご注文の詳細です:"
+msgstr ""
+"ご注文ありがとうございます#%(order.pk)s!ご注文を承りましたことをお知らせいた"
+"します。以下、ご注文の詳細です:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "合計"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2070,35 +2153,38 @@ msgstr "合計価格"
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(config.EMAIL_HOST_USER)s."
-msgstr "ご不明な点がございましたら、%(config.EMAIL_HOST_USER)sまでお気軽にお問い合わせください。"
+msgstr ""
+"ご不明な点がございましたら、%(config.EMAIL_HOST_USER)sまでお気軽にお問い合わ"
+"せください。"
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "よろしくお願いします、
%(config.PROJECT_NAME)sのチーム。"
+msgstr "よろしくお願いします、
%(config.PROJECT_NAME)sチーム"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "無断複写・転載を禁じます。"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "注文の配達"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
-msgstr "こんにちは、%(user_first_name)sです、"
+msgstr "こんにちは%(user_first_name)s、"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
" details of your order:"
-msgstr "ご注文の№%(order_uuid)sが正常に処理されました!以下はご注文の詳細です:"
+msgstr ""
+"ご注文の№%(order_uuid)sが正常に処理されました!以下はご注文の詳細です:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2106,22 +2192,24 @@ msgstr ""
"追加\n"
" 追加情報"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "価値"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
-msgstr "ご不明な点がございましたら、%(contact_email)sまでお気軽にお問い合わせください。"
+msgstr ""
+"ご不明な点がございましたら、%(contact_email)sまでお気軽にお問い合わせくださ"
+"い。"
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "よろしくお願いします、
%(project_name)sのチーム。"
+msgstr "よろしくお願いします、
%(project_name)sチーム"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2130,9 +2218,12 @@ msgstr "キー"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
-msgstr "ご注文ありがとうございます!ご購入を確認させていただきました。以下、ご注文の詳細です:"
+msgstr ""
+"ご注文ありがとうございます!ご購入を確認させていただきました。以下、ご注文の"
+"詳細です:"
#: core/templates/shipped_order_created_email.html:123
#: core/templates/shipped_order_delivered_email.html:123
@@ -2148,7 +2239,7 @@ msgstr "ご注文の商品は以下の住所に配送されます:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "よろしくお願いします、
%(config.PROJECT_NAME)sチーム。"
+msgstr "よろしくお願いします、
%(config.PROJECT_NAME)sチーム"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2167,30 +2258,20 @@ msgstr "データとタイムアウトの両方が必要"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "無効なタイムアウト値です。"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model}はモデルでなければならない"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data}はリストオブジェクトでなければならない"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | お問い合わせ| お問い合わせ"
+msgstr "{config.PROJECT_NAME}|コンタクト開始| お問い合わせはこちらから"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
-msgstr "{config.PROJECT_NAME}|注文確認| 注文確認"
+msgstr "{config.PROJECT_NAME}|注文確認| ご注文の確認"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME}|プロジェクト名| 注文の配信"
+msgstr "{config.PROJECT_NAME}|ご注文は配送されますか?"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2203,21 +2284,23 @@ msgstr "NOMINATIM_URLパラメータを設定する必要があります!"
#: core/validators.py:16
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
-msgstr "画像の寸法は、w{max_width} x h{max_height}ピクセルを超えないこと。"
+msgstr ""
+"画像のサイズは w{max_width} x h{max_height} ピクセルを超えないようにしてくだ"
+"さい!"
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "無効な電話番号形式"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "デジタルアセットのダウンロードは1回限りです。"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "ファビコンが見つかりません"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "ジオコーディングエラー:{e}"
diff --git a/core/locale/kk_KZ/LC_MESSAGES/django.mo b/core/locale/kk_KZ/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/core/locale/kk_KZ/LC_MESSAGES/django.mo and b/core/locale/kk_KZ/LC_MESSAGES/django.mo differ
diff --git a/core/locale/kk_KZ/LC_MESSAGES/django.po b/core/locale/kk_KZ/LC_MESSAGES/django.po
index 8a0441eb..f4aec1bb 100644
--- a/core/locale/kk_KZ/LC_MESSAGES/django.po
+++ b/core/locale/kk_KZ/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -16,117 +16,115 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr ""
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr ""
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
"if set to false, this object can't be seen by users without needed permission"
msgstr ""
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr ""
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr ""
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr ""
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr ""
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr ""
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr ""
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr ""
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr ""
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr ""
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr ""
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
+#: core/admin.py:101
+msgid "selected items have been activated."
msgstr ""
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
msgstr ""
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
msgstr ""
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr ""
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr ""
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr ""
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr ""
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr ""
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr ""
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr ""
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr ""
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr ""
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr ""
@@ -178,7 +176,7 @@ msgstr ""
msgid "successful"
msgstr ""
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr ""
@@ -200,7 +198,7 @@ msgstr ""
msgid "send a message to the support team"
msgstr ""
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr ""
@@ -398,7 +396,7 @@ msgid ""
"transaction is initiated."
msgstr ""
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr ""
@@ -702,7 +700,7 @@ msgstr ""
msgid "add or remove feedback on an order–product relation"
msgstr ""
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr ""
@@ -750,8 +748,8 @@ msgstr ""
msgid "Quantity"
msgstr ""
-#: core/filters.py:73 core/filters.py:355 core/models.py:229 core/models.py:307
-#: core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr ""
@@ -812,1182 +810,1216 @@ msgstr ""
msgid "Product UUID"
msgstr ""
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr ""
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr ""
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr ""
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr ""
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr ""
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr ""
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr ""
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
msgstr ""
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr ""
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr ""
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr ""
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr ""
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr ""
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr ""
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr ""
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr ""
-#: core/graphene/mutations.py:326
-msgid "add a product to the wishlist"
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
msgstr ""
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr ""
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
#, python-brace-format
msgid "wishlist {wishlist_uuid} not found"
msgstr ""
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:370
+msgid "add a product to the wishlist"
+msgstr ""
+
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr ""
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr ""
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr ""
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr ""
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
"please send the attributes as the string formatted like attr1=value1,"
"attr2=value2"
msgstr ""
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr ""
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr ""
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr ""
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr ""
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
msgstr ""
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr ""
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr ""
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr ""
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr ""
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr ""
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr ""
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr ""
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr ""
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr ""
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
-#: core/graphene/object_types.py:133
+#: core/graphene/object_types.py:135
msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr ""
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr ""
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr ""
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr ""
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr ""
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr ""
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr ""
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr ""
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr ""
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr ""
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr ""
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr ""
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
msgstr ""
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr ""
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr ""
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr ""
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr ""
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr ""
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr ""
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr ""
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr ""
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr ""
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr ""
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr ""
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr ""
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr ""
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr ""
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr ""
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr ""
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr ""
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr ""
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr ""
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr ""
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr ""
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr ""
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr ""
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr ""
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr ""
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr ""
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr ""
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr ""
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr ""
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr ""
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr ""
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr ""
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr ""
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr ""
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr ""
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr ""
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr ""
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr ""
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr ""
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr ""
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr ""
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr ""
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr ""
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr ""
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr ""
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr ""
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr ""
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr ""
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr ""
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr ""
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr ""
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr ""
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr ""
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr ""
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr ""
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr ""
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr ""
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr ""
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr ""
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr ""
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr ""
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr ""
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr ""
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr ""
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr ""
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr ""
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr ""
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr ""
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr ""
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr ""
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr ""
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr ""
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr ""
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr ""
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr ""
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr ""
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr ""
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr ""
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr ""
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr ""
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr ""
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr ""
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr ""
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr ""
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr ""
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr ""
-
-#: core/models.py:358
-msgid "product name"
-msgstr ""
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr ""
-
-#: core/models.py:364
-msgid "product description"
-msgstr ""
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr ""
-
-#: core/models.py:372
-msgid "part number"
-msgstr ""
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr ""
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr ""
-
-#: core/models.py:465
-msgid "string"
-msgstr ""
-
-#: core/models.py:466
-msgid "integer"
-msgstr ""
-
-#: core/models.py:467
-msgid "float"
-msgstr ""
-
-#: core/models.py:468
-msgid "boolean"
-msgstr ""
-
-#: core/models.py:469
-msgid "array"
-msgstr ""
-
-#: core/models.py:470
-msgid "object"
-msgstr ""
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr ""
-
-#: core/models.py:473
-msgid "value type"
-msgstr ""
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr ""
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr ""
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr ""
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr ""
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr ""
-
-#: core/models.py:507 core/models.py:546 core/models.py:617 core/models.py:1361
-msgid "associated product"
-msgstr ""
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr ""
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr ""
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr ""
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr ""
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr ""
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr ""
-
-#: core/models.py:540
-msgid "display priority"
-msgstr ""
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr ""
-
-#: core/models.py:559
-msgid "product images"
-msgstr ""
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr ""
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr ""
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr ""
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr ""
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr ""
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr ""
-
-#: core/models.py:586
-msgid "included products"
-msgstr ""
-
-#: core/models.py:590
-msgid "promotion"
-msgstr ""
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr ""
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr ""
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr ""
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr ""
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr ""
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr ""
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr ""
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr ""
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr ""
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr ""
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr ""
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr ""
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr ""
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr ""
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr ""
-#: core/models.py:660
-msgid "products that the user has marked as wanted"
+#: core/models.py:605
+msgid "category this product belongs to"
msgstr ""
-#: core/models.py:668
-msgid "user who owns this wishlist"
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
msgstr ""
-#: core/models.py:669
-msgid "wishlist owner"
+#: core/models.py:620
+msgid "tags that help describe or group this product"
msgstr ""
-#: core/models.py:677
-msgid "wishlist"
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
msgstr ""
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
+#: core/models.py:626
+msgid "is product digital"
msgstr ""
-#: core/models.py:724
-msgid "documentary"
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
msgstr ""
-#: core/models.py:725
-msgid "documentaries"
+#: core/models.py:633
+msgid "product name"
msgstr ""
-#: core/models.py:735
-msgid "unresolved"
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
msgstr ""
-#: core/models.py:744
-msgid "address line for the customer"
+#: core/models.py:639
+msgid "product description"
msgstr ""
-#: core/models.py:745
-msgid "address line"
+#: core/models.py:646
+msgid "part number for this product"
msgstr ""
-#: core/models.py:747
-msgid "street"
+#: core/models.py:647
+msgid "part number"
msgstr ""
-#: core/models.py:748
-msgid "district"
+#: core/models.py:753
+msgid "category of this attribute"
msgstr ""
-#: core/models.py:749
-msgid "city"
-msgstr ""
-
-#: core/models.py:750
-msgid "region"
-msgstr ""
-
-#: core/models.py:751
-msgid "postal code"
-msgstr ""
-
-#: core/models.py:752
-msgid "country"
-msgstr ""
-
-#: core/models.py:759
-msgid "geolocation point: (longitude, latitude)"
-msgstr ""
-
-#: core/models.py:762
-msgid "full JSON response from geocoder for this address"
+#: core/models.py:761
+msgid "group of this attribute"
msgstr ""
#: core/models.py:767
-msgid "stored JSON response from the geocoding service"
+msgid "string"
+msgstr ""
+
+#: core/models.py:768
+msgid "integer"
+msgstr ""
+
+#: core/models.py:769
+msgid "float"
+msgstr ""
+
+#: core/models.py:770
+msgid "boolean"
+msgstr ""
+
+#: core/models.py:771
+msgid "array"
+msgstr ""
+
+#: core/models.py:772
+msgid "object"
+msgstr ""
+
+#: core/models.py:774
+msgid "type of the attribute's value"
msgstr ""
#: core/models.py:775
+msgid "value type"
+msgstr ""
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr ""
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr ""
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr ""
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr ""
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr ""
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr ""
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr ""
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr ""
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr ""
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr ""
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr ""
+
+#: core/models.py:883
+msgid "display priority"
+msgstr ""
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr ""
+
+#: core/models.py:902
+msgid "product images"
+msgstr ""
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr ""
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr ""
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr ""
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr ""
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr ""
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr ""
+
+#: core/models.py:962
+msgid "included products"
+msgstr ""
+
+#: core/models.py:966
+msgid "promotion"
+msgstr ""
+
+#: core/models.py:991
+msgid "products that the user has marked as wanted"
+msgstr ""
+
+#: core/models.py:999
+msgid "user who owns this wishlist"
+msgstr ""
+
+#: core/models.py:1000
+msgid "wishlist owner"
+msgstr ""
+
+#: core/models.py:1008
+msgid "wishlist"
+msgstr ""
+
+#: core/models.py:1075
+msgid "documentary"
+msgstr ""
+
+#: core/models.py:1076
+msgid "documentaries"
+msgstr ""
+
+#: core/models.py:1086
+msgid "unresolved"
+msgstr ""
+
+#: core/models.py:1132
+msgid "address line for the customer"
+msgstr ""
+
+#: core/models.py:1133
+msgid "address line"
+msgstr ""
+
+#: core/models.py:1135
+msgid "street"
+msgstr ""
+
+#: core/models.py:1136
+msgid "district"
+msgstr ""
+
+#: core/models.py:1137
+msgid "city"
+msgstr ""
+
+#: core/models.py:1138
+msgid "region"
+msgstr ""
+
+#: core/models.py:1139
+msgid "postal code"
+msgstr ""
+
+#: core/models.py:1140
+msgid "country"
+msgstr ""
+
+#: core/models.py:1147
+msgid "geolocation point: (longitude, latitude)"
+msgstr ""
+
+#: core/models.py:1150
+msgid "full JSON response from geocoder for this address"
+msgstr ""
+
+#: core/models.py:1155
+msgid "stored JSON response from the geocoding service"
+msgstr ""
+
+#: core/models.py:1163
msgid "address"
msgstr ""
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr ""
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr ""
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr ""
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr ""
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr ""
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr ""
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr ""
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr ""
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr ""
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr ""
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr ""
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr ""
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr ""
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr ""
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr ""
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr ""
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
msgstr ""
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr ""
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
msgstr ""
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr ""
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr ""
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr ""
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr ""
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr ""
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr ""
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr ""
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr ""
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr ""
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr ""
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr ""
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr ""
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr ""
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr ""
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr ""
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr ""
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr ""
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr ""
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr ""
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
msgstr ""
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr ""
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr ""
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr ""
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr ""
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr ""
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr ""
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
msgstr ""
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr ""
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr ""
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr ""
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr ""
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr ""
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr ""
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr ""
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr ""
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr ""
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr ""
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr ""
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr ""
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr ""
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr ""
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr ""
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
msgstr ""
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr ""
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr ""
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr ""
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr ""
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr ""
-#: core/models.py:1490
+#: core/models.py:1970
msgid "references the specific product in an order that this feedback is about"
msgstr ""
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr ""
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr ""
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr ""
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr ""
@@ -1996,13 +2028,13 @@ msgid ""
"you must provide a comment, rating, and order product uuid to add feedback."
msgstr ""
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr ""
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2011,7 +2043,7 @@ msgid "order confirmation"
msgstr ""
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2034,14 +2066,14 @@ msgid ""
msgstr ""
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr ""
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2062,45 +2094,45 @@ msgid "best regards,
the %(config.PROJECT_NAME)s team"
msgstr ""
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
" details of your order:"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr ""
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
msgstr ""
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr ""
@@ -2148,27 +2180,17 @@ msgstr ""
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr ""
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr ""
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr ""
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
msgstr ""
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr ""
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr ""
@@ -2190,15 +2212,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr ""
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr ""
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr ""
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr ""
diff --git a/core/locale/nl_NL/LC_MESSAGES/django.mo b/core/locale/nl_NL/LC_MESSAGES/django.mo
index a8a6ee7b..f411d933 100644
Binary files a/core/locale/nl_NL/LC_MESSAGES/django.mo and b/core/locale/nl_NL/LC_MESSAGES/django.mo differ
diff --git a/core/locale/nl_NL/LC_MESSAGES/django.po b/core/locale/nl_NL/LC_MESSAGES/django.po
index 1827f846..ce5cc34e 100644
--- a/core/locale/nl_NL/LC_MESSAGES/django.po
+++ b/core/locale/nl_NL/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,120 +13,117 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Uniek ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr "Unieke ID wordt gebruikt om elk databaseobject te identificeren"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Is actief"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Als false is ingesteld, kan dit object niet worden gezien door gebruikers "
"zonder de benodigde toestemming"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Gemaakt"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Wanneer het object voor het eerst in de database verscheen"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Gewijzigd"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Wanneer het object voor het laatst bewerkt is"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Vertalingen"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Algemeen"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relaties"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metagegevens"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Tijdstempels"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr "Activeer geselecteerde %(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s met succes geactiveerd!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Geselecteerde items zijn geactiveerd!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Deactiveer geselecteerde %(verbose_name_plural)s"
+msgstr "Deactiveer geselecteerd %(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s met succes gedeactiveerd."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Geselecteerde items zijn gedeactiveerd!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Attribuut Waarde"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Attribuutwaarden"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Afbeelding"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Afbeeldingen"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Voorraad"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Aandelen"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Product bestellen"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Producten bestellen"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Kinderen"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Config"
@@ -178,7 +175,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Succesvol"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Cache I/O"
@@ -188,7 +185,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"Alleen een sleutel gebruiken om toegestane gegevens uit de cache te lezen.\n"
-"Sleutel, gegevens en time-out met verificatie toepassen om gegevens naar de cache te schrijven."
+"Sleutel, gegevens en time-out met verificatie toepassen om gegevens naar de "
+"cache te schrijven."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -202,7 +200,7 @@ msgstr "Verkrijg de blootstelbare parameters van de applicatie"
msgid "send a message to the support team"
msgstr "Stuur een bericht naar het ondersteuningsteam"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Vraag een CORSed URL op. Alleen https toegestaan."
@@ -246,8 +244,7 @@ msgstr ""
"opslaan"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Enkele velden van een bestaande attribuutgroep herschrijven door niet-"
"wijzigbare velden op te slaan"
@@ -302,8 +299,7 @@ msgstr ""
"attributen worden opgeslagen"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Herschrijf sommige velden van een bestaande attribuutwaarde door niet-"
"wijzigbare velden op te slaan"
@@ -341,16 +337,15 @@ msgstr "Alle categorieën weergeven (eenvoudige weergave)"
#: core/docs/drf/viewsets.py:152
msgid "for non-staff users, only their own orders are returned."
msgstr ""
-"Voor niet-personeelsleden worden alleen hun eigen bestellingen "
-"geretourneerd."
+"Voor niet-personeelsleden worden alleen hun eigen bestellingen geretourneerd."
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
-"Hoofdlettergevoelig substring zoeken in human_readable_id, "
-"order_products.product.name en order_products.product.partnumber"
+"Hoofdlettergevoelig substring zoeken in human_readable_id, order_products."
+"product.name en order_products.product.partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -383,13 +378,13 @@ msgstr "Filter op bestelstatus (hoofdlettergevoelige substringmatch)"
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Sorteer op een van: uuid, human_readable_id, user_email, gebruiker, status, "
-"gemaakt, gewijzigd, buy_time, willekeurig. Voorvoegsel met '-' voor aflopend"
-" (bijv. '-buy_time')."
+"gemaakt, gewijzigd, buy_time, willekeurig. Voorvoegsel met '-' voor aflopend "
+"(bijv. '-buy_time')."
#: core/docs/drf/viewsets.py:210
msgid "retrieve a single order (detailed view)"
@@ -431,15 +426,14 @@ msgstr ""
"wordt de aankoop afgerond met het saldo van de gebruiker; als "
"`force_payment` wordt gebruikt, wordt een transactie gestart."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "een bestelling kopen zonder een account aan te maken"
#: core/docs/drf/viewsets.py:246
msgid "finalizes the order purchase for a non-registered user."
msgstr ""
-"Rondt de aankoop van de bestelling af voor een niet-geregistreerde "
-"gebruiker."
+"Rondt de aankoop van de bestelling af voor een niet-geregistreerde gebruiker."
#: core/docs/drf/viewsets.py:254
msgid "add product to order"
@@ -573,18 +567,28 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filter op een of meer attribuutnaam-/waardeparen. \n"
"- **Syntaxis**: `attr_name=methode-waarde[;attr2=methode2-waarde2]...`\n"
-"- **Methodes** (standaard op `icontains` indien weggelaten): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
-"- Waarde typen**: JSON wordt eerst geprobeerd (zodat je lijsten/dicten kunt doorgeven), `true`/`false` voor booleans, integers, floats; anders behandeld als string. \n"
-"- **Base64**: prefix met `b64-` om URL-veilige base64-encodering van de ruwe waarde. \n"
+"- **Methodes** (standaard op `icontains` indien weggelaten): `iexact`, "
+"`exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, "
+"`endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
+"- Waarde typen**: JSON wordt eerst geprobeerd (zodat je lijsten/dicten kunt "
+"doorgeven), `true`/`false` voor booleans, integers, floats; anders behandeld "
+"als string. \n"
+"- **Base64**: prefix met `b64-` om URL-veilige base64-encodering van de ruwe "
+"waarde. \n"
"Voorbeelden: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`."
@@ -639,11 +643,14 @@ msgstr "(exact) Digitaal vs. fysiek"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Door komma's gescheiden lijst van velden om op te sorteren. Voorvoegsel met `-` voor aflopend. \n"
-"**Toegestaan:** uuid, beoordeling, naam, slug, gemaakt, gewijzigd, prijs, willekeurig"
+"Door komma's gescheiden lijst van velden om op te sorteren. Voorvoegsel met "
+"`-` voor aflopend. \n"
+"**Toegestaan:** uuid, beoordeling, naam, slug, gemaakt, gewijzigd, prijs, "
+"willekeurig"
#: core/docs/drf/viewsets.py:441
msgid "retrieve a single product (detailed view)"
@@ -751,8 +758,7 @@ msgstr "alle order-productrelaties weergeven (eenvoudige weergave)"
#: core/docs/drf/viewsets.py:629
msgid "retrieve a single order–product relation (detailed view)"
-msgstr ""
-"een enkele bestelling-productrelatie ophalen (gedetailleerde weergave)"
+msgstr "een enkele bestelling-productrelatie ophalen (gedetailleerde weergave)"
#: core/docs/drf/viewsets.py:636
msgid "create a new order–product relation"
@@ -774,7 +780,7 @@ msgstr "een order-productrelatie verwijderen"
msgid "add or remove feedback on an order–product relation"
msgstr "feedback toevoegen of verwijderen op een order-productrelatie"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Geen zoekterm opgegeven."
@@ -822,8 +828,8 @@ msgstr "Attributen"
msgid "Quantity"
msgstr "Hoeveelheid"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Slak"
@@ -885,217 +891,240 @@ msgstr "Niveau"
msgid "Product UUID"
msgstr "Product UUID"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Sleutel om te zoeken of te plaatsen in de cache"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Gegevens om op te slaan in de cache"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Time-out in seconden om de gegevens in de cache te plaatsen"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Gecachte gegevens"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Camelized JSON-gegevens van de opgevraagde URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Alleen URL's die beginnen met http(s):// zijn toegestaan"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Een product aan de bestelling toevoegen"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Order {order_uuid} niet gevonden"
+msgstr "Bestelling {order_uuid} niet gevonden!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Een product uit de bestelling verwijderen"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Alle producten uit de bestelling verwijderen"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Een bestelling kopen"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Geef order_uuid of order_hr_id - wederzijds exclusief!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Verkeerd type kwam uit order.buy() methode: {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Een actie uitvoeren op een lijst met producten in de bestelling"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Verwijderen/toevoegen"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "De actie moet \"toevoegen\" of \"verwijderen\" zijn!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Een actie uitvoeren op een lijst met producten in het verlanglijstje"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Geef de waarde `wishlist_uuid` op."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "wens {wishlist_uuid} niet gevonden!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Een product aan de bestelling toevoegen"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Verlanglijst {wishlist_uuid} niet gevonden"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Een product uit de bestelling verwijderen"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Een product uit de bestelling verwijderen"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Een product uit de bestelling verwijderen"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Een bestelling kopen"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
"Stuur de attributen als de string opgemaakt als attr1=waarde1,attr2=waarde2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Feedback toevoegen of verwijderen voor het orderproduct"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "De actie moet `toevoegen` of `verwijderen` zijn!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Orderproduct {order_product_uuid} niet gevonden!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Originele adresstring geleverd door de gebruiker"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} bestaat niet: {uuid}"
+msgstr "{name} bestaat niet: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Limiet moet tussen 1 en 10 liggen"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - werkt als een charme"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Attributen"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Gegroepeerde kenmerken"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Groepen van kenmerken"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Categorieën"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Merken"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Categorieën"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Opwaarderingspercentage"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Welke attributen en waarden kunnen worden gebruikt om deze categorie te "
"filteren."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Minimale en maximale prijzen voor producten in deze categorie, indien "
"beschikbaar."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tags voor deze categorie"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Producten in deze categorie"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Verkopers"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Breedtegraad (Y-coördinaat)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Lengtegraad (X-coördinaat)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Hoe"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Waarderingswaarde van 1 tot en met 10, of 0 indien niet ingesteld."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Vertegenwoordigt feedback van een gebruiker."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Meldingen"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Download url voor dit bestelproduct indien van toepassing"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Een lijst met bestelde producten in deze bestelling"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Factuuradres"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1103,879 +1132,885 @@ msgstr ""
"Verzendadres voor deze bestelling, leeg laten als dit hetzelfde is als het "
"factuuradres of als dit niet van toepassing is"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Totale prijs van deze bestelling"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Totale hoeveelheid producten in bestelling"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Zijn alle producten in de bestelling digitaal"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transacties voor deze bestelling"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Bestellingen"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Afbeelding URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Afbeeldingen van het product"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Categorie"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Reacties"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Merk"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Attribuutgroepen"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Prijs"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Hoeveelheid"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Aantal terugkoppelingen"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Producten"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Promocodes"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Producten te koop"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promoties"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Verkoper"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Product"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Gewenste producten"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Verlanglijst"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Getagde producten"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Product tags"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Getagde categorieën"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Categorieën' tags"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Naam project"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Bedrijf E-mail"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Bedrijfsnaam"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Adres"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Telefoonnummer bedrijf"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"e-mail van', soms moet deze worden gebruikt in plaats van de "
"hostgebruikerswaarde"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Gebruiker e-mail hosten"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Maximumbedrag voor betaling"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Minimumbedrag voor betaling"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Analytics-gegevens"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Advertentiegegevens"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configuratie"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Taalcode"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Naam van de taal"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Taalvlag, indien aanwezig :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Een lijst met ondersteunde talen opvragen"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Producten zoekresultaten"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Zoekresultaten"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Ouder van deze groep"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Ouderattribuutgroep"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Naam attribuutgroep"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Attribuutgroep"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Slaat referenties en eindpunten op die vereist zijn voor API-communicatie "
"van de verkoper"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Authenticatie-info"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr ""
"Definieer de opmaak voor producten die zijn opgehaald bij deze leverancier"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Verkoper winstpercentage"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Naam van deze verkoper"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Naam verkoper"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Interne tagidentifier voor de producttag"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Tag naam"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Gebruiksvriendelijke naam voor de producttag"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Tag weergavenaam"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Productlabel"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "categorie tag"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "categorie tags"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Upload een afbeelding die deze categorie vertegenwoordigt"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Categorie afbeelding"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Definieer een toeslagpercentage voor producten in deze categorie"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Ouder van deze categorie om een hiërarchische structuur te vormen"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Oudercategorie"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Naam categorie"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Geef deze categorie een naam"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Voeg een gedetailleerde beschrijving toe voor deze categorie"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Categorie beschrijving"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "tags die deze categorie helpen beschrijven of groeperen"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Prioriteit"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Naam van dit merk"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Merknaam"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Upload een logo dat dit merk vertegenwoordigt"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Klein merkimago"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Upload een groot logo dat dit merk vertegenwoordigt"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Groot merkimago"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Een gedetailleerde beschrijving van het merk toevoegen"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Merknaam"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Optionele categorieën waarmee dit merk wordt geassocieerd"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Categorieën"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Categorie waartoe dit product behoort"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Dit product optioneel koppelen aan een merk"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Tags die dit product helpen beschrijven of groeperen"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Geeft aan of dit product digitaal wordt geleverd"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Is product digitaal"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Zorg voor een duidelijke identificerende naam voor het product"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Naam product"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Voeg een gedetailleerde beschrijving van het product toe"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Productbeschrijving"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Onderdeelnummer voor dit product"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Onderdeelnummer"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Categorie van dit kenmerk"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Groep van dit kenmerk"
-
-#: core/models.py:465
-msgid "string"
-msgstr "String"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Integer"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Vlotter"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Booleaans"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Array"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Object"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Type waarde van het kenmerk"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Waardetype"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Naam van dit kenmerk"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Naam attribuut"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Attribuut"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Attribuut van deze waarde"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Het specifieke product geassocieerd met de waarde van dit kenmerk"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Bijbehorend product"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "De specifieke waarde voor dit kenmerk"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "Geef alternatieve tekst voor de afbeelding voor toegankelijkheid"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Alt-tekst afbeelding"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Upload het afbeeldingsbestand voor dit product"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Product afbeelding"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Bepaalt de volgorde waarin afbeeldingen worden weergegeven"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Prioriteit weergeven"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "Het product dat deze afbeelding vertegenwoordigt"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Product afbeeldingen"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Kortingspercentage voor de geselecteerde producten"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Kortingspercentage"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Geef deze promotie een unieke naam"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Naam promotie"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Promotie beschrijving"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Selecteer welke producten onder deze promotie vallen"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Meegeleverde producten"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Promotie"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "De verkoper die dit product levert"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Geassocieerde verkoper"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Eindprijs voor de klant na winstmarges"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Verkoopprijs"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "Het product dat bij deze voorraadvermelding hoort"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Bijbehorend product"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "De prijs die voor dit product aan de verkoper is betaald"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Aankoopprijs verkoper"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Beschikbare hoeveelheid van het product in voorraad"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Hoeveelheid op voorraad"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "Door de verkoper toegewezen SKU om het product te identificeren"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "Verkoper SKU"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Digitaal bestand gekoppeld aan deze voorraad indien van toepassing"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Digitaal bestand"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Voorraadboekingen"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Categorie waartoe dit product behoort"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Dit product optioneel koppelen aan een merk"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Tags die dit product helpen beschrijven of groeperen"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Geeft aan of dit product digitaal wordt geleverd"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Is product digitaal"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Zorg voor een duidelijke identificerende naam voor het product"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Naam product"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Voeg een gedetailleerde beschrijving van het product toe"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Productbeschrijving"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Onderdeelnummer voor dit product"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Onderdeelnummer"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Categorie van dit kenmerk"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Groep van dit kenmerk"
+
+#: core/models.py:767
+msgid "string"
+msgstr "String"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Integer"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Vlotter"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Booleaans"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Array"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Object"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Type waarde van het kenmerk"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Waardetype"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Naam van dit kenmerk"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Naam attribuut"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Attribuut"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Attribuut van deze waarde"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Het specifieke product geassocieerd met de waarde van dit kenmerk"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "De specifieke waarde voor dit kenmerk"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Geef alternatieve tekst voor de afbeelding voor toegankelijkheid"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Alt-tekst afbeelding"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Upload het afbeeldingsbestand voor dit product"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Product afbeelding"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Bepaalt de volgorde waarin afbeeldingen worden weergegeven"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Prioriteit weergeven"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "Het product dat deze afbeelding vertegenwoordigt"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Product afbeeldingen"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Kortingspercentage voor de geselecteerde producten"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Kortingspercentage"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Geef deze promotie een unieke naam"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Naam promotie"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Promotie beschrijving"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Selecteer welke producten onder deze promotie vallen"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Meegeleverde producten"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Promotie"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Producten die de gebruiker als gewenst heeft gemarkeerd"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Gebruiker die eigenaar is van deze verlanglijst"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Eigenaar verlanglijstje"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Verlanglijst"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} bestaat niet: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documentaire"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentaires"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Onopgelost"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Adresregel voor de klant"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Adresregel"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Straat"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "District"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Stad"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Regio"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Postcode"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Land"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolocatie Punt (lengtegraad, breedtegraad)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Volledig JSON-antwoord van geocoder voor dit adres"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Opgeslagen JSON-antwoord van de geocoderingsservice"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Adres"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adressen"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Unieke code die een gebruiker gebruikt om een korting te verzilveren"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Promo code identificatie"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr ""
"Vast kortingsbedrag dat wordt toegepast als percentage niet wordt gebruikt"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Vast kortingsbedrag"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr ""
"Kortingspercentage dat wordt toegepast als het vaste bedrag niet wordt "
"gebruikt"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Kortingspercentage"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Tijdstempel wanneer de promocode verloopt"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Geldigheidsduur einde"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Tijdstempel vanaf wanneer deze promocode geldig is"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Begin geldigheidsduur"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
-"Tijdstempel wanneer de promocode werd gebruikt, leeg indien nog niet "
-"gebruikt"
+"Tijdstempel wanneer de promocode werd gebruikt, leeg indien nog niet gebruikt"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Gebruik tijdstempel"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Gebruiker toegewezen aan deze promocode indien van toepassing"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Toegewezen gebruiker"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Kortingscode"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Actiecodes"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
msgstr ""
-"Er moet slechts één type korting worden gedefinieerd (bedrag of percentage),"
-" maar niet beide of geen van beide."
+"Er moet slechts één type korting worden gedefinieerd (bedrag of percentage), "
+"maar niet beide of geen van beide."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Promocode is al gebruikt"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Ongeldig kortingstype voor promocode {self.uuid}"
+msgstr "Ongeldig kortingstype voor promocode {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "Het factuuradres dat voor deze bestelling is gebruikt"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Optionele promotiecode toegepast op deze bestelling"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Kortingscode toegepast"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "Het verzendadres dat voor deze bestelling is gebruikt"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Verzendadres"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Huidige status van de order in zijn levenscyclus"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Bestelstatus"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"JSON-structuur van meldingen om weer te geven aan gebruikers, in admin UI "
"wordt de tabelweergave gebruikt"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "JSON-weergave van bestelattributen voor deze bestelling"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "De gebruiker die de bestelling heeft geplaatst"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Gebruiker"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "De tijdstempel waarop de bestelling is afgerond"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Tijd kopen"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Een menselijk leesbare identificatiecode voor de bestelling"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "menselijk leesbare ID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Bestel"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Een gebruiker mag maar één lopende order tegelijk hebben!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr ""
"U kunt geen producten toevoegen aan een bestelling die niet in behandeling "
"is."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "U kunt geen inactieve producten toevoegen aan uw bestelling"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "Je kunt niet meer producten toevoegen dan er op voorraad zijn"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
-"U kunt geen producten verwijderen uit een bestelling die niet in behandeling"
-" is."
+"U kunt geen producten verwijderen uit een bestelling die niet in behandeling "
+"is."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} bestaat niet met query <{query}>"
+msgstr "{name} bestaat niet met query <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Promocode bestaat niet"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "Je kunt alleen fysieke producten kopen met opgegeven verzendadres!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Adres bestaat niet"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"U kunt op dit moment niet kopen. Probeer het over een paar minuten nog eens."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Ongeldige krachtwaarde"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Je kunt geen lege bestelling kopen!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+"U kunt geen producten verwijderen uit een bestelling die niet in behandeling "
+"is."
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Een gebruiker zonder saldo kan niet kopen met saldo!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Onvoldoende fondsen om de bestelling te voltooien"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1983,122 +2018,124 @@ msgstr ""
"u niet kunt kopen zonder registratie, geef dan de volgende informatie: "
"klantnaam, e-mail klant, telefoonnummer klant"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
-"Ongeldige betalingsmethode: {payment_method} van "
-"{available_payment_methods}!"
+"Ongeldige betalingsmethode: {payment_method} van {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "De prijs die de klant bij aankoop voor dit product heeft betaald"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Aankoopprijs bij bestelling"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "Interne opmerkingen voor beheerders over dit bestelde product"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Interne opmerkingen"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Meldingen van gebruikers"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "JSON weergave van de attributen van dit item"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Geordende producteigenschappen"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Verwijzing naar de bovenliggende bestelling die dit product bevat"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Ouderlijk bevel"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Het specifieke product dat bij deze bestelregel hoort"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Hoeveelheid van dit specifieke product in de bestelling"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Hoeveelheid product"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Huidige status van dit product in de bestelling"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Status productlijn"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Orderproduct moet een bijbehorende order hebben!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "verkeerde actie opgegeven voor feedback: {action}"
+msgstr "Verkeerde actie opgegeven voor feedback: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
-"U kunt geen producten verwijderen uit een bestelling die niet in behandeling"
-" is."
+"U kunt geen producten verwijderen uit een bestelling die niet in behandeling "
+"is."
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Downloaden"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Downloads"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr ""
"U kunt geen digitale activa downloaden voor een niet-afgeronde bestelling"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Opmerkingen van gebruikers over hun ervaring met het product"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Reacties"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"Verwijst naar het specifieke product in een bestelling waar deze feedback "
"over gaat"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Gerelateerd product bestellen"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Door de gebruiker toegekende waardering voor het product"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Productbeoordeling"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Feedback"
@@ -2109,13 +2146,13 @@ msgstr ""
"Om feedback toe te voegen, moet je een opmerking, beoordeling en "
"productidentificatie opgeven."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Fout tijdens aanmaken promocode: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2124,7 +2161,7 @@ msgid "order confirmation"
msgstr "Orderbevestiging"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2141,7 +2178,8 @@ msgstr "Hallo %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Hartelijk dank voor uw bestelling #%(order.pk)s! We zijn blij om u te "
@@ -2149,14 +2187,14 @@ msgstr ""
"vindt u de gegevens van uw bestelling:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Totaal"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2176,23 +2214,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Vriendelijke groeten,
het %(config.PROJECT_NAME)s-team"
+msgstr "Vriendelijke groeten,
het %(config.PROJECT_NAME)s team"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Alle rechten voorbehouden"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Bestelling geleverd"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hallo %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2201,7 +2239,7 @@ msgstr ""
"We hebben uw bestelling succesvol verwerkt №%(order_uuid)s! Hieronder vindt "
"u de details van uw bestelling:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2209,12 +2247,12 @@ msgstr ""
"aanvullende\n"
" informatie"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Waarde"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2223,10 +2261,10 @@ msgstr ""
"Als je vragen hebt, kun je contact opnemen met onze klantenservice op "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Vriendelijke groeten,
het %(project_name)s-team"
+msgstr "Vriendelijke groeten,
het %(project_name)s team"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2235,7 +2273,8 @@ msgstr "Sleutel"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Bedankt voor uw bestelling! We zijn blij om uw aankoop te bevestigen. "
@@ -2255,7 +2294,7 @@ msgstr "Je bestelling wordt afgeleverd op het volgende adres:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Vriendelijke groeten,
het %(config.PROJECT_NAME)s-team"
+msgstr "Vriendelijke groeten,
Het %(config.PROJECT_NAME)s team"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2272,33 +2311,22 @@ msgstr "Zowel gegevens als time-out zijn vereist"
#: core/utils/caching.py:43
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
-msgstr ""
-"Ongeldige time-outwaarde, deze moet tussen 0 en 216000 seconden liggen"
-
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} moet model zijn"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} moet een lijstobject zijn"
+msgstr "Ongeldige time-outwaarde, deze moet tussen 0 en 216000 seconden liggen"
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Neem contact met ons op"
+msgstr "{config.PROJECT_NAME} | neem contact met ons op"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
-msgstr "{config.PROJECT_NAME}. | Orderbevestiging"
+msgstr "{config.PROJECT_NAME} | Orderbevestiging"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME}. | Geleverd"
+msgstr "{config.PROJECT_NAME} | Bestelling afgeleverd"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2319,15 +2347,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Ongeldig formaat telefoonnummer"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "U kunt het digitale goed maar één keer downloaden"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon niet gevonden"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Fout bij geocodering: {e}"
diff --git a/core/locale/pl_PL/LC_MESSAGES/django.mo b/core/locale/pl_PL/LC_MESSAGES/django.mo
index 50475887..393bde22 100644
Binary files a/core/locale/pl_PL/LC_MESSAGES/django.mo and b/core/locale/pl_PL/LC_MESSAGES/django.mo differ
diff --git a/core/locale/pl_PL/LC_MESSAGES/django.po b/core/locale/pl_PL/LC_MESSAGES/django.po
index 98d57a93..ddfaf4d2 100644
--- a/core/locale/pl_PL/LC_MESSAGES/django.po
+++ b/core/locale/pl_PL/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,122 +13,119 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Unikalny identyfikator"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"Unikalny identyfikator służy do jednoznacznej identyfikacji dowolnego "
"obiektu bazy danych"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Jest aktywny"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Jeśli ustawione na false, obiekt ten nie może być widoczny dla użytkowników "
"bez wymaganych uprawnień."
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Utworzony"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Kiedy obiekt po raz pierwszy pojawił się w bazie danych"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Zmodyfikowany"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Kiedy obiekt był ostatnio edytowany"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Tłumaczenia"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Ogólne"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relacje"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadane"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Znaczniki czasu"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr "Aktywuj wybrane %(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s aktywowany pomyślnie!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Wybrane elementy zostały aktywowane!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Dezaktywacja wybranych %(verbose_name_plural)s"
+msgstr "Dezaktywacja wybranego %(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "Funkcja %(verbose_name_plural)s została pomyślnie dezaktywowana."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Wybrane elementy zostały dezaktywowane!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Wartość atrybutu"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Wartości atrybutów"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Obraz"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Obrazy"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stan magazynowy"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Akcje"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Zamów produkt"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Zamawianie produktów"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Dzieci"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Konfiguracja"
@@ -180,7 +177,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Udany"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Pamięć podręczna we/wy"
@@ -190,7 +187,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"Zastosuj tylko klucz, aby odczytać dozwolone dane z pamięci podręcznej.\n"
-"Zastosuj klucz, dane i limit czasu z uwierzytelnianiem, aby zapisać dane w pamięci podręcznej."
+"Zastosuj klucz, dane i limit czasu z uwierzytelnianiem, aby zapisać dane w "
+"pamięci podręcznej."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -204,7 +202,7 @@ msgstr "Uzyskaj dostępne parametry aplikacji"
msgid "send a message to the support team"
msgstr "Wyślij wiadomość do zespołu wsparcia"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Żądanie adresu URL CORSed. Dozwolony jest tylko protokół https."
@@ -247,8 +245,7 @@ msgstr ""
"nieedytowalnych"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Przepisanie niektórych pól istniejącej grupy atrybutów z zachowaniem "
"atrybutów nieedytowalnych"
@@ -303,8 +300,7 @@ msgstr ""
"nieedytowalnych"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Przepisz niektóre pola istniejącej wartości atrybutu, zapisując wartości "
"nieedytowalne"
@@ -347,11 +343,11 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
-"Wyszukiwanie podciągów z uwzględnieniem wielkości liter w human_readable_id,"
-" order_products.product.name i order_products.product.partnumber."
+"Wyszukiwanie podciągów z uwzględnieniem wielkości liter w human_readable_id, "
+"order_products.product.name i order_products.product.partnumber."
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -384,14 +380,14 @@ msgstr "Filtrowanie według identyfikatora UUID użytkownika"
#: core/docs/drf/viewsets.py:195
msgid "Filter by order status (case-insensitive substring match)"
msgstr ""
-"Filtrowanie według statusu zamówienia (dopasowanie podciągu z uwzględnieniem"
-" wielkości liter)"
+"Filtrowanie według statusu zamówienia (dopasowanie podciągu z uwzględnieniem "
+"wielkości liter)"
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Kolejność według jednego z: uuid, human_readable_id, user_email, user, "
"status, created, modified, buy_time, random. Prefiks z \"-\" dla malejącego "
@@ -437,7 +433,7 @@ msgstr ""
"finalizowany przy użyciu salda użytkownika; Jeśli użyto `force_payment`, "
"transakcja jest inicjowana."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "zakup zamówienia bez tworzenia konta"
@@ -571,18 +567,28 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtrowanie według jednej lub więcej par atrybut/wartość. \n"
"- Składnia**: `attr_name=method-value[;attr2=method2-value2]...`\n"
-"- **Metody** (domyślnie `icontains` jeśli pominięte): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
-"- Wpisywanie wartości**: JSON jest próbowany jako pierwszy (więc można przekazywać listy/dykty), `true`/`false` dla booleans, integers, floats; w przeciwnym razie traktowane jako string. \n"
-"- Base64**: prefiks z `b64-` do bezpiecznego dla adresów URL kodowania base64 surowej wartości. \n"
+"- **Metody** (domyślnie `icontains` jeśli pominięte): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
+"- Wpisywanie wartości**: JSON jest próbowany jako pierwszy (więc można "
+"przekazywać listy/dykty), `true`/`false` dla booleans, integers, floats; w "
+"przeciwnym razie traktowane jako string. \n"
+"- Base64**: prefiks z `b64-` do bezpiecznego dla adresów URL kodowania "
+"base64 surowej wartości. \n"
"Przykłady: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\", \"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`"
@@ -637,10 +643,12 @@ msgstr "(dokładnie) Cyfrowe vs. fizyczne"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Rozdzielana przecinkami lista pól do posortowania. Prefiks z `-` dla sortowania malejącego. \n"
+"Rozdzielana przecinkami lista pól do posortowania. Prefiks z `-` dla "
+"sortowania malejącego. \n"
"**Dozwolone:** uuid, rating, name, slug, created, modified, price, random"
#: core/docs/drf/viewsets.py:441
@@ -770,7 +778,7 @@ msgstr "usunąć relację zamówienie-produkt"
msgid "add or remove feedback on an order–product relation"
msgstr "dodawanie lub usuwanie opinii na temat relacji zamówienie-produkt"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Nie podano wyszukiwanego hasła."
@@ -818,8 +826,8 @@ msgstr "Atrybuty"
msgid "Quantity"
msgstr "Ilość"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Ślimak"
@@ -880,216 +888,239 @@ msgstr "Poziom"
msgid "Product UUID"
msgstr "UUID produktu"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Klucz do wyszukania lub ustawienia w pamięci podręcznej"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Dane do przechowywania w pamięci podręcznej"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Limit czasu w sekundach na wprowadzenie danych do pamięci podręcznej"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Dane w pamięci podręcznej"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Kamelizowane dane JSON z żądanego adresu URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Dozwolone są tylko adresy URL zaczynające się od http(s)://"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Dodawanie produktu do zamówienia"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Nie znaleziono zamówienia {order_uuid}"
+msgstr "Nie znaleziono zamówienia {order_uuid}!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Usunięcie produktu z zamówienia"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Usuń wszystkie produkty z zamówienia"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Kup zamówienie"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Podaj albo order_uuid albo order_hr_id - wzajemnie się wykluczają!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Nieprawidłowy typ pochodzi z metody order.buy(): {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Wykonanie akcji na liście produktów w zamówieniu"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Usuń/Dodaj"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Akcją musi być \"dodaj\" lub \"usuń\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Wykonanie akcji na liście produktów na liście życzeń"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Podaj wartość `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Lista życzeń {wishlist_uuid} nie została znaleziona!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Dodawanie produktu do zamówienia"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Lista życzeń {wishlist_uuid} nie została znaleziona"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Usunięcie produktu z zamówienia"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Usunięcie produktu z zamówienia"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Usunięcie produktu z zamówienia"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Kup zamówienie"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
"Prześlij atrybuty jako ciąg znaków sformatowany w następujący sposób: "
"attr1=value1,attr2=value2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Dodawanie lub usuwanie opinii dla produktu zamówienia"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Akcją musi być `add` lub `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Orderproduct {order_product_uuid} nie został znaleziony!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Oryginalny ciąg adresu podany przez użytkownika"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} nie istnieje: {uuid}"
+msgstr "{name} nie istnieje: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Limit musi wynosić od 1 do 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - działa jak urok"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Atrybuty"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Atrybuty pogrupowane"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Grupy atrybutów"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Kategorie"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Marki"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Kategorie"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Procentowy narzut"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Które atrybuty i wartości mogą być używane do filtrowania tej kategorii."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Minimalne i maksymalne ceny produktów w tej kategorii, jeśli są dostępne."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tagi dla tej kategorii"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Produkty w tej kategorii"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Sprzedawcy"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Szerokość geograficzna (współrzędna Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Długość geograficzna (współrzędna X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Jak"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Wartość oceny od 1 do 10 włącznie lub 0, jeśli nie jest ustawiona."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Reprezentuje informacje zwrotne od użytkownika."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Powiadomienia"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Adres URL pobierania dla tego produktu zamówienia, jeśli dotyczy"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Lista zamówionych produktów w tym zamówieniu"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Adres rozliczeniowy"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1097,733 +1128,730 @@ msgstr ""
"Adres wysyłki dla tego zamówienia, pozostaw pusty, jeśli jest taki sam jak "
"adres rozliczeniowy lub jeśli nie dotyczy"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Całkowita cena tego zamówienia"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Całkowita ilość produktów w zamówieniu"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Czy wszystkie produkty w zamówieniu są cyfrowe?"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transakcje dla tego zamówienia"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Zamówienia"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "Adres URL obrazu"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Zdjęcia produktu"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Kategoria"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Informacje zwrotne"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Marka"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Grupy atrybutów"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Cena"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Ilość"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Liczba informacji zwrotnych"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Produkty"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Promocodes"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Produkty w sprzedaży"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promocje"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Sprzedawca"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Produkt"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Produkty z listy życzeń"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Listy życzeń"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Produkty Tagged"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Tagi produktu"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Kategorie oznaczone tagami"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Tagi kategorii"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Nazwa projektu"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Firmowy adres e-mail"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Nazwa firmy"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Adres firmy"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Numer telefonu firmy"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
-msgstr "\"email from\", czasami musi być użyty zamiast wartości użytkownika hosta"
+msgstr ""
+"\"email from\", czasami musi być użyty zamiast wartości użytkownika hosta"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Użytkownik hosta poczty e-mail"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Maksymalna kwota płatności"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Minimalna kwota płatności"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Dane analityczne"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Dane reklamowe"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Konfiguracja"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Kod języka"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Nazwa języka"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Flaga języka, jeśli istnieje :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Pobierz listę obsługiwanych języków"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Wyniki wyszukiwania produktów"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Wyniki wyszukiwania produktów"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Rodzic tej grupy"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Grupa atrybutów nadrzędnych"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Nazwa grupy atrybutów"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Grupa atrybutów"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Przechowuje dane uwierzytelniające i punkty końcowe wymagane do komunikacji "
"API dostawcy."
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Informacje o uwierzytelnianiu"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Definiowanie znaczników dla produktów pobranych od tego dostawcy"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Procentowa marża sprzedawcy"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Nazwa tego sprzedawcy"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Nazwa sprzedawcy"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Wewnętrzny identyfikator tagu produktu"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Nazwa tagu"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Przyjazna dla użytkownika nazwa etykiety produktu"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Wyświetlana nazwa znacznika"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Etykieta produktu"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "tag kategorii"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "tagi kategorii"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Prześlij obraz reprezentujący tę kategorię"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Obraz kategorii"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Zdefiniuj procentowy narzut dla produktów w tej kategorii."
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Rodzic tej kategorii w celu utworzenia struktury hierarchicznej"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Kategoria nadrzędna"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Nazwa kategorii"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Podaj nazwę dla tej kategorii"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Dodaj szczegółowy opis dla tej kategorii"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Opis kategorii"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "tagi, które pomagają opisać lub pogrupować tę kategorię"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Priorytet"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Nazwa tej marki"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Nazwa marki"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Prześlij logo reprezentujące tę markę"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Mały wizerunek marki"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Prześlij duże logo reprezentujące tę markę"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Duży wizerunek marki"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Dodaj szczegółowy opis marki"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Opis marki"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Opcjonalne kategorie, z którymi powiązana jest ta marka"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Kategorie"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Kategoria, do której należy ten produkt"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Opcjonalnie można powiązać ten produkt z marką"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Tagi, które pomagają opisać lub pogrupować ten produkt"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Wskazuje, czy produkt jest dostarczany cyfrowo."
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Czy produkt jest cyfrowy?"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Wyraźna nazwa identyfikująca produkt"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Nazwa produktu"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Dodaj szczegółowy opis produktu"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Opis produktu"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Numer części dla tego produktu"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Numer części"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Kategoria tego atrybutu"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Grupa tego atrybutu"
-
-#: core/models.py:465
-msgid "string"
-msgstr "String"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Integer"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Pływak"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Wartość logiczna"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Tablica"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Obiekt"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Typ wartości atrybutu"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Typ wartości"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Nazwa tego atrybutu"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Nazwa atrybutu"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Atrybut"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Atrybut tej wartości"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Konkretny produkt powiązany z wartością tego atrybutu"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Produkt powiązany"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "Konkretna wartość dla tego atrybutu"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr ""
-"Zapewnienie alternatywnego tekstu dla obrazu w celu ułatwienia dostępu"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Tekst alternatywny obrazu"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Prześlij plik obrazu dla tego produktu"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Obraz produktu"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Określa kolejność wyświetlania obrazów"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Priorytet wyświetlania"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "Produkt, który przedstawia ten obraz"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Zdjęcia produktów"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Rabat procentowy na wybrane produkty"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Procent rabatu"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Podaj unikalną nazwę tej promocji"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Nazwa promocji"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Opis promocji"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Wybierz produkty objęte promocją"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Dołączone produkty"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Promocja"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "Sprzedawca dostarczający ten produkt"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Powiązany sprzedawca"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Ostateczna cena dla klienta po uwzględnieniu marży"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Cena sprzedaży"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "Produkt powiązany z tym wpisem magazynowym"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Produkt powiązany"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "Cena zapłacona sprzedawcy za ten produkt"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Cena zakupu przez sprzedawcę"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Dostępna ilość produktu w magazynie"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Ilość w magazynie"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "Jednostki SKU przypisane przez dostawcę w celu identyfikacji produktu"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "SKU sprzedawcy"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Plik cyfrowy powiązany z tymi zapasami, jeśli dotyczy"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Plik cyfrowy"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Zapisy magazynowe"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Kategoria, do której należy ten produkt"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Opcjonalnie można powiązać ten produkt z marką"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Tagi, które pomagają opisać lub pogrupować ten produkt"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Wskazuje, czy produkt jest dostarczany cyfrowo."
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Czy produkt jest cyfrowy?"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Wyraźna nazwa identyfikująca produkt"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Nazwa produktu"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Dodaj szczegółowy opis produktu"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Opis produktu"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Numer części dla tego produktu"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Numer części"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Kategoria tego atrybutu"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Grupa tego atrybutu"
+
+#: core/models.py:767
+msgid "string"
+msgstr "String"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Integer"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Pływak"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Wartość logiczna"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Tablica"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Obiekt"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Typ wartości atrybutu"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Typ wartości"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Nazwa tego atrybutu"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Nazwa atrybutu"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Atrybut"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Atrybut tej wartości"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Konkretny produkt powiązany z wartością tego atrybutu"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "Konkretna wartość dla tego atrybutu"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Zapewnienie alternatywnego tekstu dla obrazu w celu ułatwienia dostępu"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Tekst alternatywny obrazu"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Prześlij plik obrazu dla tego produktu"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Obraz produktu"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Określa kolejność wyświetlania obrazów"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Priorytet wyświetlania"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "Produkt, który przedstawia ten obraz"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Zdjęcia produktów"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Rabat procentowy na wybrane produkty"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Procent rabatu"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Podaj unikalną nazwę tej promocji"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Nazwa promocji"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Opis promocji"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Wybierz produkty objęte promocją"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Dołączone produkty"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Promocja"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Produkty, które użytkownik oznaczył jako poszukiwane"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Użytkownik posiadający tę listę życzeń"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Właściciel listy życzeń"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Lista życzeń"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} nie istnieje: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Film dokumentalny"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Filmy dokumentalne"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Nierozwiązany"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Linia adresu dla klienta"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Linia adresowa"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "ul."
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Okręg"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Miasto"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Region"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Kod pocztowy"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Kraj"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Geolocation Point(Longitude, Latitude)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Pełna odpowiedź JSON z geokodera dla tego adresu"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Przechowywana odpowiedź JSON z usługi geokodowania"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Adres"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adresy"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Unikalny kod używany przez użytkownika do realizacji rabatu."
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Identyfikator kodu promocyjnego"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Stała kwota rabatu stosowana, jeśli procent nie jest używany"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Stała kwota rabatu"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Rabat procentowy stosowany w przypadku niewykorzystania stałej kwoty"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Rabat procentowy"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Znacznik czasu wygaśnięcia kodu promocyjnego"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Końcowy czas ważności"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Znacznik czasu, od którego ten kod promocyjny jest ważny"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Czas rozpoczęcia ważności"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Znacznik czasu użycia kodu promocyjnego, pusty, jeśli nie został jeszcze "
"użyty."
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Znacznik czasu użycia"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Użytkownik przypisany do tego kodu promocyjnego, jeśli dotyczy"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Przypisany użytkownik"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Kod promocyjny"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Kody promocyjne"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1831,141 +1859,150 @@ msgstr ""
"Należy zdefiniować tylko jeden rodzaj rabatu (kwotowy lub procentowy), ale "
"nie oba lub żaden z nich."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Kod promocyjny został już wykorzystany"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Nieprawidłowy typ rabatu dla kodu promocyjnego {self.uuid}."
+msgstr "Nieprawidłowy typ rabatu dla kodu promocyjnego {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "Adres rozliczeniowy użyty dla tego zamówienia"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Opcjonalny kod promocyjny zastosowany do tego zamówienia"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Zastosowany kod promocyjny"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "Adres wysyłki użyty dla tego zamówienia"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Adres wysyłki"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Aktualny status zamówienia w jego cyklu życia"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Status zamówienia"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"Struktura JSON powiadomień do wyświetlenia użytkownikom, w interfejsie "
"administratora używany jest widok tabeli"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "Reprezentacja JSON atrybutów zamówienia dla tego zamówienia"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "Użytkownik, który złożył zamówienie"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Użytkownik"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Znacznik czasu, kiedy zamówienie zostało sfinalizowane"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Kup czas"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Czytelny dla człowieka identyfikator zamówienia"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "Identyfikator czytelny dla człowieka"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Zamówienie"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
-msgstr ""
-"Użytkownik może mieć tylko jedno oczekujące zlecenie w danym momencie!"
+msgstr "Użytkownik może mieć tylko jedno oczekujące zlecenie w danym momencie!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr ""
"Nie można dodać produktów do zamówienia, które nie jest zamówieniem "
"oczekującym."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Nie można dodać nieaktywnych produktów do zamówienia"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "Nie można dodać więcej produktów niż jest dostępnych w magazynie"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
"Nie można usunąć produktów z zamówienia, które nie jest zamówieniem "
"oczekującym."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} nie istnieje z zapytaniem <{query}>."
+msgstr "{name} nie istnieje z zapytaniem <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Kod promocyjny nie istnieje"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "Możesz kupować tylko produkty fizyczne z podanym adresem wysyłki!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Adres nie istnieje"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"W tej chwili nie możesz dokonać zakupu, spróbuj ponownie za kilka minut."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Nieprawidłowa wartość siły"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Nie można kupić pustego zamówienia!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+"Nie można usunąć produktów z zamówienia, które nie jest zamówieniem "
+"oczekującym."
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Użytkownik bez salda nie może kupować za saldo!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Niewystarczające środki do zrealizowania zamówienia"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1974,7 +2011,7 @@ msgstr ""
"informacje: imię i nazwisko klienta, adres e-mail klienta, numer telefonu "
"klienta."
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
@@ -1982,115 +2019,117 @@ msgstr ""
"Nieprawidłowa metoda płatności: {payment_method} z "
"{available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "Cena zapłacona przez klienta za ten produkt w momencie zakupu."
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Cena zakupu w momencie zamówienia"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr ""
-"Wewnętrzne komentarze dla administratorów dotyczące tego zamówionego "
-"produktu"
+"Wewnętrzne komentarze dla administratorów dotyczące tego zamówionego produktu"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Uwagi wewnętrzne"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Powiadomienia użytkownika"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "Reprezentacja JSON atrybutów tego elementu"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Zamówione atrybuty produktu"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Odniesienie do zamówienia nadrzędnego zawierającego ten produkt"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Zamówienie nadrzędne"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Konkretny produkt powiązany z tą linią zamówienia"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Ilość tego konkretnego produktu w zamówieniu"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Ilość produktu"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Aktualny status tego produktu w zamówieniu"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Status linii produktów"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Orderproduct musi mieć powiązane zamówienie!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "nieprawidłowe działanie określone dla informacji zwrotnej: {action}"
+msgstr "Nieprawidłowa akcja określona dla informacji zwrotnej: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
"Nie można usunąć produktów z zamówienia, które nie jest zamówieniem "
"oczekującym."
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Pobierz"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Pliki do pobrania"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "Nie można pobrać zasobu cyfrowego dla nieukończonego zamówienia."
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Komentarze użytkowników na temat ich doświadczeń z produktem"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Komentarze zwrotne"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"Odnosi się do konkretnego produktu w zamówieniu, którego dotyczy ta "
"informacja zwrotna."
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Powiązany produkt zamówienia"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Ocena produktu przypisana przez użytkownika"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Ocena produktu"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Informacje zwrotne"
@@ -2101,13 +2140,13 @@ msgstr ""
"Aby dodać opinię, należy podać komentarz, ocenę i identyfikator produktu "
"zamówienia."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Błąd podczas tworzenia kodu promocyjnego: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2116,7 +2155,7 @@ msgid "order confirmation"
msgstr "Potwierdzenie zamówienia"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2127,13 +2166,14 @@ msgstr "Logo"
#: core/templates/shipped_order_delivered_email.html:100
#, python-format
msgid "hello %(order.user.first_name)s,"
-msgstr "Witam %(order.user.first_name)s,"
+msgstr "Witaj %(order.user.first_name)s,"
#: core/templates/digital_order_created_email.html:102
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Dziękujemy za zamówienie #%(order.pk)s! Z przyjemnością informujemy, że "
@@ -2141,14 +2181,14 @@ msgstr ""
"zamówienia:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Łącznie"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2168,32 +2208,32 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Z wyrazami szacunku,
zespół %(config.PROJECT_NAME)s"
+msgstr "Najlepsze pozdrowienia,
zespół %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Wszelkie prawa zastrzeżone"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Zamówienie dostarczone"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Witaj %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
" details of your order:"
msgstr ""
-"Pomyślnie przetworzyliśmy Twoje zamówienie №%(order_uuid)s! Poniżej znajdują"
-" się szczegóły zamówienia:"
+"Pomyślnie przetworzyliśmy Twoje zamówienie №%(order_uuid)s! Poniżej znajdują "
+"się szczegóły zamówienia:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2201,12 +2241,12 @@ msgstr ""
"dodatkowe\n"
" informacje"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Wartość"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2215,10 +2255,10 @@ msgstr ""
"Jeśli masz jakiekolwiek pytania, skontaktuj się z naszym działem pomocy "
"technicznej pod adresem %(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Z wyrazami szacunku,
zespół %(project_name)s"
+msgstr "Najlepsze pozdrowienia,
zespół %(project_name)s"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2227,7 +2267,8 @@ msgstr "Klucz"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Dziękujemy za zamówienie! Z przyjemnością potwierdzamy zakup. Poniżej "
@@ -2247,7 +2288,7 @@ msgstr "Zamówienie zostanie dostarczone pod następujący adres:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Z wyrazami szacunku, zespół %(config.PROJECT_NAME)s"
+msgstr "Z wyrazami szacunku,
Zespół %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2268,27 +2309,17 @@ msgstr ""
"Nieprawidłowa wartość limitu czasu, musi zawierać się w przedziale od 0 do "
"216000 sekund."
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} musi być modelem"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} musi być obiektem listy"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Kontakt zainicjowany"
+msgstr "{config.PROJECT_NAME} | zainicjowany kontakt"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Potwierdzenie zamówienia"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr "{config.PROJECT_NAME} | Zamówienie dostarczone"
@@ -2311,15 +2342,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Nieprawidłowy format numeru telefonu"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Zasób cyfrowy można pobrać tylko raz"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "nie znaleziono favicon"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Błąd geokodowania: {e}"
diff --git a/core/locale/pt_BR/LC_MESSAGES/django.mo b/core/locale/pt_BR/LC_MESSAGES/django.mo
index a97749b1..5f2c14e5 100644
Binary files a/core/locale/pt_BR/LC_MESSAGES/django.mo and b/core/locale/pt_BR/LC_MESSAGES/django.mo differ
diff --git a/core/locale/pt_BR/LC_MESSAGES/django.po b/core/locale/pt_BR/LC_MESSAGES/django.po
index 4aa66926..ed2db556 100644
--- a/core/locale/pt_BR/LC_MESSAGES/django.po
+++ b/core/locale/pt_BR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,122 +13,119 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "ID exclusivo"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"O ID exclusivo é usado para identificar com segurança qualquer objeto do "
"banco de dados"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Está ativo"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Se definido como false, esse objeto não poderá ser visto por usuários sem a "
"permissão necessária"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Criado"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Quando o objeto apareceu pela primeira vez no banco de dados"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modificado"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Quando o objeto foi editado pela última vez"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Traduções"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Geral"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relações"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadados"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Carimbos de data/hora"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "Ativar %(verbose_name_plural)s selecionados"
+msgstr "Ativar o %(verbose_name_plural)s selecionado"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s ativado com sucesso!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Os itens selecionados foram ativados!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Desativar %(verbose_name_plural)s selecionados"
+msgstr "Desativar o %(verbose_name_plural)s selecionado"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s desativado com sucesso."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Os itens selecionados foram desativados!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Valor do atributo"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Valores de atributos"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Imagem"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Imagens"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Estoque"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Ações"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Pedido de produto"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Solicitar produtos"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Crianças"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Configuração"
@@ -180,7 +177,7 @@ msgstr "Momental"
msgid "successful"
msgstr "Bem-sucedido"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "E/S do cache"
@@ -190,7 +187,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"Aplicar somente uma chave para ler dados permitidos do cache.\n"
-"Aplicar chave, dados e tempo limite com autenticação para gravar dados no cache."
+"Aplicar chave, dados e tempo limite com autenticação para gravar dados no "
+"cache."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -204,7 +202,7 @@ msgstr "Obter os parâmetros expostos do aplicativo"
msgid "send a message to the support team"
msgstr "Envie uma mensagem para a equipe de suporte"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Solicite um URL com CORS. Somente https é permitido."
@@ -246,8 +244,7 @@ msgid "rewrite an existing attribute group saving non-editables"
msgstr "Reescrever um grupo de atributos existente salvando os não editáveis"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Reescreva alguns campos de um grupo de atributos existente salvando os não "
"editáveis"
@@ -298,8 +295,7 @@ msgid "rewrite an existing attribute value saving non-editables"
msgstr "Reescreva um valor de atributo existente salvando os não editáveis"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Reescreva alguns campos de um valor de atributo existente salvando os não "
"editáveis"
@@ -340,12 +336,12 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"Pesquisa de substring sem distinção entre maiúsculas e minúsculas em "
-"human_readable_id, order_products.product.name e "
-"order_products.product.partnumber"
+"human_readable_id, order_products.product.name e order_products.product."
+"partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -381,9 +377,9 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Ordene por uma das seguintes opções: uuid, human_readable_id, user_email, "
"user, status, created, modified, buy_time, random. Prefixe com '-' para "
@@ -428,7 +424,7 @@ msgstr ""
"concluída usando o saldo do usuário; se `force_payment` for usado, uma "
"transação será iniciada."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "comprar um pedido sem criar uma conta"
@@ -564,18 +560,28 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtrar por um ou mais pares de nome/valor de atributo. \n"
"- **Sintaxe**: `attr_name=method-value[;attr2=method2-value2]...`\n"
-"- Métodos** (o padrão é `icontains` se omitido): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
-"- Digitação de valores**: JSON é tentado primeiro (para que você possa passar listas/dicas), `true`/`false` para booleanos, inteiros, flutuantes; caso contrário, é tratado como string. \n"
-"- Base64**: prefixo com `b64-` para codificar o valor bruto com base64 de forma segura para a URL. \n"
+"- Métodos** (o padrão é `icontains` se omitido): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
+"- Digitação de valores**: JSON é tentado primeiro (para que você possa "
+"passar listas/dicas), `true`/`false` para booleanos, inteiros, flutuantes; "
+"caso contrário, é tratado como string. \n"
+"- Base64**: prefixo com `b64-` para codificar o valor bruto com base64 de "
+"forma segura para a URL. \n"
"Exemplos: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\", \"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`"
@@ -631,11 +637,14 @@ msgstr "(exato) Digital vs. físico"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Lista de campos separada por vírgulas para classificação. Prefixe com `-` para classificação decrescente. \n"
-"**Permitido:** uuid, classificação, nome, slug, criado, modificado, preço, aleatório"
+"Lista de campos separada por vírgulas para classificação. Prefixe com `-` "
+"para classificação decrescente. \n"
+"**Permitido:** uuid, classificação, nome, slug, criado, modificado, preço, "
+"aleatório"
#: core/docs/drf/viewsets.py:441
msgid "retrieve a single product (detailed view)"
@@ -761,7 +770,7 @@ msgstr "excluir uma relação pedido-produto"
msgid "add or remove feedback on an order–product relation"
msgstr "adicionar ou remover feedback em uma relação pedido-produto"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Nenhum termo de pesquisa foi fornecido."
@@ -809,8 +818,8 @@ msgstr "Atributos"
msgid "Quantity"
msgstr "Quantidade"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Lesma"
@@ -872,215 +881,238 @@ msgstr "Nível"
msgid "Product UUID"
msgstr "UUID do produto"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Chave para procurar ou colocar no cache"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Dados a serem armazenados no cache"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Tempo limite em segundos para definir os dados para o cache"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Dados em cache"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Dados JSON camelizados da URL solicitada"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Somente URLs que começam com http(s):// são permitidos"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Adicionar um produto ao pedido"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Pedido {order_uuid} não encontrado"
+msgstr "Pedido {order_uuid} não encontrado!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Remover um produto do pedido"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Remover todos os produtos do pedido"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Comprar um pedido"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "Forneça order_uuid ou order_hr_id - mutuamente exclusivos!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "O tipo errado veio do método order.buy(): {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Executar uma ação em uma lista de produtos no pedido"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Remover/Adicionar"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "A ação deve ser \"adicionar\" ou \"remover\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Executar uma ação em uma lista de produtos na lista de desejos"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Forneça o valor `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Lista de desejos {wishlist_uuid} não encontrada!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Adicionar um produto ao pedido"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Lista de desejos {wishlist_uuid} não encontrada"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Remover um produto do pedido"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Remover um produto do pedido"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Remover um produto do pedido"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Comprar um pedido"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
"Envie os atributos como uma string formatada como attr1=value1,attr2=value2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Adicionar ou excluir um feedback para o produto do pedido"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "A ação deve ser `add` ou `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Orderproduct {order_product_uuid} não encontrado!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Cadeia de endereços original fornecida pelo usuário"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} não existe: {uuid}"
+msgstr "{name} não existe: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "O limite deve estar entre 1 e 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - funciona muito bem"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Atributos"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Atributos agrupados"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Grupos de atributos"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Categorias"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Marcas"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Categorias"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Porcentagem de marcação"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Quais atributos e valores podem ser usados para filtrar essa categoria."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr "Preços mínimo e máximo dos produtos dessa categoria, se disponíveis."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Tags para esta categoria"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Produtos desta categoria"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Vendors"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Latitude (coordenada Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Longitude (coordenada X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Como fazer"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr ""
"Valor de classificação de 1 a 10, inclusive, ou 0 se não estiver definido."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Representa o feedback de um usuário."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Notificações"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "URL de download para este produto do pedido, se aplicável"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Uma lista dos produtos solicitados nesse pedido"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Endereço de cobrança"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1088,875 +1120,878 @@ msgstr ""
"Endereço de entrega para este pedido, deixe em branco se for o mesmo que o "
"endereço de cobrança ou se não for aplicável"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Preço total deste pedido"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Quantidade total de produtos no pedido"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Todos os produtos estão no pedido digital?"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Transações para esta ordem"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Pedidos"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "URL da imagem"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Imagens do produto"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Categoria"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Feedbacks"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Brand"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Grupos de atributos"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Preço"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Quantidade"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Número de feedbacks"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Produtos"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Códigos promocionais"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Produtos à venda"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promoções"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Vendor"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Produto"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Produtos da lista de desejos"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Listas de desejos"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Produtos marcados"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Etiquetas do produto"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Categorias de tags"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Tags das categorias"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Nome do projeto"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "E-mail da empresa"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Nome da empresa"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Endereço da empresa"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Número de telefone da empresa"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"'email from', às vezes ele deve ser usado em vez do valor do usuário do host"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Usuário do host de e-mail"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Valor máximo para pagamento"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Valor mínimo para pagamento"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Dados analíticos"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Dados do anúncio"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configuração"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Código do idioma"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Nome do idioma"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Sinalizador de idioma, se houver :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Obter uma lista de idiomas suportados"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Resultados da pesquisa de produtos"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Resultados da pesquisa de produtos"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Pai deste grupo"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Grupo de atributos pai"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Nome do grupo de atributos"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Grupo de atributos"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Armazena as credenciais e os pontos de extremidade necessários para a "
"comunicação da API do fornecedor"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Informações de autenticação"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Definir a marcação para produtos recuperados desse fornecedor"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Porcentagem da margem de lucro do fornecedor"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Nome do fornecedor"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Nome do fornecedor"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Identificador de tag interno para a tag do produto"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Nome da etiqueta"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Nome de fácil utilização para a etiqueta do produto"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Nome de exibição da tag"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Etiqueta do produto"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "tag de categoria"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "tags de categoria"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Faça upload de uma imagem que represente essa categoria"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Imagem da categoria"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Definir uma porcentagem de majoração para os produtos dessa categoria"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Pai dessa categoria para formar uma estrutura hierárquica"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Categoria dos pais"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Nome da categoria"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Forneça um nome para essa categoria"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Adicione uma descrição detalhada para essa categoria"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Descrição da categoria"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "tags que ajudam a descrever ou agrupar essa categoria"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Prioridade"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Nome da marca"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Nome da marca"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Faça upload de um logotipo que represente essa marca"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Imagem pequena da marca"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Faça upload de um logotipo grande que represente essa marca"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Imagem de marca grande"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Adicione uma descrição detalhada da marca"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Descrição da marca"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Categorias opcionais às quais essa marca está associada"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Categorias"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Categoria à qual este produto pertence"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Opcionalmente, associe esse produto a uma marca"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Tags que ajudam a descrever ou agrupar este produto"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Indica se esse produto é entregue digitalmente"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "O produto é digital"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Fornecer um nome de identificação claro para o produto"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Nome do produto"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Adicione uma descrição detalhada do produto"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Descrição do produto"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Número de peça para este produto"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Número da peça"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Categoria desse atributo"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Grupo desse atributo"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Cordas"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Inteiro"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Flutuação"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Booleano"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Matriz"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Objeto"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Tipo do valor do atributo"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Tipo de valor"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Nome desse atributo"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Nome do atributo"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Atributo"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Atributo desse valor"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "O produto específico associado ao valor desse atributo"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Produto associado"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "O valor específico para esse atributo"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr ""
-"Forneça um texto alternativo para a imagem para fins de acessibilidade"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Texto alternativo da imagem"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Faça o upload do arquivo de imagem para este produto"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Imagem do produto"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Determina a ordem em que as imagens são exibidas"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Prioridade de exibição"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "O produto que esta imagem representa"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Imagens do produto"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Desconto percentual para os produtos selecionados"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Porcentagem de desconto"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Forneça um nome exclusivo para essa promoção"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Nome da promoção"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Descrição da promoção"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Selecione quais produtos estão incluídos nessa promoção"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Produtos incluídos"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Promoção"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "O fornecedor que fornece esse estoque de produtos"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Fornecedor associado"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Preço final para o cliente após as marcações"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Preço de venda"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "O produto associado a essa entrada em estoque"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Produto associado"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "O preço pago ao fornecedor por esse produto"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Preço de compra do fornecedor"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Quantidade disponível do produto em estoque"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Quantidade em estoque"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "SKU atribuído pelo fornecedor para identificar o produto"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "SKU do fornecedor"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Arquivo digital associado a esse estoque, se aplicável"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Arquivo digital"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Entradas de estoque"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Categoria à qual este produto pertence"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Opcionalmente, associe esse produto a uma marca"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Tags que ajudam a descrever ou agrupar este produto"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Indica se esse produto é entregue digitalmente"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "O produto é digital"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Fornecer um nome de identificação claro para o produto"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Nome do produto"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Adicione uma descrição detalhada do produto"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Descrição do produto"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Número de peça para este produto"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Número da peça"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Categoria desse atributo"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Grupo desse atributo"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Cordas"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Inteiro"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Flutuação"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Booleano"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Matriz"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Objeto"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Tipo do valor do atributo"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Tipo de valor"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Nome desse atributo"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Nome do atributo"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Atributo"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Atributo desse valor"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "O produto específico associado ao valor desse atributo"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "O valor específico para esse atributo"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Forneça um texto alternativo para a imagem para fins de acessibilidade"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Texto alternativo da imagem"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Faça o upload do arquivo de imagem para este produto"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Imagem do produto"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Determina a ordem em que as imagens são exibidas"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Prioridade de exibição"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "O produto que esta imagem representa"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Imagens do produto"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Desconto percentual para os produtos selecionados"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Porcentagem de desconto"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Forneça um nome exclusivo para essa promoção"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Nome da promoção"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Descrição da promoção"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Selecione quais produtos estão incluídos nessa promoção"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Produtos incluídos"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Promoção"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Produtos que o usuário marcou como desejados"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Usuário que possui esta lista de desejos"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Proprietário da lista de desejos"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Lista de desejos"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} não existe: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documentário"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentários"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Não resolvido"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Linha de endereço do cliente"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Linha de endereço"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Rua"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Distrito"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Cidade"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Região"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Código postal"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "País"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Ponto de geolocalização (Longitude, Latitude)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Resposta JSON completa do geocodificador para este endereço"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Resposta JSON armazenada do serviço de geocodificação"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Endereço"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Endereços"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Código exclusivo usado por um usuário para resgatar um desconto"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Identificador de código promocional"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Valor de desconto fixo aplicado se a porcentagem não for usada"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Valor do desconto fixo"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Desconto percentual aplicado se o valor fixo não for usado"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Desconto percentual"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Registro de data e hora em que o código promocional expira"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Tempo de validade final"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr ""
"Registro de data e hora a partir do qual esse código promocional é válido"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Hora de início da validade"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Registro de data e hora em que o código promocional foi usado, em branco se "
"ainda não tiver sido usado"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Registro de data e hora de uso"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Usuário atribuído a esse código promocional, se aplicável"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Usuário atribuído"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Código promocional"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Códigos promocionais"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
msgstr ""
-"Apenas um tipo de desconto deve ser definido (valor ou porcentagem), mas não"
-" ambos ou nenhum."
+"Apenas um tipo de desconto deve ser definido (valor ou porcentagem), mas não "
+"ambos ou nenhum."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "O código promocional já foi usado"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Tipo de desconto inválido para o código promocional {self.uuid}"
+msgstr "Tipo de desconto inválido para o código promocional {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "O endereço de cobrança usado para esse pedido"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Código promocional opcional aplicado a este pedido"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Código promocional aplicado"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "O endereço de entrega usado para esse pedido"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Endereço de entrega"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Status atual do pedido em seu ciclo de vida"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Status do pedido"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"Estrutura JSON de notificações a serem exibidas aos usuários; na interface "
"do usuário do administrador, é usada a visualização de tabela"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "Representação JSON dos atributos do pedido para esse pedido"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "O usuário que fez o pedido"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Usuário"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "O registro de data e hora em que o pedido foi finalizado"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Tempo de compra"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Um identificador legível por humanos para o pedido"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "ID legível por humanos"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Pedido"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Um usuário deve ter apenas uma ordem pendente por vez!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "Não é possível adicionar produtos a um pedido que não esteja pendente"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Não é possível adicionar produtos inativos ao pedido"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr ""
"Não é possível adicionar mais produtos do que os disponíveis em estoque"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "Não é possível remover produtos de um pedido que não esteja pendente"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} não existe com a consulta <{query}>"
+msgstr "{name} não existe com a consulta <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "O código promocional não existe"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
-"Você só pode comprar produtos físicos com o endereço de entrega "
-"especificado!"
+"Você só pode comprar produtos físicos com o endereço de entrega especificado!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "O endereço não existe"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"Não é possível comprar neste momento, tente novamente em alguns minutos."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Valor de força inválido"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Você não pode comprar um pedido vazio!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "Não é possível comprar um pedido sem um usuário!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Um usuário sem saldo não pode comprar com saldo!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Fundos insuficientes para concluir o pedido"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1964,7 +1999,7 @@ msgstr ""
"Não é possível comprar sem registro, forneça as seguintes informações: nome "
"do cliente, e-mail do cliente, número de telefone do cliente"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
@@ -1972,115 +2007,118 @@ msgstr ""
"Método de pagamento inválido: {payment_method} de "
"{available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "O preço pago pelo cliente por esse produto no momento da compra"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Preço de compra no momento do pedido"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr ""
"Comentários internos para administradores sobre este produto encomendado"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Comentários internos"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Notificações do usuário"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "Representação JSON dos atributos desse item"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Atributos ordenados do produto"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Referência ao pedido pai que contém esse produto"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Ordem dos pais"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "O produto específico associado a essa linha de pedido"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Quantidade desse produto específico no pedido"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Quantidade do produto"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Status atual desse produto no pedido"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Status da linha de produtos"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "O Orderproduct deve ter um pedido associado!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "ação incorreta especificada para feedback: {action}"
+msgstr "Ação incorreta especificada para o feedback: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "você não pode dar feedback a um pedido que não foi recebido"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Baixar"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Downloads"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr ""
"Não é possível fazer download de um ativo digital para um pedido não "
"concluído"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr ""
"Comentários fornecidos pelo usuário sobre sua experiência com o produto"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Comentários de feedback"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
-"Faz referência ao produto específico em um pedido sobre o qual se trata esse"
-" feedback"
+"Faz referência ao produto específico em um pedido sobre o qual se trata esse "
+"feedback"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Produto de pedido relacionado"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Classificação atribuída pelo usuário ao produto"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Avaliação do produto"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Feedback"
@@ -2091,13 +2129,13 @@ msgstr ""
"Você deve fornecer um comentário, uma classificação e o uuid do produto do "
"pedido para adicionar feedback."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Erro durante a criação do código promocional: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2106,7 +2144,7 @@ msgid "order confirmation"
msgstr "Confirmação de pedido"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2123,21 +2161,22 @@ msgstr "Olá %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Obrigado por seu pedido #%(order.pk)s! Temos o prazer de informá-lo de que "
"seu pedido foi colocado em prática. Abaixo estão os detalhes de seu pedido:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Total"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2157,23 +2196,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Com os melhores cumprimentos,
da equipe de %(config.PROJECT_NAME)s"
+msgstr "Atenciosamente,
a equipe %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Todos os direitos reservados"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Pedido entregue"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Olá %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2182,7 +2221,7 @@ msgstr ""
"Seu pedido №%(order_uuid)s foi processado com sucesso! Abaixo estão os "
"detalhes de seu pedido:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2190,12 +2229,12 @@ msgstr ""
"adicionais\n"
" informações adicionais"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Valor"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2204,10 +2243,10 @@ msgstr ""
"Se tiver alguma dúvida, entre em contato com nosso suporte em "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Atenciosamente,
a equipe de %(project_name)s"
+msgstr "Atenciosamente,
a equipe %(project_name)s"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2216,7 +2255,8 @@ msgstr "Chave"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Obrigado por seu pedido! Temos o prazer de confirmar sua compra. Abaixo "
@@ -2236,7 +2276,7 @@ msgstr "Seu pedido será entregue no seguinte endereço:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Com os melhores cumprimentos,
a equipe de %(config.PROJECT_NAME)s"
+msgstr "Com os melhores cumprimentos,
A equipe %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2255,30 +2295,20 @@ msgstr "São necessários dados e tempo limite"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "Valor de tempo limite inválido, deve estar entre 0 e 216000 segundos"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} deve ser o modelo"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} deve ser um objeto de lista"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Entre em contato conosco iniciado"
+msgstr "{config.PROJECT_NAME} | entre em contato conosco iniciado"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
-msgstr "{config.PROJECT_NAME} | Confirmação de pedido"
+msgstr "{config.PROJECT_NAME} | Confirmação do pedido"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME} | Order Delivered"
+msgstr "{config.PROJECT_NAME} | Pedido entregue"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2298,15 +2328,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Formato de número telefônico inválido"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Você só pode fazer o download do ativo digital uma vez"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon não encontrado"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Erro de geocodificação: {e}"
diff --git a/core/locale/ro_RO/LC_MESSAGES/django.mo b/core/locale/ro_RO/LC_MESSAGES/django.mo
index 3c7a6afd..0bc23179 100644
Binary files a/core/locale/ro_RO/LC_MESSAGES/django.mo and b/core/locale/ro_RO/LC_MESSAGES/django.mo differ
diff --git a/core/locale/ro_RO/LC_MESSAGES/django.po b/core/locale/ro_RO/LC_MESSAGES/django.po
index 73985fcd..2871dd1e 100644
--- a/core/locale/ro_RO/LC_MESSAGES/django.po
+++ b/core/locale/ro_RO/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,122 +13,119 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "ID unic"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"ID-ul unic este utilizat pentru a identifica cu siguranță orice obiect din "
"baza de date"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Este activ"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
-"Dacă este setat la false, acest obiect nu poate fi văzut de utilizatori fără"
-" permisiunea necesară"
+"Dacă este setat la false, acest obiect nu poate fi văzut de utilizatori fără "
+"permisiunea necesară"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Creat"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Când a apărut pentru prima dată obiectul în baza de date"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Modificat"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Când a fost editat obiectul ultima dată"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Traduceri"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Generalități"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Relații"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Metadate"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Timestamps"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "Activați %(verbose_name_plural)s selectate"
+msgstr "Activați %(verbose_name_plural)s selectat"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s activat cu succes!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Articolele selectate au fost activate!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Dezactivați %(verbose_name_plural)s selectate"
+msgstr "Dezactivați %(verbose_name_plural)s selectat"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s dezactivat cu succes."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Articolele selectate au fost dezactivate!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Atribut Valoare"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Valori ale atributului"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Imagine"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Imagini"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Stoc"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Stocuri"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "Comanda Produs"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "Comandați produse"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Copii"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Configurare"
@@ -180,7 +177,7 @@ msgstr "Momental"
msgid "successful"
msgstr "De succes"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Cache I/O"
@@ -190,7 +187,8 @@ msgid ""
"apply key, data and timeout with authentication to write data to cache."
msgstr ""
"Aplicați doar o cheie pentru a citi datele permise din cache.\n"
-"Aplicați o cheie, date și timeout cu autentificare pentru a scrie date în cache."
+"Aplicați o cheie, date și timeout cu autentificare pentru a scrie date în "
+"cache."
#: core/docs/drf/views.py:32
msgid "get a list of supported languages"
@@ -204,15 +202,15 @@ msgstr "Obțineți parametrii expunibili ai aplicației"
msgid "send a message to the support team"
msgstr "Trimiteți un mesaj echipei de asistență"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Solicitați un URL CORSed. Numai https este permis."
#: core/docs/drf/views.py:85
msgid "global search endpoint to query across project's tables"
msgstr ""
-"Punct final de căutare globală pentru a efectua interogări în toate tabelele"
-" proiectului"
+"Punct final de căutare globală pentru a efectua interogări în toate tabelele "
+"proiectului"
#: core/docs/drf/views.py:91
msgid "purchase an order as a business"
@@ -223,8 +221,8 @@ msgid ""
"purchase an order as a business, using the provided `products` with "
"`product_uuid` and `attributes`."
msgstr ""
-"Achiziționați o comandă ca o afacere, utilizând `products` cu `product_uuid`"
-" și `attributes` furnizate."
+"Achiziționați o comandă ca o afacere, utilizând `products` cu `product_uuid` "
+"și `attributes` furnizate."
#: core/docs/drf/viewsets.py:43
msgid "list all attribute groups (simple view)"
@@ -245,12 +243,10 @@ msgstr "Ștergerea unui grup de atribute"
#: core/docs/drf/viewsets.py:59
msgid "rewrite an existing attribute group saving non-editables"
msgstr ""
-"Rescrierea unui grup de atribute existent cu salvarea elementelor "
-"needitabile"
+"Rescrierea unui grup de atribute existent cu salvarea elementelor needitabile"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Rescrierea unor câmpuri ale unui grup de atribute existent, cu salvarea "
"elementelor needitabile"
@@ -303,8 +299,7 @@ msgstr ""
"Rescrierea unei valori de atribut existente care salvează non-editabile"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Rescrierea unor câmpuri ale unei valori de atribut existente salvând "
"elementele needitabile"
@@ -347,8 +342,8 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
"Căutare de substring insensibilă la majuscule în human_readable_id, "
"order_products.product.name și order_products.product.partnumber"
@@ -387,9 +382,9 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Ordonați după unul dintre: uuid, human_readable_id, user_email, user, "
"status, created, modified, buy_time, random. Prefixați cu \"-\" pentru "
@@ -435,7 +430,7 @@ msgstr ""
"achiziția este finalizată utilizând soldul utilizatorului; Dacă se "
"utilizează `force_payment`, este inițiată o tranzacție."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "achiziționarea unei comenzi fără crearea unui cont"
@@ -571,18 +566,29 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Filtrați după una sau mai multe perechi nume de atribut/valoare. \n"
"- **Sintaxa**: `attr_name=method-value[;attr2=method2-value2]...`\n"
-"- **Metode** (valoarea implicită este `icontains` dacă este omisă): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`\n"
-"- **Value typing**: JSON este încercat în primul rând (astfel încât să puteți trece liste/dicte), `true`/`false` pentru booleeni, întregi, float; în caz contrar tratat ca string. \n"
-"- **Base64**: prefix cu `b64-` pentru a codifica valoarea brută în baza64 în condiții de siguranță URL. \n"
+"- **Metode** (valoarea implicită este `icontains` dacă este omisă): "
+"`iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, "
+"`istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, "
+"`gt`, `gte`, `in`\n"
+"- **Value typing**: JSON este încercat în primul rând (astfel încât să "
+"puteți trece liste/dicte), `true`/`false` pentru booleeni, întregi, float; "
+"în caz contrar tratat ca string. \n"
+"- **Base64**: prefix cu `b64-` pentru a codifica valoarea brută în baza64 în "
+"condiții de siguranță URL. \n"
"Exemple: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`"
@@ -637,10 +643,12 @@ msgstr "(exact) Digital vs. fizic"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Lista de câmpuri separate prin virgulă după care se face sortarea. Prefixați cu `-` pentru descrescător. \n"
+"Lista de câmpuri separate prin virgulă după care se face sortarea. Prefixați "
+"cu `-` pentru descrescător. \n"
"**Autorizate:** uuid, rating, nume, slug, creat, modificat, preț, aleatoriu"
#: core/docs/drf/viewsets.py:441
@@ -708,8 +716,8 @@ msgstr "Autocompletare adresă de intrare"
#: core/docs/drf/viewsets.py:576
msgid "raw data query string, please append with data from geo-IP endpoint"
msgstr ""
-"docker compose exec app poetry run python manage.py deepl_translate -l en-gb"
-" -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
+"docker compose exec app poetry run python manage.py deepl_translate -l en-gb "
+"-l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l "
"it-it -l ja-jp -l kk-kz -l nl-nl -l pl-pl -l pt-br -l ro-ro -l ru-ru -l zh-"
"hans -a core -a geo -a plăți -a vibes_auth -a blog"
@@ -771,7 +779,7 @@ msgstr "ștergeți o relație comandă-produs"
msgid "add or remove feedback on an order–product relation"
msgstr "adăugarea sau eliminarea feedback-ului într-o relație comandă-produs"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Nu a fost furnizat niciun termen de căutare."
@@ -819,8 +827,8 @@ msgstr "Atribute"
msgid "Quantity"
msgstr "Cantitate"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Melc"
@@ -883,219 +891,242 @@ msgstr "Nivel"
msgid "Product UUID"
msgstr "UUID produs"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Cheie care trebuie căutată sau introdusă în cache"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Date de stocat în cache"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Timeout în secunde pentru a seta datele în cache"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Date în cache"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Date JSON Camelizate de la URL-ul solicitat"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Sunt permise numai URL-urile care încep cu http(s)://"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Adăugați un produs la comandă"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Comanda {order_uuid} nu a fost găsită"
+msgstr "Comanda {order_uuid} nu a fost găsită!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Eliminați un produs din comandă"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Eliminați toate produsele din comandă"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Cumpărați o comandă"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr ""
"Vă rugăm să furnizați fie order_uuid sau order_hr_id - se exclud reciproc!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Metoda order.buy() a generat un tip greșit: {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Efectuați o acțiune asupra unei liste de produse din comandă"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Eliminare/adăugare"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Acțiunea trebuie să fie fie \"adăugare\" sau \"eliminare\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Efectuați o acțiune pe o listă de produse din lista de dorințe"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Vă rugăm să furnizați valoarea `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Wishlist {wishlist_uuid} nu a fost găsit!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Adăugați un produs la comandă"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Lista dorințelor {wishlist_uuid} nu a fost găsită"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Eliminați un produs din comandă"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Eliminați un produs din comandă"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Eliminați un produs din comandă"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Cumpărați o comandă"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
"Vă rugăm să trimiteți atributele sub formă de șir format ca attr1=valoare1, "
"attr2=valoare2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Adăugați sau ștergeți un feedback pentru comandaprodus"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Acțiunea trebuie să fie `add` sau `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Comandaprodus {order_product_uuid} nu a fost găsită!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Șirul de adrese original furnizat de utilizator"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} nu există: {uuid}"
+msgstr "{name} nu există: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Limita trebuie să fie între 1 și 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - funcționează ca un farmec"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Atribute"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Atribute grupate"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Grupuri de atribute"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Categorii"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Mărci"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Categorii"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Procentul de majorare"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Atributele și valorile care pot fi utilizate pentru filtrarea acestei "
"categorii."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
-msgstr ""
-"Prețurile minime și maxime pentru produsele din această categorie, dacă sunt"
-" disponibile."
-
#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
+msgstr ""
+"Prețurile minime și maxime pentru produsele din această categorie, dacă sunt "
+"disponibile."
+
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Etichete pentru această categorie"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Produse din această categorie"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Furnizori"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Latitudine (coordonata Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Longitudine (coordonata X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Cum să"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "Valoare nominală de la 1 la 10, inclusiv, sau 0 dacă nu este setată."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Reprezintă feedback de la un utilizator."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Notificări"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "URL de descărcare pentru acest produs de comandă, dacă este cazul"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "O listă a produselor comandate în această comandă"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Adresa de facturare"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1103,736 +1134,732 @@ msgstr ""
"Adresa de expediere pentru această comandă, lăsați în alb dacă este aceeași "
"cu adresa de facturare sau dacă nu se aplică"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Prețul total al acestei comenzi"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Cantitatea totală de produse din comandă"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Sunt toate produsele din comanda digitală"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Tranzacții pentru această comandă"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Ordine"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "URL imagine"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "Imagini ale produsului"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Categorie"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Feedback-uri"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Marca"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Grupuri de atribute"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Preț"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Cantitate"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Numărul de reacții"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "Produse"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Coduri promoționale"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Produse scoase la vânzare"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "Promoții"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Furnizor"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "Produs"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Produse dorite"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Liste de dorințe"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Produse etichetate"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Etichete de produs"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Categorii etichetate"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Etichete \"Categorii"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Numele proiectului"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Email companie"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Numele companiei"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Adresa companiei"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Numărul de telefon al companiei"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"\"e-mail de la\", uneori trebuie să fie utilizat în locul valorii "
"utilizatorului gazdă"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Utilizator gazdă e-mail"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Suma maximă pentru plată"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Suma minimă pentru plată"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Date analitice"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Date publicitare"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Configurație"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Codul limbii"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Numele limbii"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Indicatorul de limbă, dacă există :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Obțineți o listă a limbilor acceptate"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Rezultate căutare produse"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Rezultate căutare produse"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Părinte al acestui grup"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Grup de atribute părinte"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Numele grupului de atribute"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Grup de atribute"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
"Stochează acreditările și punctele finale necesare pentru comunicarea API a "
"furnizorului"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Informații privind autentificarea"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr ""
"Definirea marjei de profit pentru produsele preluate de la acest furnizor"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Procentul de majorare al furnizorului"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Numele acestui vânzător"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Numele furnizorului"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Identificator intern de etichetă pentru eticheta produsului"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Nume etichetă"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Nume ușor de utilizat pentru eticheta produsului"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Nume afișare etichetă"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Etichetă produs"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "etichetă de categorie"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "Etichete de categorie"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Încărcați o imagine care reprezintă această categorie"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Categorie imagine"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
-msgstr ""
-"Definiți un procent de majorare pentru produsele din această categorie"
+msgstr "Definiți un procent de majorare pentru produsele din această categorie"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Părinte al acestei categorii pentru a forma o structură ierarhică"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Categoria de părinți"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Numele categoriei"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Furnizați un nume pentru această categorie"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Adăugați o descriere detaliată pentru această categorie"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Descriere categorie"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "etichete care ajută la descrierea sau gruparea acestei categorii"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Prioritate"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Denumirea acestui brand"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Nume de marcă"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Încărcați un logo care reprezintă acest brand"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Brand imagine mică"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Încărcați un logo mare care reprezintă acest brand"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Imagine de marcă mare"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Adăugați o descriere detaliată a mărcii"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Descrierea mărcii"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Categorii opționale cu care acest brand este asociat"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Categorii"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Categoria din care face parte acest produs"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "Opțional, asociați acest produs cu un brand"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Etichete care ajută la descrierea sau gruparea acestui produs"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Indică dacă acest produs este livrat digital"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Produsul este digital"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Furnizați o denumire clară de identificare a produsului"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Denumirea produsului"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Adăugați o descriere detaliată a produsului"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Descrierea produsului"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Numărul piesei pentru acest produs"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Numărul piesei"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Categoria acestui atribut"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Grupul acestui atribut"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Șir de caractere"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Număr întreg"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Float"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Boolean"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Array"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Obiect"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Tipul valorii atributului"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Tipul de valoare"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Denumirea acestui atribut"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Numele atributului"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Atribut"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Atributul acestei valori"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Produsul specific asociat cu valoarea acestui atribut"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "Produs asociat"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "Valoarea specifică pentru acest atribut"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "Furnizați text alternativ pentru imagine pentru accesibilitate"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "Textul alt al imaginii"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "Încărcați fișierul de imagine pentru acest produs"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "Imaginea produsului"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "Determină ordinea în care sunt afișate imaginile"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "Prioritatea afișării"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "Produsul pe care îl reprezintă această imagine"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "Imagini ale produsului"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "Procentul de reducere pentru produsele selectate"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "Procent de reducere"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "Furnizați un nume unic pentru această promoție"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "Numele promoției"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "Descrierea promoției"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "Selectați ce produse sunt incluse în această promoție"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "Produse incluse"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "Promovare"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "Furnizorul care furnizează acest stoc de produse"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "Furnizor asociat"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "Prețul final pentru client după majorări"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "Prețul de vânzare"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "Produsul asociat cu această intrare în stoc"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "Produs asociat"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "Prețul plătit vânzătorului pentru acest produs"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "Prețul de achiziție al furnizorului"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "Cantitatea disponibilă a produsului în stoc"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "Cantitate în stoc"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "SKU atribuit de furnizor pentru identificarea produsului"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "SKU al furnizorului"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "Fișier digital asociat cu acest stoc, dacă este cazul"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "Fișier digital"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "Intrări pe stoc"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Categoria din care face parte acest produs"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "Opțional, asociați acest produs cu un brand"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Etichete care ajută la descrierea sau gruparea acestui produs"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Indică dacă acest produs este livrat digital"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Produsul este digital"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Furnizați o denumire clară de identificare a produsului"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Denumirea produsului"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Adăugați o descriere detaliată a produsului"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Descrierea produsului"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Numărul piesei pentru acest produs"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Numărul piesei"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Categoria acestui atribut"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Grupul acestui atribut"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Șir de caractere"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Număr întreg"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Float"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Boolean"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Array"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Obiect"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Tipul valorii atributului"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Tipul de valoare"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Denumirea acestui atribut"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Numele atributului"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Atribut"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Atributul acestei valori"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Produsul specific asociat cu valoarea acestui atribut"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "Valoarea specifică pentru acest atribut"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "Furnizați text alternativ pentru imagine pentru accesibilitate"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "Textul alt al imaginii"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "Încărcați fișierul de imagine pentru acest produs"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "Imaginea produsului"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "Determină ordinea în care sunt afișate imaginile"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "Prioritatea afișării"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "Produsul pe care îl reprezintă această imagine"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "Imagini ale produsului"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "Procentul de reducere pentru produsele selectate"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "Procent de reducere"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "Furnizați un nume unic pentru această promoție"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "Numele promoției"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "Descrierea promoției"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "Selectați ce produse sunt incluse în această promoție"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "Produse incluse"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "Promovare"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Produse pe care utilizatorul le-a marcat ca fiind dorite"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Utilizatorul care deține această listă de dorințe"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Proprietarul listei de dorințe"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Lista dorințelor"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} nu există: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Documentar"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Documentare"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Nerezolvat"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Linia de adresă pentru client"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Linia de adresă"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Strada"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Districtul"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Oraș"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Regiunea"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Cod poștal"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Țara"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Punct de geolocație (longitudine, latitudine)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Răspuns JSON complet de la geocoder pentru această adresă"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Răspuns JSON stocat de la serviciul de geocodare"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Adresă"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Adrese"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Cod unic utilizat de un utilizator pentru a răscumpăra o reducere"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Cod promoțional de identificare"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Valoarea fixă a reducerii aplicate dacă procentul nu este utilizat"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Valoarea fixă a reducerii"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "Procentul de reducere aplicat dacă suma fixă nu este utilizată"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Reducere procentuală"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Data la care expiră codul promoțional"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Timpul final de valabilitate"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Timestamp de la care acest cod promoțional este valabil"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Ora de începere a valabilității"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Momentul în care codul promoțional a fost utilizat, gol dacă nu a fost "
"utilizat încă"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Timestamp de utilizare"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Utilizatorul atribuit acestui cod promoțional, dacă este cazul"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Utilizator atribuit"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Cod promoțional"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Coduri promoționale"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
@@ -1840,140 +1867,149 @@ msgstr ""
"Trebuie definit un singur tip de reducere (sumă sau procent), dar nu ambele "
"sau niciuna."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Codul promoțional a fost deja utilizat"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Tip de reducere invalid pentru codul promoțional {self.uuid}"
+msgstr "Tip de reducere invalid pentru codul promoțional {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "Adresa de facturare utilizată pentru această comandă"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Cod promoțional opțional aplicat la această comandă"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Cod promoțional aplicat"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "Adresa de expediere utilizată pentru această comandă"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Adresa de expediere"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Stadiul actual al comenzii în ciclul său de viață"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Stadiul comenzii"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
"Structura JSON a notificărilor care urmează să fie afișate utilizatorilor, "
"în interfața de administrare este utilizată vizualizarea tabelară"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "Reprezentarea JSON a atributelor comenzii pentru această comandă"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "Utilizatorul care a plasat comanda"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Utilizator"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Momentul în care comanda a fost finalizată"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Cumpărați timp"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Un identificator ușor de citit pentru comandă"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "ID lizibil de către om"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Comandă"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr ""
"Un utilizator trebuie să aibă un singur ordin în așteptare la un moment dat!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "Nu puteți adăuga produse la o comandă care nu este în așteptare"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Nu puteți adăuga produse inactive la comandă"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "Nu puteți adăuga mai multe produse decât cele disponibile în stoc"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr ""
"Nu puteți elimina produse dintr-o comandă care nu este o comandă în curs"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} nu există cu interogarea <{query}>"
+msgstr "{name} nu există cu interogarea <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Codul promoțional nu există"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
"Puteți cumpăra numai produse fizice cu adresa de expediere specificată!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Adresa nu există"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"Nu puteți achiziționa în acest moment, vă rugăm să încercați din nou în "
"câteva minute."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Valoare forță invalidă"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Nu puteți achiziționa o comandă goală!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr ""
+"Nu puteți elimina produse dintr-o comandă care nu este o comandă în curs"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Un utilizator fără sold nu poate cumpăra cu sold!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Insuficiența fondurilor pentru finalizarea comenzii"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1981,122 +2017,124 @@ msgstr ""
"nu puteți cumpăra fără înregistrare, vă rugăm să furnizați următoarele "
"informații: nume client, e-mail client, număr de telefon client"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
-"Metodă de plată invalidă: {payment_method} de la "
-"{available_payment_methods}!"
+"Metodă de plată invalidă: {payment_method} de la {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "Prețul plătit de client pentru acest produs la momentul achiziției"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Prețul de achiziție la momentul comenzii"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr ""
"Comentarii interne pentru administratori cu privire la acest produs comandat"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Observații interne"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Notificări pentru utilizatori"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "Reprezentarea JSON a atributelor acestui element"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Atribute de produs ordonate"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Trimitere la comanda mamă care conține acest produs"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Ordinul părinților"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Produsul specific asociat cu această linie de comandă"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Cantitatea acestui produs specific din comandă"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Cantitatea produsului"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Starea actuală a acestui produs în comandă"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Starea liniei de produse"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "Comandaprodusul trebuie să aibă o comandă asociată!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "acțiune greșită specificată pentru feedback: {action}"
+msgstr "Acțiune greșită specificată pentru feedback: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr ""
"Nu puteți elimina produse dintr-o comandă care nu este o comandă în curs"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Descărcare"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Descărcări"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "Nu puteți descărca un bun digital pentru o comandă nefinalizată"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr ""
"Comentarii furnizate de utilizatori cu privire la experiența lor cu produsul"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Comentarii de feedback"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
-"Face referire la produsul specific dintr-o comandă despre care este vorba în"
-" acest feedback"
+"Face referire la produsul specific dintr-o comandă despre care este vorba în "
+"acest feedback"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Produs aferent comenzii"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Rating atribuit de utilizator pentru produs"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Evaluarea produsului"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Feedback"
@@ -2104,16 +2142,16 @@ msgstr "Feedback"
msgid ""
"you must provide a comment, rating, and order product uuid to add feedback."
msgstr ""
-"trebuie să furnizați un comentariu, un rating și uuid-ul produsului comandat"
-" pentru a adăuga feedback."
+"trebuie să furnizați un comentariu, un rating și uuid-ul produsului comandat "
+"pentru a adăuga feedback."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Eroare în timpul creării codului promoțional: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2122,7 +2160,7 @@ msgid "order confirmation"
msgstr "Confirmarea comenzii"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2139,7 +2177,8 @@ msgstr "Bună ziua %(order.user.first_name)s,"
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
"Vă mulțumim pentru comanda dvs. #%(order.pk)s! Suntem încântați să vă "
@@ -2147,14 +2186,14 @@ msgstr ""
"comenzii dvs:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Total"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2174,23 +2213,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "Salutări,
echipa %(config.PROJECT_NAME)s"
+msgstr "Cele mai bune salutări,
echipa %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Toate drepturile rezervate"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Comanda livrată"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Bună ziua %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2199,7 +2238,7 @@ msgstr ""
"Am procesat cu succes comanda dvs. №%(order_uuid)s! Mai jos sunt detaliile "
"comenzii dvs:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2207,12 +2246,12 @@ msgstr ""
"informații suplimentare\n"
" informații suplimentare"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Valoare"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2221,7 +2260,7 @@ msgstr ""
"Dacă aveți întrebări, nu ezitați să contactați asistența noastră la "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Cele mai bune salutări,
echipa %(project_name)s"
@@ -2233,11 +2272,12 @@ msgstr "Cheie"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
-"Vă mulțumim pentru comanda dvs.! Suntem încântați să vă confirmăm achiziția."
-" Mai jos sunt detaliile comenzii dvs:"
+"Vă mulțumim pentru comanda dvs.! Suntem încântați să vă confirmăm achiziția. "
+"Mai jos sunt detaliile comenzii dvs:"
#: core/templates/shipped_order_created_email.html:123
#: core/templates/shipped_order_delivered_email.html:123
@@ -2253,7 +2293,7 @@ msgstr "Comanda dvs. va fi livrată la următoarea adresă:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "Salutări,
echipa %(config.PROJECT_NAME)s"
+msgstr "Salutări,
Echipa %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2272,30 +2312,20 @@ msgstr "Sunt necesare atât datele, cât și timpul de așteptare"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "Valoare timeout invalidă, trebuie să fie între 0 și 216000 secunde"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} trebuie să fie model"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} trebuie să fie un obiect listă"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Contactați-ne inițiat"
+msgstr "{config.PROJECT_NAME} | contactați-ne inițiat"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Confirmarea comenzii"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME} | Comanda livrată"
+msgstr "{config.PROJECT_NAME} | Livrarea comenzii"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2316,15 +2346,15 @@ msgstr ""
msgid "invalid phone number format"
msgstr "Format invalid al numărului de telefon"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Puteți descărca activul digital o singură dată"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon nu a fost găsit"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Eroare de geocodare: {e}"
diff --git a/core/locale/ru_RU/LC_MESSAGES/django.mo b/core/locale/ru_RU/LC_MESSAGES/django.mo
index 2bc8cb1b..b5fd4df8 100644
Binary files a/core/locale/ru_RU/LC_MESSAGES/django.mo and b/core/locale/ru_RU/LC_MESSAGES/django.mo differ
diff --git a/core/locale/ru_RU/LC_MESSAGES/django.po b/core/locale/ru_RU/LC_MESSAGES/django.po
index e496d6da..a5c17d17 100644
--- a/core/locale/ru_RU/LC_MESSAGES/django.po
+++ b/core/locale/ru_RU/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,128 +13,125 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "Уникальный идентификатор"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr ""
"Уникальный идентификатор используется для точной идентификации любого "
"объекта базы данных"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "Активен"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr ""
"Если установлено значение false, этот объект не может быть виден "
"пользователям без необходимого разрешения"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "Создано"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "Когда объект впервые появился в базе данных"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "Модифицированный"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "Когда объект был отредактирован в последний раз"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "Переводы"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "Общие сведения"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "Отношения"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "Метаданные"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "Временные метки"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
-msgstr "Активировать выбранные %(verbose_name_plural)s"
+msgstr "Активировать выбранный %(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s успешно активирован!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "Выбранные сущности активированы!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
-msgstr "Деактивировать выбранные %(verbose_name_plural)s"
+msgstr "Деактивировать выбранный %(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "%(verbose_name_plural)s успешно деактивирован."
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "Выбранные сущности были деактивированы!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "Значение атрибута"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "Значения атрибутов"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "Изображение"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "Изображения"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "Наличие"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "Наличия"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
-msgstr "Заказать товар"
+msgstr "Заказанный товар"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
-msgstr "Заказать товары"
+msgstr "Заказанные товары"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "Дети"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "Конфигурация"
#: core/apps.py:8
msgid "core"
-msgstr "Ядро"
+msgstr "Главное"
#: core/choices.py:4 core/choices.py:20
msgid "finished"
@@ -180,7 +177,7 @@ msgstr "Моментальный"
msgid "successful"
msgstr "Успешный"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "Ввод/вывод кэша"
@@ -204,7 +201,7 @@ msgstr "Получите параметры приложения, которые
msgid "send a message to the support team"
msgstr "Отправьте сообщение в службу поддержки"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "Запросите URL-адрес с поддержкой CORS. Допускается только https."
@@ -248,8 +245,7 @@ msgstr ""
"элементов"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr ""
"Переписывание некоторых полей существующей группы атрибутов с сохранением "
"нередактируемых полей"
@@ -303,8 +299,7 @@ msgstr ""
"значений"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr ""
"Переписывание некоторых полей существующего значения атрибута с сохранением "
"нередактируемых значений"
@@ -348,11 +343,11 @@ msgstr ""
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
-"Поиск подстроки с учетом регистра в human_readable_id, "
-"order_products.product.name и order_products.product.partnumber"
+"Поиск подстроки с учетом регистра в human_readable_id, order_products."
+"product.name и order_products.product.partnumber"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -388,9 +383,9 @@ msgstr ""
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
"Упорядочивайте по одному из следующих признаков: uuid, human_readable_id, "
"user_email, user, status, created, modified, buy_time, random. Префикс '-' "
@@ -437,7 +432,7 @@ msgstr ""
"завершается с использованием баланса пользователя; если используется "
"`force_payment`, инициируется транзакция."
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "приобретение заказа без создания учетной записи"
@@ -466,8 +461,8 @@ msgid ""
"adds a list of products to an order using the provided `product_uuid` and "
"`attributes`."
msgstr ""
-"Добавляет список товаров в заказ, используя предоставленные `product_uuid` и"
-" `attributes`."
+"Добавляет список товаров в заказ, используя предоставленные `product_uuid` и "
+"`attributes`."
#: core/docs/drf/viewsets.py:266
msgid "remove product from order"
@@ -490,8 +485,8 @@ msgid ""
"removes a list of products from an order using the provided `product_uuid` "
"and `attributes`"
msgstr ""
-"Удаляет список товаров из заказа, используя предоставленные `product_uuid` и"
-" `attributes`."
+"Удаляет список товаров из заказа, используя предоставленные `product_uuid` и "
+"`attributes`."
#: core/docs/drf/viewsets.py:281
msgid "list all wishlists (simple view)"
@@ -572,18 +567,29 @@ msgstr ""
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"Фильтр по одной или нескольким парам имя/значение атрибута. \n"
"- **Синтаксис**: `attr_name=method-value[;attr2=method2-value2]...`.\n"
-"- **Методы** (по умолчанию используется `icontains`, если опущено): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in`.\n"
-"- **Типизация значений**: JSON сначала пытается принять значение (так что вы можете передавать списки/дискреты), `true`/`false` для булевых, целых чисел, плавающих; в противном случае обрабатывается как строка. \n"
-"- **Base64**: префикс `b64-` для безопасного для URL base64-кодирования исходного значения. \n"
+"- **Методы** (по умолчанию используется `icontains`, если опущено): "
+"`iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, "
+"`istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, "
+"`gt`, `gte`, `in`.\n"
+"- **Типизация значений**: JSON сначала пытается принять значение (так что вы "
+"можете передавать списки/дискреты), `true`/`false` для булевых, целых чисел, "
+"плавающих; в противном случае обрабатывается как строка. \n"
+"- **Base64**: префикс `b64-` для безопасного для URL base64-кодирования "
+"исходного значения. \n"
"Примеры: \n"
"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\", \"bluetooth\"]`,\n"
"`b64-description=icontains-aGVhdC1jb2xk`."
@@ -638,11 +644,14 @@ msgstr "(точно) Цифровые и физические"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
-"Список полей для сортировки, разделенных запятыми. Для сортировки по убыванию используйте префикс `-`. \n"
-"**Разрешенные:** uuid, рейтинг, название, slug, created, modified, price, random"
+"Список полей для сортировки, разделенных запятыми. Для сортировки по "
+"убыванию используйте префикс `-`. \n"
+"**Разрешенные:** uuid, рейтинг, название, slug, created, modified, price, "
+"random"
#: core/docs/drf/viewsets.py:441
msgid "retrieve a single product (detailed view)"
@@ -770,7 +779,7 @@ msgstr "удалить отношение \"заказ-продукт"
msgid "add or remove feedback on an order–product relation"
msgstr "добавлять или удалять отзывы о связи заказ-продукт"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "Поисковый запрос не предоставлен."
@@ -818,8 +827,8 @@ msgstr "Атрибуты"
msgid "Quantity"
msgstr "Количество"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "Слаг"
@@ -882,220 +891,243 @@ msgstr "Уровень"
msgid "Product UUID"
msgstr "UUID продукта"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "Ключ, который нужно найти в тайнике или вложить в него"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "Данные для хранения в кэше"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "Тайм-аут в секундах для занесения данных в кэш"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "Кэшированные данные"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "Camelized JSON-данные из запрашиваемого URL"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "Допускаются только URL-адреса, начинающиеся с http(s)://"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "Добавить товар в заказ"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "Заказ {order_uuid} не найден"
+msgstr "Заказ {order_uuid} не найден!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "Удалить продукт из заказа"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "Удалить все товары из заказа"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "Купить заказ"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr ""
"Пожалуйста, укажите либо order_uuid, либо order_hr_id - взаимоисключающие "
"варианты!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "Неправильный тип получен из метода order.buy(): {type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "Выполните действие над списком товаров в заказе"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "Удалить/добавить"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "Действие должно быть либо \"добавить\", либо \"удалить\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "Выполните действие над списком продуктов в списке желаний"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "Пожалуйста, укажите значение `wishlist_uuid`."
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "Список желаний {wishlist_uuid} не найден!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "Добавить товар в заказ"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "Список желаний {wishlist_uuid} не найден"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "Удалить продукт из заказа"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "Удалить продукт из заказа"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "Удалить продукт из заказа"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "Купить заказ"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr ""
"Пожалуйста, отправьте атрибуты в виде строки, отформатированной как "
"attr1=value1,attr2=value2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "Добавить или удалить отзыв для продукта заказа"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "Действие должно быть либо `add`, либо `remove`!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "Заказ товара {order_product_uuid} не найден!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "Оригинальная строка адреса, предоставленная пользователем"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} не существует: {uuid}"
+msgstr "{name} не существует: {uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "Предел должен быть от 1 до 10"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - работает как шарм"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "Атрибуты"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "Сгруппированные атрибуты"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "Группы атрибутов"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "Категории"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "Бренды"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "Категории"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "Процент наценки"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr ""
"Какие атрибуты и значения можно использовать для фильтрации этой категории."
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr ""
"Минимальные и максимальные цены на товары в этой категории, если они "
"доступны."
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "Теги для этой категории"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "Продукты в этой категории"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "Поставщики"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "Широта (координата Y)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "Долгота (координата X)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "Как"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr ""
"Значение рейтинга от 1 до 10, включительно, или 0, если он не установлен."
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "Представляет собой отзыв пользователя."
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "Уведомления"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "Если применимо, загрузите url для этого продукта заказа"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "Список товаров, заказанных в этом заказе"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "Адрес для выставления счетов"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
@@ -1103,877 +1135,881 @@ msgstr ""
"Адрес доставки для данного заказа, оставьте пустым, если он совпадает с "
"адресом выставления счета или не применяется"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "Общая стоимость этого заказа"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "Общее количество продуктов в заказе"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "Все ли товары в заказе представлены в цифровом виде"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "Операции для этого заказа"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "Заказы"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "URL-адрес изображения"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
-msgstr "Изображения продукта"
+msgstr "Изображения товара"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "Категория"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "Отзывы"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "Бренд"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "Группы атрибутов"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "Цена"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "Количество"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "Количество отзывов"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
-msgstr "Продукция"
+msgstr "Товары"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "Промокоды"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "Продукты в продаже"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
-msgstr "Акции"
+msgstr "Промоакции"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "Поставщик"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
-msgstr "Продукт"
+msgstr "Товар"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "Продукты из списка желаний"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "Списки желаний"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "Tagged products"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "Теги товара"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "Категории с метками"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "Теги категорий"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "Название проекта"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "Электронная почта компании"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "Название компании"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "Адрес компании"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "Номер телефона компании"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr ""
"'email from', иногда его нужно использовать вместо значения пользователя "
"хоста."
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "Пользователь узла электронной почты"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "Максимальная сумма для оплаты"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "Минимальная сумма для оплаты"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "Аналитические данные"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "Рекламные данные"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "Конфигурация"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "Код языка"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "Название языка"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "Языковой флаг, если он существует :)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "Получите список поддерживаемых языков"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "Результаты поиска товаров"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "Результаты поиска товаров"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "Родитель этой группы"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "Родительская группа атрибутов"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "Имя группы атрибутов"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "Группа атрибутов"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr ""
-"Хранит учетные данные и конечные точки, необходимые для взаимодействия с API"
-" поставщика."
+"Хранит учетные данные и конечные точки, необходимые для взаимодействия с API "
+"поставщика."
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "Информация об аутентификации"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "Определите наценку для товаров, полученных от этого продавца"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "Процент наценки поставщика"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "Имя этого продавца"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "Название поставщика"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "Внутренний идентификатор тега для тега продукта"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "Название тега"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "Удобное название для метки продукта"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "Отображаемое имя тега"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "Метка продукта"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "тег категории"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "теги категорий"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "Загрузите изображение, представляющее эту категорию"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "Изображение категории"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "Определите процент наценки для товаров в этой категории"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "Родитель данной категории для формирования иерархической структуры"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "Родительская категория"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "Название категории"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "Укажите название этой категории"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "Добавьте подробное описание для этой категории"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "Описание категории"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "теги, которые помогают описать или сгруппировать эту категорию"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "Приоритет"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "Название этой марки"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "Название бренда"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "Загрузите логотип, представляющий этот бренд"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "Маленький образ бренда"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "Загрузите большой логотип, представляющий этот бренд"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "Большой имидж бренда"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "Добавьте подробное описание бренда"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "Описание бренда"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "Дополнительные категории, с которыми ассоциируется этот бренд"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "Категории"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "Категория, к которой относится этот продукт"
+#: core/models.py:515
+msgid "the vendor supplying this product stock"
+msgstr "Поставщик, поставляющий данный товар на склад"
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "По желанию ассоциируйте этот продукт с брендом"
+#: core/models.py:516
+msgid "associated vendor"
+msgstr "Ассоциированный поставщик"
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "Теги, которые помогают описать или сгруппировать этот продукт"
+#: core/models.py:520
+msgid "final price to the customer after markups"
+msgstr "Окончательная цена для покупателя после наценок"
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "Указывает, поставляется ли этот продукт в цифровом виде"
+#: core/models.py:521
+msgid "selling price"
+msgstr "Цена продажи"
-#: core/models.py:351
-msgid "is product digital"
-msgstr "Является ли продукт цифровым"
+#: core/models.py:526
+msgid "the product associated with this stock entry"
+msgstr "Продукт, связанный с этой складской записью"
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "Обеспечьте четкое идентификационное название продукта"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "Название продукта"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "Добавьте подробное описание продукта"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "Описание товара"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "Парт. номер для данного товара"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "Парт. номер"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "Категория этого атрибута"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "Группа этого атрибута"
-
-#: core/models.py:465
-msgid "string"
-msgstr "Строка"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "Целое число"
-
-#: core/models.py:467
-msgid "float"
-msgstr "Поплавок"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "Булево"
-
-#: core/models.py:469
-msgid "array"
-msgstr "Массив"
-
-#: core/models.py:470
-msgid "object"
-msgstr "Объект"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "Тип значения атрибута"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "Тип значения"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "Имя этого атрибута"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "Имя атрибута"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "Атрибут"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "Атрибут этого значения"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "Конкретный продукт, связанный со значением этого атрибута"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
msgid "associated product"
msgstr "Сопутствующий товар"
-#: core/models.py:512
+#: core/models.py:534
+msgid "the price paid to the vendor for this product"
+msgstr "Цена, уплаченная продавцу за этот продукт"
+
+#: core/models.py:535
+msgid "vendor purchase price"
+msgstr "Цена покупки у поставщика"
+
+#: core/models.py:539
+msgid "available quantity of the product in stock"
+msgstr "Доступное количество продукта на складе"
+
+#: core/models.py:540
+msgid "quantity in stock"
+msgstr "Количество на складе"
+
+#: core/models.py:544
+msgid "vendor-assigned SKU for identifying the product"
+msgstr "Присвоенный поставщиком SKU для идентификации продукта"
+
+#: core/models.py:545
+msgid "vendor sku"
+msgstr "SKU поставщика"
+
+#: core/models.py:551
+msgid "digital file associated with this stock if applicable"
+msgstr "Цифровой файл, связанный с этой акцией, если применимо"
+
+#: core/models.py:552
+msgid "digital file"
+msgstr "Цифровой файл"
+
+#: core/models.py:561
+msgid "stock entries"
+msgstr "Наличия"
+
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "Категория, к которой относится этот продукт"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "По желанию ассоциируйте этот продукт с брендом"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "Теги, которые помогают описать или сгруппировать этот продукт"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "Указывает, поставляется ли этот продукт в цифровом виде"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "Является ли продукт цифровым"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "Обеспечьте четкое идентификационное название продукта"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "Название продукта"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "Добавьте подробное описание продукта"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "Описание товара"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "Парт. номер для данного товара"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "Парт. номер"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "Категория этого атрибута"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "Группа этого атрибута"
+
+#: core/models.py:767
+msgid "string"
+msgstr "Строка"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "Целое число"
+
+#: core/models.py:769
+msgid "float"
+msgstr "Поплавок"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "Булево"
+
+#: core/models.py:771
+msgid "array"
+msgstr "Массив"
+
+#: core/models.py:772
+msgid "object"
+msgstr "Объект"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "Тип значения атрибута"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "Тип значения"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "Имя этого атрибута"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "Имя атрибута"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "Атрибут"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "Атрибут этого значения"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "Конкретный продукт, связанный со значением этого атрибута"
+
+#: core/models.py:837
msgid "the specific value for this attribute"
msgstr "Конкретное значение для этого атрибута"
-#: core/models.py:528
+#: core/models.py:871
msgid "provide alternative text for the image for accessibility"
msgstr ""
"Предоставьте альтернативный текст для изображения, чтобы обеспечить "
"доступность"
-#: core/models.py:529
+#: core/models.py:872
msgid "image alt text"
msgstr "Альтовый текст изображения"
-#: core/models.py:532
+#: core/models.py:875
msgid "upload the image file for this product"
msgstr "Загрузите файл изображения для этого продукта"
-#: core/models.py:533 core/models.py:558
+#: core/models.py:876 core/models.py:901
msgid "product image"
msgstr "Изображение продукта"
-#: core/models.py:539
+#: core/models.py:882
msgid "determines the order in which images are displayed"
msgstr "Определяет порядок отображения изображений"
-#: core/models.py:540
+#: core/models.py:883
msgid "display priority"
msgstr "Приоритет отображения"
-#: core/models.py:545
+#: core/models.py:888
msgid "the product that this image represents"
msgstr "Продукт, который представлен на этом изображении"
-#: core/models.py:559
+#: core/models.py:902
msgid "product images"
-msgstr "Изображения продуктов"
+msgstr "Изображения товаров"
-#: core/models.py:567
+#: core/models.py:943
msgid "percentage discount for the selected products"
msgstr "Процентная скидка на выбранные продукты"
-#: core/models.py:568
+#: core/models.py:944
msgid "discount percentage"
msgstr "Процент скидки"
-#: core/models.py:573
+#: core/models.py:949
msgid "provide a unique name for this promotion"
msgstr "Укажите уникальное имя для этой акции"
-#: core/models.py:574
+#: core/models.py:950
msgid "promotion name"
msgstr "Название акции"
-#: core/models.py:580
+#: core/models.py:956
msgid "promotion description"
msgstr "Описание акции"
-#: core/models.py:585
+#: core/models.py:961
msgid "select which products are included in this promotion"
msgstr "Выберите, какие продукты участвуют в этой акции"
-#: core/models.py:586
+#: core/models.py:962
msgid "included products"
msgstr "Включенные продукты"
-#: core/models.py:590
+#: core/models.py:966
msgid "promotion"
msgstr "Продвижение"
-#: core/models.py:605
-msgid "the vendor supplying this product stock"
-msgstr "Поставщик, поставляющий данный товар на склад"
-
-#: core/models.py:606
-msgid "associated vendor"
-msgstr "Ассоциированный поставщик"
-
-#: core/models.py:610
-msgid "final price to the customer after markups"
-msgstr "Окончательная цена для покупателя после наценок"
-
-#: core/models.py:611
-msgid "selling price"
-msgstr "Цена продажи"
-
-#: core/models.py:616
-msgid "the product associated with this stock entry"
-msgstr "Продукт, связанный с этой складской записью"
-
-#: core/models.py:624
-msgid "the price paid to the vendor for this product"
-msgstr "Цена, уплаченная продавцу за этот продукт"
-
-#: core/models.py:625
-msgid "vendor purchase price"
-msgstr "Цена покупки у поставщика"
-
-#: core/models.py:629
-msgid "available quantity of the product in stock"
-msgstr "Доступное количество продукта на складе"
-
-#: core/models.py:630
-msgid "quantity in stock"
-msgstr "Количество на складе"
-
-#: core/models.py:634
-msgid "vendor-assigned SKU for identifying the product"
-msgstr "Присвоенный поставщиком SKU для идентификации продукта"
-
-#: core/models.py:635
-msgid "vendor sku"
-msgstr "SKU поставщика"
-
-#: core/models.py:641
-msgid "digital file associated with this stock if applicable"
-msgstr "Цифровой файл, связанный с этой акцией, если применимо"
-
-#: core/models.py:642
-msgid "digital file"
-msgstr "Цифровой файл"
-
-#: core/models.py:651
-msgid "stock entries"
-msgstr "Складские состояния"
-
-#: core/models.py:660
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "Продукты, которые пользователь отметил как желаемые"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "Пользователь, владеющий этим списком желаний"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "Владелец вишлиста"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "Список желаний"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} не существует: {product_uuid}"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "Документальный фильм"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "Документальные фильмы"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "Неразрешенные"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "Адресная строка для клиента"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "Адресная строка"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "Улица"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "Округ"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "Город"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "Регион"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "Почтовый индекс"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "Страна"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "Геолокационная точка(долгота, широта)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "Полный JSON-ответ от геокодера для этого адреса"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "Сохраненный JSON-ответ от сервиса геокодирования"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "Адрес"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "Адреса"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "Уникальный код, используемый пользователем для получения скидки"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "Идентификатор промо-кода"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "Фиксированная сумма скидки, применяемая, если процент не используется"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "Фиксированная сумма скидки"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr ""
"Процентная скидка, применяемая, если фиксированная сумма не используется"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "Процентная скидка"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "Временная метка, когда истекает срок действия промокода"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "Время окончания срока действия"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "Время, с которого действует этот промокод"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "Время начала действия"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr ""
"Временная метка, когда был использован промокод, пустая, если он еще не "
"использовался"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "Временная метка использования"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "Пользователь, назначенный на этот промокод, если применимо"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "Назначенный пользователь"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "Промокод"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "Промокоды"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
msgstr ""
-"Следует определить только один тип скидки (сумма или процент), но не оба или"
-" ни один из них."
+"Следует определить только один тип скидки (сумма или процент), но не оба или "
+"ни один из них."
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "Промокоды"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "Неверный тип скидки для промокода {self.uuid}"
+msgstr "Неверный тип скидки для промокода {self.uuid}!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "Адрес для выставления счетов, используемый для данного заказа"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "Дополнительный промокод, применяемый к этому заказу"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "Примененный промокод"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "Адрес доставки, используемый для данного заказа"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "Адрес доставки"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "Текущий статус заказа в его жизненном цикле"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "Статус заказа"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr ""
-"JSON-структура уведомлений для отображения пользователям, в административном"
-" интерфейсе используется табличный вид"
+"JSON-структура уведомлений для отображения пользователям, в административном "
+"интерфейсе используется табличный вид"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "JSON-представление атрибутов заказа для этого заказа"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "Пользователь, разместивший заказ"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "Пользователь"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "Временная метка, когда заказ был завершен"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "Время покупки"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "Человекочитаемый идентификатор для заказа"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "человекочитаемый идентификатор"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "Заказать"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "Пользователь может одновременно иметь только один отложенный ордер!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "Вы не можете добавить товары в заказ, который не является отложенным."
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "Вы не можете добавить неактивные товары в заказ"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "Вы не можете добавить больше товаров, чем есть на складе"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
-msgstr ""
-"Вы не можете удалить товары из заказа, который не является отложенным."
+msgstr "Вы не можете удалить товары из заказа, который не является отложенным."
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "{name} не существует в запросе <{query}>."
+msgstr "{name} не существует с запросом <{query}>!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "Промокод не существует"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr ""
"Вы можете купить физические товары только с указанным адресом доставки!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "Адрес не существует"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr ""
"В данный момент вы не можете совершить покупку, пожалуйста, повторите "
"попытку через несколько минут."
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "Недопустимое значение силы"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "Вы не можете приобрести пустой заказ!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "Вы не можете купить заказ без пользователя!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "Пользователь без баланса не может покупать с балансом!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "Недостаточно средств для выполнения заказа"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
@@ -1981,118 +2017,120 @@ msgstr ""
"Вы не можете купить без регистрации, пожалуйста, предоставьте следующую "
"информацию: имя клиента, электронная почта клиента, номер телефона клиента"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr ""
"Неверный способ оплаты: {payment_method} от {available_payment_methods}!"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "Цена, уплаченная клиентом за данный продукт на момент покупки"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "Покупная цена на момент заказа"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
-msgstr ""
-"Внутренние комментарии для администраторов об этом заказанном продукте"
+msgstr "Внутренние комментарии для администраторов об этом заказанном продукте"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "Внутренние комментарии"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "Уведомления пользователей"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "JSON-представление атрибутов этого элемента"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "Атрибуты заказанного продукта"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "Ссылка на родительский заказ, содержащий данный продукт"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "Родительский приказ"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "Конкретный продукт, связанный с этой линией заказа"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "Количество данного товара в заказе"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "Количество продукта"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "Текущий статус этого продукта в заказе"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "Состояние продуктовой линейки"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "У заказанного продукта должен быть связанный с ним заказ!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "указано неверное действие для обратной связи: {action}"
+msgstr "Для обратной связи указано неверное действие: {action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "Вы не можете отозвать заказ, который не был получен"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "Скачать"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "Скачать"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "Вы не можете загрузить цифровой актив для незавершенного заказа"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "Комментарии пользователей об их опыте использования продукта"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "Комментарии к отзывам"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr ""
"Ссылка на конкретный продукт в заказе, о котором идет речь в этом отзыве"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "Сопутствующий товар для заказа"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "Присвоенный пользователем рейтинг продукта"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "Рейтинг продукции"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "Обратная связь"
@@ -2103,13 +2141,13 @@ msgstr ""
"чтобы добавить отзыв, необходимо указать комментарий, рейтинг и uuid "
"продукта заказа."
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "Ошибка при создании промокода: {e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2118,7 +2156,7 @@ msgid "order confirmation"
msgstr "Подтверждение заказа"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2129,27 +2167,28 @@ msgstr "Логотип"
#: core/templates/shipped_order_delivered_email.html:100
#, python-format
msgid "hello %(order.user.first_name)s,"
-msgstr "Здравствуйте %(order.user.first_name)s,"
+msgstr "Привет %(order.user.first_name)s,"
#: core/templates/digital_order_created_email.html:102
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
msgstr ""
-"Благодарим вас за заказ #%(order.pk)s! Мы рады сообщить Вам, что приняли Ваш"
-" заказ в работу. Ниже приведены детали вашего заказа:"
+"Благодарим вас за заказ #%(order.pk)s! Мы рады сообщить Вам, что приняли Ваш "
+"заказ в работу. Ниже приведены детали вашего заказа:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "Всего"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2169,23 +2208,23 @@ msgstr ""
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "С наилучшими пожеланиями,
команда %(config.PROJECT_NAME)s"
+msgstr "С наилучшими пожеланиями,
команда %(config.PROJECT_NAME)s"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "Все права защищены"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "Заказ доставлен"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
-msgstr "Здравствуйте, %(user_first_name)s,"
+msgstr "Привет %(user_first_name)s,"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
@@ -2194,7 +2233,7 @@ msgstr ""
"Мы успешно обработали ваш заказ №%(order_uuid)s! Ниже приведены детали "
"вашего заказа:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2202,12 +2241,12 @@ msgstr ""
"дополнительная\n"
" информация"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "Значение"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -2216,10 +2255,10 @@ msgstr ""
"Если у вас возникнут вопросы, обращайтесь в нашу службу поддержки по адресу "
"%(contact_email)s."
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "С наилучшими пожеланиями,
команда %(project_name)s"
+msgstr "С наилучшими пожеланиями,
команда %(project_name)s"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2228,7 +2267,8 @@ msgstr "Ключ"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr ""
"Спасибо за ваш заказ! Мы рады подтвердить вашу покупку. Ниже приведены "
@@ -2248,7 +2288,7 @@ msgstr "Ваш заказ будет доставлен по следующем
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "С наилучшими пожеланиями,
команда %(config.PROJECT_NAME)s"
+msgstr "С наилучшими пожеланиями,
Команда %(config.PROJECT_NAME)s"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2269,27 +2309,17 @@ msgstr ""
"Неверное значение тайм-аута, оно должно находиться в диапазоне от 0 до "
"216000 секунд"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model} должна быть моделью"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} должен быть объектом списка"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
-msgstr "{config.PROJECT_NAME} | Свяжитесь с нами"
+msgstr "{config.PROJECT_NAME} | свяжитесь с нами по инициативе"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
msgstr "{config.PROJECT_NAME} | Подтверждение заказа"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
msgstr "{config.PROJECT_NAME} | Заказ доставлен"
@@ -2306,22 +2336,21 @@ msgstr "Параметр NOMINATIM_URL должен быть настроен!"
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
msgstr ""
-"Размеры изображения не должны превышать w{max_width} x h{max_height} "
-"пикселей"
+"Размеры изображения не должны превышать w{max_width} x h{max_height} пикселей"
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "Неверный формат телефонного номера"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "Вы можете загрузить цифровой актив только один раз"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "favicon не найден"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "Ошибка геокодирования: {e}"
diff --git a/core/locale/zh_Hans/LC_MESSAGES/django.mo b/core/locale/zh_Hans/LC_MESSAGES/django.mo
index e15f5f93..714d4ae4 100644
Binary files a/core/locale/zh_Hans/LC_MESSAGES/django.mo and b/core/locale/zh_Hans/LC_MESSAGES/django.mo differ
diff --git a/core/locale/zh_Hans/LC_MESSAGES/django.po b/core/locale/zh_Hans/LC_MESSAGES/django.po
index f6ed35e3..0c2ae399 100644
--- a/core/locale/zh_Hans/LC_MESSAGES/django.po
+++ b/core/locale/zh_Hans/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:05+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,118 +13,115 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: core/abstract.py:12
+#: core/abstract.py:11
msgid "unique id"
msgstr "唯一 ID"
-#: core/abstract.py:13
+#: core/abstract.py:12
msgid "unique id is used to surely identify any database object"
msgstr "唯一 ID 用于确定识别任何数据库对象"
-#: core/abstract.py:20
+#: core/abstract.py:19
msgid "is active"
msgstr "处于活动状态"
-#: core/abstract.py:22
+#: core/abstract.py:20
msgid ""
-"if set to false, this object can't be seen by users without needed "
-"permission"
+"if set to false, this object can't be seen by users without needed permission"
msgstr "如果设置为 false,则没有必要权限的用户无法查看此对象"
-#: core/abstract.py:26 core/choices.py:18
+#: core/abstract.py:22 core/choices.py:18
msgid "created"
msgstr "创建"
-#: core/abstract.py:26
+#: core/abstract.py:22
msgid "when the object first appeared on the database"
msgstr "对象首次出现在数据库中的时间"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "modified"
msgstr "改装"
-#: core/abstract.py:29
+#: core/abstract.py:23
msgid "when the object was last modified"
msgstr "对象最后一次编辑的时间"
-#: core/admin.py:53
+#: core/admin.py:61
msgid "translations"
msgstr "翻译"
-#: core/admin.py:58
+#: core/admin.py:65
msgid "general"
msgstr "一般情况"
-#: core/admin.py:60
+#: core/admin.py:67
msgid "relations"
msgstr "关系"
-#: core/admin.py:65 core/admin.py:67
+#: core/admin.py:72 core/admin.py:74
msgid "metadata"
msgstr "元数据"
-#: core/admin.py:74
+#: core/admin.py:81
msgid "timestamps"
msgstr "时间戳"
-#: core/admin.py:80 core/admin.py:95
+#: core/admin.py:96
#, python-format
msgid "activate selected %(verbose_name_plural)s"
msgstr "激活选定的 %(verbose_name_plural)s"
-#: core/admin.py:83
-#, python-format
-msgid "%(verbose_name_plural)s activated successfully!"
-msgstr "%(verbose_name_plural)s_激活成功!"
+#: core/admin.py:101
+msgid "selected items have been activated."
+msgstr "所选项目已激活!"
-#: core/admin.py:85 core/admin.py:100
+#: core/admin.py:107
#, python-format
msgid "deactivate selected %(verbose_name_plural)s"
msgstr "停用选定的 %(verbose_name_plural)s"
-#: core/admin.py:88
-#, python-format
-msgid "%(verbose_name_plural)s deactivated successfully."
-msgstr "成功停用%(verbose_name_plural)s_。"
+#: core/admin.py:112
+msgid "selected items have been deactivated."
+msgstr "选定项目已停用!"
-#: core/admin.py:110 core/graphene/object_types.py:411
-#: core/graphene/object_types.py:418 core/models.py:511 core/models.py:519
+#: core/admin.py:124 core/graphene/object_types.py:421
+#: core/graphene/object_types.py:428 core/models.py:836 core/models.py:844
msgid "attribute value"
msgstr "属性值"
-#: core/admin.py:111 core/graphene/object_types.py:48 core/models.py:520
+#: core/admin.py:125 core/graphene/object_types.py:50 core/models.py:845
msgid "attribute values"
msgstr "属性值"
-#: core/admin.py:119
+#: core/admin.py:133
msgid "image"
msgstr "图片"
-#: core/admin.py:120 core/graphene/object_types.py:364
+#: core/admin.py:134 core/graphene/object_types.py:374
msgid "images"
msgstr "图片"
-#: core/admin.py:128 core/models.py:650
+#: core/admin.py:142 core/models.py:560
msgid "stock"
msgstr "库存"
-#: core/admin.py:129 core/graphene/object_types.py:465
+#: core/admin.py:143 core/graphene/object_types.py:475
msgid "stocks"
msgstr "股票"
-#: core/admin.py:139 core/models.py:1384
+#: core/admin.py:153 core/models.py:1829
msgid "order product"
msgstr "订购产品"
-#: core/admin.py:140 core/graphene/object_types.py:290 core/models.py:1385
+#: core/admin.py:154 core/graphene/object_types.py:293 core/models.py:1830
msgid "order products"
msgstr "订购产品"
-#: core/admin.py:158 core/admin.py:159
+#: core/admin.py:167 core/admin.py:168
msgid "children"
msgstr "儿童"
-#: core/admin.py:454
+#: core/admin.py:501
msgid "Config"
msgstr "配置"
@@ -176,7 +173,7 @@ msgstr "时刻"
msgid "successful"
msgstr "成功"
-#: core/docs/drf/views.py:17 core/graphene/mutations.py:35
+#: core/docs/drf/views.py:17 core/graphene/mutations.py:36
msgid "cache I/O"
msgstr "缓存输入/输出"
@@ -200,7 +197,7 @@ msgstr "获取应用程序的可公开参数"
msgid "send a message to the support team"
msgstr "向支持团队发送信息"
-#: core/docs/drf/views.py:59 core/graphene/mutations.py:54
+#: core/docs/drf/views.py:59 core/graphene/mutations.py:55
msgid "request a CORSed URL"
msgstr "请求 CORSed URL。只允许使用 https。"
@@ -216,7 +213,9 @@ msgstr "以企业身份购买订单"
msgid ""
"purchase an order as a business, using the provided `products` with "
"`product_uuid` and `attributes`."
-msgstr "使用提供的带有 `product_uuid` 和 `attributes` 的 `products` 作为企业购买订单。"
+msgstr ""
+"使用提供的带有 `product_uuid` 和 `attributes` 的 `products` 作为企业购买订"
+"单。"
#: core/docs/drf/viewsets.py:43
msgid "list all attribute groups (simple view)"
@@ -239,8 +238,7 @@ msgid "rewrite an existing attribute group saving non-editables"
msgstr "重写保存不可编辑的现有属性组"
#: core/docs/drf/viewsets.py:63
-msgid ""
-"rewrite some fields of an existing attribute group saving non-editables"
+msgid "rewrite some fields of an existing attribute group saving non-editables"
msgstr "重写现有属性组的某些字段,保存不可编辑的内容"
#: core/docs/drf/viewsets.py:70
@@ -288,8 +286,7 @@ msgid "rewrite an existing attribute value saving non-editables"
msgstr "重写现有属性值,保存不可编辑属性"
#: core/docs/drf/viewsets.py:117
-msgid ""
-"rewrite some fields of an existing attribute value saving non-editables"
+msgid "rewrite some fields of an existing attribute value saving non-editables"
msgstr "重写现有属性值的某些字段,保存不可编辑的属性值"
#: core/docs/drf/viewsets.py:124
@@ -326,11 +323,11 @@ msgstr "对于非工作人员用户,只有他们自己的订单才会被退回
#: core/docs/drf/viewsets.py:158
msgid ""
-"Case-insensitive substring search across human_readable_id, "
-"order_products.product.name, and order_products.product.partnumber"
+"Case-insensitive substring search across human_readable_id, order_products."
+"product.name, and order_products.product.partnumber"
msgstr ""
-"在 human_readable_id、order_products.product.name 和 "
-"order_products.product.partnumber 中进行不区分大小写的子串搜索"
+"在 human_readable_id、order_products.product.name 和 order_products.product."
+"partnumber 中进行不区分大小写的子串搜索"
#: core/docs/drf/viewsets.py:165
msgid "Filter orders with buy_time >= this ISO 8601 datetime"
@@ -362,11 +359,12 @@ msgstr "按订单状态筛选(不区分大小写的子串匹配)"
#: core/docs/drf/viewsets.py:201
msgid ""
-"Order by one of: uuid, human_readable_id, user_email, user, status, created,"
-" modified, buy_time, random. Prefix with '-' for descending (e.g. "
-"'-buy_time')."
+"Order by one of: uuid, human_readable_id, user_email, user, status, created, "
+"modified, buy_time, random. Prefix with '-' for descending (e.g. '-"
+"buy_time')."
msgstr ""
-"按以下一项排序:uuid、human_readable_id、user_email、user、status、created、modified、buy_time、random。前缀\"-\"表示降序(例如\"-buy_time\")。"
+"按以下一项排序:uuid、human_readable_id、user_email、user、status、created、"
+"modified、buy_time、random。前缀\"-\"表示降序(例如\"-buy_time\")。"
#: core/docs/drf/viewsets.py:210
msgid "retrieve a single order (detailed view)"
@@ -401,9 +399,11 @@ msgid ""
"finalizes the order purchase. if `force_balance` is used, the purchase is "
"completed using the user's balance; if `force_payment` is used, a "
"transaction is initiated."
-msgstr "完成订单购买。如果使用 \"force_balance\",则使用用户的余额完成购买;如果使用 \"force_payment\",则启动交易。"
+msgstr ""
+"完成订单购买。如果使用 \"force_balance\",则使用用户的余额完成购买;如果使用 "
+"\"force_payment\",则启动交易。"
-#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:280
+#: core/docs/drf/viewsets.py:245 core/graphene/mutations.py:324
msgid "purchase an order without account creation"
msgstr "无需创建账户即可购买订单"
@@ -520,17 +520,25 @@ msgstr "使用提供的 `product_uuids` 从愿望清单中删除多个产品"
msgid ""
"Filter by one or more attribute name/value pairs. \n"
"• **Syntax**: `attr_name=method-value[;attr2=method2-value2]…` \n"
-"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, `icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, `iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
-"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), `true`/`false` for booleans, integers, floats; otherwise treated as string. \n"
+"• **Methods** (defaults to `icontains` if omitted): `iexact`, `exact`, "
+"`icontains`, `contains`, `isnull`, `startswith`, `istartswith`, `endswith`, "
+"`iendswith`, `regex`, `iregex`, `lt`, `lte`, `gt`, `gte`, `in` \n"
+"• **Value typing**: JSON is attempted first (so you can pass lists/dicts), "
+"`true`/`false` for booleans, integers, floats; otherwise treated as "
+"string. \n"
"• **Base64**: prefix with `b64-` to URL-safe base64-encode the raw value. \n"
"Examples: \n"
-"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\",\"bluetooth\"]`, \n"
+"`color=exact-red`, `size=gt-10`, `features=in-[\"wifi\","
+"\"bluetooth\"]`, \n"
"`b64-description=icontains-aGVhdC1jb2xk`"
msgstr ""
"根据一个或多个属性名/值对进行筛选。 \n"
"- 语法**:`attr_name=method-value[;attr2=method2-value2]...`\n"
-"- 方法**(如果省略,默认为 `icontains`):iexact`、`exact`、`icontains`、`contains`、`isnull`、`startswith`、`istartswith`、`endswith`、`iendswith`、`regex`、`iregex`、`lt`、`lte`、`gt`、`gte`、`in`。\n"
-"- 值键入**:首先尝试使用 JSON(因此可以传递列表/字段),布尔、整数、浮点数使用 `true`/`false`,否则视为字符串。 \n"
+"- 方法**(如果省略,默认为 `icontains`):iexact`、`exact`、`icontains`、"
+"`contains`、`isnull`、`startswith`、`istartswith`、`endswith`、`iendswith`、"
+"`regex`、`iregex`、`lt`、`lte`、`gt`、`gte`、`in`。\n"
+"- 值键入**:首先尝试使用 JSON(因此可以传递列表/字段),布尔、整数、浮点数使"
+"用 `true`/`false`,否则视为字符串。 \n"
"- **Base64**:以 `b64-` 作为前缀,对原始值进行 URL 安全的 base64 编码。 \n"
"示例 \n"
"color=exact-red`、`size=gt-10`、`features=in-[\"wifi\"、\"bluetooth\"]`、\n"
@@ -586,7 +594,8 @@ msgstr "(准确)数字与实物"
#: core/docs/drf/viewsets.py:427
msgid ""
-"Comma-separated list of fields to sort by. Prefix with `-` for descending. \n"
+"Comma-separated list of fields to sort by. Prefix with `-` for "
+"descending. \n"
"**Allowed:** uuid, rating, name, slug, created, modified, price, random"
msgstr ""
"用逗号分隔的要排序的字段列表。前缀为 `-` 表示降序。 \n"
@@ -711,7 +720,7 @@ msgstr "删除订单-产品关系"
msgid "add or remove feedback on an order–product relation"
msgstr "添加或删除订单与产品关系中的反馈信息"
-#: core/elasticsearch/__init__.py:106
+#: core/elasticsearch/__init__.py:101
msgid "no search term provided."
msgstr "未提供搜索条件。"
@@ -759,8 +768,8 @@ msgstr "属性"
msgid "Quantity"
msgstr "数量"
-#: core/filters.py:73 core/filters.py:355 core/models.py:229
-#: core/models.py:307 core/models.py:388
+#: core/filters.py:73 core/filters.py:355 core/models.py:378 core/models.py:472
+#: core/models.py:663
msgid "Slug"
msgstr "蛞蝓"
@@ -821,1185 +830,1217 @@ msgstr "级别"
msgid "Product UUID"
msgstr "产品 UUID"
-#: core/graphene/mutations.py:38
+#: core/graphene/mutations.py:39
msgid "key to look for in or set into the cache"
msgstr "在缓存中查找或设置的关键字"
-#: core/graphene/mutations.py:39
+#: core/graphene/mutations.py:40
msgid "data to store in cache"
msgstr "缓存中要存储的数据"
-#: core/graphene/mutations.py:42
+#: core/graphene/mutations.py:43
msgid "timeout in seconds to set the data for into the cache"
msgstr "将数据设置为缓存的超时(以秒为单位"
-#: core/graphene/mutations.py:45
+#: core/graphene/mutations.py:46
msgid "cached data"
msgstr "缓存数据"
-#: core/graphene/mutations.py:59
+#: core/graphene/mutations.py:60
msgid "camelized JSON data from the requested URL"
msgstr "从请求的 URL 中获取驼峰化 JSON 数据"
-#: core/graphene/mutations.py:64 core/views.py:196
+#: core/graphene/mutations.py:65 core/views.py:356
msgid "only URLs starting with http(s):// are allowed"
msgstr "只允许使用以 http(s):// 开头的 URL"
-#: core/graphene/mutations.py:79
+#: core/graphene/mutations.py:80
msgid "add a product to the order"
msgstr "在订单中添加产品"
-#: core/graphene/mutations.py:100 core/graphene/mutations.py:126
-#: core/graphene/mutations.py:228 core/graphene/mutations.py:275
+#: core/graphene/mutations.py:101 core/graphene/mutations.py:127
+#: core/graphene/mutations.py:232 core/graphene/mutations.py:279
#, python-brace-format
msgid "order {order_uuid} not found"
-msgstr "未找到订单 {order_uuid}"
+msgstr "未找到 {order_uuid} 订单!"
-#: core/graphene/mutations.py:105 core/graphene/mutations.py:152
+#: core/graphene/mutations.py:106 core/graphene/mutations.py:153
msgid "remove a product from the order"
msgstr "从订单中删除产品"
-#: core/graphene/mutations.py:131
+#: core/graphene/mutations.py:132
msgid "remove all products from the order"
msgstr "从订单中删除所有产品"
-#: core/graphene/mutations.py:174
+#: core/graphene/mutations.py:175
msgid "buy an order"
msgstr "购买订单"
-#: core/graphene/mutations.py:201 core/graphene/mutations.py:253
+#: core/graphene/mutations.py:204 core/graphene/mutations.py:257
msgid "please provide either order_uuid or order_hr_id - mutually exclusive"
msgstr "请提供 order_uuid 或 order_hr_id(互斥)!"
-#: core/graphene/mutations.py:225 core/graphene/mutations.py:442
-#: core/graphene/mutations.py:483 core/viewsets.py:341
+#: core/graphene/mutations.py:229 core/graphene/mutations.py:486
+#: core/graphene/mutations.py:527 core/viewsets.py:601
msgid "wrong type came from order.buy() method: {type(instance)!s}"
msgstr "order.buy() 方法中的类型有误:{type(instance)!s}"
-#: core/graphene/mutations.py:233
+#: core/graphene/mutations.py:237
msgid "perform an action on a list of products in the order"
msgstr "对订单中的产品列表执行操作"
-#: core/graphene/mutations.py:238
+#: core/graphene/mutations.py:242
msgid "remove/add"
msgstr "删除/添加"
-#: core/graphene/mutations.py:270
+#: core/graphene/mutations.py:274 core/graphene/mutations.py:314
msgid "action must be either add or remove"
msgstr "操作必须是 \"添加 \"或 \"删除\"!"
-#: core/graphene/mutations.py:326
+#: core/graphene/mutations.py:284
+msgid "perform an action on a list of products in the wishlist"
+msgstr "对愿望清单中的产品列表执行操作"
+
+#: core/graphene/mutations.py:302
+msgid "please provide wishlist_uuid value"
+msgstr "请提供 `wishlist_uuid` 值。"
+
+#: core/graphene/mutations.py:319 core/graphene/mutations.py:392
+#: core/graphene/mutations.py:419 core/graphene/mutations.py:446
+#: core/graphene/mutations.py:489
+#, python-brace-format
+msgid "wishlist {wishlist_uuid} not found"
+msgstr "未找到 Wishlist {wishlist_uuid}!"
+
+#: core/graphene/mutations.py:370
msgid "add a product to the wishlist"
msgstr "在订单中添加产品"
-#: core/graphene/mutations.py:348 core/graphene/mutations.py:375
-#: core/graphene/mutations.py:402 core/graphene/mutations.py:445
-#, python-brace-format
-msgid "wishlist {wishlist_uuid} not found"
-msgstr "未找到愿望清单 {wishlist_uuid}"
-
-#: core/graphene/mutations.py:353
+#: core/graphene/mutations.py:397
msgid "remove a product from the wishlist"
msgstr "从订单中删除产品"
-#: core/graphene/mutations.py:380
+#: core/graphene/mutations.py:424
msgid "remove all products from the wishlist"
msgstr "从订单中删除产品"
-#: core/graphene/mutations.py:407
+#: core/graphene/mutations.py:451
msgid "buy all products from the wishlist"
msgstr "从订单中删除产品"
-#: core/graphene/mutations.py:450
+#: core/graphene/mutations.py:494
msgid "buy a product"
msgstr "购买订单"
-#: core/graphene/mutations.py:456
+#: core/graphene/mutations.py:500
msgid ""
-"please send the attributes as the string formatted like "
-"attr1=value1,attr2=value2"
+"please send the attributes as the string formatted like attr1=value1,"
+"attr2=value2"
msgstr "请以字符串形式发送属性,格式如 attr1=value1,attr2=value2"
-#: core/graphene/mutations.py:546
+#: core/graphene/mutations.py:532
+msgid "add or delete a feedback for orderproduct"
+msgstr "添加或删除订单产品的反馈信息"
+
+#: core/graphene/mutations.py:555
+msgid "action must be either `add` or `remove`"
+msgstr "操作必须是 \"添加 \"或 \"删除\"!"
+
+#: core/graphene/mutations.py:558
+#, python-brace-format
+msgid "order product {order_product_uuid} not found"
+msgstr "未找到订购产品 {order_product_uuid}!"
+
+#: core/graphene/mutations.py:621
msgid "original address string provided by the user"
msgstr "用户提供的原始地址字符串"
-#: core/graphene/mutations.py:580 core/viewsets.py:236 core/viewsets.py:344
+#: core/graphene/mutations.py:655 core/models.py:1020 core/models.py:1033
+#: core/models.py:1476 core/models.py:1505 core/models.py:1530
+#: core/viewsets.py:408 core/viewsets.py:604
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} 不存在:{uuid}不存在"
+msgstr "{name} 不存在:{uuid}!"
-#: core/graphene/mutations.py:593
+#: core/graphene/mutations.py:668
msgid "limit must be between 1 and 10"
msgstr "限值必须在 1 和 10 之间"
-#: core/graphene/mutations.py:638
+#: core/graphene/mutations.py:713
msgid "elasticsearch - works like a charm"
msgstr "ElasticSearch - 工作起来得心应手"
-#: core/graphene/object_types.py:55 core/graphene/object_types.py:273
-#: core/graphene/object_types.py:314 core/models.py:488 core/models.py:935
+#: core/graphene/object_types.py:57 core/graphene/object_types.py:276
+#: core/graphene/object_types.py:317 core/models.py:790 core/models.py:1368
msgid "attributes"
msgstr "属性"
-#: core/graphene/object_types.py:68
+#: core/graphene/object_types.py:70
msgid "grouped attributes"
msgstr "分组属性"
-#: core/graphene/object_types.py:75
+#: core/graphene/object_types.py:77
msgid "groups of attributes"
msgstr "属性组"
-#: core/graphene/object_types.py:89 core/graphene/object_types.py:123
-#: core/graphene/object_types.py:153 core/models.py:257 core/models.py:452
+#: core/graphene/object_types.py:91 core/graphene/object_types.py:125
+#: core/graphene/object_types.py:155 core/models.py:403 core/models.py:754
msgid "categories"
msgstr "类别"
-#: core/graphene/object_types.py:96 core/models.py:321
+#: core/graphene/object_types.py:98 core/models.py:486
msgid "brands"
msgstr "品牌"
-#: core/graphene/object_types.py:125
+#: core/graphene/object_types.py:127
msgid "category image url"
msgstr "类别"
-#: core/graphene/object_types.py:126 core/graphene/object_types.py:221
-#: core/models.py:191
+#: core/graphene/object_types.py:128 core/graphene/object_types.py:223
+#: core/models.py:340
msgid "markup percentage"
msgstr "加价百分比"
-#: core/graphene/object_types.py:129
+#: core/graphene/object_types.py:131
msgid "which attributes and values can be used for filtering this category."
msgstr "哪些属性和值可用于筛选该类别。"
-#: core/graphene/object_types.py:133
-msgid ""
-"minimum and maximum prices for products in this category, if available."
+#: core/graphene/object_types.py:135
+msgid "minimum and maximum prices for products in this category, if available."
msgstr "该类别产品的最低和最高价格(如有)。"
-#: core/graphene/object_types.py:135
+#: core/graphene/object_types.py:137
msgid "tags for this category"
msgstr "此类别的标签"
-#: core/graphene/object_types.py:136
+#: core/graphene/object_types.py:138
msgid "products in this category"
msgstr "该类别中的产品"
-#: core/graphene/object_types.py:228 core/models.py:120
+#: core/graphene/object_types.py:230 core/models.py:173
msgid "vendors"
msgstr "供应商"
-#: core/graphene/object_types.py:232
+#: core/graphene/object_types.py:234
msgid "Latitude (Y coordinate)"
msgstr "纬度(Y 坐标)"
-#: core/graphene/object_types.py:233
+#: core/graphene/object_types.py:235
msgid "Longitude (X coordinate)"
msgstr "经度(X 坐标)"
-#: core/graphene/object_types.py:261
+#: core/graphene/object_types.py:264
msgid "comment"
msgstr "如何"
-#: core/graphene/object_types.py:262
+#: core/graphene/object_types.py:265
msgid "rating value from 1 to 10, inclusive, or 0 if not set."
msgstr "评级值从 1 到 10(包括 10),如果未设置,则为 0。"
-#: core/graphene/object_types.py:269
+#: core/graphene/object_types.py:272
msgid "represents feedback from a user."
msgstr "代表用户的反馈意见。"
-#: core/graphene/object_types.py:274 core/graphene/object_types.py:315
-#: core/models.py:929
+#: core/graphene/object_types.py:277 core/graphene/object_types.py:318
+#: core/models.py:1362
msgid "notifications"
msgstr "通知"
-#: core/graphene/object_types.py:275
+#: core/graphene/object_types.py:278
msgid "download url for this order product if applicable"
msgstr "此订单产品的下载网址(如适用"
-#: core/graphene/object_types.py:304
+#: core/graphene/object_types.py:307
msgid "a list of order products in this order"
msgstr "该订单中的订单产品列表"
-#: core/graphene/object_types.py:306 core/models.py:899
+#: core/graphene/object_types.py:309 core/models.py:1332
msgid "billing address"
msgstr "账单地址"
-#: core/graphene/object_types.py:309
+#: core/graphene/object_types.py:312
msgid ""
"shipping address for this order, leave blank if same as billing address or "
"if not applicable"
msgstr "此订单的送货地址,如果与账单地址相同或不适用,请留空"
-#: core/graphene/object_types.py:311
+#: core/graphene/object_types.py:314
msgid "total price of this order"
msgstr "订单总价"
-#: core/graphene/object_types.py:312
+#: core/graphene/object_types.py:315
msgid "total quantity of products in order"
msgstr "订单中产品的总数量"
-#: core/graphene/object_types.py:313
+#: core/graphene/object_types.py:316
msgid "are all products in the order digital"
msgstr "订单中的所有产品都是数字产品吗?"
-#: core/graphene/object_types.py:333 core/models.py:963
+#: core/graphene/object_types.py:319
+msgid "transactions for this order"
+msgstr "此订单的交易"
+
+#: core/graphene/object_types.py:338 core/models.py:1396
msgid "orders"
msgstr "订单"
-#: core/graphene/object_types.py:349
+#: core/graphene/object_types.py:359
msgid "image url"
msgstr "图片 URL"
-#: core/graphene/object_types.py:356
+#: core/graphene/object_types.py:366
msgid "product's images"
msgstr "产品图片"
-#: core/graphene/object_types.py:363 core/models.py:256 core/models.py:331
+#: core/graphene/object_types.py:373 core/models.py:402 core/models.py:606
msgid "category"
msgstr "类别"
-#: core/graphene/object_types.py:365 core/models.py:1507
+#: core/graphene/object_types.py:375 core/models.py:1988
msgid "feedbacks"
msgstr "反馈意见"
-#: core/graphene/object_types.py:366 core/models.py:320 core/models.py:340
+#: core/graphene/object_types.py:376 core/models.py:485 core/models.py:615
msgid "brand"
msgstr "品牌"
-#: core/graphene/object_types.py:367 core/models.py:86
+#: core/graphene/object_types.py:377 core/models.py:113
msgid "attribute groups"
msgstr "属性组"
-#: core/graphene/object_types.py:368
+#: core/graphene/object_types.py:378
#: core/templates/digital_order_created_email.html:111
-#: core/templates/digital_order_delivered_email.html:110
+#: core/templates/digital_order_delivered_email.html:109
#: core/templates/shipped_order_created_email.html:109
#: core/templates/shipped_order_delivered_email.html:109
msgid "price"
msgstr "价格"
-#: core/graphene/object_types.py:369
+#: core/graphene/object_types.py:379
#: core/templates/digital_order_created_email.html:110
-#: core/templates/digital_order_delivered_email.html:109
+#: core/templates/digital_order_delivered_email.html:108
#: core/templates/shipped_order_created_email.html:108
#: core/templates/shipped_order_delivered_email.html:108
msgid "quantity"
msgstr "数量"
-#: core/graphene/object_types.py:370
+#: core/graphene/object_types.py:380
msgid "number of feedbacks"
msgstr "反馈数量"
-#: core/graphene/object_types.py:388 core/models.py:393
+#: core/graphene/object_types.py:398 core/models.py:668
msgid "products"
msgstr "产品"
-#: core/graphene/object_types.py:436
+#: core/graphene/object_types.py:446
msgid "promocodes"
msgstr "促销代码"
-#: core/graphene/object_types.py:446
+#: core/graphene/object_types.py:456
msgid "products on sale"
msgstr "销售产品"
-#: core/graphene/object_types.py:453 core/models.py:591
+#: core/graphene/object_types.py:463 core/models.py:967
msgid "promotions"
msgstr "促销活动"
-#: core/graphene/object_types.py:457 core/models.py:119
+#: core/graphene/object_types.py:467 core/models.py:172
msgid "vendor"
msgstr "供应商"
-#: core/graphene/object_types.py:458 core/models.py:392
+#: core/graphene/object_types.py:468 core/models.py:667
#: core/templates/digital_order_created_email.html:109
-#: core/templates/digital_order_delivered_email.html:108
+#: core/templates/digital_order_delivered_email.html:107
#: core/templates/shipped_order_created_email.html:107
#: core/templates/shipped_order_delivered_email.html:107
msgid "product"
msgstr "产品"
-#: core/graphene/object_types.py:469 core/models.py:661
+#: core/graphene/object_types.py:479 core/models.py:992
msgid "wishlisted products"
msgstr "心愿单上的产品"
-#: core/graphene/object_types.py:475 core/models.py:678
+#: core/graphene/object_types.py:485 core/models.py:1009
msgid "wishlists"
msgstr "愿望清单"
-#: core/graphene/object_types.py:479
+#: core/graphene/object_types.py:489
msgid "tagged products"
msgstr "标签产品"
-#: core/graphene/object_types.py:486 core/models.py:148 core/models.py:346
+#: core/graphene/object_types.py:496 core/models.py:217 core/models.py:621
msgid "product tags"
msgstr "产品标签"
-#: core/graphene/object_types.py:490
+#: core/graphene/object_types.py:500
msgid "tagged categories"
msgstr "标签类别"
-#: core/graphene/object_types.py:497
+#: core/graphene/object_types.py:507
msgid "categories tags"
msgstr "类别标签"
-#: core/graphene/object_types.py:501
+#: core/graphene/object_types.py:511
msgid "project name"
msgstr "项目名称"
-#: core/graphene/object_types.py:502
+#: core/graphene/object_types.py:512
msgid "company email"
msgstr "公司电子邮件"
-#: core/graphene/object_types.py:503
+#: core/graphene/object_types.py:513
msgid "company name"
msgstr "公司名称"
-#: core/graphene/object_types.py:504
+#: core/graphene/object_types.py:514
msgid "company address"
msgstr "公司地址"
-#: core/graphene/object_types.py:505
+#: core/graphene/object_types.py:515
msgid "company phone number"
msgstr "公司电话号码"
-#: core/graphene/object_types.py:506
+#: core/graphene/object_types.py:516
msgid "email from, sometimes it must be used instead of host user value"
msgstr "电子邮件来自\",有时必须使用它来代替主机用户值"
-#: core/graphene/object_types.py:507
+#: core/graphene/object_types.py:517
msgid "email host user"
msgstr "电子邮件主机用户"
-#: core/graphene/object_types.py:508
+#: core/graphene/object_types.py:518
msgid "maximum amount for payment"
msgstr "最高付款额"
-#: core/graphene/object_types.py:509
+#: core/graphene/object_types.py:519
msgid "minimum amount for payment"
msgstr "最低付款额"
-#: core/graphene/object_types.py:510
+#: core/graphene/object_types.py:520
msgid "analytics data"
msgstr "分析数据"
-#: core/graphene/object_types.py:511
+#: core/graphene/object_types.py:521
msgid "advertisement data"
msgstr "广告数据"
-#: core/graphene/object_types.py:514
+#: core/graphene/object_types.py:524
msgid "company configuration"
msgstr "配置"
-#: core/graphene/object_types.py:518
+#: core/graphene/object_types.py:528
msgid "language code"
msgstr "语言代码"
-#: core/graphene/object_types.py:519
+#: core/graphene/object_types.py:529
msgid "language name"
msgstr "语言名称"
-#: core/graphene/object_types.py:520
+#: core/graphene/object_types.py:530
msgid "language flag, if exists :)"
msgstr "语言标志(如果有):)"
-#: core/graphene/object_types.py:523
+#: core/graphene/object_types.py:533
msgid "supported languages"
msgstr "获取支持的语言列表"
-#: core/graphene/object_types.py:554 core/graphene/object_types.py:555
-#: core/graphene/object_types.py:556
+#: core/graphene/object_types.py:564 core/graphene/object_types.py:565
+#: core/graphene/object_types.py:566
msgid "products search results"
msgstr "产品搜索结果"
-#: core/graphene/object_types.py:557
+#: core/graphene/object_types.py:567
msgid "posts search results"
msgstr "产品搜索结果"
-#: core/models.py:71
+#: core/models.py:98
msgid "parent of this group"
msgstr "本组家长"
-#: core/models.py:72
+#: core/models.py:99
msgid "parent attribute group"
msgstr "父属性组"
-#: core/models.py:76 core/models.py:77
+#: core/models.py:103 core/models.py:104
msgid "attribute group's name"
msgstr "属性组名称"
-#: core/models.py:85 core/models.py:460
+#: core/models.py:112 core/models.py:762
msgid "attribute group"
msgstr "属性组"
-#: core/models.py:96
+#: core/models.py:150
msgid "stores credentials and endpoints required for vendor communication"
msgstr "存储供应商应用程序接口通信所需的凭证和端点"
-#: core/models.py:98
+#: core/models.py:151
msgid "authentication info"
msgstr "认证信息"
-#: core/models.py:103
+#: core/models.py:156
msgid "define the markup for products retrieved from this vendor"
msgstr "定义从该供应商获取的产品的标记"
-#: core/models.py:104
+#: core/models.py:157
msgid "vendor markup percentage"
msgstr "供应商加价百分比"
-#: core/models.py:108
+#: core/models.py:161
msgid "name of this vendor"
msgstr "供应商名称"
-#: core/models.py:109
+#: core/models.py:162
msgid "vendor name"
msgstr "供应商名称"
-#: core/models.py:133 core/models.py:158
+#: core/models.py:202 core/models.py:240
msgid "internal tag identifier for the product tag"
msgstr "产品标签的内部标签标识符"
-#: core/models.py:134 core/models.py:159
+#: core/models.py:203 core/models.py:241
msgid "tag name"
msgstr "标签名称"
-#: core/models.py:138 core/models.py:163
+#: core/models.py:207 core/models.py:245
msgid "user-friendly name for the product tag"
msgstr "方便用户使用的产品标签名称"
-#: core/models.py:139 core/models.py:164
+#: core/models.py:208 core/models.py:246
msgid "tag display name"
msgstr "标签显示名称"
-#: core/models.py:147
+#: core/models.py:216
msgid "product tag"
msgstr "产品标签"
-#: core/models.py:172
+#: core/models.py:254
msgid "category tag"
msgstr "类别标签"
-#: core/models.py:173 core/models.py:235
+#: core/models.py:255 core/models.py:384
msgid "category tags"
msgstr "类别标签"
-#: core/models.py:182
+#: core/models.py:331
msgid "upload an image representing this category"
msgstr "上传代表该类别的图片"
-#: core/models.py:185
+#: core/models.py:334
msgid "category image"
msgstr "类别 图像"
-#: core/models.py:190
+#: core/models.py:339
msgid "define a markup percentage for products in this category"
msgstr "定义该类别产品的加价百分比"
-#: core/models.py:199
+#: core/models.py:348
msgid "parent of this category to form a hierarchical structure"
msgstr "该类别的父类别,形成等级结构"
-#: core/models.py:200
+#: core/models.py:349
msgid "parent category"
msgstr "父类"
-#: core/models.py:205
+#: core/models.py:354
msgid "category name"
msgstr "类别名称"
-#: core/models.py:206
+#: core/models.py:355
msgid "provide a name for this category"
msgstr "提供该类别的名称"
-#: core/models.py:213
+#: core/models.py:362
msgid "add a detailed description for this category"
msgstr "为该类别添加详细说明"
-#: core/models.py:214
+#: core/models.py:363
msgid "category description"
msgstr "类别说明"
-#: core/models.py:234
+#: core/models.py:383
msgid "tags that help describe or group this category"
msgstr "有助于描述或归类该类别的标签"
-#: core/models.py:241 core/models.py:313
+#: core/models.py:390 core/models.py:478
msgid "priority"
msgstr "优先权"
-#: core/models.py:266
+#: core/models.py:431
msgid "name of this brand"
msgstr "品牌名称"
-#: core/models.py:267
+#: core/models.py:432
msgid "brand name"
msgstr "品牌名称"
-#: core/models.py:274
+#: core/models.py:439
msgid "upload a logo representing this brand"
msgstr "上传代表该品牌的徽标"
-#: core/models.py:276
+#: core/models.py:441
msgid "brand small image"
msgstr "品牌小形象"
-#: core/models.py:282
+#: core/models.py:447
msgid "upload a big logo representing this brand"
msgstr "上传代表该品牌的大徽标"
-#: core/models.py:284
+#: core/models.py:449
msgid "brand big image"
msgstr "品牌大形象"
-#: core/models.py:289
+#: core/models.py:454
msgid "add a detailed description of the brand"
msgstr "添加品牌的详细描述"
-#: core/models.py:290
+#: core/models.py:455
msgid "brand description"
msgstr "品牌描述"
-#: core/models.py:295
+#: core/models.py:460
msgid "optional categories that this brand is associated with"
msgstr "与该品牌相关的可选类别"
-#: core/models.py:296
+#: core/models.py:461
msgid "associated categories"
msgstr "类别"
-#: core/models.py:330
-msgid "category this product belongs to"
-msgstr "该产品所属类别"
-
-#: core/models.py:339
-msgid "optionally associate this product with a brand"
-msgstr "可选择将该产品与某个品牌联系起来"
-
-#: core/models.py:345
-msgid "tags that help describe or group this product"
-msgstr "有助于描述或归类该产品的标签"
-
-#: core/models.py:350
-msgid "indicates whether this product is digitally delivered"
-msgstr "表示该产品是否以数字方式交付"
-
-#: core/models.py:351
-msgid "is product digital"
-msgstr "产品是否数字化"
-
-#: core/models.py:357
-msgid "provide a clear identifying name for the product"
-msgstr "为产品提供一个明确的标识名称"
-
-#: core/models.py:358
-msgid "product name"
-msgstr "产品名称"
-
-#: core/models.py:363 core/models.py:579
-msgid "add a detailed description of the product"
-msgstr "添加产品的详细描述"
-
-#: core/models.py:364
-msgid "product description"
-msgstr "产品说明"
-
-#: core/models.py:371
-msgid "part number for this product"
-msgstr "该产品的零件编号"
-
-#: core/models.py:372
-msgid "part number"
-msgstr "部件编号"
-
-#: core/models.py:451
-msgid "category of this attribute"
-msgstr "该属性的类别"
-
-#: core/models.py:459
-msgid "group of this attribute"
-msgstr "该属性的组"
-
-#: core/models.py:465
-msgid "string"
-msgstr "字符串"
-
-#: core/models.py:466
-msgid "integer"
-msgstr "整数"
-
-#: core/models.py:467
-msgid "float"
-msgstr "浮动"
-
-#: core/models.py:468
-msgid "boolean"
-msgstr "布尔型"
-
-#: core/models.py:469
-msgid "array"
-msgstr "阵列"
-
-#: core/models.py:470
-msgid "object"
-msgstr "对象"
-
-#: core/models.py:472
-msgid "type of the attribute's value"
-msgstr "属性值的类型"
-
-#: core/models.py:473
-msgid "value type"
-msgstr "价值类型"
-
-#: core/models.py:478
-msgid "name of this attribute"
-msgstr "该属性的名称"
-
-#: core/models.py:479
-msgid "attribute's name"
-msgstr "属性名称"
-
-#: core/models.py:487 core/models.py:499
-#: core/templates/digital_order_delivered_email.html:135
-msgid "attribute"
-msgstr "属性"
-
-#: core/models.py:498
-msgid "attribute of this value"
-msgstr "该值的属性"
-
-#: core/models.py:506
-msgid "the specific product associated with this attribute's value"
-msgstr "与该属性值相关的特定产品"
-
-#: core/models.py:507 core/models.py:546 core/models.py:617
-#: core/models.py:1361
-msgid "associated product"
-msgstr "相关产品"
-
-#: core/models.py:512
-msgid "the specific value for this attribute"
-msgstr "该属性的具体值"
-
-#: core/models.py:528
-msgid "provide alternative text for the image for accessibility"
-msgstr "为图像提供替代文字,以便于访问"
-
-#: core/models.py:529
-msgid "image alt text"
-msgstr "图片 alt 文本"
-
-#: core/models.py:532
-msgid "upload the image file for this product"
-msgstr "上传该产品的图片文件"
-
-#: core/models.py:533 core/models.py:558
-msgid "product image"
-msgstr "产品图片"
-
-#: core/models.py:539
-msgid "determines the order in which images are displayed"
-msgstr "确定图像的显示顺序"
-
-#: core/models.py:540
-msgid "display priority"
-msgstr "显示优先级"
-
-#: core/models.py:545
-msgid "the product that this image represents"
-msgstr "该图片所代表的产品"
-
-#: core/models.py:559
-msgid "product images"
-msgstr "产品图片"
-
-#: core/models.py:567
-msgid "percentage discount for the selected products"
-msgstr "所选产品的折扣百分比"
-
-#: core/models.py:568
-msgid "discount percentage"
-msgstr "折扣百分比"
-
-#: core/models.py:573
-msgid "provide a unique name for this promotion"
-msgstr "为该促销活动提供一个独特的名称"
-
-#: core/models.py:574
-msgid "promotion name"
-msgstr "推广名称"
-
-#: core/models.py:580
-msgid "promotion description"
-msgstr "促销说明"
-
-#: core/models.py:585
-msgid "select which products are included in this promotion"
-msgstr "选择促销活动包括哪些产品"
-
-#: core/models.py:586
-msgid "included products"
-msgstr "包括产品"
-
-#: core/models.py:590
-msgid "promotion"
-msgstr "促销活动"
-
-#: core/models.py:605
+#: core/models.py:515
msgid "the vendor supplying this product stock"
msgstr "提供该产品库存的供应商"
-#: core/models.py:606
+#: core/models.py:516
msgid "associated vendor"
msgstr "相关供应商"
-#: core/models.py:610
+#: core/models.py:520
msgid "final price to the customer after markups"
msgstr "加价后给客户的最终价格"
-#: core/models.py:611
+#: core/models.py:521
msgid "selling price"
msgstr "销售价格"
-#: core/models.py:616
+#: core/models.py:526
msgid "the product associated with this stock entry"
msgstr "与该库存条目相关的产品"
-#: core/models.py:624
+#: core/models.py:527 core/models.py:832 core/models.py:889 core/models.py:1803
+msgid "associated product"
+msgstr "相关产品"
+
+#: core/models.py:534
msgid "the price paid to the vendor for this product"
msgstr "为该产品支付给供应商的价格"
-#: core/models.py:625
+#: core/models.py:535
msgid "vendor purchase price"
msgstr "供应商购买价格"
-#: core/models.py:629
+#: core/models.py:539
msgid "available quantity of the product in stock"
msgstr "产品的可用库存量"
-#: core/models.py:630
+#: core/models.py:540
msgid "quantity in stock"
msgstr "库存数量"
-#: core/models.py:634
+#: core/models.py:544
msgid "vendor-assigned SKU for identifying the product"
msgstr "供应商指定的 SKU,用于识别产品"
-#: core/models.py:635
+#: core/models.py:545
msgid "vendor sku"
msgstr "供应商 SKU"
-#: core/models.py:641
+#: core/models.py:551
msgid "digital file associated with this stock if applicable"
msgstr "与该库存相关的数字文件(如适用"
-#: core/models.py:642
+#: core/models.py:552
msgid "digital file"
msgstr "数字文件"
-#: core/models.py:651
+#: core/models.py:561
msgid "stock entries"
msgstr "库存条目"
-#: core/models.py:660
+#: core/models.py:605
+msgid "category this product belongs to"
+msgstr "该产品所属类别"
+
+#: core/models.py:614
+msgid "optionally associate this product with a brand"
+msgstr "可选择将该产品与某个品牌联系起来"
+
+#: core/models.py:620
+msgid "tags that help describe or group this product"
+msgstr "有助于描述或归类该产品的标签"
+
+#: core/models.py:625
+msgid "indicates whether this product is digitally delivered"
+msgstr "表示该产品是否以数字方式交付"
+
+#: core/models.py:626
+msgid "is product digital"
+msgstr "产品是否数字化"
+
+#: core/models.py:632
+msgid "provide a clear identifying name for the product"
+msgstr "为产品提供一个明确的标识名称"
+
+#: core/models.py:633
+msgid "product name"
+msgstr "产品名称"
+
+#: core/models.py:638 core/models.py:955
+msgid "add a detailed description of the product"
+msgstr "添加产品的详细描述"
+
+#: core/models.py:639
+msgid "product description"
+msgstr "产品说明"
+
+#: core/models.py:646
+msgid "part number for this product"
+msgstr "该产品的零件编号"
+
+#: core/models.py:647
+msgid "part number"
+msgstr "部件编号"
+
+#: core/models.py:753
+msgid "category of this attribute"
+msgstr "该属性的类别"
+
+#: core/models.py:761
+msgid "group of this attribute"
+msgstr "该属性的组"
+
+#: core/models.py:767
+msgid "string"
+msgstr "字符串"
+
+#: core/models.py:768
+msgid "integer"
+msgstr "整数"
+
+#: core/models.py:769
+msgid "float"
+msgstr "浮动"
+
+#: core/models.py:770
+msgid "boolean"
+msgstr "布尔型"
+
+#: core/models.py:771
+msgid "array"
+msgstr "阵列"
+
+#: core/models.py:772
+msgid "object"
+msgstr "对象"
+
+#: core/models.py:774
+msgid "type of the attribute's value"
+msgstr "属性值的类型"
+
+#: core/models.py:775
+msgid "value type"
+msgstr "价值类型"
+
+#: core/models.py:780
+msgid "name of this attribute"
+msgstr "该属性的名称"
+
+#: core/models.py:781
+msgid "attribute's name"
+msgstr "属性名称"
+
+#: core/models.py:789 core/models.py:824
+#: core/templates/digital_order_delivered_email.html:134
+msgid "attribute"
+msgstr "属性"
+
+#: core/models.py:823
+msgid "attribute of this value"
+msgstr "该值的属性"
+
+#: core/models.py:831
+msgid "the specific product associated with this attribute's value"
+msgstr "与该属性值相关的特定产品"
+
+#: core/models.py:837
+msgid "the specific value for this attribute"
+msgstr "该属性的具体值"
+
+#: core/models.py:871
+msgid "provide alternative text for the image for accessibility"
+msgstr "为图像提供替代文字,以便于访问"
+
+#: core/models.py:872
+msgid "image alt text"
+msgstr "图片 alt 文本"
+
+#: core/models.py:875
+msgid "upload the image file for this product"
+msgstr "上传该产品的图片文件"
+
+#: core/models.py:876 core/models.py:901
+msgid "product image"
+msgstr "产品图片"
+
+#: core/models.py:882
+msgid "determines the order in which images are displayed"
+msgstr "确定图像的显示顺序"
+
+#: core/models.py:883
+msgid "display priority"
+msgstr "显示优先级"
+
+#: core/models.py:888
+msgid "the product that this image represents"
+msgstr "该图片所代表的产品"
+
+#: core/models.py:902
+msgid "product images"
+msgstr "产品图片"
+
+#: core/models.py:943
+msgid "percentage discount for the selected products"
+msgstr "所选产品的折扣百分比"
+
+#: core/models.py:944
+msgid "discount percentage"
+msgstr "折扣百分比"
+
+#: core/models.py:949
+msgid "provide a unique name for this promotion"
+msgstr "为该促销活动提供一个独特的名称"
+
+#: core/models.py:950
+msgid "promotion name"
+msgstr "推广名称"
+
+#: core/models.py:956
+msgid "promotion description"
+msgstr "促销说明"
+
+#: core/models.py:961
+msgid "select which products are included in this promotion"
+msgstr "选择促销活动包括哪些产品"
+
+#: core/models.py:962
+msgid "included products"
+msgstr "包括产品"
+
+#: core/models.py:966
+msgid "promotion"
+msgstr "促销活动"
+
+#: core/models.py:991
msgid "products that the user has marked as wanted"
msgstr "用户标记为想要的产品"
-#: core/models.py:668
+#: core/models.py:999
msgid "user who owns this wishlist"
msgstr "拥有此愿望清单的用户"
-#: core/models.py:669
+#: core/models.py:1000
msgid "wishlist owner"
msgstr "心愿单所有者"
-#: core/models.py:677
+#: core/models.py:1008
msgid "wishlist"
msgstr "愿望清单"
-#: core/models.py:688 core/models.py:700 core/models.py:1049
-#: core/models.py:1079 core/models.py:1109
-#, python-brace-format
-msgid "{name} does not exist: {product_uuid}"
-msgstr "{name} 不存在:{product_uuid} 不存在"
-
-#: core/models.py:724
+#: core/models.py:1075
msgid "documentary"
msgstr "纪录片"
-#: core/models.py:725
+#: core/models.py:1076
msgid "documentaries"
msgstr "纪录片"
-#: core/models.py:735
+#: core/models.py:1086
msgid "unresolved"
msgstr "未解决"
-#: core/models.py:744
+#: core/models.py:1132
msgid "address line for the customer"
msgstr "客户地址栏"
-#: core/models.py:745
+#: core/models.py:1133
msgid "address line"
msgstr "地址栏"
-#: core/models.py:747
+#: core/models.py:1135
msgid "street"
msgstr "街道"
-#: core/models.py:748
+#: core/models.py:1136
msgid "district"
msgstr "地区"
-#: core/models.py:749
+#: core/models.py:1137
msgid "city"
msgstr "城市"
-#: core/models.py:750
+#: core/models.py:1138
msgid "region"
msgstr "地区"
-#: core/models.py:751
+#: core/models.py:1139
msgid "postal code"
msgstr "邮政编码"
-#: core/models.py:752
+#: core/models.py:1140
msgid "country"
msgstr "国家"
-#: core/models.py:759
+#: core/models.py:1147
msgid "geolocation point: (longitude, latitude)"
msgstr "地理位置点(经度、纬度)"
-#: core/models.py:762
+#: core/models.py:1150
msgid "full JSON response from geocoder for this address"
msgstr "地理编码器对此地址的完整 JSON 响应"
-#: core/models.py:767
+#: core/models.py:1155
msgid "stored JSON response from the geocoding service"
msgstr "存储的来自地理编码服务的 JSON 响应"
-#: core/models.py:775
+#: core/models.py:1163
msgid "address"
msgstr "地址"
-#: core/models.py:776
+#: core/models.py:1164
msgid "addresses"
msgstr "地址"
-#: core/models.py:793
+#: core/models.py:1209
msgid "unique code used by a user to redeem a discount"
msgstr "用户用于兑换折扣的唯一代码"
-#: core/models.py:794
+#: core/models.py:1210
msgid "promo code identifier"
msgstr "促销代码标识符"
-#: core/models.py:801
+#: core/models.py:1217
msgid "fixed discount amount applied if percent is not used"
msgstr "如果不使用百分比,则使用固定折扣额"
-#: core/models.py:802
+#: core/models.py:1218
msgid "fixed discount amount"
msgstr "固定折扣额"
-#: core/models.py:808
+#: core/models.py:1224
msgid "percentage discount applied if fixed amount is not used"
msgstr "未使用固定金额时适用的折扣百分比"
-#: core/models.py:809
+#: core/models.py:1225
msgid "percentage discount"
msgstr "折扣百分比"
-#: core/models.py:814
+#: core/models.py:1230
msgid "timestamp when the promocode expires"
msgstr "促销代码过期的时间戳"
-#: core/models.py:815
+#: core/models.py:1231
msgid "end validity time"
msgstr "结束有效时间"
-#: core/models.py:820
+#: core/models.py:1236
msgid "timestamp from which this promocode is valid"
msgstr "该促销代码有效的时间戳"
-#: core/models.py:821
+#: core/models.py:1237
msgid "start validity time"
msgstr "开始有效时间"
-#: core/models.py:826
+#: core/models.py:1242
msgid "timestamp when the promocode was used, blank if not used yet"
msgstr "使用促销代码的时间戳,如果尚未使用,则留空"
-#: core/models.py:827
+#: core/models.py:1243
msgid "usage timestamp"
msgstr "使用时间戳"
-#: core/models.py:832
+#: core/models.py:1248
msgid "user assigned to this promocode if applicable"
msgstr "分配给此促销代码的用户(如适用"
-#: core/models.py:833
+#: core/models.py:1249
msgid "assigned user"
msgstr "指定用户"
-#: core/models.py:840
+#: core/models.py:1256
msgid "promo code"
msgstr "促销代码"
-#: core/models.py:841
+#: core/models.py:1257
msgid "promo codes"
msgstr "促销代码"
-#: core/models.py:849
+#: core/models.py:1264
msgid ""
"only one type of discount should be defined (amount or percent), but not "
"both or neither."
-msgstr "只能定义一种折扣类型(金额或百分比),而不能同时定义两种类型或两者都不定义。"
+msgstr ""
+"只能定义一种折扣类型(金额或百分比),而不能同时定义两种类型或两者都不定义。"
-#: core/models.py:865
+#: core/models.py:1279
msgid "promocode already used"
msgstr "促销代码已被使用"
-#: core/models.py:882
+#: core/models.py:1295
#, python-brace-format
msgid "invalid discount type for promocode {self.uuid}"
-msgstr "促销代码 {self.uuid} 的折扣类型无效"
+msgstr "促销代码 {self.uuid} 的折扣类型无效!"
-#: core/models.py:898
+#: core/models.py:1331
msgid "the billing address used for this order"
msgstr "该订单使用的账单地址"
-#: core/models.py:906
+#: core/models.py:1339
msgid "optional promo code applied to this order"
msgstr "此订单可选择使用促销代码"
-#: core/models.py:907
+#: core/models.py:1340
msgid "applied promo code"
msgstr "应用促销代码"
-#: core/models.py:915
+#: core/models.py:1348
msgid "the shipping address used for this order"
msgstr "该订单使用的送货地址"
-#: core/models.py:916
+#: core/models.py:1349
msgid "shipping address"
msgstr "送货地址"
-#: core/models.py:922
+#: core/models.py:1355
msgid "current status of the order in its lifecycle"
msgstr "订单在其生命周期中的当前状态"
-#: core/models.py:923
+#: core/models.py:1356
msgid "order status"
msgstr "订单状态"
-#: core/models.py:928 core/models.py:1338
+#: core/models.py:1361 core/models.py:1780
msgid "json structure of notifications to display to users"
msgstr "向用户显示的通知的 JSON 结构,在管理用户界面中使用表格视图"
-#: core/models.py:934
+#: core/models.py:1367
msgid "json representation of order attributes for this order"
msgstr "该订单属性的 JSON 表示形式"
-#: core/models.py:940
+#: core/models.py:1373
msgid "the user who placed the order"
msgstr "下订单的用户"
-#: core/models.py:941
+#: core/models.py:1374
msgid "user"
msgstr "用户"
-#: core/models.py:947
+#: core/models.py:1380
msgid "the timestamp when the order was finalized"
msgstr "订单确定的时间戳"
-#: core/models.py:948
+#: core/models.py:1381
msgid "buy time"
msgstr "购买时间"
-#: core/models.py:955
+#: core/models.py:1388
msgid "a human-readable identifier for the order"
msgstr "订单的人工可读标识符"
-#: core/models.py:956
+#: core/models.py:1389
msgid "human readable id"
msgstr "人类可读 ID"
-#: core/models.py:962
+#: core/models.py:1395
msgid "order"
msgstr "订购"
-#: core/models.py:977
+#: core/models.py:1410
msgid "a user must have only one pending order at a time"
msgstr "用户每次只能有一个挂单!"
-#: core/models.py:1013
+#: core/models.py:1444
msgid "you cannot add products to an order that is not a pending one"
msgstr "您不能向非待处理订单添加产品"
-#: core/models.py:1019
+#: core/models.py:1449
msgid "you cannot add inactive products to order"
msgstr "您不能在订单中添加非活动产品"
-#: core/models.py:1039
+#: core/models.py:1466
msgid "you cannot add more products than available in stock"
msgstr "添加的产品数量不能超过现有库存"
-#: core/models.py:1062 core/models.py:1090 core/models.py:1100
+#: core/models.py:1488 core/models.py:1513 core/models.py:1521
msgid "you cannot remove products from an order that is not a pending one"
msgstr "您不能从非待处理订单中删除产品"
-#: core/models.py:1085
+#: core/models.py:1509
#, python-brace-format
msgid "{name} does not exist with query <{query}>"
-msgstr "查询 <{query}> 时 {name} 不存在"
+msgstr "查询 <{query}> 时,{name} 不存在!"
-#: core/models.py:1123
+#: core/models.py:1541
msgid "promocode does not exist"
msgstr "促销代码不存在"
-#: core/models.py:1134
+#: core/models.py:1547
msgid "you can only buy physical products with shipping address specified"
msgstr "您只能购买指定送货地址的实物产品!"
-#: core/models.py:1155
+#: core/models.py:1566
msgid "address does not exist"
msgstr "地址不存在"
-#: core/models.py:1167 core/models.py:1220
+#: core/models.py:1587 core/models.py:1645
msgid "you can not buy at this moment, please try again in a few minutes"
msgstr "您现在无法购买,请稍后再试。"
-#: core/models.py:1173
+#: core/models.py:1590
msgid "invalid force value"
msgstr "力值无效"
-#: core/models.py:1178 core/models.py:1224
+#: core/models.py:1596 core/models.py:1648
msgid "you cannot purchase an empty order!"
msgstr "您不能购买空单!"
-#: core/models.py:1196
+#: core/models.py:1615
+msgid "you cannot buy an order without a user"
+msgstr "没有用户就无法购买订单!"
+
+#: core/models.py:1618
+msgid "a user without a balance cannot buy with balance"
+msgstr "没有余额的用户不能使用余额购买!"
+
+#: core/models.py:1623
msgid "insufficient funds to complete the order"
msgstr "资金不足,无法完成订单"
-#: core/models.py:1233
+#: core/models.py:1657
msgid ""
"you cannot buy without registration, please provide the following "
"information: customer name, customer email, customer phone number"
msgstr "未经注册不能购买,请提供以下信息:客户姓名、客户电子邮件、客户电话号码"
-#: core/models.py:1244
+#: core/models.py:1666
#, python-brace-format
msgid ""
"invalid payment method: {payment_method} from {available_payment_methods}"
msgstr "付款方式无效:来自 {available_payment_methods} 的 {payment_method} !"
-#: core/models.py:1326
+#: core/models.py:1768
msgid "the price paid by the customer for this product at purchase time"
msgstr "客户购买该产品时支付的价格"
-#: core/models.py:1327
+#: core/models.py:1769
msgid "purchase price at order time"
msgstr "订购时的购买价格"
-#: core/models.py:1332
+#: core/models.py:1774
msgid "internal comments for admins about this ordered product"
msgstr "管理员对该订购产品的内部评论"
-#: core/models.py:1333
+#: core/models.py:1775
msgid "internal comments"
msgstr "内部意见"
-#: core/models.py:1339
+#: core/models.py:1781
msgid "user notifications"
msgstr "用户通知"
-#: core/models.py:1344
+#: core/models.py:1786
msgid "json representation of this item's attributes"
msgstr "该项属性的 JSON 表示形式"
-#: core/models.py:1345
+#: core/models.py:1787
msgid "ordered product attributes"
msgstr "有序的产品属性"
-#: core/models.py:1350
+#: core/models.py:1792
msgid "reference to the parent order that contains this product"
msgstr "对包含该产品的父订单的引用"
-#: core/models.py:1351
+#: core/models.py:1793
msgid "parent order"
msgstr "父顺序"
-#: core/models.py:1360
+#: core/models.py:1802
msgid "the specific product associated with this order line"
msgstr "与该订单项目相关的具体产品"
-#: core/models.py:1367
+#: core/models.py:1809
msgid "quantity of this specific product in the order"
msgstr "订单中该特定产品的数量"
-#: core/models.py:1368
+#: core/models.py:1810
msgid "product quantity"
msgstr "产品数量"
-#: core/models.py:1375
+#: core/models.py:1817
msgid "current status of this product in the order"
msgstr "订单中该产品的当前状态"
-#: core/models.py:1376
+#: core/models.py:1818
msgid "product line status"
msgstr "产品系列状态"
-#: core/models.py:1436
+#: core/models.py:1878
+msgid "order product must have an order"
+msgstr "订单产品必须有相关的订单!"
+
+#: core/models.py:1880
#, python-brace-format
msgid "wrong action specified for feedback: {action}"
-msgstr "为反馈指定了错误的操作:{action}"
+msgstr "为反馈指定了错误的操作:{action}!"
-#: core/models.py:1447
+#: core/models.py:1888
msgid "you cannot feedback an order which is not received"
msgstr "您不能反馈未收到的订单"
-#: core/models.py:1459
+#: core/models.py:1923
msgid "download"
msgstr "下载"
-#: core/models.py:1460
+#: core/models.py:1924
msgid "downloads"
msgstr "下载"
-#: core/models.py:1469
+#: core/models.py:1932
msgid "you can not download a digital asset for a non-finished order"
msgstr "您无法下载未完成订单的数字资产"
-#: core/models.py:1481
+#: core/models.py:1962
msgid "user-provided comments about their experience with the product"
msgstr "用户提供的产品使用体验评论"
-#: core/models.py:1482
+#: core/models.py:1963
msgid "feedback comments"
msgstr "反馈意见"
-#: core/models.py:1490
-msgid ""
-"references the specific product in an order that this feedback is about"
+#: core/models.py:1970
+msgid "references the specific product in an order that this feedback is about"
msgstr "引用该反馈意见涉及的订单中的具体产品"
-#: core/models.py:1492
+#: core/models.py:1971
msgid "related order product"
msgstr "相关订购产品"
-#: core/models.py:1497
+#: core/models.py:1976
msgid "user-assigned rating for the product"
msgstr "用户对产品的评分"
-#: core/models.py:1498
+#: core/models.py:1977
msgid "product rating"
msgstr "产品评级"
-#: core/models.py:1506
+#: core/models.py:1987
msgid "feedback"
msgstr "反馈意见"
@@ -2008,13 +2049,13 @@ msgid ""
"you must provide a comment, rating, and order product uuid to add feedback."
msgstr "您必须提供评论、评级和订单产品 uuid 才能添加反馈。"
-#: core/signals.py:62
+#: core/signals.py:63
msgid "error during promocode creation: {e!s}"
msgstr "创建促销代码时出错:{e!s}"
#: core/templates/digital_order_created_email.html:7
#: core/templates/digital_order_created_email.html:100
-#: core/templates/digital_order_delivered_email.html:7
+#: core/templates/digital_order_delivered_email.html:6
#: core/templates/shipped_order_created_email.html:7
#: core/templates/shipped_order_created_email.html:99
#: core/templates/shipped_order_delivered_email.html:7
@@ -2023,7 +2064,7 @@ msgid "order confirmation"
msgstr "订单确认"
#: core/templates/digital_order_created_email.html:95
-#: core/templates/digital_order_delivered_email.html:95
+#: core/templates/digital_order_delivered_email.html:94
#: core/templates/shipped_order_created_email.html:94
#: core/templates/shipped_order_delivered_email.html:94
msgid "logo"
@@ -2034,25 +2075,28 @@ msgstr "标志"
#: core/templates/shipped_order_delivered_email.html:100
#, python-format
msgid "hello %(order.user.first_name)s,"
-msgstr "您好 %(order.user.first_name)s、"
+msgstr "你好%(order.user.first_name)s_、"
#: core/templates/digital_order_created_email.html:102
#, python-format
msgid ""
"thank you for your order #%(order.pk)s! we are pleased to inform you that\n"
-" we have taken your order into work. below are the details of your\n"
+" we have taken your order into work. below are "
+"the details of your\n"
" order:"
-msgstr "感谢您的订单 #%(order.pk)s!我们很高兴地通知您,我们已将您的订单付诸实施。以下是您的订单详情:"
+msgstr ""
+"感谢您的订单 #%(order.pk)s!我们很高兴地通知您,我们已将您的订单付诸实施。以"
+"下是您的订单详情:"
#: core/templates/digital_order_created_email.html:112
-#: core/templates/digital_order_delivered_email.html:111
+#: core/templates/digital_order_delivered_email.html:110
#: core/templates/shipped_order_created_email.html:110
#: core/templates/shipped_order_delivered_email.html:110
msgid "total"
msgstr "总计"
#: core/templates/digital_order_created_email.html:125
-#: core/templates/digital_order_delivered_email.html:158
+#: core/templates/digital_order_delivered_email.html:157
#: core/templates/shipped_order_created_email.html:127
#: core/templates/shipped_order_delivered_email.html:127
msgid "total price"
@@ -2065,35 +2109,36 @@ msgstr "总价"
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(config.EMAIL_HOST_USER)s."
-msgstr "如果您有任何问题,请随时通过 %(config.EMAIL_HOST_USER)s 联系我们的支持人员。"
+msgstr ""
+"如果您有任何问题,请随时通过 %(config.EMAIL_HOST_USER)s 联系我们的支持人员。"
#: core/templates/digital_order_created_email.html:133
#, python-format
msgid "best regards,
the %(config.PROJECT_NAME)s team"
-msgstr "致以最诚挚的问候,
%(config.PROJECT_NAME)s团队"
+msgstr "致以最诚挚的问候,
%(config.PROJECT_NAME)s_团队"
#: core/templates/digital_order_created_email.html:139
-#: core/templates/digital_order_delivered_email.html:172
+#: core/templates/digital_order_delivered_email.html:171
msgid "all rights reserved"
msgstr "保留所有权利"
-#: core/templates/digital_order_delivered_email.html:100
+#: core/templates/digital_order_delivered_email.html:99
msgid "order delivered"
msgstr "订单已送达"
-#: core/templates/digital_order_delivered_email.html:101
+#: core/templates/digital_order_delivered_email.html:100
#, python-format
msgid "hello %(user_first_name)s,"
-msgstr "您好 %(user_first_name)s、"
+msgstr "你好%(user_first_name)s_、"
-#: core/templates/digital_order_delivered_email.html:102
+#: core/templates/digital_order_delivered_email.html:101
#, python-format
msgid ""
"we have successfully processed your order №%(order_uuid)s! below are the\n"
" details of your order:"
-msgstr "我们已成功处理了您的订单 №%(order_uuid)s_!以下是您的订单详情:"
+msgstr "我们已成功处理您的订单 №%(order_uuid)s_!以下是您的订单详情:"
-#: core/templates/digital_order_delivered_email.html:129
+#: core/templates/digital_order_delivered_email.html:128
msgid ""
"additional\n"
" information"
@@ -2101,22 +2146,22 @@ msgstr ""
"其他\n"
" 附加信息"
-#: core/templates/digital_order_delivered_email.html:138
+#: core/templates/digital_order_delivered_email.html:137
#: core/templates/json_table_widget.html:6
msgid "value"
msgstr "价值"
-#: core/templates/digital_order_delivered_email.html:164
+#: core/templates/digital_order_delivered_email.html:163
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
msgstr "如果您有任何问题,请随时拨打 %(contact_email)s 联系我们的支持人员。"
-#: core/templates/digital_order_delivered_email.html:166
+#: core/templates/digital_order_delivered_email.html:165
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "致以最诚挚的问候,
%(project_name)s团队"
+msgstr "致以最诚挚的问候,
%(project_name)s_团队"
#: core/templates/json_table_widget.html:5
msgid "key"
@@ -2125,7 +2170,8 @@ msgstr "钥匙"
#: core/templates/shipped_order_created_email.html:101
#: core/templates/shipped_order_delivered_email.html:101
msgid ""
-"thank you for your order! we are pleased to confirm your purchase. below are\n"
+"thank you for your order! we are pleased to confirm your purchase. below "
+"are\n"
" the details of your order:"
msgstr "感谢您的订购!我们很高兴确认您的购买。以下是您的订单详情:"
@@ -2143,7 +2189,7 @@ msgstr "您的订单将送至以下地址:"
#: core/templates/shipped_order_delivered_email.html:142
#, python-format
msgid "best regards,
The %(config.PROJECT_NAME)s team"
-msgstr "谨致问候,
%(config.PROJECT_NAME)s团队"
+msgstr "致以最诚挚的问候,
%(config.PROJECT_NAME)s_团队"
#: core/templates/shipped_order_created_email.html:147
#: core/templates/shipped_order_delivered_email.html:147
@@ -2162,30 +2208,20 @@ msgstr "需要数据和超时"
msgid "invalid timeout value, it must be between 0 and 216000 seconds"
msgstr "超时值无效,必须介于 0 和 216000 秒之间"
-#: core/utils/db.py:14
-#, python-brace-format
-msgid "{model} must be model"
-msgstr "{model}必须是模型"
-
-#: core/utils/db.py:16
-#, python-brace-format
-msgid "{data} must be list object"
-msgstr "{data} 必须是列表对象"
-
#: core/utils/emailing.py:21
#, python-brace-format
msgid "{config.PROJECT_NAME} | contact us initiated"
msgstr "{config.PROJECT_NAME}| 联系我们"
-#: core/utils/emailing.py:57
+#: core/utils/emailing.py:60
#, python-brace-format
msgid "{config.PROJECT_NAME} | order confirmation"
-msgstr "{config.PROJECT_NAME} | 订单确认| 订单确认"
+msgstr "{config.PROJECT_NAME}| 订单确认"
-#: core/utils/emailing.py:89
+#: core/utils/emailing.py:95
#, python-brace-format
msgid "{config.PROJECT_NAME} | order delivered"
-msgstr "{config.PROJECT_NAME}(项目名称| 已交付订单"
+msgstr "{config.PROJECT_NAME} | 订单已送达"
#: core/utils/messages.py:3
msgid "you do not have permission to perform this action."
@@ -2198,21 +2234,21 @@ msgstr "必须配置 NOMINATIM_URL 参数!"
#: core/validators.py:16
#, python-brace-format
msgid "image dimensions should not exceed w{max_width} x h{max_height} pixels"
-msgstr "图片尺寸不应超过 w{max_width} x h{max_height} 像素"
+msgstr "图像尺寸不应超过 w{max_width} x h{max_height} 像素!"
#: core/validators.py:22
msgid "invalid phone number format"
msgstr "电话号码格式无效"
-#: core/views.py:266
+#: core/views.py:475
msgid "you can only download the digital asset once"
msgstr "您只能下载一次数字资产"
-#: core/views.py:302
+#: core/views.py:528
msgid "favicon not found"
msgstr "未找到 favicon"
-#: core/viewsets.py:684
+#: core/viewsets.py:1099
#, python-brace-format
msgid "Geocoding error: {e}"
msgstr "地理编码错误:{e}"
diff --git a/core/management/commands/__init__.py b/core/management/commands/__init__.py
index e69de29b..524885a7 100644
--- a/core/management/commands/__init__.py
+++ b/core/management/commands/__init__.py
@@ -0,0 +1,7 @@
+from django.conf import settings
+
+
+class RootDirectory:
+ def __init__(self):
+ self.label = "root"
+ self.path = settings.BASE_DIR / "evibes"
diff --git a/core/management/commands/check_translated.py b/core/management/commands/check_translated.py
index d32dcc14..b7a4683a 100644
--- a/core/management/commands/check_translated.py
+++ b/core/management/commands/check_translated.py
@@ -7,6 +7,8 @@ import polib
from django.apps import apps
from django.core.management.base import BaseCommand, CommandError
+from core.management.commands import RootDirectory
+
# Patterns to identify placeholders
PLACEHOLDER_REGEXES = [
re.compile(r"\{[^}]+"), # {name}, {type(instance)!s}, etc.
@@ -37,7 +39,7 @@ def load_po_sanitized(path: str) -> polib.POFile:
with open(path, encoding="utf-8") as f:
text = f.read()
except OSError as e:
- raise CommandError(f"{path}: cannot read file ({e})")
+ raise CommandError(f"{path}: cannot read file ({e})") from e
# fix fuzzy flags and empty header entries
text = re.sub(r"^#,(?!\s)", "#, ", text, flags=re.MULTILINE)
parts = text.split("\n\n", 1)
@@ -52,7 +54,7 @@ def load_po_sanitized(path: str) -> polib.POFile:
tmp.close()
return polib.pofile(tmp.name)
except Exception as e:
- raise CommandError(f"{path}: syntax error after sanitization ({e})")
+ raise CommandError(f"{path}: syntax error after sanitization ({e})") from e
finally:
with contextlib.suppress(OSError):
os.unlink(tmp.name)
@@ -94,7 +96,11 @@ class Command(BaseCommand):
apps_to_scan: set[str] = set(options["target_apps"])
root_path: str = options.get("root_path") or "/app/"
- for app_conf in apps.get_app_configs():
+ configs = list(apps.get_app_configs())
+ # noinspection PyTypeChecker
+ configs.append(RootDirectory()) # type: ignore [arg-type]
+
+ for app_conf in configs:
if app_conf.label not in apps_to_scan:
continue
diff --git a/core/management/commands/deepl_translate.py b/core/management/commands/deepl_translate.py
index 765a03a5..70f4c9f1 100644
--- a/core/management/commands/deepl_translate.py
+++ b/core/management/commands/deepl_translate.py
@@ -7,6 +7,8 @@ import requests
from django.apps import apps
from django.core.management.base import BaseCommand, CommandError
+from core.management.commands import RootDirectory
+
# Mapping from Django locale codes to DeepL API codes
DEEPL_TARGET_LANGUAGES_MAPPING = {
"en-gb": "EN-GB",
@@ -118,12 +120,18 @@ class Command(BaseCommand):
)
def handle(self, *args, **options) -> None:
- target_langs: list[str] = options["target_languages"]
- target_apps: set[str] = set(options["target_apps"])
+ target_langs = options["target_languages"]
+ target_apps = set(options["target_apps"])
auth_key = os.environ.get("DEEPL_AUTH_KEY")
if not auth_key:
raise CommandError("DEEPL_AUTH_KEY not set")
+ # attempt to import readline for interactive fill
+ try:
+ import readline
+ except ImportError:
+ readline = None # type: ignore [assignment]
+
for target_lang in target_langs:
api_code = DEEPL_TARGET_LANGUAGES_MAPPING.get(target_lang)
if not api_code:
@@ -135,7 +143,9 @@ class Command(BaseCommand):
self.stdout.write(self.style.MIGRATE_HEADING(f"→ Translating into {target_lang}"))
- for app_conf in apps.get_app_configs():
+ configs = list(apps.get_app_configs()) + [RootDirectory()]
+
+ for app_conf in configs:
if app_conf.label not in target_apps:
continue
@@ -146,7 +156,6 @@ class Command(BaseCommand):
self.stdout.write(f"• {app_conf.label}: loading English PO…")
en_po = load_po_sanitized(en_path)
-
if not en_po:
raise CommandError(f"Failed to load en_GB PO for {app_conf.label}")
@@ -154,11 +163,26 @@ class Command(BaseCommand):
if missing:
self.stdout.write(self.style.NOTICE(f"⚠️ {len(missing)} missing in en_GB"))
for e in missing:
- input_msgstr = input(f"Enter translation for '{e.msgid}': ").strip()
- if input_msgstr:
- e.msgstr = input_msgstr
+ default = e.msgid
+ if readline:
+
+ def hook():
+ readline.insert_text(default) # noqa: B023
+ readline.redisplay()
+
+ readline.set_pre_input_hook(hook) # type: ignore [attr-defined]
+
+ prompt = f"Enter translation for '{e.msgid}': "
+ user_in = input(prompt).strip()
+
+ if readline:
+ readline.set_pre_input_hook(None) # type: ignore [attr-defined]
+
+ if user_in:
+ e.msgstr = user_in
else:
e.msgstr = e.msgid
+
en_po.save(en_path)
self.stdout.write(self.style.SUCCESS("Updated en_GB PO"))
@@ -172,13 +196,13 @@ class Command(BaseCommand):
"LC_MESSAGES",
)
os.makedirs(tgt_dir, exist_ok=True)
- tgt_path = os.path.join(tgt_dir, "django.po")
+ tgt_path = os.path.join(str(tgt_dir), "django.po")
old_tgt = None
if os.path.exists(tgt_path):
self.stdout.write(f" loading existing {target_lang} PO…")
try:
- old_tgt = load_po_sanitized(tgt_path)
+ old_tgt = load_po_sanitized(str(tgt_path))
except Exception as e:
self.stdout.write(self.style.WARNING(f"Existing PO parse error({e!s}), starting fresh"))
@@ -207,8 +231,8 @@ class Command(BaseCommand):
protected = []
maps: list[list[str]] = []
- for e in to_trans:
- txt = source_map[e.msgid]
+ for entry in to_trans:
+ txt = source_map[entry.msgid]
p_txt, p_map = placeholderize(txt)
protected.append(p_txt)
maps.append(p_map)
@@ -222,16 +246,16 @@ class Command(BaseCommand):
resp.raise_for_status()
result = resp.json()
except Exception as exc:
- raise CommandError(f"DeepL error: {exc} – {resp.text}")
+ raise CommandError(f"DeepL error: {exc} – {resp.text}") from exc
trans = result.get("translations", [])
if len(trans) != len(to_trans):
raise CommandError(f"Got {len(trans)} translations, expected {len(to_trans)}")
- for e, obj, pmap in zip(to_trans, trans, maps, strict=True):
- e.msgstr = deplaceholderize(obj["text"], pmap)
+ for entry, obj, pmap in zip(to_trans, trans, maps, strict=True):
+ entry.msgstr = deplaceholderize(obj["text"], pmap)
- new_po.save(tgt_path)
+ new_po.save(str(tgt_path))
self.stdout.write(self.style.SUCCESS(f"Saved {tgt_path}"))
self.stdout.write(self.style.SUCCESS("Done."))
diff --git a/core/management/commands/delete_never_ordered_products.py b/core/management/commands/delete_never_ordered_products.py
new file mode 100644
index 00000000..ce15bf30
--- /dev/null
+++ b/core/management/commands/delete_never_ordered_products.py
@@ -0,0 +1,33 @@
+from django.core.management.base import BaseCommand
+
+from core.models import AttributeValue, Product, ProductImage
+
+
+class Command(BaseCommand):
+ help = "Delete Product rows with no OrderProduct, in batches"
+
+ def add_arguments(self, parser):
+ parser.add_argument(
+ "-s",
+ "--size",
+ required=False,
+ default=5000,
+ help="Chunk size to delete",
+ )
+
+ def handle(self, *args, **options):
+ size = options["size"]
+ while True:
+ batch_ids = list(Product.objects.filter(orderproduct__isnull=True).values_list("pk", flat=True)[:size])
+ if not batch_ids:
+ break
+ try:
+ AttributeValue.objects.filter(product_id__in=batch_ids).delete()
+ ProductImage.objects.filter(product_id__in=batch_ids).delete()
+ Product.objects.filter(pk__in=batch_ids).delete()
+ except Exception as e:
+ self.stdout.write("Couldn't delete some of the products(will retry later): %s" % str(e))
+ continue
+ self.stdout.write(f"Deleted {len(batch_ids)} products…")
+
+ self.stdout.write("✅ All unordered products removed.")
diff --git a/core/management/commands/delete_products_by_description.py b/core/management/commands/delete_products_by_description.py
new file mode 100644
index 00000000..ffa66f54
--- /dev/null
+++ b/core/management/commands/delete_products_by_description.py
@@ -0,0 +1,35 @@
+from django.core.management.base import BaseCommand
+
+from core.models import AttributeValue, Product, ProductImage
+
+
+class Command(BaseCommand):
+ help = "Delete Product rows with special description, in batches"
+
+ def add_arguments(self, parser):
+ parser.add_argument(
+ "-s",
+ "--size",
+ required=False,
+ default=5000,
+ help="Chunk size to delete",
+ )
+
+ def handle(self, *args, **options):
+ size = options["size"]
+ while True:
+ batch_ids = list(
+ Product.objects.filter(description__iexact="EVIBES_DELETED_PRODUCT").values_list("pk", flat=True)[:size]
+ )
+ if not batch_ids:
+ break
+ try:
+ AttributeValue.objects.filter(product_id__in=batch_ids).delete()
+ ProductImage.objects.filter(product_id__in=batch_ids).delete()
+ Product.objects.filter(pk__in=batch_ids).delete()
+ except Exception as e:
+ self.stdout.write("Couldn't delete some of the products(will retry later): %s" % str(e))
+ continue
+ self.stdout.write(f"Deleted {len(batch_ids)} products…")
+
+ self.stdout.write("✅ All unordered products removed.")
diff --git a/core/management/commands/fix_fuzzy.py b/core/management/commands/fix_fuzzy.py
index ce047e32..f0d5af60 100644
--- a/core/management/commands/fix_fuzzy.py
+++ b/core/management/commands/fix_fuzzy.py
@@ -52,12 +52,22 @@ class Command(BaseCommand):
new_lines.append("\n")
continue
- fuzzy_idx = next((i for i, line in enumerate(ent) if line.startswith("#,") and "fuzzy" in line), None)
+ if any(
+ line.startswith("#~") or (line.startswith("#,") and line.lstrip("#, ").startswith("msgid "))
+ for line in ent
+ ):
+ changed = True
+ continue
+
+ fuzzy_idx = next(
+ (i for i, line in enumerate(ent) if line.startswith("#,") and "fuzzy" in line),
+ None,
+ )
+
if fuzzy_idx is not None:
- flag_line = ent[fuzzy_idx]
- remaining = [f.strip() for f in flag_line[2:].split(",") if f.strip() != "fuzzy"]
- if remaining:
- ent[fuzzy_idx] = "#, " + ", ".join(remaining) + "\n"
+ flags = [f.strip() for f in ent[fuzzy_idx][2:].split(",") if f.strip() != "fuzzy"]
+ if flags:
+ ent[fuzzy_idx] = "#, " + ", ".join(flags) + "\n"
else:
del ent[fuzzy_idx]
@@ -75,4 +85,4 @@ class Command(BaseCommand):
f.writelines(new_lines)
self.stdout.write(self.style.SUCCESS(f" → Updated {filepath}"))
else:
- self.stdout.write(" (no fuzzy entries found)")
+ self.stdout.write(" (no changes)")
diff --git a/core/management/commands/fix_prices.py b/core/management/commands/fix_prices.py
index 2a27fd72..6a077690 100644
--- a/core/management/commands/fix_prices.py
+++ b/core/management/commands/fix_prices.py
@@ -5,7 +5,7 @@ from django.core.management.base import BaseCommand
from core.models import Product
from core.vendors import AbstractVendor
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
class Command(BaseCommand):
@@ -15,7 +15,7 @@ class Command(BaseCommand):
for product in Product.objects.filter(stocks__isnull=False):
for stock in product.stocks.all():
try:
- stock.price = AbstractVendor.round_price_marketologically(stock.price) # type: ignore
+ stock.price = AbstractVendor.round_price_marketologically(stock.price)
stock.save()
except Exception as e:
self.stdout.write(self.style.WARNING(f"Couldn't fix price on {stock.uuid}"))
diff --git a/core/management/commands/translate_fields.py b/core/management/commands/translate_fields.py
index d431ec81..53538b4f 100644
--- a/core/management/commands/translate_fields.py
+++ b/core/management/commands/translate_fields.py
@@ -61,16 +61,16 @@ class Command(BaseCommand):
try:
module_path, model_name, field_name = target.rsplit(".", 2)
- except ValueError:
+ except ValueError as e:
raise CommandError(
"Invalid target format. Use app.module.Model.field, e.g. core.models.Product.description"
- )
+ ) from e
try:
module = importlib.import_module(module_path)
model = getattr(module, model_name)
except (ImportError, AttributeError) as e:
- raise CommandError(f"Could not import model '{model_name}' from '{module_path}': {e}")
+ raise CommandError(f"Could not import model '{model_name}' from '{module_path}': {e}") from e
dest_suffix = lang.replace("-", "_")
dest_field = f"{field_name}_{dest_suffix}"
diff --git a/core/managers.py b/core/managers.py
index e1978732..3ee4b579 100644
--- a/core/managers.py
+++ b/core/managers.py
@@ -5,24 +5,24 @@ from constance import config
from django.contrib.gis.geos import Point
from django.db import models
-logger = logging.getLogger("django.request")
+logger = logging.getLogger("django")
class AddressManager(models.Manager):
- def create(self, raw_data: str, **kwargs): # type: ignore
- if not raw_data:
+ def create(self, **kwargs):
+ if not kwargs.get("raw_data"):
raise ValueError("'raw_data' (address string) must be provided.")
- params: dict[str, str | int] = {
+ params: dict[str, str | int] = { # type: ignore [annotation-unchecked]
"format": "json",
"addressdetails": 1,
- "q": raw_data,
+ "q": kwargs.get("raw_data"),
}
resp = requests.get(config.NOMINATIM_URL.rstrip("/") + "/search", params=params)
resp.raise_for_status()
results = resp.json()
if not results:
- raise ValueError(f"No geocoding result for address: {raw_data}")
+ raise ValueError(f"No geocoding result for address: {kwargs.get('raw_data')}")
data = results[0]
addr = data.get("address", {})
@@ -51,7 +51,7 @@ class AddressManager(models.Manager):
address_line_2 = ""
return super().get_or_create(
- raw_data=raw_data,
+ raw_data=kwargs.get("raw_data"),
address_line=f"{address_line_1}, {address_line_2}",
street=street,
district=district,
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
index 657d41f1..ddfced4c 100644
--- a/core/migrations/0001_initial.py
+++ b/core/migrations/0001_initial.py
@@ -17,980 +17,2693 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
- name='Feedback',
+ name="Feedback",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('comment', models.TextField(blank=True,
- help_text='user-provided comments about their experience with the product',
- null=True, verbose_name='feedback comments')),
- ('rating', models.FloatField(blank=True, help_text='user-assigned rating for the product', null=True,
- validators=[django.core.validators.MinValueValidator(0),
- django.core.validators.MaxValueValidator(10)],
- verbose_name='product rating')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "comment",
+ models.TextField(
+ blank=True,
+ help_text="user-provided comments about their experience with the product",
+ null=True,
+ verbose_name="feedback comments",
+ ),
+ ),
+ (
+ "rating",
+ models.FloatField(
+ blank=True,
+ help_text="user-assigned rating for the product",
+ null=True,
+ validators=[
+ django.core.validators.MinValueValidator(0),
+ django.core.validators.MaxValueValidator(10),
+ ],
+ verbose_name="product rating",
+ ),
+ ),
],
options={
- 'verbose_name': 'feedback',
- 'verbose_name_plural': 'feedbacks',
+ "verbose_name": "feedback",
+ "verbose_name_plural": "feedbacks",
},
),
migrations.CreateModel(
- name='OrderProduct',
+ name="OrderProduct",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('buy_price', models.FloatField(blank=True,
- help_text='the price paid by the customer for this product at purchase time',
- null=True, verbose_name='purchase price at order time')),
- ('comments',
- models.TextField(blank=True, help_text='internal comments for admins about this ordered product',
- null=True, verbose_name='internal comments')),
- ('notifications',
- models.JSONField(blank=True, help_text='json structure of notifications to display to users',
- null=True, verbose_name='user notifications')),
- ('attributes',
- models.JSONField(blank=True, help_text="json representation of this item's attributes", null=True,
- verbose_name='ordered product attributes')),
- ('quantity',
- models.PositiveIntegerField(default=1, help_text='quantity of this specific product in the order',
- verbose_name='product quantity')),
- ('status', models.CharField(
- choices=[('FINISHED', 'finished'), ('DELIVERING', 'delivering'), ('DELIVERED', 'delivered'),
- ('CANCELED', 'canceled'), ('FAILED', 'failed'), ('PENDING', 'pending'),
- ('ACCEPTED', 'accepted'), ('RETURNED', 'money returned')], default='PENDING',
- help_text='current status of this product in the order', max_length=128,
- verbose_name='product line status')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "buy_price",
+ models.FloatField(
+ blank=True,
+ help_text="the price paid by the customer for this product at purchase time",
+ null=True,
+ verbose_name="purchase price at order time",
+ ),
+ ),
+ (
+ "comments",
+ models.TextField(
+ blank=True,
+ help_text="internal comments for admins about this ordered product",
+ null=True,
+ verbose_name="internal comments",
+ ),
+ ),
+ (
+ "notifications",
+ models.JSONField(
+ blank=True,
+ help_text="json structure of notifications to display to users",
+ null=True,
+ verbose_name="user notifications",
+ ),
+ ),
+ (
+ "attributes",
+ models.JSONField(
+ blank=True,
+ help_text="json representation of this item's attributes",
+ null=True,
+ verbose_name="ordered product attributes",
+ ),
+ ),
+ (
+ "quantity",
+ models.PositiveIntegerField(
+ default=1,
+ help_text="quantity of this specific product in the order",
+ verbose_name="product quantity",
+ ),
+ ),
+ (
+ "status",
+ models.CharField(
+ choices=[
+ ("FINISHED", "finished"),
+ ("DELIVERING", "delivering"),
+ ("DELIVERED", "delivered"),
+ ("CANCELED", "canceled"),
+ ("FAILED", "failed"),
+ ("PENDING", "pending"),
+ ("ACCEPTED", "accepted"),
+ ("RETURNED", "money returned"),
+ ],
+ default="PENDING",
+ help_text="current status of this product in the order",
+ max_length=128,
+ verbose_name="product line status",
+ ),
+ ),
],
options={
- 'verbose_name': 'order product',
- 'verbose_name_plural': 'order products',
+ "verbose_name": "order product",
+ "verbose_name_plural": "order products",
},
),
migrations.CreateModel(
- name='Product',
+ name="Product",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('is_digital',
- models.BooleanField(default=False, help_text='indicates whether this product is digitally delivered',
- verbose_name='is product digital')),
- ('name', models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- verbose_name='product name')),
- ('name_en_GB',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_ar_AR',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_cs_CZ',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_da_DK',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_de_DE',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_en_US',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_es_ES',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_fr_FR',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_hi_IN',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_it_IT',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_ja_JP',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_kk_KZ',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_nl_NL',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_pl_PL',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_pt_BR',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_ro_RO',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_ru_RU',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('name_zh_hans',
- models.CharField(help_text='provide a clear identifying name for the product', max_length=255,
- null=True, verbose_name='product name')),
- ('description',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_en_GB',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_ar_AR',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_cs_CZ',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_da_DK',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_de_DE',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_en_US',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_es_ES',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_fr_FR',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_hi_IN',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_it_IT',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_ja_JP',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_kk_KZ',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_nl_NL',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_pl_PL',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_pt_BR',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_ro_RO',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_ru_RU',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
- ('description_zh_hans',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='product description')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "is_digital",
+ models.BooleanField(
+ default=False,
+ help_text="indicates whether this product is digitally delivered",
+ verbose_name="is product digital",
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_en_GB",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_ar_AR",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_cs_CZ",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_da_DK",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_de_DE",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_en_US",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_es_ES",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_fr_FR",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_hi_IN",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_it_IT",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_ja_JP",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_kk_KZ",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_nl_NL",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_pl_PL",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_pt_BR",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_ro_RO",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_ru_RU",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "name_zh_hans",
+ models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
+ ),
+ (
+ "description",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_en_GB",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_ar_AR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_cs_CZ",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_da_DK",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_de_DE",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_en_US",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_es_ES",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_fr_FR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_hi_IN",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_it_IT",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_ja_JP",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_kk_KZ",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_nl_NL",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_pl_PL",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_pt_BR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_ro_RO",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_ru_RU",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
+ (
+ "description_zh_hans",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="product description",
+ ),
+ ),
],
options={
- 'verbose_name': 'product',
- 'verbose_name_plural': 'products',
+ "verbose_name": "product",
+ "verbose_name_plural": "products",
},
),
migrations.CreateModel(
- name='ProductImage',
+ name="ProductImage",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('alt',
- models.CharField(help_text='provide alternative text for the image for accessibility', max_length=255,
- verbose_name='image alt text')),
- ('image', models.ImageField(help_text='upload the image file for this product',
- upload_to=core.utils.get_product_uuid_as_path,
- verbose_name='product image')),
- ('priority',
- models.IntegerField(default=1, help_text='determines the order in which images are displayed',
- validators=[django.core.validators.MinValueValidator(1)],
- verbose_name='display priority')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "alt",
+ models.CharField(
+ help_text="provide alternative text for the image for accessibility",
+ max_length=255,
+ verbose_name="image alt text",
+ ),
+ ),
+ (
+ "image",
+ models.ImageField(
+ help_text="upload the image file for this product",
+ upload_to=core.utils.get_product_uuid_as_path,
+ verbose_name="product image",
+ ),
+ ),
+ (
+ "priority",
+ models.IntegerField(
+ default=1,
+ help_text="determines the order in which images are displayed",
+ validators=[django.core.validators.MinValueValidator(1)],
+ verbose_name="display priority",
+ ),
+ ),
],
options={
- 'verbose_name': 'product image',
- 'verbose_name_plural': 'product images',
- 'ordering': ('priority',),
+ "verbose_name": "product image",
+ "verbose_name_plural": "product images",
+ "ordering": ("priority",),
},
),
migrations.CreateModel(
- name='ProductTag',
+ name="ProductTag",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('tag_name', models.CharField(help_text='internal tag identifier for the product tag', max_length=255,
- verbose_name='tag name')),
- ('name', models.CharField(help_text='user-friendly name for the product tag', max_length=255,
- verbose_name='tag display name')),
- ('name_en_GB',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_ar_AR',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_cs_CZ',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_da_DK',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_de_DE',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_en_US',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_es_ES',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_fr_FR',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_hi_IN',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_it_IT',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_ja_JP',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_kk_KZ',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_nl_NL',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_pl_PL',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_pt_BR',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_ro_RO',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_ru_RU',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
- ('name_zh_hans',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- verbose_name='tag display name')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "tag_name",
+ models.CharField(
+ help_text="internal tag identifier for the product tag", max_length=255, verbose_name="tag name"
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_en_GB",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ar_AR",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_cs_CZ",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_da_DK",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_de_DE",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_en_US",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_es_ES",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_fr_FR",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_hi_IN",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_it_IT",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ja_JP",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_kk_KZ",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_nl_NL",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_pl_PL",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_pt_BR",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ro_RO",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ru_RU",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_zh_hans",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ verbose_name="tag display name",
+ ),
+ ),
],
options={
- 'verbose_name': 'product tag',
- 'verbose_name_plural': 'product tags',
+ "verbose_name": "product tag",
+ "verbose_name_plural": "product tags",
},
),
migrations.CreateModel(
- name='PromoCode',
+ name="PromoCode",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('code', models.CharField(default=core.utils.get_random_code,
- help_text='unique code used by a user to redeem a discount', max_length=20,
- unique=True, verbose_name='promo code identifier')),
- ('discount_amount', models.DecimalField(blank=True, decimal_places=2,
- help_text='fixed discount amount applied if percent is not used',
- max_digits=10, null=True,
- verbose_name='fixed discount amount')),
- ('discount_percent',
- models.IntegerField(blank=True, help_text='percentage discount applied if fixed amount is not used',
- null=True, validators=[django.core.validators.MinValueValidator(1),
- django.core.validators.MaxValueValidator(100)],
- verbose_name='percentage discount')),
- ('end_time',
- models.DateTimeField(blank=True, help_text='timestamp when the promocode expires', null=True,
- verbose_name='end validity time')),
- ('start_time',
- models.DateTimeField(blank=True, help_text='timestamp from which this promocode is valid', null=True,
- verbose_name='start validity time')),
- ('used_on', models.DateTimeField(blank=True,
- help_text='timestamp when the promocode was used, blank if not used yet',
- null=True, verbose_name='usage timestamp')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "code",
+ models.CharField(
+ default=core.utils.get_random_code,
+ help_text="unique code used by a user to redeem a discount",
+ max_length=20,
+ unique=True,
+ verbose_name="promo code identifier",
+ ),
+ ),
+ (
+ "discount_amount",
+ models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ help_text="fixed discount amount applied if percent is not used",
+ max_digits=10,
+ null=True,
+ verbose_name="fixed discount amount",
+ ),
+ ),
+ (
+ "discount_percent",
+ models.IntegerField(
+ blank=True,
+ help_text="percentage discount applied if fixed amount is not used",
+ null=True,
+ validators=[
+ django.core.validators.MinValueValidator(1),
+ django.core.validators.MaxValueValidator(100),
+ ],
+ verbose_name="percentage discount",
+ ),
+ ),
+ (
+ "end_time",
+ models.DateTimeField(
+ blank=True,
+ help_text="timestamp when the promocode expires",
+ null=True,
+ verbose_name="end validity time",
+ ),
+ ),
+ (
+ "start_time",
+ models.DateTimeField(
+ blank=True,
+ help_text="timestamp from which this promocode is valid",
+ null=True,
+ verbose_name="start validity time",
+ ),
+ ),
+ (
+ "used_on",
+ models.DateTimeField(
+ blank=True,
+ help_text="timestamp when the promocode was used, blank if not used yet",
+ null=True,
+ verbose_name="usage timestamp",
+ ),
+ ),
],
options={
- 'verbose_name': 'promo code',
- 'verbose_name_plural': 'promo codes',
+ "verbose_name": "promo code",
+ "verbose_name_plural": "promo codes",
},
),
migrations.CreateModel(
- name='Promotion',
+ name="Promotion",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('discount_percent', models.IntegerField(help_text='percentage discount for the selected products',
- validators=[django.core.validators.MinValueValidator(1),
- django.core.validators.MaxValueValidator(100)],
- verbose_name='discount percentage')),
- ('name',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, unique=True,
- verbose_name='promotion name')),
- ('name_en_GB',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_ar_AR',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_cs_CZ',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_da_DK',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_de_DE',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_en_US',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_es_ES',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_fr_FR',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_hi_IN',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_it_IT',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_ja_JP',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_kk_KZ',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_nl_NL',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_pl_PL',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_pt_BR',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_ro_RO',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_ru_RU',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('name_zh_hans',
- models.CharField(help_text='provide a unique name for this promotion', max_length=256, null=True,
- unique=True, verbose_name='promotion name')),
- ('description',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_en_GB',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_ar_AR',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_cs_CZ',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_da_DK',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_de_DE',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_en_US',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_es_ES',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_fr_FR',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_hi_IN',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_it_IT',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_ja_JP',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_kk_KZ',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_nl_NL',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_pl_PL',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_pt_BR',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_ro_RO',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_ru_RU',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
- ('description_zh_hans',
- models.TextField(blank=True, help_text='add a detailed description of the product', null=True,
- verbose_name='promotion description')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "discount_percent",
+ models.IntegerField(
+ help_text="percentage discount for the selected products",
+ validators=[
+ django.core.validators.MinValueValidator(1),
+ django.core.validators.MaxValueValidator(100),
+ ],
+ verbose_name="discount percentage",
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_en_GB",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_ar_AR",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_cs_CZ",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_da_DK",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_de_DE",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_en_US",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_es_ES",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_fr_FR",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_hi_IN",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_it_IT",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_ja_JP",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_kk_KZ",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_nl_NL",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_pl_PL",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_pt_BR",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_ro_RO",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_ru_RU",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "name_zh_hans",
+ models.CharField(
+ help_text="provide a unique name for this promotion",
+ max_length=256,
+ null=True,
+ unique=True,
+ verbose_name="promotion name",
+ ),
+ ),
+ (
+ "description",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_en_GB",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_ar_AR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_cs_CZ",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_da_DK",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_de_DE",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_en_US",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_es_ES",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_fr_FR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_hi_IN",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_it_IT",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_ja_JP",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_kk_KZ",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_nl_NL",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_pl_PL",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_pt_BR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_ro_RO",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_ru_RU",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
+ (
+ "description_zh_hans",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description of the product",
+ null=True,
+ verbose_name="promotion description",
+ ),
+ ),
],
options={
- 'verbose_name': 'promotion',
- 'verbose_name_plural': 'promotions',
+ "verbose_name": "promotion",
+ "verbose_name_plural": "promotions",
},
),
migrations.CreateModel(
- name='Stock',
+ name="Stock",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('price', models.FloatField(default=0.0, help_text='final price to the customer after markups',
- verbose_name='selling price')),
- ('purchase_price',
- models.FloatField(default=0.0, help_text='the price paid to the vendor for this product',
- verbose_name='vendor purchase price')),
- ('quantity', models.IntegerField(default=0, help_text='available quantity of the product in stock',
- verbose_name='quantity in stock')),
- ('sku', models.CharField(help_text='vendor-assigned SKU for identifying the product', max_length=255,
- verbose_name='vendor sku')),
- ('digital_asset', models.FileField(blank=True, default=None,
- help_text='digital file associated with this stock if applicable',
- null=True, upload_to='downloadables/', verbose_name='digital file')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "price",
+ models.FloatField(
+ default=0.0, help_text="final price to the customer after markups", verbose_name="selling price"
+ ),
+ ),
+ (
+ "purchase_price",
+ models.FloatField(
+ default=0.0,
+ help_text="the price paid to the vendor for this product",
+ verbose_name="vendor purchase price",
+ ),
+ ),
+ (
+ "quantity",
+ models.IntegerField(
+ default=0,
+ help_text="available quantity of the product in stock",
+ verbose_name="quantity in stock",
+ ),
+ ),
+ (
+ "sku",
+ models.CharField(
+ help_text="vendor-assigned SKU for identifying the product",
+ max_length=255,
+ verbose_name="vendor sku",
+ ),
+ ),
+ (
+ "digital_asset",
+ models.FileField(
+ blank=True,
+ default=None,
+ help_text="digital file associated with this stock if applicable",
+ null=True,
+ upload_to="downloadables/",
+ verbose_name="digital file",
+ ),
+ ),
],
options={
- 'verbose_name': 'stock',
- 'verbose_name_plural': 'stock entries',
+ "verbose_name": "stock",
+ "verbose_name_plural": "stock entries",
},
),
migrations.CreateModel(
- name='Vendor',
+ name="Vendor",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('authentication', models.JSONField(blank=True,
- help_text='stores credentials and endpoints required for vendor communication',
- null=True, verbose_name='authentication info')),
- ('markup_percent',
- models.IntegerField(default=0, help_text='define the markup for products retrieved from this vendor',
- validators=[django.core.validators.MinValueValidator(0),
- django.core.validators.MaxValueValidator(100)],
- verbose_name='vendor markup percentage')),
- ('name', models.CharField(help_text='name of this vendor', max_length=255, verbose_name='vendor name')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "authentication",
+ models.JSONField(
+ blank=True,
+ help_text="stores credentials and endpoints required for vendor communication",
+ null=True,
+ verbose_name="authentication info",
+ ),
+ ),
+ (
+ "markup_percent",
+ models.IntegerField(
+ default=0,
+ help_text="define the markup for products retrieved from this vendor",
+ validators=[
+ django.core.validators.MinValueValidator(0),
+ django.core.validators.MaxValueValidator(100),
+ ],
+ verbose_name="vendor markup percentage",
+ ),
+ ),
+ ("name", models.CharField(help_text="name of this vendor", max_length=255, verbose_name="vendor name")),
],
options={
- 'verbose_name': 'vendor',
- 'verbose_name_plural': 'vendors',
+ "verbose_name": "vendor",
+ "verbose_name_plural": "vendors",
},
),
migrations.CreateModel(
- name='Wishlist',
+ name="Wishlist",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
],
options={
- 'verbose_name': 'wishlist',
- 'verbose_name_plural': 'wishlists',
+ "verbose_name": "wishlist",
+ "verbose_name_plural": "wishlists",
},
),
migrations.CreateModel(
- name='AttributeGroup',
+ name="AttributeGroup",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('name', models.CharField(help_text="attribute group's name", max_length=255,
- verbose_name="attribute group's name")),
- ('name_en_GB', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_ar_AR', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_cs_CZ', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_da_DK', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_de_DE', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_en_US', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_es_ES', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_fr_FR', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_hi_IN', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_it_IT', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_ja_JP', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_kk_KZ', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_nl_NL', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_pl_PL', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_pt_BR', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_ro_RO', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_ru_RU', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('name_zh_hans', models.CharField(help_text="attribute group's name", max_length=255, null=True,
- verbose_name="attribute group's name")),
- ('parent', models.ForeignKey(blank=True, help_text='parent of this group', null=True,
- on_delete=django.db.models.deletion.CASCADE, related_name='children',
- to='core.attributegroup', verbose_name='parent attribute group')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="attribute group's name", max_length=255, verbose_name="attribute group's name"
+ ),
+ ),
+ (
+ "name_en_GB",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_ar_AR",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_cs_CZ",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_da_DK",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_de_DE",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_en_US",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_es_ES",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_fr_FR",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_hi_IN",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_it_IT",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_ja_JP",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_kk_KZ",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_nl_NL",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_pl_PL",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_pt_BR",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_ro_RO",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_ru_RU",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "name_zh_hans",
+ models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ (
+ "parent",
+ models.ForeignKey(
+ blank=True,
+ help_text="parent of this group",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="children",
+ to="core.attributegroup",
+ verbose_name="parent attribute group",
+ ),
+ ),
],
options={
- 'verbose_name': 'attribute group',
- 'verbose_name_plural': 'attribute groups',
+ "verbose_name": "attribute group",
+ "verbose_name_plural": "attribute groups",
},
),
migrations.CreateModel(
- name='Attribute',
+ name="Attribute",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('value_type', models.CharField(
- choices=[('string', 'string'), ('integer', 'integer'), ('float', 'float'), ('boolean', 'boolean'),
- ('array', 'array'), ('object', 'object')], help_text="type of the attribute's value",
- max_length=50, verbose_name='value type')),
- ('name',
- models.CharField(help_text='name of this attribute', max_length=255, verbose_name="attribute's name")),
- ('name_en_GB', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_ar_AR', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_cs_CZ', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_da_DK', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_de_DE', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_en_US', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_es_ES', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_fr_FR', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_hi_IN', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_it_IT', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_ja_JP', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_kk_KZ', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_nl_NL', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_pl_PL', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_pt_BR', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_ro_RO', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_ru_RU', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('name_zh_hans', models.CharField(help_text='name of this attribute', max_length=255, null=True,
- verbose_name="attribute's name")),
- ('group',
- models.ForeignKey(help_text='group of this attribute', on_delete=django.db.models.deletion.CASCADE,
- related_name='attributes', to='core.attributegroup',
- verbose_name='attribute group')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "value_type",
+ models.CharField(
+ choices=[
+ ("string", "string"),
+ ("integer", "integer"),
+ ("float", "float"),
+ ("boolean", "boolean"),
+ ("array", "array"),
+ ("object", "object"),
+ ],
+ help_text="type of the attribute's value",
+ max_length=50,
+ verbose_name="value type",
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_en_GB",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_ar_AR",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_cs_CZ",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_da_DK",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_de_DE",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_en_US",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_es_ES",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_fr_FR",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_hi_IN",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_it_IT",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_ja_JP",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_kk_KZ",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_nl_NL",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_pl_PL",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_pt_BR",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_ro_RO",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_ru_RU",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "name_zh_hans",
+ models.CharField(
+ help_text="name of this attribute", max_length=255, null=True, verbose_name="attribute's name"
+ ),
+ ),
+ (
+ "group",
+ models.ForeignKey(
+ help_text="group of this attribute",
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="attributes",
+ to="core.attributegroup",
+ verbose_name="attribute group",
+ ),
+ ),
],
options={
- 'verbose_name': 'attribute',
- 'verbose_name_plural': 'attributes',
+ "verbose_name": "attribute",
+ "verbose_name_plural": "attributes",
},
),
migrations.CreateModel(
- name='AttributeValue',
+ name="AttributeValue",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('value',
- models.TextField(help_text='the specific value for this attribute', verbose_name='attribute value')),
- ('value_en_GB', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_ar_AR', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_cs_CZ', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_da_DK', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_de_DE', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_en_US', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_es_ES', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_fr_FR', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_hi_IN', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_it_IT', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_ja_JP', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_kk_KZ', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_nl_NL', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_pl_PL', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_pt_BR', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_ro_RO', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_ru_RU', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('value_zh_hans', models.TextField(help_text='the specific value for this attribute', null=True,
- verbose_name='attribute value')),
- ('attribute',
- models.ForeignKey(help_text='attribute of this value', on_delete=django.db.models.deletion.CASCADE,
- related_name='values', to='core.attribute', verbose_name='attribute')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "value",
+ models.TextField(help_text="the specific value for this attribute", verbose_name="attribute value"),
+ ),
+ (
+ "value_en_GB",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_ar_AR",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_cs_CZ",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_da_DK",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_de_DE",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_en_US",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_es_ES",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_fr_FR",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_hi_IN",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_it_IT",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_ja_JP",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_kk_KZ",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_nl_NL",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_pl_PL",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_pt_BR",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_ro_RO",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_ru_RU",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "value_zh_hans",
+ models.TextField(
+ help_text="the specific value for this attribute", null=True, verbose_name="attribute value"
+ ),
+ ),
+ (
+ "attribute",
+ models.ForeignKey(
+ help_text="attribute of this value",
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="values",
+ to="core.attribute",
+ verbose_name="attribute",
+ ),
+ ),
],
options={
- 'verbose_name': 'attribute value',
- 'verbose_name_plural': 'attribute values',
+ "verbose_name": "attribute value",
+ "verbose_name_plural": "attribute values",
},
),
migrations.CreateModel(
- name='Category',
+ name="Category",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('image', models.ImageField(help_text='upload an image representing this category', null=True,
- upload_to='categories/',
- validators=[core.validators.validate_category_image_dimensions],
- verbose_name='category image')),
- ('markup_percent',
- models.IntegerField(default=0, help_text='define a markup percentage for products in this category',
- validators=[django.core.validators.MinValueValidator(0),
- django.core.validators.MaxValueValidator(100)],
- verbose_name='markup percentage')),
- ('name', models.CharField(help_text='provide a name for this category', max_length=255,
- verbose_name='category name')),
- ('name_en_GB', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_ar_AR', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_cs_CZ', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_da_DK', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_de_DE', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_en_US', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_es_ES', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_fr_FR', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_hi_IN', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_it_IT', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_ja_JP', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_kk_KZ', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_nl_NL', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_pl_PL', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_pt_BR', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_ro_RO', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_ru_RU', models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('name_zh_hans',
- models.CharField(help_text='provide a name for this category', max_length=255, null=True,
- verbose_name='category name')),
- ('description',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_en_GB',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_ar_AR',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_cs_CZ',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_da_DK',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_de_DE',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_en_US',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_es_ES',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_fr_FR',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_hi_IN',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_it_IT',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_ja_JP',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_kk_KZ',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_nl_NL',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_pl_PL',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_pt_BR',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_ro_RO',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_ru_RU',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('description_zh_hans',
- models.TextField(blank=True, help_text='add a detailed description for this category', null=True,
- verbose_name='category description')),
- ('lft', models.PositiveIntegerField(editable=False)),
- ('rght', models.PositiveIntegerField(editable=False)),
- ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
- ('level', models.PositiveIntegerField(editable=False)),
- ('parent', mptt.fields.TreeForeignKey(blank=True,
- help_text='parent of this category to form a hierarchical structure',
- null=True, on_delete=django.db.models.deletion.CASCADE,
- related_name='children', to='core.category',
- verbose_name='parent category')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "image",
+ models.ImageField(
+ help_text="upload an image representing this category",
+ null=True,
+ upload_to="categories/",
+ validators=[core.validators.validate_category_image_dimensions],
+ verbose_name="category image",
+ ),
+ ),
+ (
+ "markup_percent",
+ models.IntegerField(
+ default=0,
+ help_text="define a markup percentage for products in this category",
+ validators=[
+ django.core.validators.MinValueValidator(0),
+ django.core.validators.MaxValueValidator(100),
+ ],
+ verbose_name="markup percentage",
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="provide a name for this category", max_length=255, verbose_name="category name"
+ ),
+ ),
+ (
+ "name_en_GB",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_ar_AR",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_cs_CZ",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_da_DK",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_de_DE",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_en_US",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_es_ES",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_fr_FR",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_hi_IN",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_it_IT",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_ja_JP",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_kk_KZ",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_nl_NL",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_pl_PL",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_pt_BR",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_ro_RO",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_ru_RU",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "name_zh_hans",
+ models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ verbose_name="category name",
+ ),
+ ),
+ (
+ "description",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_en_GB",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_ar_AR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_cs_CZ",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_da_DK",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_de_DE",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_en_US",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_es_ES",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_fr_FR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_hi_IN",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_it_IT",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_ja_JP",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_kk_KZ",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_nl_NL",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_pl_PL",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_pt_BR",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_ro_RO",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_ru_RU",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ (
+ "description_zh_hans",
+ models.TextField(
+ blank=True,
+ help_text="add a detailed description for this category",
+ null=True,
+ verbose_name="category description",
+ ),
+ ),
+ ("lft", models.PositiveIntegerField(editable=False)),
+ ("rght", models.PositiveIntegerField(editable=False)),
+ ("tree_id", models.PositiveIntegerField(db_index=True, editable=False)),
+ ("level", models.PositiveIntegerField(editable=False)),
+ (
+ "parent",
+ mptt.fields.TreeForeignKey(
+ blank=True,
+ help_text="parent of this category to form a hierarchical structure",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="children",
+ to="core.category",
+ verbose_name="parent category",
+ ),
+ ),
],
options={
- 'verbose_name': 'category',
- 'verbose_name_plural': 'categories',
- 'ordering': ['tree_id', 'lft'],
+ "verbose_name": "category",
+ "verbose_name_plural": "categories",
+ "ordering": ["tree_id", "lft"],
},
),
migrations.CreateModel(
- name='Brand',
+ name="Brand",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('name', models.CharField(help_text='name of this brand', max_length=255, verbose_name='brand name')),
- ('category',
- models.ForeignKey(blank=True, help_text='optional category that this brand is associated with',
- null=True, on_delete=django.db.models.deletion.PROTECT, to='core.category',
- verbose_name='associated category')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ ("name", models.CharField(help_text="name of this brand", max_length=255, verbose_name="brand name")),
+ (
+ "category",
+ models.ForeignKey(
+ blank=True,
+ help_text="optional category that this brand is associated with",
+ null=True,
+ on_delete=django.db.models.deletion.PROTECT,
+ to="core.category",
+ verbose_name="associated category",
+ ),
+ ),
],
options={
- 'verbose_name': 'brand',
- 'verbose_name_plural': 'brands',
+ "verbose_name": "brand",
+ "verbose_name_plural": "brands",
},
),
migrations.AddField(
- model_name='attribute',
- name='categories',
- field=models.ManyToManyField(help_text='category of this attribute', related_name='attributes',
- to='core.category', verbose_name='categories'),
+ model_name="attribute",
+ name="categories",
+ field=models.ManyToManyField(
+ help_text="category of this attribute",
+ related_name="attributes",
+ to="core.category",
+ verbose_name="categories",
+ ),
),
migrations.CreateModel(
- name='Order',
+ name="Order",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('status', models.CharField(
- choices=[('PENDING', 'pending'), ('FAILED', 'failed'), ('PAYMENT', 'payment'),
- ('CREATED', 'created'), ('DELIVERING', 'delivering'), ('FINISHED', 'finished')],
- default='PENDING', help_text='current status of the order in its lifecycle', max_length=64,
- verbose_name='order status')),
- ('notifications',
- models.JSONField(blank=True, help_text='json structure of notifications to display to users',
- null=True, verbose_name='notifications')),
- ('attributes',
- models.JSONField(blank=True, help_text='json representation of order attributes for this order',
- null=True, verbose_name='attributes')),
- ('buy_time',
- models.DateTimeField(blank=True, default=None, help_text='the timestamp when the order was finalized',
- null=True, verbose_name='buy time')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "status",
+ models.CharField(
+ choices=[
+ ("PENDING", "pending"),
+ ("FAILED", "failed"),
+ ("PAYMENT", "payment"),
+ ("CREATED", "created"),
+ ("DELIVERING", "delivering"),
+ ("FINISHED", "finished"),
+ ],
+ default="PENDING",
+ help_text="current status of the order in its lifecycle",
+ max_length=64,
+ verbose_name="order status",
+ ),
+ ),
+ (
+ "notifications",
+ models.JSONField(
+ blank=True,
+ help_text="json structure of notifications to display to users",
+ null=True,
+ verbose_name="notifications",
+ ),
+ ),
+ (
+ "attributes",
+ models.JSONField(
+ blank=True,
+ help_text="json representation of order attributes for this order",
+ null=True,
+ verbose_name="attributes",
+ ),
+ ),
+ (
+ "buy_time",
+ models.DateTimeField(
+ blank=True,
+ default=None,
+ help_text="the timestamp when the order was finalized",
+ null=True,
+ verbose_name="buy time",
+ ),
+ ),
],
options={
- 'verbose_name': 'order',
- 'verbose_name_plural': 'orders',
+ "verbose_name": "order",
+ "verbose_name_plural": "orders",
},
),
]
diff --git a/core/migrations/0002_initial.py b/core/migrations/0002_initial.py
index af993959..8907808a 100644
--- a/core/migrations/0002_initial.py
+++ b/core/migrations/0002_initial.py
@@ -7,101 +7,205 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
initial = True
dependencies = [
- ('core', '0001_initial'),
+ ("core", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
- model_name='order',
- name='user',
- field=models.ForeignKey(help_text='the user who placed the order', on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL, verbose_name='user'),
+ model_name="order",
+ name="user",
+ field=models.ForeignKey(
+ help_text="the user who placed the order",
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="orders",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="user",
+ ),
),
migrations.AddField(
- model_name='orderproduct',
- name='order',
- field=models.ForeignKey(help_text='reference to the parent order that contains this product', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='order_products', to='core.order', verbose_name='parent order'),
+ model_name="orderproduct",
+ name="order",
+ field=models.ForeignKey(
+ help_text="reference to the parent order that contains this product",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="order_products",
+ to="core.order",
+ verbose_name="parent order",
+ ),
),
migrations.AddField(
- model_name='feedback',
- name='order_product',
- field=models.OneToOneField(help_text='references the specific product in an order that this feedback is about', on_delete=django.db.models.deletion.CASCADE, to='core.orderproduct', verbose_name='related order product'),
+ model_name="feedback",
+ name="order_product",
+ field=models.OneToOneField(
+ help_text="references the specific product in an order that this feedback is about",
+ on_delete=django.db.models.deletion.CASCADE,
+ to="core.orderproduct",
+ verbose_name="related order product",
+ ),
),
migrations.AddField(
- model_name='product',
- name='brand',
- field=models.ForeignKey(blank=True, help_text='optionally associate this product with a brand', null=True, on_delete=django.db.models.deletion.CASCADE, to='core.brand', verbose_name='brand'),
+ model_name="product",
+ name="brand",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="optionally associate this product with a brand",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ to="core.brand",
+ verbose_name="brand",
+ ),
),
migrations.AddField(
- model_name='product',
- name='category',
- field=models.ForeignKey(help_text='category this product belongs to', on_delete=django.db.models.deletion.CASCADE, to='core.category', verbose_name='category'),
+ model_name="product",
+ name="category",
+ field=models.ForeignKey(
+ help_text="category this product belongs to",
+ on_delete=django.db.models.deletion.CASCADE,
+ to="core.category",
+ verbose_name="category",
+ ),
),
migrations.AddField(
- model_name='orderproduct',
- name='product',
- field=models.ForeignKey(blank=True, help_text='the specific product associated with this order line', null=True, on_delete=django.db.models.deletion.PROTECT, to='core.product', verbose_name='associated product'),
+ model_name="orderproduct",
+ name="product",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="the specific product associated with this order line",
+ null=True,
+ on_delete=django.db.models.deletion.PROTECT,
+ to="core.product",
+ verbose_name="associated product",
+ ),
),
migrations.AddField(
- model_name='attributevalue',
- name='product',
- field=models.ForeignKey(help_text="the specific product associated with this attribute's value", null=True, on_delete=django.db.models.deletion.CASCADE, related_name='attributes', to='core.product', verbose_name='associated product'),
+ model_name="attributevalue",
+ name="product",
+ field=models.ForeignKey(
+ help_text="the specific product associated with this attribute's value",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="attributes",
+ to="core.product",
+ verbose_name="associated product",
+ ),
),
migrations.AddField(
- model_name='productimage',
- name='product',
- field=models.ForeignKey(help_text='the product that this image represents', on_delete=django.db.models.deletion.CASCADE, related_name='images', to='core.product', verbose_name='associated product'),
+ model_name="productimage",
+ name="product",
+ field=models.ForeignKey(
+ help_text="the product that this image represents",
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="images",
+ to="core.product",
+ verbose_name="associated product",
+ ),
),
migrations.AddField(
- model_name='product',
- name='tags',
- field=models.ManyToManyField(blank=True, help_text='tags that help describe or group this product', to='core.producttag', verbose_name='product tags'),
+ model_name="product",
+ name="tags",
+ field=models.ManyToManyField(
+ blank=True,
+ help_text="tags that help describe or group this product",
+ to="core.producttag",
+ verbose_name="product tags",
+ ),
),
migrations.AddField(
- model_name='promocode',
- name='user',
- field=models.ForeignKey(blank=True, help_text='user assigned to this promocode if applicable', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='promocodes', to=settings.AUTH_USER_MODEL, verbose_name='assigned user'),
+ model_name="promocode",
+ name="user",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="user assigned to this promocode if applicable",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="promocodes",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="assigned user",
+ ),
),
migrations.AddField(
- model_name='order',
- name='promo_code',
- field=models.ForeignKey(blank=True, help_text='optional promo code applied to this order', null=True, on_delete=django.db.models.deletion.PROTECT, to='core.promocode', verbose_name='applied promo code'),
+ model_name="order",
+ name="promo_code",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="optional promo code applied to this order",
+ null=True,
+ on_delete=django.db.models.deletion.PROTECT,
+ to="core.promocode",
+ verbose_name="applied promo code",
+ ),
),
migrations.AddField(
- model_name='promotion',
- name='products',
- field=models.ManyToManyField(blank=True, help_text='select which products are included in this promotion', to='core.product', verbose_name='included products'),
+ model_name="promotion",
+ name="products",
+ field=models.ManyToManyField(
+ blank=True,
+ help_text="select which products are included in this promotion",
+ to="core.product",
+ verbose_name="included products",
+ ),
),
migrations.AddField(
- model_name='stock',
- name='product',
- field=models.ForeignKey(blank=True, help_text='the product associated with this stock entry', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='stocks', to='core.product', verbose_name='associated product'),
+ model_name="stock",
+ name="product",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="the product associated with this stock entry",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="stocks",
+ to="core.product",
+ verbose_name="associated product",
+ ),
),
migrations.AddIndex(
- model_name='vendor',
- index=django.contrib.postgres.indexes.GinIndex(fields=['authentication'], name='core_vendor_authent_80dc1f_gin'),
+ model_name="vendor",
+ index=django.contrib.postgres.indexes.GinIndex(
+ fields=["authentication"], name="core_vendor_authent_80dc1f_gin"
+ ),
),
migrations.AddField(
- model_name='stock',
- name='vendor',
- field=models.ForeignKey(help_text='the vendor supplying this product stock', on_delete=django.db.models.deletion.CASCADE, to='core.vendor', verbose_name='associated vendor'),
+ model_name="stock",
+ name="vendor",
+ field=models.ForeignKey(
+ help_text="the vendor supplying this product stock",
+ on_delete=django.db.models.deletion.CASCADE,
+ to="core.vendor",
+ verbose_name="associated vendor",
+ ),
),
migrations.AddField(
- model_name='wishlist',
- name='products',
- field=models.ManyToManyField(blank=True, help_text='products that the user has marked as wanted', to='core.product', verbose_name='wishlisted products'),
+ model_name="wishlist",
+ name="products",
+ field=models.ManyToManyField(
+ blank=True,
+ help_text="products that the user has marked as wanted",
+ to="core.product",
+ verbose_name="wishlisted products",
+ ),
),
migrations.AddField(
- model_name='wishlist',
- name='user',
- field=models.OneToOneField(blank=True, help_text='user who owns this wishlist', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='user_related_wishlist', to=settings.AUTH_USER_MODEL, verbose_name='wishlist owner'),
+ model_name="wishlist",
+ name="user",
+ field=models.OneToOneField(
+ blank=True,
+ help_text="user who owns this wishlist",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="user_related_wishlist",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="wishlist owner",
+ ),
),
migrations.AddIndex(
- model_name='orderproduct',
- index=django.contrib.postgres.indexes.GinIndex(fields=['notifications', 'attributes'], name='core_orderp_notific_cd27e9_gin'),
+ model_name="orderproduct",
+ index=django.contrib.postgres.indexes.GinIndex(
+ fields=["notifications", "attributes"], name="core_orderp_notific_cd27e9_gin"
+ ),
),
]
diff --git a/core/migrations/0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more.py b/core/migrations/0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more.py
index 769a5a5f..80caf008 100644
--- a/core/migrations/0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more.py
+++ b/core/migrations/0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more.py
@@ -4,495 +4,1054 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0002_initial'),
+ ("core", "0002_initial"),
]
operations = [
migrations.AlterField(
- model_name='attribute',
- name='name',
- field=models.CharField(help_text='name of this attribute', max_length=255, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_ar_AR',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_cs_CZ',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_da_DK',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_de_DE',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_en_GB',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_en_US',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_es_ES',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_fr_FR',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_hi_IN',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_it_IT',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_ja_JP',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_kk_KZ',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_nl_NL',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_pl_PL',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_pt_BR',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_ro_RO',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_ru_RU',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attribute',
- name='name_zh_hans',
- field=models.CharField(help_text='name of this attribute', max_length=255, null=True, unique=True, verbose_name="attribute's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name',
- field=models.CharField(help_text="attribute group's name", max_length=255, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_ar_AR',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_cs_CZ',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_da_DK',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_de_DE',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_en_GB',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_en_US',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_es_ES',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_fr_FR',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_hi_IN',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_it_IT',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_ja_JP',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_kk_KZ',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_nl_NL',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_pl_PL',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_pt_BR',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_ro_RO',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_ru_RU',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='attributegroup',
- name='name_zh_hans',
- field=models.CharField(help_text="attribute group's name", max_length=255, null=True, unique=True, verbose_name="attribute group's name"),
- ),
- migrations.AlterField(
- model_name='brand',
- name='name',
- field=models.CharField(help_text='name of this brand', max_length=255, unique=True, verbose_name='brand name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name',
- field=models.CharField(help_text='provide a name for this category', max_length=255, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_ar_AR',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_cs_CZ',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_da_DK',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_de_DE',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_en_GB',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_en_US',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_es_ES',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_fr_FR',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_hi_IN',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_it_IT',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_ja_JP',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_kk_KZ',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_nl_NL',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_pl_PL',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_pt_BR',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_ro_RO',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_ru_RU',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='category',
- name='name_zh_hans',
- field=models.CharField(help_text='provide a name for this category', max_length=255, null=True, unique=True, verbose_name='category name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_ar_AR',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_cs_CZ',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_da_DK',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_de_DE',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_en_GB',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_en_US',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_es_ES',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_fr_FR',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_hi_IN',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_it_IT',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_ja_JP',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_kk_KZ',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_nl_NL',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_pl_PL',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_pt_BR',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_ro_RO',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_ru_RU',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='product',
- name='name_zh_hans',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, unique=True, verbose_name='product name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_ar_AR',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_cs_CZ',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_da_DK',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_de_DE',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_en_GB',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_en_US',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_es_ES',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_fr_FR',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_hi_IN',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_it_IT',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_ja_JP',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_kk_KZ',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_nl_NL',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_pl_PL',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_pt_BR',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_ro_RO',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_ru_RU',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='producttag',
- name='name_zh_hans',
- field=models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True, unique=True, verbose_name='tag display name'),
- ),
- migrations.AlterField(
- model_name='vendor',
- name='name',
- field=models.CharField(help_text='name of this vendor', max_length=255, unique=True, verbose_name='vendor name'),
+ model_name="attribute",
+ name="name",
+ field=models.CharField(
+ help_text="name of this attribute", max_length=255, unique=True, verbose_name="attribute's name"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_ar_AR",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_cs_CZ",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_da_DK",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_de_DE",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_en_GB",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_en_US",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_es_ES",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_fr_FR",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_hi_IN",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_it_IT",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_ja_JP",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_kk_KZ",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_nl_NL",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_pl_PL",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_pt_BR",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_ro_RO",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_ru_RU",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attribute",
+ name="name_zh_hans",
+ field=models.CharField(
+ help_text="name of this attribute",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name",
+ field=models.CharField(
+ help_text="attribute group's name", max_length=255, unique=True, verbose_name="attribute group's name"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_ar_AR",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_cs_CZ",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_da_DK",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_de_DE",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_en_GB",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_en_US",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_es_ES",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_fr_FR",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_hi_IN",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_it_IT",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_ja_JP",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_kk_KZ",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_nl_NL",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_pl_PL",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_pt_BR",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_ro_RO",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_ru_RU",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="attributegroup",
+ name="name_zh_hans",
+ field=models.CharField(
+ help_text="attribute group's name",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="attribute group's name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="brand",
+ name="name",
+ field=models.CharField(
+ help_text="name of this brand", max_length=255, unique=True, verbose_name="brand name"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name",
+ field=models.CharField(
+ help_text="provide a name for this category", max_length=255, unique=True, verbose_name="category name"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_ar_AR",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_cs_CZ",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_da_DK",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_de_DE",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_en_GB",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_en_US",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_es_ES",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_fr_FR",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_hi_IN",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_it_IT",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_ja_JP",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_kk_KZ",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_nl_NL",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_pl_PL",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_pt_BR",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_ro_RO",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_ru_RU",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="name_zh_hans",
+ field=models.CharField(
+ help_text="provide a name for this category",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="category name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_ar_AR",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_cs_CZ",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_da_DK",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_de_DE",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_en_GB",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_en_US",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_es_ES",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_fr_FR",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_hi_IN",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_it_IT",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_ja_JP",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_kk_KZ",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_nl_NL",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_pl_PL",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_pt_BR",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_ro_RO",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_ru_RU",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="name_zh_hans",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="product name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_ar_AR",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_cs_CZ",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_da_DK",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_de_DE",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_en_GB",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_en_US",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_es_ES",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_fr_FR",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_hi_IN",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_it_IT",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_ja_JP",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_kk_KZ",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_nl_NL",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_pl_PL",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_pt_BR",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_ro_RO",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_ru_RU",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="producttag",
+ name="name_zh_hans",
+ field=models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="vendor",
+ name="name",
+ field=models.CharField(
+ help_text="name of this vendor", max_length=255, unique=True, verbose_name="vendor name"
+ ),
),
]
diff --git a/core/migrations/0004_alter_product_name_alter_product_name_ar_ar_and_more.py b/core/migrations/0004_alter_product_name_alter_product_name_ar_ar_and_more.py
index 6e36c2d6..a47d03af 100644
--- a/core/migrations/0004_alter_product_name_alter_product_name_ar_ar_and_more.py
+++ b/core/migrations/0004_alter_product_name_alter_product_name_ar_ar_and_more.py
@@ -4,105 +4,198 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more'),
+ ("core", "0003_alter_attribute_name_alter_attribute_name_ar_ar_and_more"),
]
operations = [
migrations.AlterField(
- model_name='product',
- name='name',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, verbose_name='product name'),
+ model_name="product",
+ name="name",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_ar_AR',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_ar_AR",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_cs_CZ',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_cs_CZ",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_da_DK',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_da_DK",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_de_DE',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_de_DE",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_en_GB',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_en_GB",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_en_US',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_en_US",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_es_ES',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_es_ES",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_fr_FR',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_fr_FR",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_hi_IN',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_hi_IN",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_it_IT',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_it_IT",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_ja_JP',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_ja_JP",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_kk_KZ',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_kk_KZ",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_nl_NL',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_nl_NL",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_pl_PL',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_pl_PL",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_pt_BR',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_pt_BR",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_ro_RO',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_ro_RO",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_ru_RU',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_ru_RU",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
migrations.AlterField(
- model_name='product',
- name='name_zh_hans',
- field=models.CharField(help_text='provide a clear identifying name for the product', max_length=255, null=True, verbose_name='product name'),
+ model_name="product",
+ name="name_zh_hans",
+ field=models.CharField(
+ help_text="provide a clear identifying name for the product",
+ max_length=255,
+ null=True,
+ verbose_name="product name",
+ ),
),
]
diff --git a/core/migrations/0005_remove_brand_category_brand_categories.py b/core/migrations/0005_remove_brand_category_brand_categories.py
index ed34cded..176538a3 100644
--- a/core/migrations/0005_remove_brand_category_brand_categories.py
+++ b/core/migrations/0005_remove_brand_category_brand_categories.py
@@ -4,19 +4,23 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0004_alter_product_name_alter_product_name_ar_ar_and_more'),
+ ("core", "0004_alter_product_name_alter_product_name_ar_ar_and_more"),
]
operations = [
migrations.RemoveField(
- model_name='brand',
- name='category',
+ model_name="brand",
+ name="category",
),
migrations.AddField(
- model_name='brand',
- name='categories',
- field=models.ManyToManyField(blank=True, help_text='optional categories that this brand is associated with', to='core.category', verbose_name='associated categories'),
+ model_name="brand",
+ name="categories",
+ field=models.ManyToManyField(
+ blank=True,
+ help_text="optional categories that this brand is associated with",
+ to="core.category",
+ verbose_name="associated categories",
+ ),
),
]
diff --git a/core/migrations/0006_alter_order_status.py b/core/migrations/0006_alter_order_status.py
index 109fac86..41fd1bf9 100644
--- a/core/migrations/0006_alter_order_status.py
+++ b/core/migrations/0006_alter_order_status.py
@@ -4,15 +4,28 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0005_remove_brand_category_brand_categories'),
+ ("core", "0005_remove_brand_category_brand_categories"),
]
operations = [
migrations.AlterField(
- model_name='order',
- name='status',
- field=models.CharField(choices=[('PENDING', 'pending'), ('FAILED', 'failed'), ('PAYMENT', 'payment'), ('CREATED', 'created'), ('DELIVERING', 'delivering'), ('FINISHED', 'finished'), ('MOMENTAL', 'momental')], default='PENDING', help_text='current status of the order in its lifecycle', max_length=64, verbose_name='order status'),
+ model_name="order",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("PENDING", "pending"),
+ ("FAILED", "failed"),
+ ("PAYMENT", "payment"),
+ ("CREATED", "created"),
+ ("DELIVERING", "delivering"),
+ ("FINISHED", "finished"),
+ ("MOMENTAL", "momental"),
+ ],
+ default="PENDING",
+ help_text="current status of the order in its lifecycle",
+ max_length=64,
+ verbose_name="order status",
+ ),
),
]
diff --git a/core/migrations/0007_alter_category_image.py b/core/migrations/0007_alter_category_image.py
index 25ffc9c1..77939b03 100644
--- a/core/migrations/0007_alter_category_image.py
+++ b/core/migrations/0007_alter_category_image.py
@@ -7,16 +7,20 @@ import core.validators
class Migration(migrations.Migration):
dependencies = [
- ('core', '0006_alter_order_status'),
+ ("core", "0006_alter_order_status"),
]
operations = [
migrations.AlterField(
- model_name='category',
- name='image',
- field=models.ImageField(blank=True, help_text='upload an image representing this category', null=True,
- upload_to='categories/',
- validators=[core.validators.validate_category_image_dimensions],
- verbose_name='category image'),
+ model_name="category",
+ name="image",
+ field=models.ImageField(
+ blank=True,
+ help_text="upload an image representing this category",
+ null=True,
+ upload_to="categories/",
+ validators=[core.validators.validate_category_image_dimensions],
+ verbose_name="category image",
+ ),
),
]
diff --git a/core/migrations/0008_digitalassetdownload.py b/core/migrations/0008_digitalassetdownload.py
index 5739ebb5..32a3873e 100644
--- a/core/migrations/0008_digitalassetdownload.py
+++ b/core/migrations/0008_digitalassetdownload.py
@@ -9,33 +9,57 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('core', '0007_alter_category_image'),
+ ("core", "0007_alter_category_image"),
]
operations = [
migrations.CreateModel(
- name='DigitalAssetDownload',
+ name="DigitalAssetDownload",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('num_downloads', models.IntegerField(default=0)),
- ('order_product',
- models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='download',
- to='core.orderproduct')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ ("num_downloads", models.IntegerField(default=0)),
+ (
+ "order_product",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.CASCADE, related_name="download", to="core.orderproduct"
+ ),
+ ),
],
options={
- 'verbose_name': 'download',
- 'verbose_name_plural': 'downloads',
+ "verbose_name": "download",
+ "verbose_name_plural": "downloads",
},
),
]
diff --git a/core/migrations/0009_documentary.py b/core/migrations/0009_documentary.py
index d368b1c9..8beb86b4 100644
--- a/core/migrations/0009_documentary.py
+++ b/core/migrations/0009_documentary.py
@@ -11,32 +11,57 @@ import core.utils
class Migration(migrations.Migration):
dependencies = [
- ('core', '0008_digitalassetdownload'),
+ ("core", "0008_digitalassetdownload"),
]
operations = [
migrations.CreateModel(
- name='Documentary',
+ name="Documentary",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('document', models.FileField(upload_to=core.utils.get_product_uuid_as_path)),
- ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documentaries',
- to='core.product')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ ("document", models.FileField(upload_to=core.utils.get_product_uuid_as_path)),
+ (
+ "product",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE, related_name="documentaries", to="core.product"
+ ),
+ ),
],
options={
- 'verbose_name': 'documentary',
- 'verbose_name_plural': 'documentaries',
+ "verbose_name": "documentary",
+ "verbose_name_plural": "documentaries",
},
),
]
diff --git a/core/migrations/0010_product_partnumber.py b/core/migrations/0010_product_partnumber.py
index e447e697..3628270e 100644
--- a/core/migrations/0010_product_partnumber.py
+++ b/core/migrations/0010_product_partnumber.py
@@ -4,15 +4,20 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0009_documentary'),
+ ("core", "0009_documentary"),
]
operations = [
migrations.AddField(
- model_name='product',
- name='partnumber',
- field=models.CharField(default=None, help_text='part number for this product', null=True, unique=True, verbose_name='part number'),
+ model_name="product",
+ name="partnumber",
+ field=models.CharField(
+ default=None,
+ help_text="part number for this product",
+ null=True,
+ unique=True,
+ verbose_name="part number",
+ ),
),
]
diff --git a/core/migrations/0011_brand_big_logo_brand_description_and_more.py b/core/migrations/0011_brand_big_logo_brand_description_and_more.py
index 53e8890a..8dbb4df0 100644
--- a/core/migrations/0011_brand_big_logo_brand_description_and_more.py
+++ b/core/migrations/0011_brand_big_logo_brand_description_and_more.py
@@ -7,138 +7,222 @@ import core.validators
class Migration(migrations.Migration):
dependencies = [
- ('core', '0010_product_partnumber'),
+ ("core", "0010_product_partnumber"),
]
operations = [
migrations.AddField(
- model_name='brand',
- name='big_logo',
- field=models.ImageField(blank=True, help_text='upload a big logo representing this brand', null=True,
- upload_to='brands/',
- validators=[core.validators.validate_category_image_dimensions],
- verbose_name='brand big image'),
+ model_name="brand",
+ name="big_logo",
+ field=models.ImageField(
+ blank=True,
+ help_text="upload a big logo representing this brand",
+ null=True,
+ upload_to="brands/",
+ validators=[core.validators.validate_category_image_dimensions],
+ verbose_name="brand big image",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_ar_AR',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_ar_AR",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_cs_CZ',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_cs_CZ",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_da_DK',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_da_DK",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_de_DE',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_de_DE",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_en_GB',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_en_GB",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_en_US',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_en_US",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_es_ES',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_es_ES",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_fr_FR',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_fr_FR",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_hi_IN',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_hi_IN",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_it_IT',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_it_IT",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_ja_JP',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_ja_JP",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_kk_KZ',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_kk_KZ",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_nl_NL',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_nl_NL",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_pl_PL',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_pl_PL",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_pt_BR',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_pt_BR",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_ro_RO',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_ro_RO",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_ru_RU',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_ru_RU",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='description_zh_hans',
- field=models.TextField(blank=True, help_text='add a detailed description of the brand', null=True,
- verbose_name='brand description'),
+ model_name="brand",
+ name="description_zh_hans",
+ field=models.TextField(
+ blank=True,
+ help_text="add a detailed description of the brand",
+ null=True,
+ verbose_name="brand description",
+ ),
),
migrations.AddField(
- model_name='brand',
- name='small_logo',
- field=models.ImageField(blank=True, help_text='upload a logo representing this brand', null=True,
- upload_to='brands/',
- validators=[core.validators.validate_category_image_dimensions],
- verbose_name='brand small image'),
+ model_name="brand",
+ name="small_logo",
+ field=models.ImageField(
+ blank=True,
+ help_text="upload a logo representing this brand",
+ null=True,
+ upload_to="brands/",
+ validators=[core.validators.validate_category_image_dimensions],
+ verbose_name="brand small image",
+ ),
),
]
diff --git a/core/migrations/0012_alter_order_user.py b/core/migrations/0012_alter_order_user.py
index 97465a31..2213f5ab 100644
--- a/core/migrations/0012_alter_order_user.py
+++ b/core/migrations/0012_alter_order_user.py
@@ -6,16 +6,23 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0011_brand_big_logo_brand_description_and_more'),
+ ("core", "0011_brand_big_logo_brand_description_and_more"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
- model_name='order',
- name='user',
- field=models.ForeignKey(blank=True, help_text='the user who placed the order', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='orders', to=settings.AUTH_USER_MODEL, verbose_name='user'),
+ model_name="order",
+ name="user",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="the user who placed the order",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="orders",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="user",
+ ),
),
]
diff --git a/core/migrations/0013_product_slug.py b/core/migrations/0013_product_slug.py
index fbf8b75f..412aeef4 100644
--- a/core/migrations/0013_product_slug.py
+++ b/core/migrations/0013_product_slug.py
@@ -5,15 +5,21 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0012_alter_order_user'),
+ ("core", "0012_alter_order_user"),
]
operations = [
migrations.AddField(
- model_name='product',
- name='slug',
- field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, null=True, blank=True, editable=False, populate_from=('category.name', 'brand.name', 'name'), unique=True),
+ model_name="product",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True,
+ null=True,
+ blank=True,
+ editable=False,
+ populate_from=("category.name", "brand.name", "name"),
+ unique=True,
+ ),
),
]
diff --git a/core/migrations/0014_alter_product_slug.py b/core/migrations/0014_alter_product_slug.py
index b1b5f7f4..db3fba48 100644
--- a/core/migrations/0014_alter_product_slug.py
+++ b/core/migrations/0014_alter_product_slug.py
@@ -5,15 +5,21 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0013_product_slug'),
+ ("core", "0013_product_slug"),
]
operations = [
migrations.AlterField(
- model_name='product',
- name='slug',
- field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True, populate_from=('uuid', 'category.name', 'brand.name', 'name'), unique=True),
+ model_name="product",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True,
+ blank=True,
+ editable=False,
+ null=True,
+ populate_from=("uuid", "category.name", "brand.name", "name"),
+ unique=True,
+ ),
),
]
diff --git a/core/migrations/0015_alter_product_slug.py b/core/migrations/0015_alter_product_slug.py
index 5cd41799..d0d284bf 100644
--- a/core/migrations/0015_alter_product_slug.py
+++ b/core/migrations/0015_alter_product_slug.py
@@ -5,15 +5,21 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0014_alter_product_slug'),
+ ("core", "0014_alter_product_slug"),
]
operations = [
migrations.AlterField(
- model_name='product',
- name='slug',
- field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True, populate_from=('category__name', 'name'), unique=True),
+ model_name="product",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True,
+ blank=True,
+ editable=False,
+ null=True,
+ populate_from=("category__name", "name"),
+ unique=True,
+ ),
),
]
diff --git a/core/migrations/0016_alter_product_slug.py b/core/migrations/0016_alter_product_slug.py
index 32875776..01ed1c17 100644
--- a/core/migrations/0016_alter_product_slug.py
+++ b/core/migrations/0016_alter_product_slug.py
@@ -5,15 +5,21 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
- ('core', '0015_alter_product_slug'),
+ ("core", "0015_alter_product_slug"),
]
operations = [
migrations.AlterField(
- model_name='product',
- name='slug',
- field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True, populate_from=('uuid', 'category__name', 'name'), unique=True),
+ model_name="product",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True,
+ blank=True,
+ editable=False,
+ null=True,
+ populate_from=("uuid", "category__name", "name"),
+ unique=True,
+ ),
),
]
diff --git a/core/migrations/0017_order_human_readable_id.py b/core/migrations/0017_order_human_readable_id.py
index 48d73cb0..36572585 100644
--- a/core/migrations/0017_order_human_readable_id.py
+++ b/core/migrations/0017_order_human_readable_id.py
@@ -7,15 +7,18 @@ import core.utils
class Migration(migrations.Migration):
dependencies = [
- ('core', '0016_alter_product_slug'),
+ ("core", "0016_alter_product_slug"),
]
operations = [
migrations.AddField(
- model_name='order',
- name='human_readable_id',
- field=models.CharField(default=core.utils.generate_human_readable_id,
- help_text='a human-readable identifier for the order', max_length=8,
- verbose_name='human readable id'),
+ model_name="order",
+ name="human_readable_id",
+ field=models.CharField(
+ default=core.utils.generate_human_readable_id,
+ help_text="a human-readable identifier for the order",
+ max_length=8,
+ verbose_name="human readable id",
+ ),
),
]
diff --git a/core/migrations/0018_alter_order_human_readable_id.py b/core/migrations/0018_alter_order_human_readable_id.py
index 10f7899f..5fe3e70a 100644
--- a/core/migrations/0018_alter_order_human_readable_id.py
+++ b/core/migrations/0018_alter_order_human_readable_id.py
@@ -8,11 +8,7 @@ def fix_duplicates(apps, schema_editor):
if schema_editor:
pass
Order = apps.get_model("core", "Order")
- duplicates = (
- Order.objects.values("human_readable_id")
- .annotate(count=Count("uuid"))
- .filter(count__gt=1)
- )
+ duplicates = Order.objects.values("human_readable_id").annotate(count=Count("uuid")).filter(count__gt=1)
for duplicate in duplicates:
h_id = duplicate["human_readable_id"]
orders = Order.objects.filter(human_readable_id=h_id).order_by("uuid")
@@ -20,6 +16,7 @@ def fix_duplicates(apps, schema_editor):
new_id = order.human_readable_id
while Order.objects.filter(human_readable_id=new_id).exists():
from core.utils import generate_human_readable_id
+
new_id = generate_human_readable_id()
order.human_readable_id = new_id
order.save()
@@ -35,16 +32,20 @@ def reverse_func(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
- ('core', '0017_order_human_readable_id'),
+ ("core", "0017_order_human_readable_id"),
]
operations = [
migrations.RunPython(fix_duplicates, reverse_func),
migrations.AlterField(
- model_name='order',
- name='human_readable_id',
- field=models.CharField(default=core.utils.generate_human_readable_id,
- help_text='a human-readable identifier for the order', max_length=8, unique=True,
- verbose_name='human readable id'),
+ model_name="order",
+ name="human_readable_id",
+ field=models.CharField(
+ default=core.utils.generate_human_readable_id,
+ help_text="a human-readable identifier for the order",
+ max_length=8,
+ unique=True,
+ verbose_name="human readable id",
+ ),
),
]
diff --git a/core/migrations/0019_address.py b/core/migrations/0019_address.py
index 229c86c6..1c3bce8e 100644
--- a/core/migrations/0019_address.py
+++ b/core/migrations/0019_address.py
@@ -11,46 +11,86 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('core', '0018_alter_order_human_readable_id'),
+ ("core", "0018_alter_order_human_readable_id"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
- name='Address',
+ name="Address",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('street', models.CharField(max_length=255, null=True, verbose_name='street')),
- ('district', models.CharField(max_length=255, null=True, verbose_name='district')),
- ('city', models.CharField(max_length=100, null=True, verbose_name='city')),
- ('region', models.CharField(max_length=100, null=True, verbose_name='region')),
- ('postal_code', models.CharField(max_length=20, null=True, verbose_name='postal code')),
- ('country', models.CharField(max_length=40, null=True, verbose_name='country')),
- ('location', django.contrib.gis.db.models.fields.PointField(blank=True, geography=True,
- help_text='geolocation point: (longitude, latitude)',
- null=True, srid=4326)),
- ('raw_data', models.JSONField(blank=True, help_text='full JSON response from geocoder for this address',
- null=True)),
- ('api_response',
- models.JSONField(blank=True, help_text='stored JSON response from the geocoding service', null=True)),
- ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE,
- to=settings.AUTH_USER_MODEL)),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ ("street", models.CharField(max_length=255, null=True, verbose_name="street")),
+ ("district", models.CharField(max_length=255, null=True, verbose_name="district")),
+ ("city", models.CharField(max_length=100, null=True, verbose_name="city")),
+ ("region", models.CharField(max_length=100, null=True, verbose_name="region")),
+ ("postal_code", models.CharField(max_length=20, null=True, verbose_name="postal code")),
+ ("country", models.CharField(max_length=40, null=True, verbose_name="country")),
+ (
+ "location",
+ django.contrib.gis.db.models.fields.PointField(
+ blank=True,
+ geography=True,
+ help_text="geolocation point: (longitude, latitude)",
+ null=True,
+ srid=4326,
+ ),
+ ),
+ (
+ "raw_data",
+ models.JSONField(
+ blank=True, help_text="full JSON response from geocoder for this address", null=True
+ ),
+ ),
+ (
+ "api_response",
+ models.JSONField(
+ blank=True, help_text="stored JSON response from the geocoding service", null=True
+ ),
+ ),
+ (
+ "user",
+ models.ForeignKey(
+ blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
+ ),
+ ),
],
options={
- 'verbose_name': 'address',
- 'verbose_name_plural': 'addresses',
- 'indexes': [models.Index(fields=['location'], name='core_addres_locatio_eb6b39_idx')],
+ "verbose_name": "address",
+ "verbose_name_plural": "addresses",
+ "indexes": [models.Index(fields=["location"], name="core_addres_locatio_eb6b39_idx")],
},
),
]
diff --git a/core/migrations/0020_order_billing_address_order_shipping_address.py b/core/migrations/0020_order_billing_address_order_shipping_address.py
index 430b124e..718186f0 100644
--- a/core/migrations/0020_order_billing_address_order_shipping_address.py
+++ b/core/migrations/0020_order_billing_address_order_shipping_address.py
@@ -5,7 +5,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('core', '0019_address'),
+ ("core", "0019_address"),
]
operations = [
@@ -17,29 +17,30 @@ class Migration(migrations.Migration):
),
reverse_sql=migrations.RunSQL.noop,
),
-
migrations.AddField(
- model_name='order',
- name='billing_address',
+ model_name="order",
+ name="billing_address",
field=models.ForeignKey(
- blank=True, null=True,
+ blank=True,
+ null=True,
on_delete=models.deletion.CASCADE,
- related_name='billing_address_order',
- to='core.address',
- verbose_name='billing address',
- help_text='the billing address used for this order',
+ related_name="billing_address_order",
+ to="core.address",
+ verbose_name="billing address",
+ help_text="the billing address used for this order",
),
),
migrations.AddField(
- model_name='order',
- name='shipping_address',
+ model_name="order",
+ name="shipping_address",
field=models.ForeignKey(
- blank=True, null=True,
+ blank=True,
+ null=True,
on_delete=models.deletion.CASCADE,
- related_name='shipping_address_order',
- to='core.address',
- verbose_name='shipping address',
- help_text='the shipping address used for this order',
+ related_name="shipping_address_order",
+ to="core.address",
+ verbose_name="shipping address",
+ help_text="the shipping address used for this order",
),
),
]
diff --git a/core/migrations/0021_rename_name_ar_ar_attribute_name_ar_ar_and_more.py b/core/migrations/0021_rename_name_ar_ar_attribute_name_ar_ar_and_more.py
index ca4135dd..26e88bd0 100644
--- a/core/migrations/0021_rename_name_ar_ar_attribute_name_ar_ar_and_more.py
+++ b/core/migrations/0021_rename_name_ar_ar_attribute_name_ar_ar_and_more.py
@@ -5,943 +5,943 @@ from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
- ('core', '0020_order_billing_address_order_shipping_address'),
+ ("core", "0020_order_billing_address_order_shipping_address"),
]
operations = [
migrations.RenameField(
- model_name='attribute',
- old_name='name_ar_AR',
- new_name='name_ar_ar',
+ model_name="attribute",
+ old_name="name_ar_AR",
+ new_name="name_ar_ar",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_cs_CZ',
- new_name='name_cs_cz',
+ model_name="attribute",
+ old_name="name_cs_CZ",
+ new_name="name_cs_cz",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_da_DK',
- new_name='name_da_dk',
+ model_name="attribute",
+ old_name="name_da_DK",
+ new_name="name_da_dk",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_de_DE',
- new_name='name_de_de',
+ model_name="attribute",
+ old_name="name_de_DE",
+ new_name="name_de_de",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_en_GB',
- new_name='name_en_gb',
+ model_name="attribute",
+ old_name="name_en_GB",
+ new_name="name_en_gb",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_en_US',
- new_name='name_en_us',
+ model_name="attribute",
+ old_name="name_en_US",
+ new_name="name_en_us",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_es_ES',
- new_name='name_es_es',
+ model_name="attribute",
+ old_name="name_es_ES",
+ new_name="name_es_es",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_fr_FR',
- new_name='name_fr_fr',
+ model_name="attribute",
+ old_name="name_fr_FR",
+ new_name="name_fr_fr",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_hi_IN',
- new_name='name_hi_in',
+ model_name="attribute",
+ old_name="name_hi_IN",
+ new_name="name_hi_in",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_it_IT',
- new_name='name_it_it',
+ model_name="attribute",
+ old_name="name_it_IT",
+ new_name="name_it_it",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_ja_JP',
- new_name='name_ja_jp',
+ model_name="attribute",
+ old_name="name_ja_JP",
+ new_name="name_ja_jp",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_kk_KZ',
- new_name='name_kk_kz',
+ model_name="attribute",
+ old_name="name_kk_KZ",
+ new_name="name_kk_kz",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_nl_NL',
- new_name='name_nl_nl',
+ model_name="attribute",
+ old_name="name_nl_NL",
+ new_name="name_nl_nl",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_pl_PL',
- new_name='name_pl_pl',
+ model_name="attribute",
+ old_name="name_pl_PL",
+ new_name="name_pl_pl",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_pt_BR',
- new_name='name_pt_br',
+ model_name="attribute",
+ old_name="name_pt_BR",
+ new_name="name_pt_br",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_ro_RO',
- new_name='name_ro_ro',
+ model_name="attribute",
+ old_name="name_ro_RO",
+ new_name="name_ro_ro",
),
migrations.RenameField(
- model_name='attribute',
- old_name='name_ru_RU',
- new_name='name_ru_ru',
+ model_name="attribute",
+ old_name="name_ru_RU",
+ new_name="name_ru_ru",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_ar_AR',
- new_name='name_ar_ar',
+ model_name="attributegroup",
+ old_name="name_ar_AR",
+ new_name="name_ar_ar",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_cs_CZ',
- new_name='name_cs_cz',
+ model_name="attributegroup",
+ old_name="name_cs_CZ",
+ new_name="name_cs_cz",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_da_DK',
- new_name='name_da_dk',
+ model_name="attributegroup",
+ old_name="name_da_DK",
+ new_name="name_da_dk",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_de_DE',
- new_name='name_de_de',
+ model_name="attributegroup",
+ old_name="name_de_DE",
+ new_name="name_de_de",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_en_GB',
- new_name='name_en_gb',
+ model_name="attributegroup",
+ old_name="name_en_GB",
+ new_name="name_en_gb",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_en_US',
- new_name='name_en_us',
+ model_name="attributegroup",
+ old_name="name_en_US",
+ new_name="name_en_us",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_es_ES',
- new_name='name_es_es',
+ model_name="attributegroup",
+ old_name="name_es_ES",
+ new_name="name_es_es",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_fr_FR',
- new_name='name_fr_fr',
+ model_name="attributegroup",
+ old_name="name_fr_FR",
+ new_name="name_fr_fr",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_hi_IN',
- new_name='name_hi_in',
+ model_name="attributegroup",
+ old_name="name_hi_IN",
+ new_name="name_hi_in",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_it_IT',
- new_name='name_it_it',
+ model_name="attributegroup",
+ old_name="name_it_IT",
+ new_name="name_it_it",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_ja_JP',
- new_name='name_ja_jp',
+ model_name="attributegroup",
+ old_name="name_ja_JP",
+ new_name="name_ja_jp",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_kk_KZ',
- new_name='name_kk_kz',
+ model_name="attributegroup",
+ old_name="name_kk_KZ",
+ new_name="name_kk_kz",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_nl_NL',
- new_name='name_nl_nl',
+ model_name="attributegroup",
+ old_name="name_nl_NL",
+ new_name="name_nl_nl",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_pl_PL',
- new_name='name_pl_pl',
+ model_name="attributegroup",
+ old_name="name_pl_PL",
+ new_name="name_pl_pl",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_pt_BR',
- new_name='name_pt_br',
+ model_name="attributegroup",
+ old_name="name_pt_BR",
+ new_name="name_pt_br",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_ro_RO',
- new_name='name_ro_ro',
+ model_name="attributegroup",
+ old_name="name_ro_RO",
+ new_name="name_ro_ro",
),
migrations.RenameField(
- model_name='attributegroup',
- old_name='name_ru_RU',
- new_name='name_ru_ru',
+ model_name="attributegroup",
+ old_name="name_ru_RU",
+ new_name="name_ru_ru",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_ar_AR',
- new_name='value_ar_ar',
+ model_name="attributevalue",
+ old_name="value_ar_AR",
+ new_name="value_ar_ar",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_cs_CZ',
- new_name='value_cs_cz',
+ model_name="attributevalue",
+ old_name="value_cs_CZ",
+ new_name="value_cs_cz",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_da_DK',
- new_name='value_da_dk',
+ model_name="attributevalue",
+ old_name="value_da_DK",
+ new_name="value_da_dk",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_de_DE',
- new_name='value_de_de',
+ model_name="attributevalue",
+ old_name="value_de_DE",
+ new_name="value_de_de",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_en_GB',
- new_name='value_en_gb',
+ model_name="attributevalue",
+ old_name="value_en_GB",
+ new_name="value_en_gb",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_en_US',
- new_name='value_en_us',
+ model_name="attributevalue",
+ old_name="value_en_US",
+ new_name="value_en_us",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_es_ES',
- new_name='value_es_es',
+ model_name="attributevalue",
+ old_name="value_es_ES",
+ new_name="value_es_es",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_fr_FR',
- new_name='value_fr_fr',
+ model_name="attributevalue",
+ old_name="value_fr_FR",
+ new_name="value_fr_fr",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_hi_IN',
- new_name='value_hi_in',
+ model_name="attributevalue",
+ old_name="value_hi_IN",
+ new_name="value_hi_in",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_it_IT',
- new_name='value_it_it',
+ model_name="attributevalue",
+ old_name="value_it_IT",
+ new_name="value_it_it",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_ja_JP',
- new_name='value_ja_jp',
+ model_name="attributevalue",
+ old_name="value_ja_JP",
+ new_name="value_ja_jp",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_kk_KZ',
- new_name='value_kk_kz',
+ model_name="attributevalue",
+ old_name="value_kk_KZ",
+ new_name="value_kk_kz",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_nl_NL',
- new_name='value_nl_nl',
+ model_name="attributevalue",
+ old_name="value_nl_NL",
+ new_name="value_nl_nl",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_pl_PL',
- new_name='value_pl_pl',
+ model_name="attributevalue",
+ old_name="value_pl_PL",
+ new_name="value_pl_pl",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_pt_BR',
- new_name='value_pt_br',
+ model_name="attributevalue",
+ old_name="value_pt_BR",
+ new_name="value_pt_br",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_ro_RO',
- new_name='value_ro_ro',
+ model_name="attributevalue",
+ old_name="value_ro_RO",
+ new_name="value_ro_ro",
),
migrations.RenameField(
- model_name='attributevalue',
- old_name='value_ru_RU',
- new_name='value_ru_ru',
+ model_name="attributevalue",
+ old_name="value_ru_RU",
+ new_name="value_ru_ru",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_ar_AR',
- new_name='description_ar_ar',
+ model_name="brand",
+ old_name="description_ar_AR",
+ new_name="description_ar_ar",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_cs_CZ',
- new_name='description_cs_cz',
+ model_name="brand",
+ old_name="description_cs_CZ",
+ new_name="description_cs_cz",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_da_DK',
- new_name='description_da_dk',
+ model_name="brand",
+ old_name="description_da_DK",
+ new_name="description_da_dk",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_de_DE',
- new_name='description_de_de',
+ model_name="brand",
+ old_name="description_de_DE",
+ new_name="description_de_de",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_en_GB',
- new_name='description_en_gb',
+ model_name="brand",
+ old_name="description_en_GB",
+ new_name="description_en_gb",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_en_US',
- new_name='description_en_us',
+ model_name="brand",
+ old_name="description_en_US",
+ new_name="description_en_us",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_es_ES',
- new_name='description_es_es',
+ model_name="brand",
+ old_name="description_es_ES",
+ new_name="description_es_es",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_fr_FR',
- new_name='description_fr_fr',
+ model_name="brand",
+ old_name="description_fr_FR",
+ new_name="description_fr_fr",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_hi_IN',
- new_name='description_hi_in',
+ model_name="brand",
+ old_name="description_hi_IN",
+ new_name="description_hi_in",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_it_IT',
- new_name='description_it_it',
+ model_name="brand",
+ old_name="description_it_IT",
+ new_name="description_it_it",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_ja_JP',
- new_name='description_ja_jp',
+ model_name="brand",
+ old_name="description_ja_JP",
+ new_name="description_ja_jp",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_kk_KZ',
- new_name='description_kk_kz',
+ model_name="brand",
+ old_name="description_kk_KZ",
+ new_name="description_kk_kz",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_nl_NL',
- new_name='description_nl_nl',
+ model_name="brand",
+ old_name="description_nl_NL",
+ new_name="description_nl_nl",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_pl_PL',
- new_name='description_pl_pl',
+ model_name="brand",
+ old_name="description_pl_PL",
+ new_name="description_pl_pl",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_pt_BR',
- new_name='description_pt_br',
+ model_name="brand",
+ old_name="description_pt_BR",
+ new_name="description_pt_br",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_ro_RO',
- new_name='description_ro_ro',
+ model_name="brand",
+ old_name="description_ro_RO",
+ new_name="description_ro_ro",
),
migrations.RenameField(
- model_name='brand',
- old_name='description_ru_RU',
- new_name='description_ru_ru',
+ model_name="brand",
+ old_name="description_ru_RU",
+ new_name="description_ru_ru",
),
migrations.RenameField(
- model_name='category',
- old_name='description_ar_AR',
- new_name='description_ar_ar',
+ model_name="category",
+ old_name="description_ar_AR",
+ new_name="description_ar_ar",
),
migrations.RenameField(
- model_name='category',
- old_name='description_cs_CZ',
- new_name='description_cs_cz',
+ model_name="category",
+ old_name="description_cs_CZ",
+ new_name="description_cs_cz",
),
migrations.RenameField(
- model_name='category',
- old_name='description_da_DK',
- new_name='description_da_dk',
+ model_name="category",
+ old_name="description_da_DK",
+ new_name="description_da_dk",
),
migrations.RenameField(
- model_name='category',
- old_name='description_de_DE',
- new_name='description_de_de',
+ model_name="category",
+ old_name="description_de_DE",
+ new_name="description_de_de",
),
migrations.RenameField(
- model_name='category',
- old_name='description_en_GB',
- new_name='description_en_gb',
+ model_name="category",
+ old_name="description_en_GB",
+ new_name="description_en_gb",
),
migrations.RenameField(
- model_name='category',
- old_name='description_en_US',
- new_name='description_en_us',
+ model_name="category",
+ old_name="description_en_US",
+ new_name="description_en_us",
),
migrations.RenameField(
- model_name='category',
- old_name='description_es_ES',
- new_name='description_es_es',
+ model_name="category",
+ old_name="description_es_ES",
+ new_name="description_es_es",
),
migrations.RenameField(
- model_name='category',
- old_name='description_fr_FR',
- new_name='description_fr_fr',
+ model_name="category",
+ old_name="description_fr_FR",
+ new_name="description_fr_fr",
),
migrations.RenameField(
- model_name='category',
- old_name='description_hi_IN',
- new_name='description_hi_in',
+ model_name="category",
+ old_name="description_hi_IN",
+ new_name="description_hi_in",
),
migrations.RenameField(
- model_name='category',
- old_name='description_it_IT',
- new_name='description_it_it',
+ model_name="category",
+ old_name="description_it_IT",
+ new_name="description_it_it",
),
migrations.RenameField(
- model_name='category',
- old_name='description_ja_JP',
- new_name='description_ja_jp',
+ model_name="category",
+ old_name="description_ja_JP",
+ new_name="description_ja_jp",
),
migrations.RenameField(
- model_name='category',
- old_name='description_kk_KZ',
- new_name='description_kk_kz',
+ model_name="category",
+ old_name="description_kk_KZ",
+ new_name="description_kk_kz",
),
migrations.RenameField(
- model_name='category',
- old_name='description_nl_NL',
- new_name='description_nl_nl',
+ model_name="category",
+ old_name="description_nl_NL",
+ new_name="description_nl_nl",
),
migrations.RenameField(
- model_name='category',
- old_name='description_pl_PL',
- new_name='description_pl_pl',
+ model_name="category",
+ old_name="description_pl_PL",
+ new_name="description_pl_pl",
),
migrations.RenameField(
- model_name='category',
- old_name='description_pt_BR',
- new_name='description_pt_br',
+ model_name="category",
+ old_name="description_pt_BR",
+ new_name="description_pt_br",
),
migrations.RenameField(
- model_name='category',
- old_name='description_ro_RO',
- new_name='description_ro_ro',
+ model_name="category",
+ old_name="description_ro_RO",
+ new_name="description_ro_ro",
),
migrations.RenameField(
- model_name='category',
- old_name='description_ru_RU',
- new_name='description_ru_ru',
+ model_name="category",
+ old_name="description_ru_RU",
+ new_name="description_ru_ru",
),
migrations.RenameField(
- model_name='category',
- old_name='name_ar_AR',
- new_name='name_ar_ar',
+ model_name="category",
+ old_name="name_ar_AR",
+ new_name="name_ar_ar",
),
migrations.RenameField(
- model_name='category',
- old_name='name_cs_CZ',
- new_name='name_cs_cz',
+ model_name="category",
+ old_name="name_cs_CZ",
+ new_name="name_cs_cz",
),
migrations.RenameField(
- model_name='category',
- old_name='name_da_DK',
- new_name='name_da_dk',
+ model_name="category",
+ old_name="name_da_DK",
+ new_name="name_da_dk",
),
migrations.RenameField(
- model_name='category',
- old_name='name_de_DE',
- new_name='name_de_de',
+ model_name="category",
+ old_name="name_de_DE",
+ new_name="name_de_de",
),
migrations.RenameField(
- model_name='category',
- old_name='name_en_GB',
- new_name='name_en_gb',
+ model_name="category",
+ old_name="name_en_GB",
+ new_name="name_en_gb",
),
migrations.RenameField(
- model_name='category',
- old_name='name_en_US',
- new_name='name_en_us',
+ model_name="category",
+ old_name="name_en_US",
+ new_name="name_en_us",
),
migrations.RenameField(
- model_name='category',
- old_name='name_es_ES',
- new_name='name_es_es',
+ model_name="category",
+ old_name="name_es_ES",
+ new_name="name_es_es",
),
migrations.RenameField(
- model_name='category',
- old_name='name_fr_FR',
- new_name='name_fr_fr',
+ model_name="category",
+ old_name="name_fr_FR",
+ new_name="name_fr_fr",
),
migrations.RenameField(
- model_name='category',
- old_name='name_hi_IN',
- new_name='name_hi_in',
+ model_name="category",
+ old_name="name_hi_IN",
+ new_name="name_hi_in",
),
migrations.RenameField(
- model_name='category',
- old_name='name_it_IT',
- new_name='name_it_it',
+ model_name="category",
+ old_name="name_it_IT",
+ new_name="name_it_it",
),
migrations.RenameField(
- model_name='category',
- old_name='name_ja_JP',
- new_name='name_ja_jp',
+ model_name="category",
+ old_name="name_ja_JP",
+ new_name="name_ja_jp",
),
migrations.RenameField(
- model_name='category',
- old_name='name_kk_KZ',
- new_name='name_kk_kz',
+ model_name="category",
+ old_name="name_kk_KZ",
+ new_name="name_kk_kz",
),
migrations.RenameField(
- model_name='category',
- old_name='name_nl_NL',
- new_name='name_nl_nl',
+ model_name="category",
+ old_name="name_nl_NL",
+ new_name="name_nl_nl",
),
migrations.RenameField(
- model_name='category',
- old_name='name_pl_PL',
- new_name='name_pl_pl',
+ model_name="category",
+ old_name="name_pl_PL",
+ new_name="name_pl_pl",
),
migrations.RenameField(
- model_name='category',
- old_name='name_pt_BR',
- new_name='name_pt_br',
+ model_name="category",
+ old_name="name_pt_BR",
+ new_name="name_pt_br",
),
migrations.RenameField(
- model_name='category',
- old_name='name_ro_RO',
- new_name='name_ro_ro',
+ model_name="category",
+ old_name="name_ro_RO",
+ new_name="name_ro_ro",
),
migrations.RenameField(
- model_name='category',
- old_name='name_ru_RU',
- new_name='name_ru_ru',
+ model_name="category",
+ old_name="name_ru_RU",
+ new_name="name_ru_ru",
),
migrations.RenameField(
- model_name='product',
- old_name='description_ar_AR',
- new_name='description_ar_ar',
+ model_name="product",
+ old_name="description_ar_AR",
+ new_name="description_ar_ar",
),
migrations.RenameField(
- model_name='product',
- old_name='description_cs_CZ',
- new_name='description_cs_cz',
+ model_name="product",
+ old_name="description_cs_CZ",
+ new_name="description_cs_cz",
),
migrations.RenameField(
- model_name='product',
- old_name='description_da_DK',
- new_name='description_da_dk',
+ model_name="product",
+ old_name="description_da_DK",
+ new_name="description_da_dk",
),
migrations.RenameField(
- model_name='product',
- old_name='description_de_DE',
- new_name='description_de_de',
+ model_name="product",
+ old_name="description_de_DE",
+ new_name="description_de_de",
),
migrations.RenameField(
- model_name='product',
- old_name='description_en_GB',
- new_name='description_en_gb',
+ model_name="product",
+ old_name="description_en_GB",
+ new_name="description_en_gb",
),
migrations.RenameField(
- model_name='product',
- old_name='description_en_US',
- new_name='description_en_us',
+ model_name="product",
+ old_name="description_en_US",
+ new_name="description_en_us",
),
migrations.RenameField(
- model_name='product',
- old_name='description_es_ES',
- new_name='description_es_es',
+ model_name="product",
+ old_name="description_es_ES",
+ new_name="description_es_es",
),
migrations.RenameField(
- model_name='product',
- old_name='description_fr_FR',
- new_name='description_fr_fr',
+ model_name="product",
+ old_name="description_fr_FR",
+ new_name="description_fr_fr",
),
migrations.RenameField(
- model_name='product',
- old_name='description_hi_IN',
- new_name='description_hi_in',
+ model_name="product",
+ old_name="description_hi_IN",
+ new_name="description_hi_in",
),
migrations.RenameField(
- model_name='product',
- old_name='description_it_IT',
- new_name='description_it_it',
+ model_name="product",
+ old_name="description_it_IT",
+ new_name="description_it_it",
),
migrations.RenameField(
- model_name='product',
- old_name='description_ja_JP',
- new_name='description_ja_jp',
+ model_name="product",
+ old_name="description_ja_JP",
+ new_name="description_ja_jp",
),
migrations.RenameField(
- model_name='product',
- old_name='description_kk_KZ',
- new_name='description_kk_kz',
+ model_name="product",
+ old_name="description_kk_KZ",
+ new_name="description_kk_kz",
),
migrations.RenameField(
- model_name='product',
- old_name='description_nl_NL',
- new_name='description_nl_nl',
+ model_name="product",
+ old_name="description_nl_NL",
+ new_name="description_nl_nl",
),
migrations.RenameField(
- model_name='product',
- old_name='description_pl_PL',
- new_name='description_pl_pl',
+ model_name="product",
+ old_name="description_pl_PL",
+ new_name="description_pl_pl",
),
migrations.RenameField(
- model_name='product',
- old_name='description_pt_BR',
- new_name='description_pt_br',
+ model_name="product",
+ old_name="description_pt_BR",
+ new_name="description_pt_br",
),
migrations.RenameField(
- model_name='product',
- old_name='description_ro_RO',
- new_name='description_ro_ro',
+ model_name="product",
+ old_name="description_ro_RO",
+ new_name="description_ro_ro",
),
migrations.RenameField(
- model_name='product',
- old_name='description_ru_RU',
- new_name='description_ru_ru',
+ model_name="product",
+ old_name="description_ru_RU",
+ new_name="description_ru_ru",
),
migrations.RenameField(
- model_name='product',
- old_name='name_ar_AR',
- new_name='name_ar_ar',
+ model_name="product",
+ old_name="name_ar_AR",
+ new_name="name_ar_ar",
),
migrations.RenameField(
- model_name='product',
- old_name='name_cs_CZ',
- new_name='name_cs_cz',
+ model_name="product",
+ old_name="name_cs_CZ",
+ new_name="name_cs_cz",
),
migrations.RenameField(
- model_name='product',
- old_name='name_da_DK',
- new_name='name_da_dk',
+ model_name="product",
+ old_name="name_da_DK",
+ new_name="name_da_dk",
),
migrations.RenameField(
- model_name='product',
- old_name='name_de_DE',
- new_name='name_de_de',
+ model_name="product",
+ old_name="name_de_DE",
+ new_name="name_de_de",
),
migrations.RenameField(
- model_name='product',
- old_name='name_en_GB',
- new_name='name_en_gb',
+ model_name="product",
+ old_name="name_en_GB",
+ new_name="name_en_gb",
),
migrations.RenameField(
- model_name='product',
- old_name='name_en_US',
- new_name='name_en_us',
+ model_name="product",
+ old_name="name_en_US",
+ new_name="name_en_us",
),
migrations.RenameField(
- model_name='product',
- old_name='name_es_ES',
- new_name='name_es_es',
+ model_name="product",
+ old_name="name_es_ES",
+ new_name="name_es_es",
),
migrations.RenameField(
- model_name='product',
- old_name='name_fr_FR',
- new_name='name_fr_fr',
+ model_name="product",
+ old_name="name_fr_FR",
+ new_name="name_fr_fr",
),
migrations.RenameField(
- model_name='product',
- old_name='name_hi_IN',
- new_name='name_hi_in',
+ model_name="product",
+ old_name="name_hi_IN",
+ new_name="name_hi_in",
),
migrations.RenameField(
- model_name='product',
- old_name='name_it_IT',
- new_name='name_it_it',
+ model_name="product",
+ old_name="name_it_IT",
+ new_name="name_it_it",
),
migrations.RenameField(
- model_name='product',
- old_name='name_ja_JP',
- new_name='name_ja_jp',
+ model_name="product",
+ old_name="name_ja_JP",
+ new_name="name_ja_jp",
),
migrations.RenameField(
- model_name='product',
- old_name='name_kk_KZ',
- new_name='name_kk_kz',
+ model_name="product",
+ old_name="name_kk_KZ",
+ new_name="name_kk_kz",
),
migrations.RenameField(
- model_name='product',
- old_name='name_nl_NL',
- new_name='name_nl_nl',
+ model_name="product",
+ old_name="name_nl_NL",
+ new_name="name_nl_nl",
),
migrations.RenameField(
- model_name='product',
- old_name='name_pl_PL',
- new_name='name_pl_pl',
+ model_name="product",
+ old_name="name_pl_PL",
+ new_name="name_pl_pl",
),
migrations.RenameField(
- model_name='product',
- old_name='name_pt_BR',
- new_name='name_pt_br',
+ model_name="product",
+ old_name="name_pt_BR",
+ new_name="name_pt_br",
),
migrations.RenameField(
- model_name='product',
- old_name='name_ro_RO',
- new_name='name_ro_ro',
+ model_name="product",
+ old_name="name_ro_RO",
+ new_name="name_ro_ro",
),
migrations.RenameField(
- model_name='product',
- old_name='name_ru_RU',
- new_name='name_ru_ru',
+ model_name="product",
+ old_name="name_ru_RU",
+ new_name="name_ru_ru",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_ar_AR',
- new_name='name_ar_ar',
+ model_name="producttag",
+ old_name="name_ar_AR",
+ new_name="name_ar_ar",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_cs_CZ',
- new_name='name_cs_cz',
+ model_name="producttag",
+ old_name="name_cs_CZ",
+ new_name="name_cs_cz",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_da_DK',
- new_name='name_da_dk',
+ model_name="producttag",
+ old_name="name_da_DK",
+ new_name="name_da_dk",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_de_DE',
- new_name='name_de_de',
+ model_name="producttag",
+ old_name="name_de_DE",
+ new_name="name_de_de",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_en_GB',
- new_name='name_en_gb',
+ model_name="producttag",
+ old_name="name_en_GB",
+ new_name="name_en_gb",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_en_US',
- new_name='name_en_us',
+ model_name="producttag",
+ old_name="name_en_US",
+ new_name="name_en_us",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_es_ES',
- new_name='name_es_es',
+ model_name="producttag",
+ old_name="name_es_ES",
+ new_name="name_es_es",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_fr_FR',
- new_name='name_fr_fr',
+ model_name="producttag",
+ old_name="name_fr_FR",
+ new_name="name_fr_fr",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_hi_IN',
- new_name='name_hi_in',
+ model_name="producttag",
+ old_name="name_hi_IN",
+ new_name="name_hi_in",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_it_IT',
- new_name='name_it_it',
+ model_name="producttag",
+ old_name="name_it_IT",
+ new_name="name_it_it",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_ja_JP',
- new_name='name_ja_jp',
+ model_name="producttag",
+ old_name="name_ja_JP",
+ new_name="name_ja_jp",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_kk_KZ',
- new_name='name_kk_kz',
+ model_name="producttag",
+ old_name="name_kk_KZ",
+ new_name="name_kk_kz",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_nl_NL',
- new_name='name_nl_nl',
+ model_name="producttag",
+ old_name="name_nl_NL",
+ new_name="name_nl_nl",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_pl_PL',
- new_name='name_pl_pl',
+ model_name="producttag",
+ old_name="name_pl_PL",
+ new_name="name_pl_pl",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_pt_BR',
- new_name='name_pt_br',
+ model_name="producttag",
+ old_name="name_pt_BR",
+ new_name="name_pt_br",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_ro_RO',
- new_name='name_ro_ro',
+ model_name="producttag",
+ old_name="name_ro_RO",
+ new_name="name_ro_ro",
),
migrations.RenameField(
- model_name='producttag',
- old_name='name_ru_RU',
- new_name='name_ru_ru',
+ model_name="producttag",
+ old_name="name_ru_RU",
+ new_name="name_ru_ru",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_ar_AR',
- new_name='description_ar_ar',
+ model_name="promotion",
+ old_name="description_ar_AR",
+ new_name="description_ar_ar",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_cs_CZ',
- new_name='description_cs_cz',
+ model_name="promotion",
+ old_name="description_cs_CZ",
+ new_name="description_cs_cz",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_da_DK',
- new_name='description_da_dk',
+ model_name="promotion",
+ old_name="description_da_DK",
+ new_name="description_da_dk",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_de_DE',
- new_name='description_de_de',
+ model_name="promotion",
+ old_name="description_de_DE",
+ new_name="description_de_de",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_en_GB',
- new_name='description_en_gb',
+ model_name="promotion",
+ old_name="description_en_GB",
+ new_name="description_en_gb",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_en_US',
- new_name='description_en_us',
+ model_name="promotion",
+ old_name="description_en_US",
+ new_name="description_en_us",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_es_ES',
- new_name='description_es_es',
+ model_name="promotion",
+ old_name="description_es_ES",
+ new_name="description_es_es",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_fr_FR',
- new_name='description_fr_fr',
+ model_name="promotion",
+ old_name="description_fr_FR",
+ new_name="description_fr_fr",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_hi_IN',
- new_name='description_hi_in',
+ model_name="promotion",
+ old_name="description_hi_IN",
+ new_name="description_hi_in",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_it_IT',
- new_name='description_it_it',
+ model_name="promotion",
+ old_name="description_it_IT",
+ new_name="description_it_it",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_ja_JP',
- new_name='description_ja_jp',
+ model_name="promotion",
+ old_name="description_ja_JP",
+ new_name="description_ja_jp",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_kk_KZ',
- new_name='description_kk_kz',
+ model_name="promotion",
+ old_name="description_kk_KZ",
+ new_name="description_kk_kz",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_nl_NL',
- new_name='description_nl_nl',
+ model_name="promotion",
+ old_name="description_nl_NL",
+ new_name="description_nl_nl",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_pl_PL',
- new_name='description_pl_pl',
+ model_name="promotion",
+ old_name="description_pl_PL",
+ new_name="description_pl_pl",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_pt_BR',
- new_name='description_pt_br',
+ model_name="promotion",
+ old_name="description_pt_BR",
+ new_name="description_pt_br",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_ro_RO',
- new_name='description_ro_ro',
+ model_name="promotion",
+ old_name="description_ro_RO",
+ new_name="description_ro_ro",
),
migrations.RenameField(
- model_name='promotion',
- old_name='description_ru_RU',
- new_name='description_ru_ru',
+ model_name="promotion",
+ old_name="description_ru_RU",
+ new_name="description_ru_ru",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_ar_AR',
- new_name='name_ar_ar',
+ model_name="promotion",
+ old_name="name_ar_AR",
+ new_name="name_ar_ar",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_cs_CZ',
- new_name='name_cs_cz',
+ model_name="promotion",
+ old_name="name_cs_CZ",
+ new_name="name_cs_cz",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_da_DK',
- new_name='name_da_dk',
+ model_name="promotion",
+ old_name="name_da_DK",
+ new_name="name_da_dk",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_de_DE',
- new_name='name_de_de',
+ model_name="promotion",
+ old_name="name_de_DE",
+ new_name="name_de_de",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_en_GB',
- new_name='name_en_gb',
+ model_name="promotion",
+ old_name="name_en_GB",
+ new_name="name_en_gb",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_en_US',
- new_name='name_en_us',
+ model_name="promotion",
+ old_name="name_en_US",
+ new_name="name_en_us",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_es_ES',
- new_name='name_es_es',
+ model_name="promotion",
+ old_name="name_es_ES",
+ new_name="name_es_es",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_fr_FR',
- new_name='name_fr_fr',
+ model_name="promotion",
+ old_name="name_fr_FR",
+ new_name="name_fr_fr",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_hi_IN',
- new_name='name_hi_in',
+ model_name="promotion",
+ old_name="name_hi_IN",
+ new_name="name_hi_in",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_it_IT',
- new_name='name_it_it',
+ model_name="promotion",
+ old_name="name_it_IT",
+ new_name="name_it_it",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_ja_JP',
- new_name='name_ja_jp',
+ model_name="promotion",
+ old_name="name_ja_JP",
+ new_name="name_ja_jp",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_kk_KZ',
- new_name='name_kk_kz',
+ model_name="promotion",
+ old_name="name_kk_KZ",
+ new_name="name_kk_kz",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_nl_NL',
- new_name='name_nl_nl',
+ model_name="promotion",
+ old_name="name_nl_NL",
+ new_name="name_nl_nl",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_pl_PL',
- new_name='name_pl_pl',
+ model_name="promotion",
+ old_name="name_pl_PL",
+ new_name="name_pl_pl",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_pt_BR',
- new_name='name_pt_br',
+ model_name="promotion",
+ old_name="name_pt_BR",
+ new_name="name_pt_br",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_ro_RO',
- new_name='name_ro_ro',
+ model_name="promotion",
+ old_name="name_ro_RO",
+ new_name="name_ro_ro",
),
migrations.RenameField(
- model_name='promotion',
- old_name='name_ru_RU',
- new_name='name_ru_ru',
+ model_name="promotion",
+ old_name="name_ru_RU",
+ new_name="name_ru_ru",
),
]
diff --git a/core/migrations/0022_category_slug.py b/core/migrations/0022_category_slug.py
index fe1e3b26..cd887039 100644
--- a/core/migrations/0022_category_slug.py
+++ b/core/migrations/0022_category_slug.py
@@ -7,7 +7,7 @@ from django.db import migrations
def populate_slugs(apps, schema_editor):
if schema_editor:
pass
- Category = apps.get_model('core', 'Category')
+ Category = apps.get_model("core", "Category")
for category in Category.objects.all():
try:
if not category.slug:
@@ -18,15 +18,16 @@ def populate_slugs(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
- ('core', '0021_rename_name_ar_ar_attribute_name_ar_ar_and_more'),
+ ("core", "0021_rename_name_ar_ar_attribute_name_ar_ar_and_more"),
]
operations = [
migrations.AddField(
- model_name='category',
- name='slug',
- field=django_extensions.db.fields.AutoSlugField(allow_unicode=True, blank=True, editable=False, null=True,
- populate_from=('uuid', 'name'), unique=True),
+ model_name="category",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True, blank=True, editable=False, null=True, populate_from=("uuid", "name"), unique=True
+ ),
),
migrations.RunPython(populate_slugs, reverse_code=migrations.RunPython.noop),
]
diff --git a/core/migrations/0023_address_address_line.py b/core/migrations/0023_address_address_line.py
index 55654c18..e1f6ebf4 100644
--- a/core/migrations/0023_address_address_line.py
+++ b/core/migrations/0023_address_address_line.py
@@ -5,14 +5,15 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('core', '0022_category_slug'),
+ ("core", "0022_category_slug"),
]
operations = [
migrations.AddField(
- model_name='address',
- name='address_line',
- field=models.TextField(blank=True, help_text='address line for the customer', null=True,
- verbose_name='address line'),
+ model_name="address",
+ name="address_line",
+ field=models.TextField(
+ blank=True, help_text="address line for the customer", null=True, verbose_name="address line"
+ ),
),
]
diff --git a/core/migrations/0024_categorytag_category_tags.py b/core/migrations/0024_categorytag_category_tags.py
index 9b140e9a..71a220aa 100644
--- a/core/migrations/0024_categorytag_category_tags.py
+++ b/core/migrations/0024_categorytag_category_tags.py
@@ -9,95 +9,256 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('core', '0023_address_address_line'),
+ ("core", "0023_address_address_line"),
]
operations = [
migrations.CreateModel(
- name='CategoryTag',
+ name="CategoryTag",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('tag_name', models.CharField(help_text='internal tag identifier for the product tag', max_length=255,
- verbose_name='tag name')),
- ('name',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, unique=True,
- verbose_name='tag display name')),
- ('name_en_gb',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_ar_ar',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_cs_cz',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_da_dk',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_de_de',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_en_us',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_es_es',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_fr_fr',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_hi_in',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_it_it',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_ja_jp',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_kk_kz',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_nl_nl',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_pl_pl',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_pt_br',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_ro_ro',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_ru_ru',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
- ('name_zh_hans',
- models.CharField(help_text='user-friendly name for the product tag', max_length=255, null=True,
- unique=True, verbose_name='tag display name')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ (
+ "tag_name",
+ models.CharField(
+ help_text="internal tag identifier for the product tag", max_length=255, verbose_name="tag name"
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_en_gb",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ar_ar",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_cs_cz",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_da_dk",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_de_de",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_en_us",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_es_es",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_fr_fr",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_hi_in",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_it_it",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ja_jp",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_kk_kz",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_nl_nl",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_pl_pl",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_pt_br",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ro_ro",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_ru_ru",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
+ (
+ "name_zh_hans",
+ models.CharField(
+ help_text="user-friendly name for the product tag",
+ max_length=255,
+ null=True,
+ unique=True,
+ verbose_name="tag display name",
+ ),
+ ),
],
options={
- 'verbose_name': 'category tag',
- 'verbose_name_plural': 'category tags',
+ "verbose_name": "category tag",
+ "verbose_name_plural": "category tags",
},
- bases=(django_prometheus.models.ExportModelOperationsMixin('category_tag'), models.Model),
+ bases=(django_prometheus.models.ExportModelOperationsMixin("category_tag"), models.Model),
),
migrations.AddField(
- model_name='category',
- name='tags',
- field=models.ManyToManyField(blank=True, help_text='tags that help describe or group this category',
- to='core.categorytag', verbose_name='category tags'),
+ model_name="category",
+ name="tags",
+ field=models.ManyToManyField(
+ blank=True,
+ help_text="tags that help describe or group this category",
+ to="core.categorytag",
+ verbose_name="category tags",
+ ),
),
]
diff --git a/core/migrations/0025_alter_product_category.py b/core/migrations/0025_alter_product_category.py
index 4e6cc22d..f524aef9 100644
--- a/core/migrations/0025_alter_product_category.py
+++ b/core/migrations/0025_alter_product_category.py
@@ -6,15 +6,19 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
- ('core', '0024_categorytag_category_tags'),
+ ("core", "0024_categorytag_category_tags"),
]
operations = [
migrations.AlterField(
- model_name='product',
- name='category',
- field=models.ForeignKey(help_text='category this product belongs to',
- on_delete=django.db.models.deletion.CASCADE, related_name='products',
- to='core.category', verbose_name='category'),
+ model_name="product",
+ name="category",
+ field=models.ForeignKey(
+ help_text="category this product belongs to",
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="products",
+ to="core.category",
+ verbose_name="category",
+ ),
),
]
diff --git a/core/migrations/0026_brand_slug_alter_category_slug_alter_product_slug.py b/core/migrations/0026_brand_slug_alter_category_slug_alter_product_slug.py
index 3a0a57b3..39905993 100644
--- a/core/migrations/0026_brand_slug_alter_category_slug_alter_product_slug.py
+++ b/core/migrations/0026_brand_slug_alter_category_slug_alter_product_slug.py
@@ -5,7 +5,6 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("core", "0025_alter_product_category"),
]
diff --git a/core/migrations/0027_brand_priority_alter_brand_slug.py b/core/migrations/0027_brand_priority_alter_brand_slug.py
index 0aca9c40..5427bc2c 100644
--- a/core/migrations/0027_brand_priority_alter_brand_slug.py
+++ b/core/migrations/0027_brand_priority_alter_brand_slug.py
@@ -5,7 +5,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("core", "0026_brand_slug_alter_category_slug_alter_product_slug"),
]
diff --git a/core/migrations/0028_alter_category_slug_alter_product_slug.py b/core/migrations/0028_alter_category_slug_alter_product_slug.py
index e14befd4..552057fa 100644
--- a/core/migrations/0028_alter_category_slug_alter_product_slug.py
+++ b/core/migrations/0028_alter_category_slug_alter_product_slug.py
@@ -5,7 +5,6 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("core", "0027_brand_priority_alter_brand_slug"),
]
diff --git a/core/migrations/0029_alter_category_slug.py b/core/migrations/0029_alter_category_slug.py
index 1c11d24d..d0ef9170 100644
--- a/core/migrations/0029_alter_category_slug.py
+++ b/core/migrations/0029_alter_category_slug.py
@@ -5,7 +5,6 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("core", "0028_alter_category_slug_alter_product_slug"),
]
diff --git a/core/migrations/0030_alter_category_slug.py b/core/migrations/0030_alter_category_slug.py
index b46497e8..8ad88128 100644
--- a/core/migrations/0030_alter_category_slug.py
+++ b/core/migrations/0030_alter_category_slug.py
@@ -5,7 +5,6 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("core", "0029_alter_category_slug"),
]
diff --git a/core/migrations/0031_alter_product_slug.py b/core/migrations/0031_alter_product_slug.py
index cebf2052..39b0fa1b 100644
--- a/core/migrations/0031_alter_product_slug.py
+++ b/core/migrations/0031_alter_product_slug.py
@@ -5,7 +5,6 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("core", "0030_alter_category_slug"),
]
diff --git a/core/migrations/0032_alter_brand_slug_alter_category_slug_and_more.py b/core/migrations/0032_alter_brand_slug_alter_category_slug_and_more.py
index 237c5935..eb6005ab 100644
--- a/core/migrations/0032_alter_brand_slug_alter_category_slug_and_more.py
+++ b/core/migrations/0032_alter_brand_slug_alter_category_slug_and_more.py
@@ -5,7 +5,6 @@ from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("core", "0031_alter_product_slug"),
]
diff --git a/core/migrations/0033_alter_category_slug.py b/core/migrations/0033_alter_category_slug.py
index 034beed6..a022aba5 100644
--- a/core/migrations/0033_alter_category_slug.py
+++ b/core/migrations/0033_alter_category_slug.py
@@ -6,7 +6,6 @@ import core.utils.db
class Migration(migrations.Migration):
-
dependencies = [
("core", "0032_alter_brand_slug_alter_category_slug_and_more"),
]
diff --git a/core/migrations/0034_category_priority_alter_brand_priority.py b/core/migrations/0034_category_priority_alter_brand_priority.py
index cd64f3f1..08c161fe 100644
--- a/core/migrations/0034_category_priority_alter_brand_priority.py
+++ b/core/migrations/0034_category_priority_alter_brand_priority.py
@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("core", "0033_alter_category_slug"),
]
diff --git a/core/migrations/0035_alter_brand_slug_alter_category_slug_and_more.py b/core/migrations/0035_alter_brand_slug_alter_category_slug_and_more.py
new file mode 100644
index 00000000..16a5702d
--- /dev/null
+++ b/core/migrations/0035_alter_brand_slug_alter_category_slug_and_more.py
@@ -0,0 +1,59 @@
+# Generated by Django 5.2 on 2025-06-29 13:09
+
+import core.utils.db
+import django_extensions.db.fields
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0034_category_priority_alter_brand_priority"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="brand",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True,
+ blank=True,
+ editable=False,
+ max_length=88,
+ null=True,
+ overwrite=True,
+ populate_from=("name",),
+ unique=True,
+ verbose_name="Slug",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="category",
+ name="slug",
+ field=core.utils.db.TweakedAutoSlugField(
+ allow_unicode=True,
+ blank=True,
+ editable=False,
+ max_length=88,
+ null=True,
+ overwrite=True,
+ populate_from=("parent__name", "name"),
+ unique=True,
+ verbose_name="Slug",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="product",
+ name="slug",
+ field=django_extensions.db.fields.AutoSlugField(
+ allow_unicode=True,
+ blank=True,
+ editable=False,
+ max_length=88,
+ null=True,
+ overwrite=True,
+ populate_from=("name", "brand__slug", "category__slug", "uuid"),
+ unique=True,
+ verbose_name="Slug",
+ ),
+ ),
+ ]
diff --git a/core/migrations/0036_vendor_b2b_auth_token_vendor_users.py b/core/migrations/0036_vendor_b2b_auth_token_vendor_users.py
new file mode 100644
index 00000000..0d2c74a2
--- /dev/null
+++ b/core/migrations/0036_vendor_b2b_auth_token_vendor_users.py
@@ -0,0 +1,30 @@
+# Generated by Django 5.2 on 2025-07-28 08:55
+
+import core.utils
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("core", "0035_alter_brand_slug_alter_category_slug_and_more"),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="vendor",
+ name="b2b_auth_token",
+ field=models.CharField(
+ blank=True,
+ default=core.utils.generate_human_readable_token,
+ max_length=20,
+ null=True,
+ ),
+ ),
+ migrations.AddField(
+ model_name="vendor",
+ name="users",
+ field=models.ManyToManyField(blank=True, related_name="vendors", to=settings.AUTH_USER_MODEL),
+ ),
+ ]
diff --git a/core/models.py b/core/models.py
index 2e8e637a..dca0c750 100644
--- a/core/models.py
+++ b/core/models.py
@@ -1,15 +1,17 @@
import datetime
import json
import logging
-from decimal import Decimal
-from typing import Optional, Self
+from typing import Any, Optional, Self
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.postgres.indexes import GinIndex
from django.core.cache import cache
from django.core.exceptions import BadRequest, ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
+from django.db import transaction
from django.db.models import (
CASCADE,
PROTECT,
@@ -28,7 +30,10 @@ from django.db.models import (
Max,
OneToOneField,
PositiveIntegerField,
+ QuerySet,
TextField,
+ UUIDField,
+ URLField,
)
from django.db.models.indexes import Index
from django.http import Http404
@@ -49,6 +54,7 @@ from core.utils import (
generate_human_readable_id,
get_product_uuid_as_path,
get_random_code,
+ generate_human_readable_token,
)
from core.utils.db import TweakedAutoSlugField, unicode_slugify_function
from core.utils.lists import FAILED_STATUSES
@@ -56,13 +62,39 @@ from core.validators import validate_category_image_dimensions
from evibes.settings import CURRENCY_CODE
from payments.models import Transaction
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
-class AttributeGroup(ExportModelOperationsMixin("attribute_group"), NiceModel):
+class AttributeGroup(ExportModelOperationsMixin("attribute_group"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a group of attributes, which can be hierarchical.
+
+ This class is used to manage and organize attribute groups. An attribute
+ group can have a parent group, forming a hierarchical structure. This can
+ be useful for categorizing and managing attributes more effectively in a
+ complex system.
+
+ Attributes:
+ parent (Self): A foreign key referencing the parent of this group. It
+ can be null or blank if the group does not have a parent. The parent
+ group organizes the hierarchical structure.
+ name (str): The unique name of the attribute group. It is limited to a
+ maximum of 255 characters.
+ is_publicly_visible (bool): Indicates if the attribute group is visible
+ publicly.
+
+ Meta:
+ verbose_name: A human-readable name for the class, set to 'attribute
+ group'.
+ verbose_name_plural: A human-readable plural name for the class, set to
+ 'attribute groups'.
+ """
+
is_publicly_visible = True
+ attributes: QuerySet["Attribute"]
+ children: QuerySet["Self"]
- parent: Self = ForeignKey( # type: ignore
+ parent = ForeignKey(
"self",
on_delete=CASCADE,
null=True,
@@ -71,7 +103,7 @@ class AttributeGroup(ExportModelOperationsMixin("attribute_group"), NiceModel):
help_text=_("parent of this group"),
verbose_name=_("parent attribute group"),
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
verbose_name=_("attribute group's name"),
help_text=_("attribute group's name"),
@@ -86,24 +118,50 @@ class AttributeGroup(ExportModelOperationsMixin("attribute_group"), NiceModel):
verbose_name_plural = _("attribute groups")
-class Vendor(ExportModelOperationsMixin("vendor"), NiceModel):
+class Vendor(ExportModelOperationsMixin("vendor"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a vendor entity capable of storing information about external vendors and
+ their interaction requirements.
+
+ The Vendor class is used to define and manage information related to an external vendor.
+ It stores the vendor's name, authentication details required for communication,
+ and the percentage markup applied to products retrieved from the vendor. This model also
+ maintains additional metadata and constraints, making it suitable for use in systems
+ that interact with third-party vendors.
+
+ Attributes:
+ authentication (dict): Credentials and endpoint information required for vendor
+ communication, stored in a JSON field.
+ markup_percent (int): The markup percentage applied to products sent by this
+ vendor. Must be an integer between 0 and 100 inclusive.
+ name (str): The unique name of the vendor, with a maximum length of 255
+ characters.
+
+ Meta:
+ verbose_name (str): Singular name of the vendor entity ("vendor").
+ verbose_name_plural (str): Plural name of the vendor entities ("vendors").
+ indexes (list): List of database indexes applied to this model, including a
+ GIN index on the 'authentication' field.
+
+ Returns:
+ str: The vendor's name when the instance is represented as a string.
+ """
+
is_publicly_visible = False
- authentication: dict = JSONField( # type: ignore
+ authentication = JSONField(
blank=True,
null=True,
- help_text=_(
- "stores credentials and endpoints required for vendor communication"
- ),
+ help_text=_("stores credentials and endpoints required for vendor communication"),
verbose_name=_("authentication info"),
)
- markup_percent: int = IntegerField( # type: ignore
+ markup_percent = IntegerField(
default=0,
validators=[MinValueValidator(0), MaxValueValidator(100)],
help_text=_("define the markup for products retrieved from this vendor"),
verbose_name=_("vendor markup percentage"),
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
help_text=_("name of this vendor"),
verbose_name=_("vendor name"),
@@ -111,10 +169,23 @@ class Vendor(ExportModelOperationsMixin("vendor"), NiceModel):
null=False,
unique=True,
)
+ users = ManyToManyField(to="vibes_auth.User", related_name="vendors", blank=True)
+ b2b_auth_token = CharField(default=generate_human_readable_token, max_length=20, null=True, blank=True)
def __str__(self) -> str:
return self.name
+ def save(self, **kwargs) -> None:
+ users = self.users.filter(is_active=True)
+ users = users.exclude(attributes__icontains="is_business")
+ if users.count() > 0:
+ for user in users:
+ if not user.attributes:
+ user.attributes = {}
+ user.attributes.update({"is_business": True})
+ user.save()
+ return super().save(**kwargs)
+
class Meta:
verbose_name = _("vendor")
verbose_name_plural = _("vendors")
@@ -123,17 +194,33 @@ class Vendor(ExportModelOperationsMixin("vendor"), NiceModel):
]
-class ProductTag(ExportModelOperationsMixin("product_tag"), NiceModel):
+class ProductTag(ExportModelOperationsMixin("product_tag"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a product tag used for classifying or identifying products.
+
+ The ProductTag class is designed to uniquely identify and classify products
+ through a combination of an internal tag identifier and a user-friendly
+ display name. It supports operations exported through mixins and provides
+ metadata customization for administrative purposes.
+
+ Attributes:
+ is_publicly_visible: A boolean indicating whether the tag is publicly
+ visible.
+ tag_name: Internal tag identifier for the product tag.
+ name: User-friendly name for the product tag.
+
+ """
+
is_publicly_visible = True
- tag_name: str = CharField( # type: ignore
+ tag_name = CharField(
blank=False,
null=False,
max_length=255,
help_text=_("internal tag identifier for the product tag"),
verbose_name=_("tag name"),
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
help_text=_("user-friendly name for the product tag"),
verbose_name=_("tag display name"),
@@ -148,17 +235,30 @@ class ProductTag(ExportModelOperationsMixin("product_tag"), NiceModel):
verbose_name_plural = _("product tags")
-class CategoryTag(ExportModelOperationsMixin("category_tag"), NiceModel):
+class CategoryTag(ExportModelOperationsMixin("category_tag"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a category tag used for products.
+
+ This class models a category tag that can be used to associate and classify products.
+ It includes attributes for an internal tag identifier and a user-friendly display name.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates if the category tag is publicly visible.
+ tag_name (str): Internal tag identifier for the product tag.
+ name (str): User-friendly name for the product tag.
+
+ """
+
is_publicly_visible = True
- tag_name: str = CharField( # type: ignore
+ tag_name = CharField(
blank=False,
null=False,
max_length=255,
help_text=_("internal tag identifier for the product tag"),
verbose_name=_("tag name"),
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
help_text=_("user-friendly name for the product tag"),
verbose_name=_("tag display name"),
@@ -173,10 +273,77 @@ class CategoryTag(ExportModelOperationsMixin("category_tag"), NiceModel):
verbose_name_plural = _("category tags")
-class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel):
+class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a category entity to organize and group related items in a hierarchical
+ structure. Categories may have hierarchical relationships with other categories,
+ supporting parent-child relationships. The class includes fields for metadata and
+ visual representation, which serve as a foundation for category-related features.
+
+ This class is typically used to define and manage product categories or other similar
+ groupings within an application, allowing users or administrators to specify the
+ name, description, and hierarchy of categories, as well as assign attributes like
+ images, tags, or priority.
+
+ Attributes
+ ----------
+ is_publicly_visible
+ A flag indicating whether the category is visible to the public.
+
+ image : ImageField
+ Represents an optional image associated with the category. The image is used
+ to visually represent the category.
+
+ markup_percent
+ Specifies the markup percentage for products in this category. It is validated
+ to ensure values fall between 0 and 100.
+
+ parent
+ Represents the parent category in a hierarchical structure. This forms category
+ relationships to enable nesting.
+
+ name
+ The name of the category, which also must be unique. This serves as the primary
+ identifier for the category.
+
+ description
+ An optional detailed description explaining the purpose or details of the category.
+
+ slug
+ A unique, auto-generated field created from the category's name and parent name,
+ suitable for use in URLs and identifying the category.
+
+ tags
+ Optional tags used to group or describe the category better.
+
+ priority
+ Represents the priority of the category, which could be used for sorting or
+ rendering purposes.
+
+ Methods
+ -------
+ __str__()
+ Returns the name of the category as its string representation.
+
+ get_tree_depth()
+ Computes the depth of the category in the hierarchical structure. It determines
+ the maximum depth of its descendants or returns zero if the category is a leaf.
+
+ ------------
+ verbose_name
+ Specifies the singular human-readable name for the category model.
+
+ verbose_name_plural
+ Specifies the plural human-readable name for the category model.
+
+ ordering : list
+ Defines the default ordering for category instances, based on their hierarchical
+ structure.
+ """
+
is_publicly_visible = True
- image = ImageField( # type: ignore
+ image = ImageField(
blank=True,
null=True,
help_text=_("upload an image representing this category"),
@@ -184,13 +351,13 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel):
validators=[validate_category_image_dimensions],
verbose_name=_("category image"),
)
- markup_percent: int = IntegerField( # type: ignore
+ markup_percent = IntegerField(
default=0,
validators=[MinValueValidator(0), MaxValueValidator(100)],
help_text=_("define a markup percentage for products in this category"),
verbose_name=_("markup percentage"),
)
- parent: Self = TreeForeignKey(
+ parent = TreeForeignKey(
"self",
on_delete=CASCADE,
blank=True,
@@ -200,21 +367,21 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel):
verbose_name=_("parent category"),
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
verbose_name=_("category name"),
help_text=_("provide a name for this category"),
unique=True,
)
- description: str = TextField( # type: ignore
+ description = TextField(
blank=True,
null=True,
help_text=_("add a detailed description for this category"),
verbose_name=_("category description"),
)
- slug: str = TweakedAutoSlugField( # type: ignore
+ slug = TweakedAutoSlugField(
populate_from=(
"parent__name",
"name",
@@ -228,13 +395,13 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel):
null=True,
verbose_name=_("Slug"),
)
- tags: CategoryTag = ManyToManyField( # type: ignore
+ tags = ManyToManyField(
"core.CategoryTag",
blank=True,
help_text=_("tags that help describe or group this category"),
verbose_name=_("category tags"),
)
- priority: int = PositiveIntegerField( # type: ignore
+ priority = PositiveIntegerField(
default=0,
null=False,
blank=False,
@@ -247,10 +414,7 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel):
def get_tree_depth(self):
if self.is_leaf_node():
return 0
- return (
- self.get_descendants().aggregate(max_depth=Max("level"))["max_depth"]
- - self.get_level()
- )
+ return self.get_descendants().aggregate(max_depth=Max("level"))["max_depth"] - self.get_level()
class Meta:
verbose_name = _("category")
@@ -258,16 +422,35 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel):
ordering = ["tree_id", "lft"]
-class Brand(ExportModelOperationsMixin("brand"), NiceModel):
+class Brand(ExportModelOperationsMixin("brand"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a Brand object in the system.
+
+ This class handles information and attributes related to a brand, including its name, logos,
+ description, associated categories, a unique slug, and priority order.
+ It allows for the organization and representation of brand-related data within the application.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates if the brand is visible publicly.
+ name (str): The name of the brand.
+ small_logo (ImageField): An optional small logo image file representing the brand.
+ big_logo (ImageField): An optional large logo image file representing the brand.
+ description (str): An optional textual description providing details about the brand.
+ categories (Category): Optional categories associated with this brand.
+ slug (str): A unique auto-generated slug used for SEO-friendly URLs.
+ priority (int): Specifies the priority ranking of the brand.
+
+ """
+
is_publicly_visible = True
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
help_text=_("name of this brand"),
verbose_name=_("brand name"),
unique=True,
)
- small_logo = ImageField( # type: ignore
+ small_logo = ImageField(
upload_to="brands/",
blank=True,
null=True,
@@ -275,7 +458,7 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel):
validators=[validate_category_image_dimensions],
verbose_name=_("brand small image"),
)
- big_logo = ImageField( # type: ignore
+ big_logo = ImageField(
upload_to="brands/",
blank=True,
null=True,
@@ -283,19 +466,19 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel):
validators=[validate_category_image_dimensions],
verbose_name=_("brand big image"),
)
- description: str = TextField( # type: ignore
+ description = TextField(
blank=True,
null=True,
help_text=_("add a detailed description of the brand"),
verbose_name=_("brand description"),
)
- categories: Category = ManyToManyField( # type: ignore
+ categories = ManyToManyField(
"core.Category",
blank=True,
help_text=_("optional categories that this brand is associated with"),
verbose_name=_("associated categories"),
)
- slug: str = AutoSlugField( # type: ignore
+ slug = AutoSlugField(
populate_from=("name",),
allow_unicode=True,
unique=True,
@@ -306,7 +489,7 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel):
slugify_function=unicode_slugify_function,
verbose_name=_("Slug"),
)
- priority: int = PositiveIntegerField( # type: ignore
+ priority = PositiveIntegerField(
default=0,
null=False,
blank=False,
@@ -321,17 +504,127 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel):
verbose_name_plural = _("brands")
-class Product(ExportModelOperationsMixin("product"), NiceModel):
+class Stock(ExportModelOperationsMixin("stock"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents the stock of a product managed in the system.
+
+ This class provides details about the relationship between vendors, products,
+ and their stock information, as well as inventory-related properties like price,
+ purchase price, quantity, SKU, and digital assets. It is part of the inventory
+ management system to allow tracking and evaluation of products available from
+ various vendors.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates if the stock is publicly visible. Defaults to False.
+ vendor (ForeignKey): The vendor supplying this product stock.
+ price (float): The final price to the customer after markups.
+ product (ForeignKey): The product associated with this stock entry.
+ purchase_price (float): The price paid to the vendor for this product.
+ quantity (int): Available quantity of the product in stock.
+ sku (str): Vendor-assigned SKU for identifying the product.
+ digital_asset (FileField): Digital file associated with this stock if applicable.
+ """
+
+ is_publicly_visible = False
+
+ vendor = ForeignKey(
+ "core.Vendor",
+ on_delete=CASCADE,
+ help_text=_("the vendor supplying this product stock"),
+ verbose_name=_("associated vendor"),
+ )
+ price = FloatField(
+ default=0.0,
+ help_text=_("final price to the customer after markups"),
+ verbose_name=_("selling price"),
+ )
+ product = ForeignKey(
+ "core.Product",
+ on_delete=CASCADE,
+ help_text=_("the product associated with this stock entry"),
+ verbose_name=_("associated product"),
+ related_name="stocks",
+ blank=True,
+ null=True,
+ )
+ purchase_price = FloatField(
+ default=0.0,
+ help_text=_("the price paid to the vendor for this product"),
+ verbose_name=_("vendor purchase price"),
+ )
+ quantity = IntegerField(
+ default=0,
+ help_text=_("available quantity of the product in stock"),
+ verbose_name=_("quantity in stock"),
+ )
+ sku = CharField(
+ max_length=255,
+ help_text=_("vendor-assigned SKU for identifying the product"),
+ verbose_name=_("vendor sku"),
+ )
+ digital_asset = FileField(
+ default=None,
+ blank=True,
+ null=True,
+ help_text=_("digital file associated with this stock if applicable"),
+ verbose_name=_("digital file"),
+ upload_to="downloadables/",
+ )
+
+ def __str__(self) -> str:
+ return f"{self.vendor.name} - {self.product!s}"
+
+ class Meta:
+ verbose_name = _("stock")
+ verbose_name_plural = _("stock entries")
+
+
+class Product(ExportModelOperationsMixin("product"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a product with attributes such as category, brand, tags, digital status, name,
+ description, part number, and slug. Provides related utility properties to retrieve
+ ratings, feedback counts, price, quantity, and total orders. Designed for use in a
+ system that handles e-commerce or inventory management.
+
+ This class interacts with related models (such as Category, Brand, and ProductTag) and
+ manages caching for frequently accessed properties to improve performance. It is used
+ to define and manipulate product data and its associated information within
+ an application.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates whether the product is visible to the public.
+ category (Category): The category this product belongs to.
+ brand (Brand, optional): Optionally associates this product with a brand.
+ tags (ProductTag): Tags that help describe or group this product.
+ is_digital (bool): Indicates whether this product is digitally delivered.
+ name (str): The identifying name for the product.
+ description (str, optional): A detailed description of the product.
+ partnumber (str): The unique part number for this product.
+ slug (str, optional): Auto-generated unique slug for the product.
+
+ Meta:
+ verbose_name (str): The singular name of the product model.
+ verbose_name_plural (str): The plural name of the product model.
+
+ Properties:
+ rating (float): The average rating of the product, rounded to 2 decimal places.
+ feedbacks_count (int): The total number of feedback entries associated with the product.
+ price (float): The lowest price of the product based on its stock, rounded to 2 decimal
+ places.
+ quantity (int): The total available quantity of the product across all its stocks.
+ total_orders (int): Counts the total orders made for the product in relevant statuses.
+ """
+
is_publicly_visible = True
- category: Category = ForeignKey( # type: ignore
+ category = ForeignKey(
"core.Category",
on_delete=CASCADE,
help_text=_("category this product belongs to"),
verbose_name=_("category"),
related_name="products",
)
- brand: Brand = ForeignKey( # type: ignore
+ brand = ForeignKey(
"core.Brand",
on_delete=CASCADE,
blank=True,
@@ -339,31 +632,31 @@ class Product(ExportModelOperationsMixin("product"), NiceModel):
help_text=_("optionally associate this product with a brand"),
verbose_name=_("brand"),
)
- tags: ProductTag = ManyToManyField( # type: ignore
+ tags = ManyToManyField(
"core.ProductTag",
blank=True,
help_text=_("tags that help describe or group this product"),
verbose_name=_("product tags"),
)
- is_digital: bool = BooleanField( # type: ignore
+ is_digital = BooleanField(
default=False,
help_text=_("indicates whether this product is digitally delivered"),
verbose_name=_("is product digital"),
blank=False,
null=False,
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
help_text=_("provide a clear identifying name for the product"),
verbose_name=_("product name"),
)
- description: str = TextField( # type: ignore
+ description = TextField(
blank=True,
null=True,
help_text=_("add a detailed description of the product"),
verbose_name=_("product description"),
)
- partnumber: str = CharField( # type: ignore
+ partnumber = CharField(
unique=True,
default=None,
blank=False,
@@ -371,7 +664,7 @@ class Product(ExportModelOperationsMixin("product"), NiceModel):
help_text=_("part number for this product"),
verbose_name=_("part number"),
)
- slug: str | None = AutoSlugField( # type: ignore
+ slug = AutoSlugField(
populate_from=(
"name",
"brand__slug",
@@ -414,15 +707,13 @@ class Product(ExportModelOperationsMixin("product"), NiceModel):
cache_key = f"product_feedbacks_count_{self.pk}"
feedbacks_count = cache.get(cache_key)
if feedbacks_count is None:
- feedbacks_count = Feedback.objects.filter(
- order_product__product_id=self.pk
- ).count()
+ feedbacks_count = Feedback.objects.filter(order_product__product_id=self.pk).count()
cache.set(cache_key, feedbacks_count, 604800)
return feedbacks_count
@property
- def price(self) -> float:
- stock = self.stocks.order_by("price").only("price").first()
+ def price(self: Self) -> float:
+ stock = self.stocks.all().order_by("-price").only("price").first()
price = stock.price if stock else 0.0
return round(price, 2)
@@ -444,25 +735,55 @@ class Product(ExportModelOperationsMixin("product"), NiceModel):
status__in=["FINISHED", "DELIVERING", "CREATED", "PAYMENT"],
).count()
+ @property
+ def personal_orders_only(self) -> bool:
+ return not self.quantity > 0 and self.price > 0.0
+
+
+class Attribute(ExportModelOperationsMixin("attribute"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents an attribute in the system.
+
+ This class is used to define and manage attributes, which are customizable
+ pieces of data that can be associated with other entities. Attributes
+ have associated categories, groups, value types, and names. The model
+ supports multiple types of values, including string, integer, float,
+ boolean, array, and object. This allows for dynamic and flexible data
+ structuring.
+
+ Attributes:
+ is_publicly_visible (bool): Denotes whether the attribute is publicly
+ visible. Defaults to True.
+
+ categories (ManyToManyField): Categories to which this attribute
+ belongs. It is a many-to-many relationship with the `Category` model.
+
+ group (ForeignKey): The group to which this attribute belongs. It is
+ a ForeignKey relation to the `AttributeGroup` model.
+
+ value_type (CharField): The type of the attribute's value. Options
+ include string, integer, float, boolean, array, or object.
+
+ name (CharField): The unique name of the attribute.
+ """
-class Attribute(ExportModelOperationsMixin("attribute"), NiceModel):
is_publicly_visible = True
- categories: Category = ManyToManyField( # type: ignore
+ categories = ManyToManyField(
"core.Category",
related_name="attributes",
help_text=_("category of this attribute"),
verbose_name=_("categories"),
)
- group: AttributeGroup = ForeignKey( # type: ignore
+ group = ForeignKey(
"core.AttributeGroup",
on_delete=CASCADE,
related_name="attributes",
help_text=_("group of this attribute"),
verbose_name=_("attribute group"),
)
- value_type: str = CharField( # type: ignore
+ value_type = CharField(
max_length=50,
choices=[
("string", _("string")),
@@ -476,7 +797,7 @@ class Attribute(ExportModelOperationsMixin("attribute"), NiceModel):
verbose_name=_("value type"),
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=255,
help_text=_("name of this attribute"),
verbose_name=_("attribute's name"),
@@ -491,17 +812,40 @@ class Attribute(ExportModelOperationsMixin("attribute"), NiceModel):
verbose_name_plural = _("attributes")
-class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel):
+class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a specific value for an attribute that is linked to a product.
+
+ This class serves the purpose of mapping a value to an attribute for a
+ specific product. It links the 'attribute' to a unique 'value', allowing
+ better organization and dynamic representation of product characteristics.
+ It also defines whether the attribute value is public through the
+ 'is_publicly_visible' attribute.
+
+ Attributes
+ ----------
+ is_publicly_visible
+ Determines if the attribute value is visible publicly. Defaults to True.
+ attribute : core.Attribute
+ The 'Attribute' object this value is linked to. Foreign key relationship
+ with 'core.Attribute'.
+ product : core.Product
+ The specific 'Product' this attribute's value is associated with.
+ Foreign key relationship with 'core.Product'.
+ value
+ Holds the specific value for this attribute as a text field.
+ """
+
is_publicly_visible = True
- attribute: Attribute = ForeignKey( # type: ignore
+ attribute = ForeignKey(
"core.Attribute",
on_delete=CASCADE,
related_name="values",
help_text=_("attribute of this value"),
verbose_name=_("attribute"),
)
- product: Product = ForeignKey( # type: ignore
+ product = ForeignKey(
"core.Product",
on_delete=CASCADE,
blank=False,
@@ -510,7 +854,7 @@ class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel):
verbose_name=_("associated product"),
related_name="attributes",
)
- value: str = TextField( # type: ignore
+ value = TextField(
verbose_name=_("attribute value"),
help_text=_("the specific value for this attribute"),
)
@@ -523,10 +867,28 @@ class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel):
verbose_name_plural = _("attribute values")
-class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel):
+class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a product image associated with a product in the system.
+
+ This class is designed to manage images for products, including functionality
+ for uploading image files, associating them with specific products, and
+ determining their display order. It also includes an accessibility feature
+ with alternative text for the images.
+
+ Attributes:
+ is_publicly_visible (bool): A flag indicating whether the image is
+ visible publicly.
+ alt (str): Alternative text for the image to support accessibility.
+ image (ImageField): The image file associated with the product.
+ priority (int): The display priority of the image. Images with lower
+ priority values are displayed first.
+ product (ForeignKey): The product associated with this image.
+ """
+
is_publicly_visible = True
- alt: str = CharField( # type: ignore
+ alt = CharField(
max_length=255,
help_text=_("provide alternative text for the image for accessibility"),
verbose_name=_("image alt text"),
@@ -536,13 +898,13 @@ class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel):
verbose_name=_("product image"),
upload_to=get_product_uuid_as_path,
)
- priority: int = IntegerField( # type: ignore
+ priority = IntegerField(
default=1,
validators=[MinValueValidator(1)],
help_text=_("determines the order in which images are displayed"),
verbose_name=_("display priority"),
)
- product: ForeignKey = ForeignKey(
+ product = ForeignKey(
"core.Product",
on_delete=CASCADE,
help_text=_("the product that this image represents"),
@@ -562,27 +924,60 @@ class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel):
verbose_name_plural = _("product images")
-class Promotion(ExportModelOperationsMixin("promotion"), NiceModel):
+class Promotion(ExportModelOperationsMixin("promotion"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a promotional campaign for products with a discount.
+
+ This class is used to define and manage promotional campaigns that offer a
+ percentage-based discount for products. The class includes attributes for
+ setting the discount rate, providing details about the promotion, and linking
+ it to the applicable products. It integrates with the product catalog to
+ determine the affected items in the campaign.
+
+ Attributes:
+ is_publicly_visible: A class-level attribute indicating whether the promotion
+ is publicly visible.
+ discount_percent: IntegerField. Specifies the percentage discount for the
+ selected products. Must be between 1 and 100 inclusive.
+ name: CharField. A unique name for the promotion, required for promoting
+ distinguishable campaigns. The maximum length is 256 characters.
+ description: TextField, optional. Provides a detailed description of the
+ promotion. Can be left blank or null.
+ products. Links the promotion to the products that are included
+ in its scope. Can be left blank.
+
+ Meta:
+ verbose_name: The singular name for the promotion in database and UI contexts.
+ verbose_name_plural: The pluralized name for multiple promotions in database and
+ UI contexts.
+
+ Methods:
+ __str__():
+ Returns a string representation of the promotion. If the name is
+ provided, it returns the name; otherwise, it returns the ID of the
+ promotion as a string.
+ """
+
is_publicly_visible = True
- discount_percent: int = IntegerField( # type: ignore
+ discount_percent = IntegerField(
validators=[MinValueValidator(1), MaxValueValidator(100)],
help_text=_("percentage discount for the selected products"),
verbose_name=_("discount percentage"),
)
- name: str = CharField( # type: ignore
+ name = CharField(
max_length=256,
unique=True,
help_text=_("provide a unique name for this promotion"),
verbose_name=_("promotion name"),
)
- description: str = TextField( # type: ignore
+ description = TextField(
blank=True,
null=True,
help_text=_("add a detailed description of the product"),
verbose_name=_("promotion description"),
)
- products: ManyToManyField = ManyToManyField( # type: ignore
+ products = ManyToManyField(
"core.Product",
blank=True,
help_text=_("select which products are included in this promotion"),
@@ -599,71 +994,26 @@ class Promotion(ExportModelOperationsMixin("promotion"), NiceModel):
return str(self.id)
-class Stock(ExportModelOperationsMixin("stock"), NiceModel):
+class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a user's wishlist for storing and managing desired products.
+
+ The Wishlist class provides functionality to manage a collection of products
+ that a user wishes to save. It supports operations such as adding products,
+ removing products, adding multiple products in bulk, and removing multiple
+ products in bulk. The wishlist is associated with a specific user and is
+ stored with optional public visibility status.
+ """
+
is_publicly_visible = False
- vendor: ForeignKey = ForeignKey(
- "core.Vendor",
- on_delete=CASCADE,
- help_text=_("the vendor supplying this product stock"),
- verbose_name=_("associated vendor"),
- )
- price: float = FloatField( # type: ignore
- default=0.0,
- help_text=_("final price to the customer after markups"),
- verbose_name=_("selling price"),
- )
- product: ForeignKey = ForeignKey( # type: ignore
- "core.Product",
- on_delete=CASCADE,
- help_text=_("the product associated with this stock entry"),
- verbose_name=_("associated product"),
- related_name="stocks",
- blank=True,
- null=True,
- )
- purchase_price: float = FloatField( # type: ignore
- default=0.0,
- help_text=_("the price paid to the vendor for this product"),
- verbose_name=_("vendor purchase price"),
- )
- quantity: int = IntegerField( # type: ignore
- default=0,
- help_text=_("available quantity of the product in stock"),
- verbose_name=_("quantity in stock"),
- )
- sku: str = CharField( # type: ignore
- max_length=255,
- help_text=_("vendor-assigned SKU for identifying the product"),
- verbose_name=_("vendor sku"),
- )
- digital_asset = FileField(
- default=None,
- blank=True,
- null=True,
- help_text=_("digital file associated with this stock if applicable"),
- verbose_name=_("digital file"),
- upload_to="downloadables/",
- )
-
- def __str__(self) -> str:
- return f"{self.vendor.name} - {self.product!s}" # type: ignore
-
- class Meta:
- verbose_name = _("stock")
- verbose_name_plural = _("stock entries")
-
-
-class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel):
- is_publicly_visible = False
-
- products: ManyToManyField = ManyToManyField( # type: ignore
+ products = ManyToManyField(
"core.Product",
blank=True,
help_text=_("products that the user has marked as wanted"),
verbose_name=_("wishlisted products"),
)
- user: OneToOneField = OneToOneField( # type: ignore
+ user = OneToOneField(
"vibes_auth.User",
on_delete=CASCADE,
blank=True,
@@ -686,9 +1036,10 @@ class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel):
if product in self.products.all():
return self
self.products.add(product)
- except Product.DoesNotExist:
+ except Product.DoesNotExist as dne:
name = "Product"
- raise Http404(_(f"{name} does not exist: {product_uuid}"))
+ uuid = product_uuid
+ raise Http404(_(f"{name} does not exist: {uuid}")) from dne
return self
@@ -698,9 +1049,10 @@ class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel):
if product not in self.products.all():
return self
self.products.remove(product)
- except Product.DoesNotExist:
+ except Product.DoesNotExist as dne:
name = "Product"
- raise Http404(_(f"{name} does not exist: {product_uuid}"))
+ uuid = product_uuid
+ raise Http404(_(f"{name} does not exist: {uuid}")) from dne
return self
@@ -715,12 +1067,30 @@ class Wishlist(ExportModelOperationsMixin("wishlist"), NiceModel):
return self
-class Documentary(ExportModelOperationsMixin("attribute_group"), NiceModel):
+class Documentary(ExportModelOperationsMixin("attribute_group"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Model representing a documentary record tied to a product.
+
+ This class is used to store information about documentaries related to specific
+ products, including file uploads and their metadata. It contains methods and
+ properties to handle the file type and storage path for the documentary files.
+ It extends functionality from specific mixins and provides additional custom
+ features.
+
+ Attributes:
+ is_publicly_visible: A boolean indicating if the documentary is
+ publicly visible.
+ product linking the documentary to a product.
+ document: FileField used to store the file associated with the documentary.
+
+ Meta:
+ verbose_name: Singular name for the documentary model.
+ verbose_name_plural: Plural name for the documentary model.
+ """
+
is_publicly_visible = True
- product: ForeignKey = ForeignKey(
- to=Product, on_delete=CASCADE, related_name="documentaries"
- )
+ product = ForeignKey(to=Product, on_delete=CASCADE, related_name="documentaries")
document = FileField(upload_to=get_product_uuid_as_path)
class Meta:
@@ -738,23 +1108,60 @@ class Documentary(ExportModelOperationsMixin("attribute_group"), NiceModel):
return self.document.name.split(".")[-1] or _("unresolved")
-class Address(ExportModelOperationsMixin("address"), NiceModel):
+class Address(ExportModelOperationsMixin("address"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents an address entity that includes location details and associations with
+ a user. Provides functionality for geographic and address data storage, as well
+ as integration with geocoding services.
+
+ This class is designed to store detailed address information including components
+ like street, city, region, country, and geolocation (longitude and latitude).
+
+ It supports integration with geocoding APIs, enabling the storage of raw API
+ responses for further processing or inspection. The class also allows associating
+ an address with a user, facilitating personalized data handling.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates whether the address is visible publicly.
+ address_line (str): A general address line containing information about the
+ customer's location. Optional.
+ street (str): The street name or number in the address. Optional.
+ district (str): The district related to the address. Optional.
+ city (str): The name of the city where the address is located. Optional.
+ region (str): The name of the region associated with the address. Optional.
+ postal_code (str): The postal code corresponding to the address. Optional.
+ country (str): The country where the address resides. Optional.
+ location (PointField): A geolocation represented as (longitude, latitude).
+ Allows geospatial searches. Optional.
+ raw_data (dict): The full JSON response directly from the geocoding service,
+ containing detailed information about the address. Optional.
+ api_response (dict): Stores a processed version or subset of the JSON
+ response from the geocoding service. Optional.
+ user (ForeignKey): Reference to a User entity who owns this address. Optional.
+
+ Meta:
+ verbose_name (str): Human-readable singular name for the address.
+ verbose_name_plural (str): Human-readable plural name for addresses.
+ indexes (list): Database indexes defined for improving query performance
+ on specific fields like 'location'.
+ """
+
is_publicly_visible = False
- address_line: str = TextField( # type: ignore
+ address_line = TextField(
blank=True,
null=True,
help_text=_("address line for the customer"),
verbose_name=_("address line"),
)
- street: str = CharField(_("street"), max_length=255, null=True) # type: ignore
- district: str = CharField(_("district"), max_length=255, null=True) # type: ignore
- city: str = CharField(_("city"), max_length=100, null=True) # type: ignore
- region: str = CharField(_("region"), max_length=100, null=True) # type: ignore
- postal_code: str = CharField(_("postal code"), max_length=20, null=True) # type: ignore
- country: str = CharField(_("country"), max_length=40, null=True) # type: ignore
+ street = CharField(_("street"), max_length=255, null=True)
+ district = CharField(_("district"), max_length=255, null=True)
+ city = CharField(_("city"), max_length=100, null=True)
+ region = CharField(_("region"), max_length=100, null=True)
+ postal_code = CharField(_("postal code"), max_length=20, null=True)
+ country = CharField(_("country"), max_length=40, null=True)
- location: PointField = PointField( # type: ignore
+ location: PointField = PointField(
geography=True,
srid=4326,
null=True,
@@ -762,15 +1169,15 @@ class Address(ExportModelOperationsMixin("address"), NiceModel):
help_text=_("geolocation point: (longitude, latitude)"),
)
- raw_data: dict = JSONField(blank=True, null=True, help_text=_("full JSON response from geocoder for this address")) # type: ignore
+ raw_data = JSONField(blank=True, null=True, help_text=_("full JSON response from geocoder for this address"))
- api_response: dict = JSONField( # type: ignore
+ api_response = JSONField(
blank=True,
null=True,
help_text=_("stored JSON response from the geocoding service"),
)
- user: ForeignKey = ForeignKey(to="vibes_auth.User", on_delete=CASCADE, blank=True, null=True) # type: ignore
+ user = ForeignKey(to="vibes_auth.User", on_delete=CASCADE, blank=True, null=True)
objects = AddressManager()
@@ -786,17 +1193,45 @@ class Address(ExportModelOperationsMixin("address"), NiceModel):
return f"{base} for {self.user.email}" if self.user else base
-class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel):
+class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a promotional code that can be used for discounts, managing its validity,
+ type of discount, and application.
+
+ The PromoCode class stores details about a promotional code, including its unique
+ identifier, discount properties (amount or percentage), validity period, associated
+ user (if any), and status of its usage. It includes functionality to validate and
+ apply the promo code to an order while ensuring constraints are met.
+
+ Attributes:
+ code (str): The unique identifier for the promo code.
+ discount_amount (Decimal): The fixed discount amount applied, if defined.
+ discount_percent (int): The percentage discount applied, if defined.
+ end_time (datetime): The expiration timestamp of the promo code.
+ start_time (datetime): The timestamp from when the promo code is valid.
+ used_on (datetime): The timestamp when the promo code was used (if applicable).
+ user (ForeignKey): The user associated with the promo code, if any.
+
+ Methods:
+ save(**kwargs): Ensures only one type of discount (amount or percent) is defined.
+ __str__(): Returns the promo code identifier as its string representation.
+ use(order): Applies the promo code to the given order and calculates the final price.
+
+ Meta:
+ verbose_name: Display name for the promo code model.
+ verbose_name_plural: Plural display name for the promo code model.
+ """
+
is_publicly_visible = False
- code: str = CharField( # type: ignore
+ code = CharField(
max_length=20,
unique=True,
default=get_random_code,
help_text=_("unique code used by a user to redeem a discount"),
verbose_name=_("promo code identifier"),
)
- discount_amount: Decimal = DecimalField( # type: ignore
+ discount_amount = DecimalField(
max_digits=10,
decimal_places=2,
blank=True,
@@ -804,32 +1239,32 @@ class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel):
help_text=_("fixed discount amount applied if percent is not used"),
verbose_name=_("fixed discount amount"),
)
- discount_percent: int = IntegerField( # type: ignore
+ discount_percent = IntegerField(
validators=[MinValueValidator(1), MaxValueValidator(100)],
blank=True,
null=True,
help_text=_("percentage discount applied if fixed amount is not used"),
verbose_name=_("percentage discount"),
)
- end_time: datetime = DateTimeField( # type: ignore
+ end_time = DateTimeField(
blank=True,
null=True,
help_text=_("timestamp when the promocode expires"),
verbose_name=_("end validity time"),
)
- start_time: datetime = DateTimeField( # type: ignore
+ start_time = DateTimeField(
blank=True,
null=True,
help_text=_("timestamp from which this promocode is valid"),
verbose_name=_("start validity time"),
)
- used_on: datetime = DateTimeField( # type: ignore
+ used_on = DateTimeField(
blank=True,
null=True,
help_text=_("timestamp when the promocode was used, blank if not used yet"),
verbose_name=_("usage timestamp"),
)
- user: ForeignKey = ForeignKey( # type: ignore
+ user = ForeignKey(
"vibes_auth.User",
on_delete=CASCADE,
help_text=_("user assigned to this promocode if applicable"),
@@ -848,9 +1283,7 @@ class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel):
self.discount_amount is None and self.discount_percent is None
):
raise ValidationError(
- _(
- "only one type of discount should be defined (amount or percent), but not both or neither."
- )
+ _("only one type of discount should be defined (amount or percent), but not both or neither.")
)
super().save(**kwargs)
@@ -863,36 +1296,55 @@ class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel):
return "amount"
return "percent"
- def use(self, order: "Order") -> float:
+ def use(self, order) -> float:
if self.used_on:
raise ValueError(_("promocode already used"))
- amount = order.total_price
+ if not order.attributes:
+ order.attributes = {}
+
+ promo_amount = order.total_price
if self.discount_type == "percent":
- amount -= round(amount * (self.discount_percent / 100), 2)
- order.attributes.update(
- {"promocode": str(self.uuid), "final_price": amount}
- )
+ promo_amount -= round(promo_amount * (float(self.discount_percent) / 100), 2) # type: ignore [arg-type]
+ order.attributes.update({"promocode_uuid": str(self.uuid), "final_price": promo_amount})
order.save()
elif self.discount_type == "amount":
- amount -= round(float(self.discount_amount), 2)
- order.attributes.update(
- {"promocode": str(self.uuid), "final_price": amount}
- )
+ promo_amount -= round(float(self.discount_amount), 2) # type: ignore [arg-type]
+ order.attributes.update({"promocode_uuid": str(self.uuid), "final_price": promo_amount})
order.save()
else:
raise ValueError(_(f"invalid discount type for promocode {self.uuid}"))
self.used_on = datetime.datetime.now()
self.save()
- return amount
+ return promo_amount
-class Order(ExportModelOperationsMixin("order"), NiceModel):
+class Order(ExportModelOperationsMixin("order"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents an order placed by a user.
+
+ This class models an order within the application, including its various attributes such as billing
+ and shipping information, status, associated user, notifications, and related operations.
+ Orders can have associated products, promotions can be applied, addresses set, and shipping or billing
+ details updated. Equally, functionality supports managing the products in the order lifecycle.
+
+ Attributes:
+ billing_address (Address): The billing address used for the order.
+ promo_code (PromoCode): An optional promo code applied to the order.
+ shipping_address (Address): The shipping address used for the order.
+ status (str): The current status of the order (e.g., PENDING, COMPLETED).
+ notifications (dict): JSON structure dictating notifications for the user.
+ attributes (dict): JSON representation of additional order-specific attributes.
+ user (User): The user who placed the order.
+ buy_time (datetime): Timestamp when the order was finalized.
+ human_readable_id (str): A unique human-readable identifier for the order.
+ """
+
is_publicly_visible = False
- billing_address: Address = ForeignKey( # type: ignore
+ billing_address = ForeignKey(
"core.Address",
on_delete=CASCADE,
blank=True,
@@ -901,7 +1353,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
help_text=_("the billing address used for this order"),
verbose_name=_("billing address"),
)
- promo_code: PromoCode = ForeignKey( # type: ignore
+ promo_code = ForeignKey(
"core.PromoCode",
on_delete=PROTECT,
blank=True,
@@ -909,7 +1361,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
help_text=_("optional promo code applied to this order"),
verbose_name=_("applied promo code"),
)
- shipping_address: Address = ForeignKey( # type: ignore
+ shipping_address = ForeignKey(
"core.Address",
on_delete=CASCADE,
blank=True,
@@ -918,26 +1370,26 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
help_text=_("the shipping address used for this order"),
verbose_name=_("shipping address"),
)
- status: str = CharField( # type: ignore
+ status = CharField(
default="PENDING",
max_length=64,
choices=ORDER_STATUS_CHOICES,
help_text=_("current status of the order in its lifecycle"),
verbose_name=_("order status"),
)
- notifications: dict = JSONField( # type: ignore
+ notifications = JSONField(
blank=True,
null=True,
help_text=_("json structure of notifications to display to users"),
verbose_name=_("notifications"),
)
- attributes: dict = JSONField( # type: ignore
+ attributes = JSONField(
blank=True,
null=True,
help_text=_("json representation of order attributes for this order"),
verbose_name=_("attributes"),
)
- user = ForeignKey( # type: ignore
+ user = ForeignKey(
"vibes_auth.User",
on_delete=CASCADE,
help_text=_("the user who placed the order"),
@@ -946,14 +1398,14 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
blank=True,
null=True,
)
- buy_time: datetime = DateTimeField( # type: ignore
+ buy_time = DateTimeField(
help_text=_("the timestamp when the order was finalized"),
verbose_name=_("buy time"),
default=None,
null=True,
blank=True,
)
- human_readable_id: str = CharField( # type: ignore
+ human_readable_id = CharField(
max_length=8,
help_text=_("a human-readable identifier for the order"),
verbose_name=_("human readable id"),
@@ -966,13 +1418,15 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
verbose_name_plural = _("orders")
def __str__(self) -> str:
- return f"#{self.pk} for {self.user.email if self.user else 'unregistered user'}" # type: ignore
+ return f"#{self.pk} for {self.user.email if self.user else 'unregistered user'}"
@property
def is_business(self) -> bool:
- return self.attributes.get("is_business", False) if self.attributes else False
+ return (self.attributes.get("is_business", False) if self.attributes else False) or (
+ self.user.attributes.get("is_business", False) if self.user else False
+ )
- def save(self, **kwargs):
+ def save(self, **kwargs: dict) -> Self:
pending_orders = 0
if self.user:
pending_orders = self.user.orders.filter(status="PENDING").count()
@@ -987,8 +1441,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
sum(
(
order_product.buy_price * order_product.quantity
- if order_product.status not in FAILED_STATUSES
- and order_product.buy_price is not None
+ if order_product.status not in FAILED_STATUSES and order_product.buy_price is not None
else 0.0
)
for order_product in self.order_products.all()
@@ -1004,17 +1457,15 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
def add_product(
self,
- product_uuid: str | None = None,
+ product_uuid=None,
attributes: list | None = None,
- update_quantity: bool = True,
+ update_quantity=True,
):
if attributes is None:
attributes = []
if self.status not in ["PENDING", "MOMENTAL"]:
- raise ValueError(
- _("you cannot add products to an order that is not a pending one")
- )
+ raise ValueError(_("you cannot add products to an order that is not a pending one"))
try:
product = Product.objects.get(uuid=product_uuid)
@@ -1023,12 +1474,10 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
buy_price = product.price
- promotions = Promotion.objects.filter(
- is_active=True, products__in=[product]
- ).order_by("discount_percent")
+ promotions = Promotion.objects.filter(is_active=True, products__in=[product]).order_by("discount_percent")
if promotions.exists():
- buy_price -= round(product.price * (promotions.first().discount_percent / 100), 2) # type: ignore
+ buy_price -= round(product.price * (promotions.first().discount_percent / 100), 2) # type: ignore [union-attr]
order_product, is_created = OrderProduct.objects.get_or_create(
product=product,
@@ -1038,32 +1487,29 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
)
if not is_created and update_quantity:
if product.quantity < order_product.quantity + 1:
- raise BadRequest(
- _("you cannot add more products than available in stock")
- )
+ raise BadRequest(_("you cannot add more products than available in stock"))
order_product.quantity += 1
order_product.buy_price = product.price
order_product.save()
return self
- except Product.DoesNotExist:
+ except Product.DoesNotExist as dne:
name = "Product"
- raise Http404(_(f"{name} does not exist: {product_uuid}"))
+ uuid = product_uuid
+ raise Http404(_(f"{name} does not exist: {uuid}")) from dne
def remove_product(
self,
- product_uuid: str | None = None,
- attributes: dict | None = None,
- zero_quantity: bool = False,
+ product_uuid=None,
+ attributes=None,
+ zero_quantity=False,
):
if attributes is None:
attributes = {}
if self.status not in ["PENDING", "MOMENTAL"]:
- raise ValueError(
- _("you cannot remove products from an order that is not a pending one")
- )
+ raise ValueError(_("you cannot remove products from an order that is not a pending one"))
try:
product = Product.objects.get(uuid=product_uuid)
order_product = self.order_products.get(product=product, order=self)
@@ -1077,66 +1523,52 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
order_product.quantity -= 1
order_product.save()
return self
- except Product.DoesNotExist:
+ except Product.DoesNotExist as dne:
name = "Product"
- raise Http404(_(f"{name} does not exist: {product_uuid}"))
- except OrderProduct.DoesNotExist:
+ uuid = product_uuid
+ raise Http404(_(f"{name} does not exist: {uuid}")) from dne
+ except OrderProduct.DoesNotExist as dne:
name = "OrderProduct"
- query = (
- f"product: {product_uuid}, order: {self.uuid}, attributes: {attributes}"
- )
- raise Http404(_(f"{name} does not exist with query <{query}>"))
+ query = f"product: {product_uuid}, order: {self.uuid}, attributes: {attributes}"
+ raise Http404(_(f"{name} does not exist with query <{query}>")) from dne
def remove_all_products(self):
if self.status not in ["PENDING", "MOMENTAL"]:
- raise ValueError(
- _("you cannot remove products from an order that is not a pending one")
- )
+ raise ValueError(_("you cannot remove products from an order that is not a pending one"))
for order_product in self.order_products.all():
self.order_products.remove(order_product)
order_product.delete()
return self
- def remove_products_of_a_kind(self, product_uuid: str):
+ def remove_products_of_a_kind(self, product_uuid):
if self.status not in ["PENDING", "MOMENTAL"]:
- raise ValueError(
- _("you cannot remove products from an order that is not a pending one")
- )
+ raise ValueError(_("you cannot remove products from an order that is not a pending one"))
try:
product = Product.objects.get(uuid=product_uuid)
order_product = self.order_products.get(product=product, order=self)
self.order_products.remove(order_product)
order_product.delete()
- except Product.DoesNotExist:
+ except Product.DoesNotExist as dne:
name = "Product"
- raise Http404(_(f"{name} does not exist: {product_uuid}"))
+ uuid = product_uuid
+ raise Http404(_(f"{name} does not exist: {uuid}")) from dne
return self
@property
def is_whole_digital(self):
- return (
- self.order_products.count()
- == self.order_products.filter(product__is_digital=True).count()
- )
+ return self.order_products.count() == self.order_products.filter(product__is_digital=True).count()
- def apply_promocode(self, promocode_uuid: str):
+ def apply_promocode(self, promocode_uuid):
try:
- promocode: PromoCode = PromoCode.objects.get(uuid=promocode_uuid)
- except PromoCode.DoesNotExist:
- raise Http404(_("promocode does not exist"))
+ promocode = PromoCode.objects.get(uuid=promocode_uuid)
+ except PromoCode.DoesNotExist as dne:
+ raise Http404(_("promocode does not exist")) from dne
return promocode.use(self)
- def apply_addresses(self, billing_address_uuid, shipping_address_uuid):
+ def apply_addresses(self, billing_address_uuid: str | None = None, shipping_address_uuid: str | None = None):
try:
- if not any([shipping_address_uuid, billing_address_uuid]):
- if self.is_whole_digital:
- return
- else:
- raise ValueError(
- _(
- "you can only buy physical products with shipping address specified"
- )
- )
+ if not any([shipping_address_uuid, billing_address_uuid]) and not self.is_whole_digital:
+ raise ValueError(_("you can only buy physical products with shipping address specified"))
if billing_address_uuid and not shipping_address_uuid:
shipping_address = Address.objects.get(uuid=billing_address_uuid)
@@ -1154,8 +1586,8 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
self.shipping_address = shipping_address
self.save()
- except Address.DoesNotExist:
- raise Http404(_("address does not exist"))
+ except Address.DoesNotExist as dne:
+ raise Http404(_("address does not exist")) from dne
def buy(
self,
@@ -1164,20 +1596,27 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
promocode_uuid: str | None = None,
billing_address: str | None = None,
shipping_address: str | None = None,
+ chosen_products: list | None = None,
) -> Self | Transaction | None:
- if config.DISABLED_COMMERCE:
- raise DisabledCommerceError(
- _("you can not buy at this moment, please try again in a few minutes")
- )
+ order = self
- if (not force_balance and not force_payment) or (
- force_balance and force_payment
- ):
+ if not self.attributes:
+ self.attributes = {}
+
+ if chosen_products:
+ order = Order.objects.create(status="MOMENTAL", user=self.user)
+ order.bulk_add_products(chosen_products, update_quantity=True)
+
+ if config.DISABLED_COMMERCE:
+ raise DisabledCommerceError(_("you can not buy at this moment, please try again in a few minutes"))
+
+ if (not force_balance and not force_payment) or (force_balance and force_payment):
raise ValueError(_("invalid force value"))
- self.apply_addresses(billing_address, shipping_address)
+ if any([billing_address, shipping_address]):
+ order.apply_addresses(billing_address, shipping_address)
- if self.total_quantity < 1:
+ if order.total_quantity < 1:
raise ValueError(_("you cannot purchase an empty order!"))
force = None
@@ -1188,40 +1627,46 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
if force_payment:
force = "payment"
- amount = (
- self.apply_promocode(promocode_uuid) if promocode_uuid else self.total_price
- )
+ amount = self.attributes.get("final_amount") or order.total_price
+
+ if self.attributes.get("promocode_uuid") and not self.attributes.get("final_amount"):
+ amount = order.apply_promocode(self.attributes.get("promocode_uuid"))
+
+ if promocode_uuid and not self.attributes.get("final_amount"):
+ amount = order.apply_promocode(promocode_uuid)
+
+ if not order.user:
+ raise ValueError(_("you cannot buy an order without a user"))
+
+ if not order.user.payments_balance:
+ raise ValueError(_("a user without a balance cannot buy with balance"))
match force:
case "balance":
- if self.user.payments_balance.amount < amount: # type: ignore
- raise NotEnoughMoneyError(
- _("insufficient funds to complete the order")
- )
- self.status = "CREATED"
- self.buy_time = timezone.now()
- self.order_products.all().update(status="DELIVERING")
- self.save()
- return self
+ if order.user.payments_balance.amount < amount:
+ raise NotEnoughMoneyError(_("insufficient funds to complete the order"))
+ with transaction.atomic():
+ order.status = "CREATED"
+ order.buy_time = timezone.now()
+ order.update_order_products_statuses("DELIVERING")
+ order.save()
+ return order
case "payment":
- self.status = "PAYMENT"
- self.save()
+ order.status = "PAYMENT"
+ order.buy_time = timezone.now()
+ order.save()
return Transaction.objects.create(
- balance=self.user.payments_balance, # type: ignore
+ balance=order.user.payments_balance,
amount=amount,
currency=CURRENCY_CODE,
- order=self,
+ order=order,
)
- return self
+ return order
- def buy_without_registration(
- self, products: list, promocode_uuid: str, **kwargs
- ) -> Transaction | None:
+ def buy_without_registration(self, products: list, promocode_uuid, **kwargs) -> Transaction | None:
if config.DISABLED_COMMERCE:
- raise DisabledCommerceError(
- _("you can not buy at this moment, please try again in a few minutes")
- )
+ raise DisabledCommerceError(_("you can not buy at this moment, please try again in a few minutes"))
if len(products) < 1:
raise ValueError(_("you cannot purchase an empty order!"))
@@ -1242,25 +1687,17 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
available_payment_methods = cache.get("payment_methods").get("payment_methods")
if payment_method not in available_payment_methods:
- raise ValueError(
- _(
- f"invalid payment method: {payment_method} from {available_payment_methods}"
- )
- )
+ raise ValueError(_(f"invalid payment method: {payment_method} from {available_payment_methods}"))
billing_customer_address_uuid = kwargs.get("billing_customer_address")
shipping_customer_address_uuid = kwargs.get("shipping_customer_address")
- self.apply_addresses(
- billing_customer_address_uuid, shipping_customer_address_uuid
- )
+ self.apply_addresses(billing_customer_address_uuid, shipping_customer_address_uuid)
for product_uuid in products:
self.add_product(product_uuid)
- amount = (
- self.apply_promocode(promocode_uuid) if promocode_uuid else self.total_price
- )
+ amount = self.apply_promocode(promocode_uuid) if promocode_uuid else self.total_price
self.status = "CREATED"
@@ -1301,53 +1738,79 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
self.status = "FINISHED"
self.save()
- def bulk_add_products(self, products: list):
+ def update_order_products_statuses(self, status: str = "PENDING"):
+ self.order_products.update(status=status)
+
+ def bulk_add_products(self, products: list[dict[str, Any]], update_quantity: bool = False):
for product in products:
self.add_product(
- product.get("uuid"),
+ product.get("uuid") or product.get("product_uuid"),
attributes=product.get("attributes"),
- update_quantity=False,
+ update_quantity=update_quantity,
)
return self
def bulk_remove_products(self, products: list):
for product in products:
self.remove_product(
- product.get("uuid"),
+ product.get("uuid") or product.get("product_uuid"),
attributes=product.get("attributes"),
zero_quantity=True,
)
return self
-class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel):
+class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents a product associated with an order.
+
+ The OrderProduct model maintains information about a product that is part of an order,
+ including details such as purchase price, quantity, product attributes, and status. It
+ manages notifications for the user and administrators and handles operations such as
+ returning the product balance or adding feedback. This model also provides methods and
+ properties that support business logic, such as calculating the total price or generating
+ a download URL for digital products. The model integrates with the Order and Product models
+ and stores a reference to them.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates whether this model is visible publicly.
+ buy_price (float): The price paid by the customer for this product at purchase time.
+ comments (str): Internal comments entered by admins regarding this ordered product.
+ notifications (dict): JSON structure containing notifications relevant to the product.
+ attributes (dict): JSON representation of the product's attributes as part of the order.
+ order (Order): Reference to the parent order that contains this product.
+ product (Product): Reference to the specific product associated with the order line.
+ quantity (int): Represents the quantity of this product ordered.
+ status (str): The current status of the product in the order.
+ """
+
is_publicly_visible = False
- buy_price: float = FloatField( # type: ignore
+ buy_price = FloatField(
blank=True,
null=True,
help_text=_("the price paid by the customer for this product at purchase time"),
verbose_name=_("purchase price at order time"),
)
- comments: str = TextField( # type: ignore
+ comments = TextField(
blank=True,
null=True,
help_text=_("internal comments for admins about this ordered product"),
verbose_name=_("internal comments"),
)
- notifications: dict = JSONField( # type: ignore
+ notifications = JSONField(
blank=True,
null=True,
help_text=_("json structure of notifications to display to users"),
verbose_name=_("user notifications"),
)
- attributes: dict = JSONField( # type: ignore
+ attributes = JSONField(
blank=True,
null=True,
help_text=_("json representation of this item's attributes"),
verbose_name=_("ordered product attributes"),
)
- order: Order = ForeignKey( # type: ignore
+ order = ForeignKey(
"core.Order",
on_delete=CASCADE,
help_text=_("reference to the parent order that contains this product"),
@@ -1355,7 +1818,7 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel):
related_name="order_products",
null=True,
)
- product: Product = ForeignKey( # type: ignore
+ product = ForeignKey(
"core.Product",
on_delete=PROTECT,
blank=True,
@@ -1363,14 +1826,14 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel):
help_text=_("the specific product associated with this order line"),
verbose_name=_("associated product"),
)
- quantity: int = PositiveIntegerField( # type: ignore
+ quantity = PositiveIntegerField(
blank=False,
null=False,
default=1,
help_text=_("quantity of this specific product in the order"),
verbose_name=_("product quantity"),
)
- status: str = CharField( # type: ignore
+ status = CharField(
max_length=128,
blank=False,
null=False,
@@ -1381,7 +1844,10 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel):
)
def __str__(self) -> str:
- return f"{self.product.name} for ({self.order.user.email if self.order.user else 'unregistered user'})" # type: ignore
+ return (
+ f"{self.product.name if self.product else self.uuid}"
+ f" for ({self.order.user.email if self.order and self.order.user else 'unregistered user'})"
+ )
class Meta:
verbose_name = _("order product")
@@ -1405,9 +1871,7 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel):
"errors": [
{
"detail": (
- error
- if error
- else f"Something went wrong with {self.uuid} for some reason..."
+ error if error else f"Something went wrong with {self.uuid} for some reason..."
)
},
]
@@ -1423,40 +1887,61 @@ class OrderProduct(ExportModelOperationsMixin("order_product"), NiceModel):
return self
@property
- def total_price(self) -> float:
- return round(self.buy_price * self.quantity, 2)
+ def total_price(self: Self) -> float:
+ return round(float(self.buy_price) * self.quantity, 2) # type: ignore [arg-type]
@property
- def download_url(self) -> str:
- if self.product.is_digital and self.product.stocks.first().digital_asset: # type: ignore
- return self.download.url
+ def download_url(self: Self) -> str:
+ if self.product and self.product.stocks:
+ if self.product.is_digital and self.product.stocks.first().digital_asset: # type: ignore [union-attr]
+ return self.download.url
return ""
- def do_feedback(
- self, rating: int = 10, comment: str = "", action: str = "add"
- ) -> Optional["Feedback"]:
+ def do_feedback(self, rating=10, comment="", action="add") -> Optional["Feedback"]:
+ if not self.order:
+ raise ValueError(_("order product must have an order"))
if action not in ["add", "remove"]:
raise ValueError(_(f"wrong action specified for feedback: {action}"))
if action == "remove" and self.feedback:
self.feedback.delete()
return None
if action == "add" and not self.feedback:
- if self.order.status not in ["MOMENTAL", "PENDING"]: # type: ignore
- return Feedback.objects.create(
- rating=rating, comment=comment, order_product=self
- )
+ if self.order.status not in ["MOMENTAL", "PENDING"]:
+ return Feedback.objects.create(rating=rating, comment=comment, order_product=self)
else:
- raise ValueError(
- _("you cannot feedback an order which is not received")
- )
+ raise ValueError(_("you cannot feedback an order which is not received"))
return None
-class DigitalAssetDownload(ExportModelOperationsMixin("attribute_group"), NiceModel):
+class DigitalAssetDownload(ExportModelOperationsMixin("attribute_group"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Represents the downloading functionality for digital assets associated
+ with orders.
+
+ The DigitalAssetDownload class provides the ability to manage and access
+ downloads related to order products. It maintains information about the
+ associated order product, the number of downloads, and whether the asset
+ is publicly visible. It includes a method to generate a URL for downloading
+ the asset when the associated order is in a completed status.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates whether the digital asset is
+ publicly visible. Always set to False for this class.
+ order_product (OneToOneField): Reference to the associated order product.
+ It has a one-to-one relationship with the OrderProduct model, and
+ deleting the OrderProduct will delete the associated download.
+ num_downloads (int): Indicates the number of times the digital asset
+ has been downloaded.
+
+ Methods:
+ url: Property to generate the download URL for the digital asset
+ if the associated order is in a finished status.
+ """
+
is_publicly_visible = False
- order_product: OneToOneField = OneToOneField(to=OrderProduct, on_delete=CASCADE, related_name="download") # type: ignore
- num_downloads: int = IntegerField(default=0) # type: ignore
+ order_product = OneToOneField(to=OrderProduct, on_delete=CASCADE, related_name="download")
+ num_downloads = IntegerField(default=0)
class Meta:
verbose_name = _("download")
@@ -1468,33 +1953,48 @@ class DigitalAssetDownload(ExportModelOperationsMixin("attribute_group"), NiceMo
@property
def url(self):
if self.order_product.status != "FINISHED":
- raise ValueError(
- _("you can not download a digital asset for a non-finished order")
- )
+ raise ValueError(_("you can not download a digital asset for a non-finished order"))
- return f"https://api.{config.BASE_DOMAIN}/download/{urlsafe_base64_encode(force_bytes(self.order_product.uuid))}"
+ return (
+ f"https://api.{config.BASE_DOMAIN}/download/{urlsafe_base64_encode(force_bytes(self.order_product.uuid))}"
+ )
-class Feedback(ExportModelOperationsMixin("feedback"), NiceModel):
+class Feedback(ExportModelOperationsMixin("feedback"), NiceModel): # type: ignore [misc, django-manager-missing]
+ """
+ Manages user feedback for products.
+
+ This class is designed to capture and store user feedback for specific products
+ that they have purchased. It contains attributes to store user comments,
+ a reference to the related product in the order, and a user-assigned rating. The
+ class uses database fields to effectively model and manage feedback data.
+
+ Attributes:
+ is_publicly_visible (bool): Indicates whether the feedback is visible to the public.
+ comment (str): User-provided comments about their experience with the product.
+ order_product (OrderProduct): Reference to the specific product in an order that this
+ feedback is about.
+ rating (float): User-assigned rating for the product, validated to be within the range
+ of 0 to 10.
+ """
+
is_publicly_visible = True
- comment: str = TextField( # type: ignore
+ comment = TextField(
blank=True,
null=True,
help_text=_("user-provided comments about their experience with the product"),
verbose_name=_("feedback comments"),
)
- order_product: OrderProduct = OneToOneField( # type: ignore
+ order_product = OneToOneField(
"core.OrderProduct",
on_delete=CASCADE,
blank=False,
null=False,
- help_text=_(
- "references the specific product in an order that this feedback is about"
- ),
+ help_text=_("references the specific product in an order that this feedback is about"),
verbose_name=_("related order product"),
)
- rating: float = FloatField( # type: ignore
+ rating = FloatField(
blank=True,
null=True,
help_text=_("user-assigned rating for the product"),
@@ -1503,8 +2003,27 @@ class Feedback(ExportModelOperationsMixin("feedback"), NiceModel):
)
def __str__(self) -> str:
- return f"{self.rating} by {self.order_product.order.user.email}"
+ if self.order_product and self.order_product.order and self.order_product.order.user:
+ return f"{self.rating} by {self.order_product.order.user.email}"
+ return f"{self.rating} | {self.uuid}"
class Meta:
verbose_name = _("feedback")
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")
diff --git a/core/permissions.py b/core/permissions.py
index a462229b..ff1f9c92 100644
--- a/core/permissions.py
+++ b/core/permissions.py
@@ -47,6 +47,9 @@ class EvibesPermission(permissions.BasePermission):
app_label = model._meta.app_label
model_name = model._meta.model_name
+ if view.additional.get(action) == "ALLOW":
+ return True
+
if action == "create" and view.additional.get("create") == "ALLOW":
return True
diff --git a/core/serializers/detail.py b/core/serializers/detail.py
index 1869140b..8feceb33 100644
--- a/core/serializers/detail.py
+++ b/core/serializers/detail.py
@@ -1,13 +1,12 @@
import logging
-from collections.abc import Collection
+from collections import defaultdict
from contextlib import suppress
-from typing import Any
+from typing import Collection, Any
from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
from django.db.models.functions import Length
from rest_framework.fields import JSONField, SerializerMethodField
-from rest_framework.request import Request
from rest_framework.serializers import ModelSerializer
from rest_framework_recursive.fields import RecursiveField
@@ -31,9 +30,8 @@ from core.models import (
)
from core.serializers.simple import CategorySimpleSerializer, ProductSimpleSerializer
from core.serializers.utility import AddressSerializer
-from vibes_auth.models import User
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
class AttributeGroupDetailSerializer(ModelSerializer):
@@ -76,42 +74,46 @@ class CategoryDetailSerializer(ModelSerializer):
return None
def get_filterable_attributes(self, obj: Category) -> list[dict]:
- filterable_results = cache.get(f"{obj.uuid}_filterable_results", [])
-
+ cache_key = f"{obj.uuid}_filterable_results"
+ filterable_results = cache.get(cache_key)
if filterable_results:
return filterable_results
- request: Request | None = self.context.get("request")
- user: User | AnonymousUser | None = getattr(request, "user") # noqa: B009
+ request = self.context.get("request")
+ user = getattr(request, "user", AnonymousUser())
+ attrs_qs = obj.attributes.all() if user.has_perm("view_attribute") else obj.attributes.filter(is_active=True)
+ attributes = list(attrs_qs)
- if user is None:
- user = AnonymousUser()
-
- attributes = obj.attributes.all() if user.has_perm("view_attribute") else obj.attributes.filter(is_active=True)
-
- for attr in attributes:
- distinct_vals = (
- AttributeValue.objects.annotate(value_length=Length("value"))
- .filter(attribute=attr, product__category=obj, value_length__lte=30)
- .values_list("value", flat=True)
- .distinct()
+ attr_ids = [a.id for a in attributes]
+ raw_vals = (
+ AttributeValue.objects.annotate(value_length=Length("value"))
+ .filter(
+ attribute_id__in=attr_ids,
+ product__category=obj,
+ value_length__lte=30,
)
+ .values_list("attribute_id", "value")
+ .distinct()
+ )
- distinct_vals_list = list(distinct_vals)[0:128] if len(list(distinct_vals)) > 128 else list(distinct_vals)
+ grouped = defaultdict(list)
+ for attr_id, val in raw_vals:
+ grouped[attr_id].append(val)
+ filterable_results = []
+ for attr in attributes:
+ vals = grouped.get(attr.id, [])
+ slice_vals = vals[:128] if len(vals) > 128 else vals
filterable_results.append(
{
"attribute_name": attr.name,
- "possible_values": distinct_vals_list,
+ "possible_values": slice_vals,
"value_type": attr.value_type,
}
)
- if user is None:
- user = AnonymousUser()
-
if not user.has_perm("view_attribute"):
- cache.set(f"{obj.uuid}_filterable_results", filterable_results, 86400)
+ cache.set(cache_key, filterable_results, 86400)
return filterable_results
@@ -122,14 +124,7 @@ class CategoryDetailSerializer(ModelSerializer):
else:
children = obj.children.filter(is_active=True)
- if obj.children.exists():
- return (
- CategoryDetailSerializer(children, many=True, context=self.context).data
- if obj.children.exists()
- else []
- )
- else:
- return []
+ return CategoryDetailSerializer(children, many=True, context=self.context).data if obj.children.exists() else []
class BrandDetailSerializer(ModelSerializer):
diff --git a/core/serializers/seo.py b/core/serializers/seo.py
new file mode 100644
index 00000000..780d25a5
--- /dev/null
+++ b/core/serializers/seo.py
@@ -0,0 +1,13 @@
+from rest_framework.fields import CharField, DictField, ListField
+from rest_framework.serializers import Serializer
+
+
+class SeoSnapshotSerializer(Serializer):
+ title = CharField()
+ description = CharField()
+ canonical = CharField()
+ robots = CharField()
+ hreflang = ListField(child=DictField(), required=False)
+ open_graph = DictField()
+ twitter = DictField()
+ json_ld = ListField(child=DictField())
diff --git a/core/serializers/simple.py b/core/serializers/simple.py
index f05e1a75..658f5fe4 100644
--- a/core/serializers/simple.py
+++ b/core/serializers/simple.py
@@ -1,5 +1,5 @@
-from collections.abc import Collection
from contextlib import suppress
+from typing import Collection, Any
from rest_framework.fields import JSONField, SerializerMethodField
from rest_framework.relations import PrimaryKeyRelatedField
@@ -27,8 +27,8 @@ from core.serializers.utility import AddressSerializer
class AttributeGroupSimpleSerializer(ModelSerializer):
- parent: PrimaryKeyRelatedField = PrimaryKeyRelatedField(read_only=True) # type: ignore
- children: PrimaryKeyRelatedField = PrimaryKeyRelatedField(many=True, read_only=True) # type: ignore
+ parent = PrimaryKeyRelatedField(read_only=True) # type: ignore [assignment, var-annotated]
+ children = PrimaryKeyRelatedField(many=True, read_only=True) # type: ignore [assignment, var-annotated]
class Meta:
model = AttributeGroup
@@ -59,21 +59,14 @@ class CategorySimpleSerializer(ModelSerializer):
return obj.image.url
return None
- def get_children(self, obj) -> Collection:
+ def get_children(self, obj) -> Collection[Any]:
request = self.context.get("request")
if request is not None and request.user.has_perm("view_category"):
children = obj.children.all()
else:
children = obj.children.filter(is_active=True)
- if obj.children.exists():
- return (
- CategorySimpleSerializer(children, many=True, context=self.context).data
- if obj.children.exists()
- else []
- )
- else:
- return []
+ return CategorySimpleSerializer(children, many=True, context=self.context).data if obj.children.exists() else []
class BrandSimpleSerializer(ModelSerializer):
@@ -163,6 +156,7 @@ class ProductSimpleSerializer(ModelSerializer):
price = SerializerMethodField()
quantity = SerializerMethodField()
feedbacks_count = SerializerMethodField()
+ personal_orders_only = SerializerMethodField()
class Meta:
model = Product
@@ -175,6 +169,7 @@ class ProductSimpleSerializer(ModelSerializer):
"partnumber",
"brand",
"feedbacks_count",
+ "personal_orders_only",
"category",
"tags",
"images",
@@ -196,6 +191,9 @@ class ProductSimpleSerializer(ModelSerializer):
def get_quantity(self, obj: Product) -> int:
return obj.quantity
+ def get_personal_orders_only(self, obj: Product) -> bool:
+ return obj.personal_orders_only
+
class VendorSimpleSerializer(ModelSerializer):
class Meta:
diff --git a/core/serializers/utility.py b/core/serializers/utility.py
index 0fc2437e..8ecd124a 100644
--- a/core/serializers/utility.py
+++ b/core/serializers/utility.py
@@ -89,7 +89,7 @@ class DoFeedbackSerializer(Serializer):
class CacheOperatorSerializer(Serializer):
key = CharField(required=True)
- data = JSONField(required=False) # type: ignore
+ data = JSONField(required=False) # type: ignore [assignment]
timeout = IntegerField(required=False)
@@ -122,7 +122,7 @@ class RecursiveField(Field):
class AddOrderProductSerializer(Serializer):
product_uuid = CharField(required=True)
- attributes = JSONField(required=False, default=dict)
+ attributes = ListField(required=False, child=DictField(), default=list)
class BulkAddOrderProductsSerializer(Serializer):
@@ -160,6 +160,7 @@ class BuyOrderSerializer(Serializer):
promocode_uuid = CharField(required=False)
shipping_address_uuid = CharField(required=False)
billing_address_uuid = CharField(required=False)
+ chosen_products = ListField(child=AddOrderProductSerializer(), required=False)
class BuyUnregisteredOrderSerializer(Serializer):
diff --git a/core/signals.py b/core/signals.py
index adeb3035..c58c20d6 100644
--- a/core/signals.py
+++ b/core/signals.py
@@ -10,7 +10,8 @@ from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from sentry_sdk import capture_exception
-from core.models import Category, Order, Product, PromoCode, Wishlist
+from core.models import Category, Order, Product, PromoCode, Wishlist, DigitalAssetDownload
+from core.serializers import OrderProductSimpleSerializer
from core.utils import (
generate_human_readable_id,
resolve_translations_for_elasticsearch,
@@ -19,7 +20,7 @@ from core.utils.emailing import send_order_created_email, send_order_finished_em
from evibes.utils.misc import create_object
from vibes_auth.models import User
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
@receiver(post_save, sender=User)
@@ -64,6 +65,9 @@ def create_promocode_on_user_referring(instance, created, **_kwargs):
@receiver(post_save, sender=Order)
def process_order_changes(instance, created, **_kwargs):
+ if type(instance.attributes) is not dict:
+ instance.attributes = {}
+
if not created:
if instance.status != "PENDING" and instance.user:
pending_orders = Order.objects.filter(user=instance.user, status="PENDING")
@@ -85,14 +89,25 @@ def process_order_changes(instance, created, **_kwargs):
break
if instance.status in ["CREATED", "PAYMENT"]:
+ logger.debug(
+ "Processing order changes: %s\nWith orderproducts: %s",
+ str(instance.__dict__),
+ str(OrderProductSimpleSerializer(instance.order_products.all(), many=True).data),
+ )
if not instance.is_whole_digital:
send_order_created_email.delay(instance.uuid)
- for order_product in instance.order_products.filter(status="DELIVERING"):
- if not order_product.product.is_digital:
+ for order_product in instance.order_products.filter(status="DELIVERING", product__is_digital=True):
+ if order_product.product.stocks.filter(digital_asset__isnull=False).exists():
+ order_product.status = "FINISHED"
+ download = DigitalAssetDownload.objects.create(order_product=order_product)
+ order_product.download = download
+ order_product.save()
+ order_product.order.user.payments_balance.amount -= order_product.buy_price
+ order_product.order.user.payments_balance.save()
continue
-
try:
+ logger.debug("Trying to buy: %s", str(order_product.uuid))
vendor_name = (
order_product.product.stocks.filter(price=order_product.buy_price).first().vendor.name.lower()
)
@@ -111,7 +126,9 @@ def process_order_changes(instance, created, **_kwargs):
instance.status = "FAILED"
instance.save()
- if instance.status == "FINISHED":
+ if instance.status == "FINISHED" and not instance.attributes.get("system_email_sent", False):
+ instance.attributes["system_email_sent"] = True
+ instance.save()
send_order_finished_email.delay(instance.uuid)
diff --git a/core/sitemaps.py b/core/sitemaps.py
index 0f9a629a..a3d79c09 100644
--- a/core/sitemaps.py
+++ b/core/sitemaps.py
@@ -1,5 +1,4 @@
from django.contrib.sitemaps import Sitemap
-from django.utils.text import slugify
from core.models import Brand, Category, Product
from evibes.settings import LANGUAGE_CODE
@@ -9,7 +8,7 @@ class ProductSitemap(Sitemap):
protocol = "https"
changefreq = "daily"
priority = 0.9
- limit = 40000
+ limit = 25000
def items(self):
return (
@@ -17,6 +16,8 @@ class ProductSitemap(Sitemap):
is_active=True,
brand__is_active=True,
category__is_active=True,
+ stocks__isnull=False,
+ stocks__vendor__is_active=True,
)
.only("uuid", "name", "modified", "slug")
.order_by("-modified")
@@ -33,7 +34,7 @@ class CategorySitemap(Sitemap):
protocol = "https"
changefreq = "weekly"
priority = 0.7
- limit = 40000
+ limit = 10000
def items(self):
return Category.objects.filter(is_active=True).only("uuid", "name", "modified").order_by("-modified")
@@ -42,15 +43,14 @@ class CategorySitemap(Sitemap):
return obj.modified
def location(self, obj):
- slug = slugify(obj.name)
- return f"/{LANGUAGE_CODE}/catalog/{obj.uuid}/{slug}"
+ return f"/{LANGUAGE_CODE}/catalog/{obj.slug}"
class BrandSitemap(Sitemap):
protocol = "https"
changefreq = "weekly"
priority = 0.6
- limit = 40000
+ limit = 10000
def items(self):
return Brand.objects.filter(is_active=True).only("uuid", "name", "modified").order_by("-modified")
@@ -59,5 +59,4 @@ class BrandSitemap(Sitemap):
return obj.modified
def location(self, obj):
- slug = slugify(obj.name)
- return f"/{LANGUAGE_CODE}/brand/{obj.uuid}/{slug}"
+ return f"/{LANGUAGE_CODE}/brand/{obj.slug}"
diff --git a/core/tasks.py b/core/tasks.py
index 3bbe5f33..39faaca7 100644
--- a/core/tasks.py
+++ b/core/tasks.py
@@ -13,14 +13,14 @@ from django.core.cache import cache
from core.models import Product, Promotion
from core.utils.caching import set_default_cache
-from core.vendors import delete_stale
+from core.vendors import delete_stale, VendorInactiveError
from evibes.settings import MEDIA_ROOT
logger = get_task_logger(__name__)
-@shared_task
-def update_products_task():
+@shared_task(queue="stock_updater")
+def update_products_task() -> tuple[bool, str]:
"""
Run a background task to update product data and manage stale products.
@@ -44,6 +44,8 @@ def update_products_task():
vendor = vendor_class()
try:
vendor.update_stock()
+ except VendorInactiveError:
+ logger.info(f"Skipping {vendor_class} due to inactivity")
except Exception as e:
logger.warning(f"Skipping {vendor_class} due to error: {e!s}")
@@ -54,8 +56,8 @@ def update_products_task():
return True, "Success"
-@shared_task
-def update_orderproducts_task():
+@shared_task(queue="default")
+def update_orderproducts_task() -> tuple[bool, str]:
"""
Updates the statuses of order products for all vendors listed in the
`vendors_classes`. Each vendor class in the `vendors_classes` list is
@@ -76,8 +78,8 @@ def update_orderproducts_task():
return True, "Success"
-@shared_task
-def set_default_caches_task():
+@shared_task(queue="default")
+def set_default_caches_task() -> tuple[bool, str]:
"""
Task to set default caches in the application's memory.
@@ -92,8 +94,8 @@ def set_default_caches_task():
return True, "Success"
-@shared_task
-def remove_stale_product_images():
+@shared_task(queue="default")
+def remove_stale_product_images() -> tuple[bool, str] | None:
"""
Removes stale product images from the products directory by identifying directories
whose names do not match any UUIDs currently present in the database.
@@ -139,7 +141,7 @@ def remove_stale_product_images():
logger.error("Error removing directory %s: %s", entry_path, e)
-@shared_task
+@shared_task(queue="default")
def process_promotions() -> tuple[bool, str]:
"""
Processes and updates promotions based on holiday data or default settings.
diff --git a/core/templates/digital_order_created_email.html b/core/templates/digital_order_created_email.html
index 45bb1f59..06d6e388 100644
--- a/core/templates/digital_order_created_email.html
+++ b/core/templates/digital_order_created_email.html
@@ -91,7 +91,7 @@
diff --git a/core/templates/digital_order_delivered_email.html b/core/templates/digital_order_delivered_email.html
index 7b2df364..fbf27cbc 100644
--- a/core/templates/digital_order_delivered_email.html
+++ b/core/templates/digital_order_delivered_email.html
@@ -1,5 +1,4 @@
{% load tz static i18n filters conditions %}
-
@@ -91,7 +90,7 @@
diff --git a/core/templates/shipped_order_created_email.html b/core/templates/shipped_order_created_email.html
index 722b7a53..0346a0a7 100644
--- a/core/templates/shipped_order_created_email.html
+++ b/core/templates/shipped_order_created_email.html
@@ -91,7 +91,7 @@
diff --git a/core/templates/shipped_order_delivered_email.html b/core/templates/shipped_order_delivered_email.html
index 722b7a53..0346a0a7 100644
--- a/core/templates/shipped_order_delivered_email.html
+++ b/core/templates/shipped_order_delivered_email.html
@@ -91,7 +91,7 @@
diff --git a/core/utils/__init__.py b/core/utils/__init__.py
index a1013daf..53d1f447 100644
--- a/core/utils/__init__.py
+++ b/core/utils/__init__.py
@@ -4,68 +4,116 @@ import secrets
from contextlib import contextmanager
from constance import config
+from django.conf import settings
from django.core.cache import cache
from django.db import transaction
from django.utils.crypto import get_random_string
+from django.utils.translation import get_language
from evibes.settings import DEBUG, EXPOSABLE_KEYS, LANGUAGE_CODE
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
+
+
+def graphene_current_lang():
+ """
+ Determines the currently active language code.
+
+ This function retrieves the current language from the available language
+ settings. If no language is set, it defaults to the application's default
+ language code. The language code is returned in lowercase.
+
+ Returns:
+ str: The currently active language code in lowercase.
+ """
+ return (get_language() or settings.LANGUAGE_CODE).lower()
+
+
+def graphene_abs(request, path_or_url: str) -> str:
+ """
+ Builds and returns an absolute URI for a given path or URL.
+
+ Summary:
+ This function takes a relative path or URL and constructs a fully
+ qualified absolute URI using the request object.
+
+ Args:
+ request: The request object used to build the absolute URI.
+ path_or_url: str
+ The relative path or URL to be converted to an absolute URI.
+
+ Returns:
+ str: The absolute URI corresponding to the provided path or URL.
+ """
+ return request.build_absolute_uri(path_or_url)
def get_random_code() -> str:
"""
- Generates a random string of a specified length. This method calls the
- get_random_string function to create a random alphanumeric string of
- 20 characters in length.
+ Generates a random alphanumeric string of a fixed length.
- Returns
- -------
- str
- A 20-character-long alphanumeric string.
+ This function uses a utility function to generate a random string
+ consisting of letters and digits. The length of the string is fixed
+ to 20 characters. The generated string can be used for purposes
+ such as unique identifiers or tokens.
+
+ Returns:
+ str: Randomly generated alphanumeric string of length 20.
"""
return get_random_string(20)
-def get_product_uuid_as_path(instance, filename):
+def get_product_uuid_as_path(instance, filename: str = "") -> str:
"""
- Generates a unique file path for a product using its UUID.
+ Generates a file path for a product using its UUID.
- This function constructs a file path that includes the product UUID
- in its directory structure. The path format is "products/{product_uuid}/{filename}",
- where `product_uuid` is derived from the instance's product attribute, and
- `filename` corresponds to the original name of the file being processed.
+ This function constructs a standardized file path where an uploaded file
+ is saved for a product. The path includes a `products` directory, followed
+ by the product's UUID, and concludes with the original filename. It can be
+ utilized in file storage applications to ensure unique and organized file
+ storage based on the product's identity.
- Parameters:
- instance: Object
- The model instance containing the product attribute with the desired UUID.
- filename: str
- The original name of the file for which the path is being generated.
+ Args:
+ instance: The object instance that contains a reference to the product.
+ filename: str, optional. The name of the file being uploaded. Default is an
+ empty string.
Returns:
- str
- A string representing the generated unique file path that adheres to the
- format "products/{product_uuid}/{filename}".
+ str: A string that represents the constructed file path.
"""
return "products" + "/" + str(instance.product.uuid) + "/" + filename
-def get_brand_name_as_path(instance, filename):
+def get_brand_name_as_path(instance, filename: str = "") -> str:
+ """
+ Generates a file path for a brand based on its name and the provided filename.
+
+ This function constructs a unique file path within the 'brands/' directory using
+ the name of the given instance and appends the supplied filename.
+
+ Parameters:
+ instance: An object containing a 'name' attribute.
+ filename: str, optional. The name of the file to be appended to the path.
+
+ Returns:
+ str: A string representing the constructed file path.
+ """
return "brands/" + str(instance.name) + "/" + filename
@contextmanager
def atomic_if_not_debug():
"""
- A context manager to execute a database operation within an atomic transaction
- when the `DEBUG` setting is disabled. If `DEBUG` is enabled, it bypasses
- transactional behavior. This allows safe rollback in production and easier
- debugging in development.
+ Context manager to wrap a block of code in an atomic transaction if the DEBUG
+ setting is not enabled.
- Yields
- ------
- None
- Yields control to the enclosed block of code.
+ This context manager ensures that the code block executes within an atomic
+ database transaction, preventing partial updates to the database in case of
+ an exception. If the DEBUG setting is enabled, no transaction is enforced,
+ allowing for easier debugging.
+
+ Yields:
+ None: This context manager does not return any values.
"""
if not DEBUG:
with transaction.atomic():
@@ -76,21 +124,37 @@ def atomic_if_not_debug():
def is_url_safe(url: str) -> bool:
"""
- Determine if a given URL is safe. This function evaluates whether
- the provided URL starts with "https://", making it a potentially
- secure resource by evaluating its prefix using a regular expression.
+ Determines if a given URL starts with "https://" indicating it is a secure URL.
- Arguments:
- url (str): The URL to evaluate.
+ This function checks if the provided URL adheres to secure HTTPS protocol.
+ It uses a regular expression to validate the URL prefix.
+
+ Parameters:
+ url (str): The URL string to validate.
Returns:
- bool: True if the URL starts with "https://", indicating it may
- be considered safe. False otherwise.
+ bool: True if the URL starts with "https://", False otherwise.
"""
return bool(re.match(r"^https://", url, re.IGNORECASE))
-def format_attributes(attributes: str | None = None):
+def format_attributes(attributes: str | None = None) -> dict:
+ """
+ Parses a string of attributes into a dictionary.
+
+ This function takes a string input representing attributes and their values,
+ formatted as `key=value` pairs separated by commas, and converts it into a
+ dictionary. It returns an empty dictionary if the input is `None` or invalid.
+ Invalid key-value pairs within the input string are skipped.
+
+ Parameters:
+ attributes (str | None): A comma-separated string of key-value pairs in the
+ format `key=value`, or None.
+
+ Returns:
+ dict: A dictionary where keys are the attribute names and values are their
+ corresponding values.
+ """
if not attributes:
return {}
@@ -110,7 +174,18 @@ def format_attributes(attributes: str | None = None):
return result
-def get_project_parameters():
+def get_project_parameters() -> dict:
+ """
+ Fetches project parameters from cache or configuration.
+
+ This function retrieves project parameters from a cache if available.
+ If they are not cached, it collects the parameters from a designated
+ configuration source, formats their keys to lowercase, and then stores
+ them in the cache for a limited period.
+
+ Returns:
+ dict: A dictionary containing the project parameters with lowercase keys.
+ """
parameters = cache.get("parameters", {})
if not parameters:
@@ -122,7 +197,20 @@ def get_project_parameters():
return parameters
-def resolve_translations_for_elasticsearch(instance, field_name):
+def resolve_translations_for_elasticsearch(instance, field_name) -> None:
+ """
+ Resolves translations for a given field in an Elasticsearch-compatible
+ format. It checks if the localized version of the field contains data,
+ and if not, sets it to the value of the default field.
+
+ Parameters:
+ instance: The object instance containing the field to resolve.
+ field_name (str): The base name of the field for which translations
+ are being resolved.
+
+ Returns:
+ None
+ """
field = getattr(instance, f"{field_name}_{LANGUAGE_CODE}", "")
filled_field = getattr(instance, field_name, "")
if not field:
@@ -134,12 +222,18 @@ CROCKFORD = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
def generate_human_readable_id(length: int = 6) -> str:
"""
- Generate a human-readable ID of `length` characters (from the Crockford set),
- with a single hyphen inserted:
- - 50% chance at the exact middle
- - 50% chance at a random position between characters (1 to length-1)
+ Generates a human-readable identifier using Crockford's Base32 characters.
- The final string length will be `length + 1` (including the hyphen).
+ This function creates a string of a specified length composed of randomly
+ selected characters from the Crockford Base32 alphabet. A dash is inserted
+ at a random or mid-point position in the identifier for better readability.
+
+ Parameters:
+ length (int): The length of the identifier excluding the dash. Must be
+ greater than 0. Default is 6.
+
+ Returns:
+ str: A human-readable identifier with the specified length plus a dash.
"""
chars = [secrets.choice(CROCKFORD) for _ in range(length)]
@@ -147,3 +241,17 @@ def generate_human_readable_id(length: int = 6) -> str:
chars.insert(pos, "-")
return "".join(chars)
+
+
+def generate_human_readable_token() -> str:
+ """
+ Generates a human-readable token.
+
+ This function creates a random token using characters from
+ the CROCKFORD base32 set. The generated token is 20 characters
+ long and is designed to be human-readable.
+
+ Returns:
+ str: A 20-character random token.
+ """
+ return "".join([secrets.choice(CROCKFORD) for _ in range(20)])
diff --git a/core/utils/caching.py b/core/utils/caching.py
index c912c788..6071e154 100644
--- a/core/utils/caching.py
+++ b/core/utils/caching.py
@@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _
from evibes.settings import UNSAFE_CACHE_KEYS
from vibes_auth.models import User
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
def is_safe_cache_key(key: str):
diff --git a/core/utils/db.py b/core/utils/db.py
index 3cca4558..601ee56d 100644
--- a/core/utils/db.py
+++ b/core/utils/db.py
@@ -1,22 +1,10 @@
import logging
-from django.db.models import Model
from django.db.models.constants import LOOKUP_SEP
-from django.utils.translation import gettext_lazy as _
from django_extensions.db.fields import AutoSlugField
from slugify import slugify
-logger = logging.getLogger(__name__)
-
-
-def list_to_queryset(model: Model, data: list):
- if not isinstance(model, Model):
- raise ValueError(_(f"{model} must be model"))
- if not isinstance(data, list):
- raise ValueError(_(f"{data} must be list object"))
-
- pk_list = [obj.pk for obj in data]
- return model.objects.filter(pk__in=pk_list)
+logger = logging.getLogger("django")
def unicode_slugify_function(content):
diff --git a/core/utils/emailing.py b/core/utils/emailing.py
index 750dd6e3..c262bf50 100644
--- a/core/utils/emailing.py
+++ b/core/utils/emailing.py
@@ -12,7 +12,7 @@ from core.models import Order, OrderProduct
from core.utils.constance import set_email_settings
-@shared_task
+@shared_task(queue="default")
def contact_us_email(contact_info):
set_email_settings()
connection = mail.get_connection()
@@ -30,7 +30,7 @@ def contact_us_email(contact_info):
"config": config,
},
),
- to=[config.EMAIL_HOST_USER],
+ to=[config.EMAIL_FROM],
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
connection=connection,
)
@@ -40,14 +40,17 @@ def contact_us_email(contact_info):
return True, str(contact_info.get("email"))
-@shared_task
+@shared_task(queue="default")
def send_order_created_email(order_pk: str) -> tuple[bool, str]:
try:
order = Order.objects.get(pk=order_pk)
except Order.DoesNotExist:
return False, f"Order not found with the given pk: {order_pk}"
- activate(order.user.language) # type: ignore
+ if not order.user:
+ return False, f"Order's user not found with the given pk: {order_pk}"
+
+ activate(order.user.language)
set_email_settings()
connection = mail.get_connection()
@@ -64,7 +67,7 @@ def send_order_created_email(order_pk: str) -> tuple[bool, str]:
"total_price": order.total_price,
},
),
- to=[order.user.email], # type: ignore
+ to=[order.user.email],
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
connection=connection,
)
@@ -74,13 +77,16 @@ def send_order_created_email(order_pk: str) -> tuple[bool, str]:
return True, str(order.uuid)
-@shared_task
+@shared_task(queue="default")
def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
def send_digital_assets_email(ops: list[OrderProduct]):
if len(ops) <= 0:
return
- activate(order.user.language) # type: ignore
+ if not order.user:
+ return
+
+ activate(order.user.language)
set_email_settings()
connection = mail.get_connection()
@@ -91,16 +97,16 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
template_name="digital_order_delivered_email.html",
context={
"order_uuid": order.human_readable_id,
- "user_first_name": order.user.first_name, # type: ignore
+ "user_first_name": "" or order.user.first_name,
"order_products": ops,
"project_name": config.PROJECT_NAME,
"contact_email": config.EMAIL_FROM,
- "total_price": round(sum(op.buy_price for op in ops), 2),
- "display_system_attributes": order.user.has_perm("core.view_order"), # type: ignore
+ "total_price": round(sum(0.0 or op.buy_price for op in ops), 2), # type: ignore [misc]
+ "display_system_attributes": order.user.has_perm("core.view_order"),
"today": datetime.today(),
},
),
- to=[order.user.email], # type: ignore
+ to=[order.user.email],
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
connection=connection,
)
@@ -110,7 +116,9 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
def send_thank_you_email(ops: list[OrderProduct]):
if ops:
pass
- activate(order.user.language) # type: ignore
+ if not order.user:
+ return
+ activate(order.user.language)
set_email_settings()
@@ -121,6 +129,9 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]:
except Order.DoesNotExist:
return False, f"Order not found with the given pk: {order_pk}"
+ if not order.user:
+ return False, f"Order's user not found with the given pk: {order_pk}"
+
digital_ops = []
for digital_op in order.order_products.filter(
diff --git a/core/utils/seo_builders.py b/core/utils/seo_builders.py
new file mode 100644
index 00000000..93c51470
--- /dev/null
+++ b/core/utils/seo_builders.py
@@ -0,0 +1,98 @@
+from constance import config
+from django.conf import settings
+
+
+def org_schema():
+ return {
+ "@context": "https://schema.org",
+ "@type": "Organization",
+ "name": config.COMPANY_NAME,
+ "url": f"https://{config.BASE_DOMAIN}/",
+ "logo": f"https://{config.BASE_DOMAIN}/static/logo.png",
+ }
+
+
+def website_schema():
+ return {
+ "@context": "https://schema.org",
+ "@type": "WebSite",
+ "name": config.PROJECT_NAME,
+ "url": f"https://{config.BASE_DOMAIN}/",
+ "potentialAction": {
+ "@type": "SearchAction",
+ "target": f"https://{config.BASE_DOMAIN}/search?q={{query}}",
+ "query-input": "required name=query",
+ },
+ }
+
+
+def breadcrumb_schema(items):
+ return {
+ "@context": "https://schema.org",
+ "@type": "BreadcrumbList",
+ "itemListElement": [
+ {"@type": "ListItem", "position": i + 1, "name": name, "item": url} for i, (name, url) in enumerate(items)
+ ],
+ }
+
+
+def item_list_schema(urls):
+ return {
+ "@context": "https://schema.org",
+ "@type": "ItemList",
+ "itemListElement": [{"@type": "ListItem", "position": i + 1, "url": u} for i, u in enumerate(urls)],
+ }
+
+
+def product_schema(product, images, rating=None):
+ offers = []
+ for stock in product.stocks.all():
+ offers.append(
+ {
+ "@type": "Offer",
+ "price": round(stock.price, 2),
+ "priceCurrency": settings.CURRENCY_CODE,
+ "availability": "https://schema.org/InStock" if stock.quantity > 0 else "https://schema.org/OutOfStock",
+ "sku": stock.sku,
+ "url": f"https://{config.BASE_DOMAIN}/product/{product.slug}",
+ }
+ )
+ data = {
+ "@context": "https://schema.org",
+ "@type": "Product",
+ "name": product.name,
+ "description": product.description or "",
+ "sku": product.partnumber or "",
+ "brand": {"@type": "Brand", "name": product.brand.name} if product.brand else None,
+ "image": [img.image.url for img in images] or [],
+ "offers": offers[:1] if offers else None,
+ }
+ if rating and rating["count"] > 0:
+ data["aggregateRating"] = {
+ "@type": "AggregateRating",
+ "ratingValue": rating["value"],
+ "reviewCount": rating["count"],
+ }
+ return {k: v for k, v in data.items() if v not in (None, [], {})}
+
+
+def category_schema(category, url):
+ return {
+ "@context": "https://schema.org",
+ "@type": "CollectionPage",
+ "name": category.name,
+ "description": category.description or "",
+ "url": url,
+ }
+
+
+def brand_schema(brand, url, logo_url=None):
+ data = {
+ "@context": "https://schema.org",
+ "@type": "Brand",
+ "name": brand.name,
+ "url": url,
+ }
+ if logo_url:
+ data["logo"] = logo_url
+ return data
diff --git a/core/vendors/__init__.py b/core/vendors/__init__.py
index 216c03b6..781a5b40 100644
--- a/core/vendors/__init__.py
+++ b/core/vendors/__init__.py
@@ -1,9 +1,11 @@
import json
from contextlib import suppress
+from decimal import Decimal
from math import ceil, log10
from typing import Any
-from django.db import IntegrityError
+from django.db import IntegrityError, transaction
+from django.db.models import QuerySet
from core.elasticsearch import process_query
from core.models import (
@@ -13,6 +15,7 @@ from core.models import (
Brand,
Category,
Product,
+ ProductImage,
Stock,
Vendor,
)
@@ -56,6 +59,10 @@ class VendorError(Exception):
pass
+class VendorInactiveError(VendorError):
+ pass
+
+
class AbstractVendor:
"""
Abstract class defining vendor-related operations and handling.
@@ -72,13 +79,15 @@ class AbstractVendor:
instance.
"""
- def __init__(self, vendor_name=None, currency="USD"):
+ def __init__(self, vendor_name: str | None = None, currency: str = "USD") -> None:
self.vendor_name = vendor_name
self.currency = currency
- self.blocked_attributes = []
+ self.blocked_attributes: list[Any] = []
@staticmethod
- def chunk_data(data, num_chunks=20):
+ def chunk_data(data: list[Any] | None = None, num_chunks: int = 20) -> list[list[Any]] | list[Any]:
+ if not data:
+ return []
total = len(data)
if total == 0:
return []
@@ -86,7 +95,7 @@ class AbstractVendor:
return [data[i : i + chunk_size] for i in range(0, total, chunk_size)]
@staticmethod
- def auto_convert_value(value: Any):
+ def auto_convert_value(value: Any) -> tuple[Any, str]:
"""
Attempts to convert a value to a more specific type.
Handles booleans, numbers, objects (dicts), and arrays (lists),
@@ -145,9 +154,11 @@ class AbstractVendor:
return value, "string"
@staticmethod
- def auto_resolver_helper(model: Brand | Category, resolving_name: str) -> Brand | Category | None:
+ def auto_resolver_helper(model: type[Brand] | type[Category], resolving_name: str) -> Brand | Category | None:
queryset = model.objects.filter(name=resolving_name)
if not queryset.exists():
+ if len(resolving_name) > 255:
+ resolving_name = resolving_name[:255]
return model.objects.get_or_create(name=resolving_name, defaults={"is_active": False})[0]
elif queryset.filter(is_active=True).count() > 1:
queryset = queryset.filter(is_active=True)
@@ -160,7 +171,7 @@ class AbstractVendor:
queryset.delete()
return chosen
- def auto_resolve_category(self, category_name: str):
+ def auto_resolve_category(self, category_name: str = "") -> Category | None:
if category_name:
try:
search = process_query(category_name)
@@ -176,9 +187,9 @@ class AbstractVendor:
except Category.DoesNotExist:
pass
- return self.auto_resolver_helper(Category, category_name) # type: ignore
+ return self.auto_resolver_helper(Category, category_name)
- def auto_resolve_brand(self, brand_name: str):
+ def auto_resolve_brand(self, brand_name: str = "") -> Brand | None:
if brand_name:
try:
search = process_query(brand_name)
@@ -194,7 +205,7 @@ class AbstractVendor:
except Brand.DoesNotExist:
pass
- return self.auto_resolver_helper(Brand, brand_name) # type: ignore
+ return self.auto_resolver_helper(Brand, brand_name)
def resolve_price(
self,
@@ -211,13 +222,13 @@ class AbstractVendor:
price = float(original_price)
if category and category.markup_percent:
- price *= 1 + float(category.markup_percent) / 100.0 # type: ignore
+ price *= 1 + float(category.markup_percent) / 100.0
elif vendor and vendor.markup_percent:
price *= 1 + vendor.markup_percent / 100.0
return round(price, 2)
- def resolve_price_with_currency(self, price, provider, currency=None):
+ def resolve_price_with_currency(self, price: float | int | Decimal, provider: str, currency: str = "") -> float:
rates = get_rates(provider)
rate = rates.get(currency or self.currency)
@@ -225,7 +236,7 @@ class AbstractVendor:
if not rate:
raise RatesError(f"No rate found for {currency or self.currency} in {rates} with probider {provider}...")
- return round(price / rate, 2) if rate else round(price, 2)
+ return float(round(price / rate, 2)) if rate else float(round(price, 2))
@staticmethod
def round_price_marketologically(price: float) -> float:
@@ -260,41 +271,96 @@ class AbstractVendor:
return float(psychological)
- def get_vendor_instance(self):
+ def get_vendor_instance(self) -> Vendor | None:
try:
vendor = Vendor.objects.get(name=self.vendor_name)
if vendor.is_active:
return vendor
- raise VendorError(f"Vendor {self.vendor_name!r} is inactive...")
- except Vendor.DoesNotExist:
- raise Exception(f"No matching vendor found with name {self.vendor_name!r}...")
+ raise VendorInactiveError(f"Vendor {self.vendor_name!r} is inactive...")
+ except Vendor.DoesNotExist as dne:
+ raise Exception(f"No matching vendor found with name {self.vendor_name!r}...") from dne
- def get_products(self):
+ def get_products(self) -> None:
pass
- def get_products_queryset(self):
+ def get_products_queryset(self) -> QuerySet[Product] | None:
return Product.objects.filter(stocks__vendor=self.get_vendor_instance(), orderproduct__isnull=True)
- def get_stocks_queryset(self):
+ def get_stocks_queryset(self) -> QuerySet[Stock] | None:
return Stock.objects.filter(product__in=self.get_products_queryset(), product__orderproduct__isnull=True)
- def get_attribute_values_queryset(self):
+ def get_attribute_values_queryset(self) -> QuerySet[AttributeValue] | None:
return AttributeValue.objects.filter(
product__in=self.get_products_queryset(), product__orderproduct__isnull=True
)
- def prepare_for_stock_update(self):
- self.get_products_queryset().update(is_active=False)
+ def prepare_for_stock_update(self, method: str = "deactivate") -> None:
+ products = self.get_products_queryset()
+ if products is None:
+ return
- def delete_inactives(self):
- self.get_products_queryset().filter(is_active=False).delete()
+ # noinspection PyUnreachableCode
+ match method:
+ case "deactivate":
+ products.update(is_active=False)
+ case "delete":
+ products.delete()
+ case "description":
+ products.update(description="EVIBES_DELETED_PRODUCT")
+ case _:
+ raise ValueError(f"Invalid method {method!r} for products update...")
- def delete_belongings(self):
- self.get_products_queryset().delete()
- self.get_stocks_queryset().delete()
- self.get_attribute_values_queryset().delete()
+ def delete_inactives(self, inactivation_method: str = "deactivate", size: int = 5000) -> None:
+ match inactivation_method:
+ case "deactivate":
+ filter_kwargs: dict[str, Any] = {"is_active": False}
+ case "description":
+ filter_kwargs: dict[str, Any] = {"description__exact": "EVIBES_DELETED_PRODUCT"}
+ case _:
+ raise ValueError(f"Invalid method {inactivation_method!r} for products cleaner...")
- def process_attribute(self, key: str, value, product: Product, attr_group: AttributeGroup):
+ while True:
+ products = self.get_products_queryset()
+
+ if products is None:
+ return
+
+ batch_ids = list(products.filter(**filter_kwargs).values_list("pk", flat=True)[:size])
+ if not batch_ids:
+ break
+ with suppress(Exception):
+ AttributeValue.objects.filter(product_id__in=batch_ids).delete()
+ ProductImage.objects.filter(product_id__in=batch_ids).delete()
+ Product.objects.filter(pk__in=batch_ids).delete()
+
+ def delete_belongings(self) -> None:
+ self.get_products_queryset().delete() # type: ignore [union-attr]
+ self.get_stocks_queryset().delete() # type: ignore [union-attr]
+ self.get_attribute_values_queryset().delete() # type: ignore [union-attr]
+
+ def get_or_create_attribute_safe(self, *, name: str, attr_group: AttributeGroup) -> Attribute:
+ key = name[:255]
+ try:
+ attr = Attribute.objects.get(name=key)
+ except Attribute.DoesNotExist:
+ try:
+ with transaction.atomic():
+ attr = Attribute.objects.create(
+ name=key,
+ group=attr_group,
+ is_active=True,
+ value_type="string",
+ )
+ except IntegrityError:
+ attr = Attribute.objects.get(name=key)
+
+ if not attr.is_active:
+ attr.is_active = True
+ attr.save(update_fields=["is_active"])
+
+ return attr
+
+ def process_attribute(self, key: str, value: Any, product: Product, attr_group: AttributeGroup) -> None:
if not value:
return
@@ -308,6 +374,9 @@ class AbstractVendor:
is_created = False
+ if len(key) > 255:
+ key = key[:255]
+
try:
attribute, is_created = Attribute.objects.get_or_create(
name=key,
@@ -316,15 +385,15 @@ class AbstractVendor:
defaults={"is_active": True},
)
except Attribute.MultipleObjectsReturned:
- attribute = Attribute.objects.filter(name=key, group=attr_group).order_by("uuid").first() # type: ignore
+ attribute = Attribute.objects.filter(name=key, group=attr_group).order_by("uuid").first() # type: ignore [assignment]
attribute.is_active = True
attribute.value_type = attr_value_type
- attribute.save()
+ attribute.save() # type: ignore [no-untyped-call]
except IntegrityError:
return
attribute.categories.add(product.category)
- attribute.save()
+ attribute.save() # type: ignore [no-untyped-call]
if not is_created:
return
@@ -336,12 +405,12 @@ class AbstractVendor:
defaults={"is_active": True},
)
- def update_stock(self):
+ def update_stock(self) -> None:
pass
- def update_order_products_statuses(self):
+ def update_order_products_statuses(self) -> None:
pass
-def delete_stale():
+def delete_stale() -> None:
Product.objects.filter(stocks__isnull=True, orderproduct__isnull=True).delete()
diff --git a/core/views.py b/core/views.py
index 8315af07..a3b28f30 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,5 +1,7 @@
+import logging
import mimetypes
import os
+import traceback
import requests
from django.contrib.sitemaps.views import index as _sitemap_index_view
@@ -8,9 +10,10 @@ from django.core.cache import cache
from django.core.exceptions import BadRequest
from django.http import FileResponse, Http404, JsonResponse
from django.shortcuts import redirect
-from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_decode
from django.utils.translation import gettext_lazy as _
+from django.views.decorators.cache import cache_page
+from django.views.decorators.vary import vary_on_headers
from django_ratelimit.decorators import ratelimit
from djangorestframework_camel_case.render import CamelCaseJSONRenderer
from djangorestframework_camel_case.util import camelize
@@ -51,25 +54,80 @@ from evibes import settings
from evibes.settings import LANGUAGES
from payments.serializers import TransactionProcessSerializer
+logger = logging.getLogger("django")
+
+@cache_page(60 * 60 * 12)
+@vary_on_headers("Host")
def sitemap_index(request, *args, **kwargs):
+ """
+ Handles the request for the sitemap index and returns an XML response. It ensures the response includes
+ the appropriate content type header for XML.
+
+ Args:
+ request: The HTTP request object.
+ *args: Additional positional arguments passed to the view.
+ **kwargs: Additional keyword arguments passed to the view.
+
+ Returns:
+ A response object containing the sitemap index in XML format, with the proper content type set as
+ "application/xml; charset=utf-8".
+ """
response = _sitemap_index_view(request, *args, **kwargs)
response["Content-Type"] = "application/xml; charset=utf-8"
return response
+@cache_page(60 * 60 * 24)
+@vary_on_headers("Host")
def sitemap_detail(request, *args, **kwargs):
+ """
+ Handles the detailed view response for a sitemap. This function processes
+ the request, fetches the appropriate sitemap detail response, and sets the
+ Content-Type header for XML responses.
+
+ Args:
+ request: An HTTP request object containing request metadata, such as
+ headers and HTTP method.
+ *args: Additional positional arguments provided dynamically to the
+ underlying sitemap detail view function.
+ **kwargs: Additional keyword arguments provided dynamically to the
+ underlying sitemap detail view function.
+
+ Returns:
+ HttpResponse: A response object with content representing the requested
+ sitemap details. The Content-Type header is explicitly set to
+ "application/xml; charset=utf-8".
+ """
response = _sitemap_detail_view(request, *args, **kwargs)
response["Content-Type"] = "application/xml; charset=utf-8"
return response
class CustomGraphQLView(FileUploadGraphQLView):
+ """
+ A custom GraphQL view class that extends the functionality of FileUploadGraphQLView.
+
+ This class serves as a customization extension of FileUploadGraphQLView that allows modification
+ or enhancement of specific behaviors, particularly the context handling for GraphQL requests.
+
+ """
+
def get_context(self, request):
return request
class CustomSwaggerView(SpectacularSwaggerView):
+ """
+ CustomSwaggerView is a subclass of SpectacularSwaggerView.
+
+ This class overrides the `get_context_data` method to
+ add extra context to the response. It modifies the context by
+ including the absolute URI of the current request as the `script_url`.
+ This can be useful in scenarios where the script or reference
+ URL needs to be dynamically generated and included in the context.
+ """
+
def get_context_data(self, **kwargs):
# noinspection PyUnresolvedReferences
context = super().get_context_data(**kwargs)
@@ -78,6 +136,16 @@ class CustomSwaggerView(SpectacularSwaggerView):
class CustomRedocView(SpectacularRedocView):
+ """
+ CustomRedocView provides a customized version of the SpectacularRedocView.
+
+ This class extends the SpectacularRedocView to include additional
+ functionality, such as dynamically setting the `script_url` in the
+ context data. It is designed to be used where customized behavior
+ for rendering ReDoc UI is required, specifically adapting the script
+ URL for the current request environment.
+ """
+
def get_context_data(self, **kwargs):
# noinspection PyUnresolvedReferences
context = super().get_context_data(**kwargs)
@@ -87,6 +155,25 @@ class CustomRedocView(SpectacularRedocView):
@extend_schema_view(**LANGUAGE_SCHEMA)
class SupportedLanguagesView(APIView):
+ """
+ Handles retrieving the list of supported languages.
+
+ This class provides an endpoint to return information about available languages.
+ It is configured with relevant serializers, permission classes, and renderers
+ for flexibility in response formats and access permissions. The endpoint
+ supports retrieving the list of languages with their respective codes, names,
+ and flags.
+
+ Attributes:
+ serializer_class (Serializer): Serializer used for formatting the response data.
+ permission_classes (list): Permissions applied to restrict the endpoint access.
+ renderer_classes (list): Renderers available for formatting response output.
+
+ Methods:
+ get(self, request): Retrieves the list of supported languages.
+
+ """
+
serializer_class = LanguageSerializer
permission_classes = [
AllowAny,
@@ -117,6 +204,31 @@ class SupportedLanguagesView(APIView):
@extend_schema_view(**PARAMETERS_SCHEMA)
class WebsiteParametersView(APIView):
+ """
+ Handles operations related to website parameters.
+
+ This class is a Django Rest Framework view that allows clients to retrieve
+ the parameters of a website. It uses different renderers to present the data
+ in various formats. The view is publicly accessible.
+
+ Attributes
+ ----------
+ serializer_class
+ A placeholder for a DRF serializer, it is set to None since no serializer
+ is explicitly used in this view.
+ permission_classes
+ A list indicating the permissions required to access this view. In this case,
+ `AllowAny`, meaning the view is open to everyone.
+ renderer_classes
+ A list of renderers available for this view, supporting CamelCase JSON,
+ multipart forms, XML, and YAML formats.
+
+ Methods
+ -------
+ get(request)
+ Handles HTTP GET requests to fetch website parameters.
+ """
+
serializer_class = None
permission_classes = [
AllowAny,
@@ -134,6 +246,25 @@ class WebsiteParametersView(APIView):
@extend_schema_view(**CACHE_SCHEMA)
class CacheOperatorView(APIView):
+ """
+ View for managing cache operations.
+
+ This class provides an API view for handling cache operations such as setting cache
+ data with a specified key and timeout. It leverages multiple renderer classes for
+ serializing outputs in various formats.
+
+ Attributes:
+ serializer_class (type): Serializer to validate and deserialize input data.
+ permission_classes (list): List of permission classes to apply access
+ restrictions.
+ renderer_classes (list): List of renderer classes to serialize the output
+ in desired formats.
+
+ Methods:
+ post(request, *args, **kwargs): Handles HTTP POST requests to set cache
+ data based on the provided key and timeout.
+ """
+
serializer_class = CacheOperatorSerializer
permission_classes = [
AllowAny,
@@ -159,6 +290,23 @@ class CacheOperatorView(APIView):
@extend_schema_view(**CONTACT_US_SCHEMA)
class ContactUsView(APIView):
+ """
+ Handles contact us form submissions via a REST API.
+
+ This view processes user submissions for a "Contact Us" form. It validates the received
+ data using a serializer, applies rate limiting for IP-based requests, and sends emails
+ asynchronously. The view is prepared to handle multiple response formats using configured
+ renderers.
+
+ Attributes:
+ serializer_class: The serializer class used to validate incoming data.
+ renderer_classes: A list of renderers to support multiple response formats.
+
+ Methods:
+ post: Handles POST requests to process form submissions.
+
+ """
+
serializer_class = ContactUsSerializer
renderer_classes = [
CamelCaseJSONRenderer,
@@ -178,6 +326,21 @@ class ContactUsView(APIView):
@extend_schema_view(**REQUEST_CURSED_URL_SCHEMA)
class RequestCursedURLView(APIView):
+ """
+ Handles requests for processing and validating URLs from incoming POST requests.
+
+ Particularly intended for validating and processing URLs provided by clients. It uses rate-limiting, caching, and
+ various response format renderers to optimize performance and ensure safe handling of external data.
+
+ Attributes:
+ permission_classes (list): Specifies the permissions required to access this view.
+ renderer_classes (list): Configures the response format renderers available for this view.
+
+ Methods:
+ post: Handles the POST request to validate the URL, fetches its data if valid,
+ and returns the processed response.
+ """
+
permission_classes = [
AllowAny,
]
@@ -217,8 +380,21 @@ class RequestCursedURLView(APIView):
@extend_schema_view(**SEARCH_SCHEMA)
class GlobalSearchView(APIView):
"""
- A global search endpoint.
- It returns a response grouping matched items by index.
+ Class-based view for handling global search functionality.
+
+ This class is designed to process search queries from HTTP GET requests. It is
+ capable of rendering results in multiple formats including CamelCase JSON,
+ MultiPart, XML, and YAML. The class uses a custom schema for API documentation
+ and processes search queries passed as parameters in the request.
+
+ Attributes:
+ renderer_classes (list): List of renderer classes used to serialize responses
+ into various formats such as CamelCase JSON, MultiPart, XML, and YAML.
+
+ Methods:
+ get: Handles HTTP GET requests by processing the search query and returning
+ formatted search results.
+
"""
renderer_classes = [
@@ -234,6 +410,23 @@ class GlobalSearchView(APIView):
@extend_schema_view(**BUY_AS_BUSINESS_SCHEMA)
class BuyAsBusinessView(APIView):
+ """
+ View for buying as a business.
+
+ This view handles the logic of creating orders and processing transactions when a
+ business makes a purchase. It ensures that the request data is properly validated
+ and processed, handles the creation of the order, and starts the transaction process.
+ The view also restricts the rate of requests based on the client's IP address
+ to prevent abuse.
+
+ Attributes:
+ schema (class): Extended schema for API documentation.
+
+ Methods:
+ post(request, *_args, **kwargs):
+ Handles the "POST" request to process a business purchase.
+ """
+
@ratelimit(key="ip", rate="2/h", block=True)
def post(self, request, *_args, **kwargs):
serializer = BuyAsBusinessOrderSerializer(data=request.data)
@@ -258,8 +451,29 @@ class BuyAsBusinessView(APIView):
def download_digital_asset_view(request, *args, **kwargs):
+ """
+ Handles the downloading of a digital asset associated with an order. Ensures that users
+ are permitted to download the asset only once. Validates the request, retrieves the file,
+ and serves it as a downloadable response. Returns appropriate error responses for different
+ failure scenarios.
+
+ Args:
+ request: The HTTP request object containing information about the client request.
+ *args: Additional positional arguments.
+ **kwargs: Additional keyword arguments.
+
+ Raises:
+ BadRequest: If the digital asset has already been downloaded.
+ DigitalAssetDownload.DoesNotExist: If the requested digital asset cannot be found.
+
+ Returns:
+ A FileResponse containing the digital asset file if the request is valid. Returns
+ a JsonResponse with an error message if an error occurs during the process.
+ """
try:
- uuid = force_str(urlsafe_base64_decode(kwargs["encoded_uuid"]))
+ logger.debug(f"download_digital_asset_view: {kwargs}")
+ uuid = urlsafe_base64_decode(str(kwargs.get("order_product_uuid"))).decode("utf-8")
+
download = DigitalAssetDownload.objects.get(order_product__uuid=uuid)
if download.num_downloads >= 1:
@@ -268,39 +482,76 @@ def download_digital_asset_view(request, *args, **kwargs):
download.num_downloads += 1
download.save()
- file_path = download.order_product.product.stocks.first().digital_asset.file.path
+ file_path = download.order_product.product.stocks.first().digital_asset.path
content_type, encoding = mimetypes.guess_type(file_path)
if not content_type:
content_type = "application/octet-stream"
- with open(file_path, "rb") as file:
- response = FileResponse(file, content_type=content_type)
- filename = os.path.basename(file_path)
- response["Content-Disposition"] = f'attachment; filename="{filename}"'
- return response
+ response = FileResponse(open(file_path, "rb"), content_type=content_type)
+ filename = os.path.basename(file_path)
+ response["Content-Disposition"] = f'attachment; filename="{filename}"'
+ return response
except BadRequest as e:
- return JsonResponse({"error": str(e)}, status=400)
+ return JsonResponse(camelize({"error": str(e)}), status=400)
except DigitalAssetDownload.DoesNotExist:
- return JsonResponse({"error": "Digital asset not found"}, status=404)
+ return JsonResponse(camelize({"error": "Digital asset not found"}), status=404)
except Exception as e:
capture_exception(e)
return JsonResponse(
- {"error": "An error occurred while trying to download the digital asset"},
+ camelize(
+ {
+ "error": "An error occurred while trying to download the digital asset",
+ "traceback": traceback.format_exc() if settings.DEBUG else None,
+ "received": {"order_product_uuid": kwargs.get("order_product_uuid", "")},
+ }
+ ),
status=500,
)
def favicon_view(request, *args, **kwargs):
+ """
+ Handles requests for the favicon of a website. This function attempts to serve the favicon
+ file located in the static directory of the project. If the favicon file is not found,
+ an HTTP 404 error is raised to indicate the resource is unavailable.
+
+ Args:
+ request: The HTTP request object.
+ *args: Additional positional arguments that are ignored in this function.
+ **kwargs: Additional keyword arguments that are ignored in this function.
+
+ Returns:
+ FileResponse: A file response containing the favicon image with the content-type
+ "image/x-icon".
+
+ Raises:
+ Http404: Raised if the favicon file is not found.
+ """
try:
favicon_path = os.path.join(settings.BASE_DIR, "static/favicon.png")
return FileResponse(open(favicon_path, "rb"), content_type="image/x-icon")
- except FileNotFoundError:
- raise Http404(_("favicon not found"))
+ except FileNotFoundError as fnfe:
+ raise Http404(_("favicon not found")) from fnfe
def index(request, *args, **kwargs):
+ """
+ Redirects the request to the admin index page.
+
+ The function handles incoming HTTP requests and redirects them to the Django
+ admin interface index page. It uses Django's `redirect` function for handling
+ the HTTP redirection.
+
+ Args:
+ request: The HttpRequest object representing the incoming request.
+ *args: Additional positional arguments, if any.
+ **kwargs: Additional keyword arguments, if any.
+
+ Returns:
+ HttpResponseRedirect: An HTTP response that redirects to the admin index.
+ """
return redirect("admin:index")
diff --git a/core/viewsets.py b/core/viewsets.py
index ee3db6ad..69250806 100644
--- a/core/viewsets.py
+++ b/core/viewsets.py
@@ -2,7 +2,9 @@ import logging
import uuid
from uuid import UUID
-from django.db.models import Q, QuerySet
+from constance import config
+from django.conf import settings
+from django.db.models import Q, Prefetch
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.utils.decorators import method_decorator
@@ -14,6 +16,7 @@ from drf_spectacular.utils import extend_schema_view
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
+from rest_framework.permissions import AllowAny
from rest_framework.renderers import MultiPartRenderer
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
@@ -101,16 +104,47 @@ from core.serializers import (
WishlistDetailSerializer,
WishlistSimpleSerializer,
)
+from core.serializers.seo import SeoSnapshotSerializer
from core.utils import format_attributes
from core.utils.messages import permission_denied_message
from core.utils.nominatim import fetch_address_suggestions
+from core.utils.seo_builders import (
+ org_schema,
+ website_schema,
+ breadcrumb_schema,
+ product_schema,
+ category_schema,
+ item_list_schema,
+ brand_schema,
+)
from evibes.settings import DEBUG
from payments.serializers import TransactionProcessSerializer
-logger = logging.getLogger("django.request")
+logger = logging.getLogger("django")
class EvibesViewSet(ModelViewSet):
+ """
+ Defines a viewset for managing Evibes-related operations.
+
+ The EvibesViewSet class inherits from ModelViewSet and provides functionality
+ for handling actions and operations on Evibes entities. It includes support
+ for dynamic serializer classes based on the current action, customizable
+ permissions, and rendering formats.
+
+ Attributes:
+ action_serializer_classes: Dictionary mapping action names to their specific
+ serializer classes.
+ additional: Dictionary to hold additional data related to the view.
+ permission_classes: List of permission classes applicable to this viewset.
+ renderer_classes: List of renderer classes supported for response formatting.
+
+ Methods:
+ get_serializer_class(self):
+ Returns the serializer class for the current action or the default
+ serializer class from the parent ModelViewSet.
+ """
+
action_serializer_classes: dict = {}
additional: dict = {}
permission_classes = [EvibesPermission]
@@ -122,6 +156,27 @@ class EvibesViewSet(ModelViewSet):
@extend_schema_view(**ATTRIBUTE_GROUP_SCHEMA)
class AttributeGroupViewSet(EvibesViewSet):
+ """
+ Represents a viewset for managing AttributeGroup objects.
+
+ Handles operations related to AttributeGroup, including filtering,
+ serialization, and retrieval of data. This class is part of the
+ application's API layer and provides a standardized way to process
+ requests and responses for AttributeGroup data.
+
+ Attributes:
+ queryset (QuerySet): QuerySet for retrieving all AttributeGroup objects.
+ filter_backends (list): List of filter backends used to process filters
+ in requests.
+ filterset_fields (list): List of fields on which filtering operations
+ can be performed.
+ serializer_class (Serializer): Default serializer class used for
+ processing AttributeGroup data during non-list view operations.
+ action_serializer_classes (dict): Mapping of view actions to their
+ specific serializer classes, allowing customization of serialization
+ behavior for certain actions.
+ """
+
queryset = AttributeGroup.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["is_active"]
@@ -133,6 +188,27 @@ class AttributeGroupViewSet(EvibesViewSet):
@extend_schema_view(**ATTRIBUTE_SCHEMA)
class AttributeViewSet(EvibesViewSet):
+ """
+ Handles operations related to Attribute objects within the application.
+
+ Provides a set of API endpoints to interact with Attribute data. This class
+ manages querying, filtering, and serialization of Attribute objects, allowing
+ dynamic control over the data returned, such as filtering by specific fields
+ or retrieving detailed versus simplified information depending on the request.
+
+ Attributes:
+ queryset: The base QuerySet used to represent the set of Attribute
+ objects available to this viewset.
+ filter_backends: Defines the backends used for filtering request data,
+ enabling query flexibility.
+ filterset_fields: A list of model fields that can be filtered via the API.
+ serializer_class: Represents the serializer used by default for
+ serialization and deserialization of Attribute data.
+ action_serializer_classes: A mapping that defines serializers used for
+ specific actions, such as returning less detailed data for a `list`
+ action.
+ """
+
queryset = Attribute.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["group", "value_type", "is_active"]
@@ -144,6 +220,23 @@ class AttributeViewSet(EvibesViewSet):
@extend_schema_view(**ATTRIBUTE_VALUE_SCHEMA)
class AttributeValueViewSet(EvibesViewSet):
+ """
+ A viewset for managing AttributeValue objects.
+
+ This viewset provides functionality for listing, retrieving, creating, updating, and deleting
+ AttributeValue objects. It integrates with Django REST Framework's viewset mechanisms and uses
+ appropriate serializers for different actions. Filtering capabilities are provided through the
+ DjangoFilterBackend.
+
+ Attributes:
+ queryset (QuerySet): The base queryset for AttributeValue objects.
+ filter_backends (list): A list of filtering backends applied to the viewset.
+ filterset_fields (list): Fields of the model that can be used for filtering.
+ serializer_class (Serializer): The default serializer class for the viewset.
+ action_serializer_classes (dict): A dictionary mapping action names to their corresponding
+ serializer classes.
+ """
+
queryset = AttributeValue.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["attribute", "is_active"]
@@ -155,6 +248,34 @@ class AttributeValueViewSet(EvibesViewSet):
@extend_schema_view(**CATEGORY_SCHEMA)
class CategoryViewSet(EvibesViewSet):
+ """
+ Manages views for Category-related operations.
+
+ The CategoryViewSet class is responsible for handling operations related to
+ the Category model in the system. It supports retrieving, filtering, and
+ serializing category data. The viewset also enforces permissions to ensure
+ that only authorized users can access specific data.
+
+ Attributes:
+ queryset: The base queryset used to retrieve category data, including
+ prefetching related objects such as parents, children, attributes,
+ and tags.
+ filter_backends: A list of backends for applying filters to the category
+ data.
+ filterset_class: The filter class used to define filtering behavior for
+ the category queryset.
+ serializer_class: The default serializer class used for category objects
+ when no specific action serializer is applied.
+ action_serializer_classes: A dictionary mapping specific viewset actions
+ (e.g., "list") to their corresponding serializer classes.
+
+ Methods:
+ get_queryset():
+ Retrieves the queryset for the viewset, applying permission checks
+ and filtering out inactive categories for users without sufficient
+ permissions.
+ """
+
queryset = Category.objects.all().prefetch_related("parent", "children", "attributes", "tags")
filter_backends = [DjangoFilterBackend]
filterset_class = CategoryFilter
@@ -162,6 +283,31 @@ class CategoryViewSet(EvibesViewSet):
action_serializer_classes = {
"list": CategorySimpleSerializer,
}
+ lookup_field = "lookup_value"
+ lookup_url_kwarg = "lookup_value"
+ additional = {"seo_meta": "ALLOW"}
+
+ def get_object(self):
+ queryset = self.filter_queryset(self.get_queryset())
+ lookup_value = self.kwargs[self.lookup_url_kwarg]
+
+ obj = None
+
+ try:
+ uuid_obj = UUID(lookup_value)
+ obj = queryset.filter(uuid=uuid_obj).first()
+ except (ValueError, TypeError):
+ pass
+
+ if not obj:
+ obj = queryset.filter(slug=lookup_value).first()
+
+ if not obj:
+ name = "Category"
+ raise Http404(f"{name} does not exist: {lookup_value}")
+
+ self.check_object_permissions(self.request, obj)
+ return obj
def get_queryset(self):
qs = super().get_queryset()
@@ -169,8 +315,89 @@ class CategoryViewSet(EvibesViewSet):
return qs
return qs.filter(is_active=True)
+ @action(
+ detail=True,
+ methods=["get"],
+ url_path="meta",
+ permission_classes=[
+ AllowAny,
+ ],
+ )
+ def seo_meta(self, request, **kwargs):
+ category = self.get_object()
+
+ title = f"{category.name} | {config.PROJECT_NAME}"
+ description = (category.description or "")[:180]
+ canonical = f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/catalog/{category.slug}"
+ og_image = request.build_absolute_uri(category.image.url) if getattr(category, "image", None) else ""
+
+ og = {
+ "title": title,
+ "description": description,
+ "type": "website",
+ "url": canonical,
+ "image": og_image,
+ }
+ tw = {"card": "summary_large_image", "title": title, "description": description}
+
+ crumbs = [("Home", f"https://{config.BASE_DOMAIN}/")]
+ if category.get_ancestors().exists():
+ for c in category.get_ancestors():
+ crumbs.append((c.name, f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/catalog/{c.slug}"))
+ crumbs.append((category.name, canonical))
+
+ json_ld = [org_schema(), website_schema(), breadcrumb_schema(crumbs), category_schema(category, canonical)]
+
+ product_urls = []
+ qs = (
+ Product.objects.filter(
+ is_active=True,
+ category=category,
+ brand__is_active=True,
+ stocks__vendor__is_active=True,
+ )
+ .only("slug")
+ .distinct()[:24]
+ )
+ for p in qs:
+ product_urls.append(f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/product/{p.slug}")
+ if product_urls:
+ json_ld.append(item_list_schema(product_urls))
+
+ payload = {
+ "title": title,
+ "description": description,
+ "canonical": canonical,
+ "robots": "index,follow",
+ "open_graph": og,
+ "twitter": tw,
+ "json_ld": json_ld,
+ }
+ return Response(SeoSnapshotSerializer(payload).data)
+
class BrandViewSet(EvibesViewSet):
+ """
+ Represents a viewset for managing Brand instances.
+
+ This class provides functionality for querying, filtering, and
+ serializing Brand objects. It uses Django's ViewSet framework
+ to simplify the implementation of API endpoints for Brand objects.
+
+ Attributes:
+ queryset: The base queryset containing all Brand instances.
+ filter_backends: A list of filtering backends to apply to the
+ queryset. The default is [DjangoFilterBackend].
+ filterset_class: The filter class used to define the filtering
+ logic for this viewset. The default is BrandFilter.
+ serializer_class: The default serializer class used for the
+ detailed representation of Brand objects. The default is
+ BrandDetailSerializer.
+ action_serializer_classes: A dictionary mapping specific actions
+ to their corresponding serializer classes. The "list" action
+ uses the BrandSimpleSerializer class.
+ """
+
queryset = Brand.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_class = BrandFilter
@@ -178,10 +405,126 @@ class BrandViewSet(EvibesViewSet):
action_serializer_classes = {
"list": BrandSimpleSerializer,
}
+ lookup_field = "lookup_value"
+ lookup_url_kwarg = "lookup_value"
+ additional = {"seo_meta": "ALLOW"}
+
+ def get_object(self):
+ queryset = self.filter_queryset(self.get_queryset())
+ lookup_value = self.kwargs[self.lookup_url_kwarg]
+
+ obj = None
+
+ try:
+ uuid_obj = UUID(lookup_value)
+ obj = queryset.filter(uuid=uuid_obj).first()
+ except (ValueError, TypeError):
+ pass
+
+ if not obj:
+ obj = queryset.filter(slug=lookup_value).first()
+
+ if not obj:
+ name = "Brand"
+ raise Http404(f"{name} does not exist: {lookup_value}")
+
+ self.check_object_permissions(self.request, obj)
+ return obj
+
+ def get_queryset(self):
+ queryset = Brand.objects.all()
+
+ if self.request.user.has_perm("view_category"):
+ queryset = queryset.prefetch_related("categories")
+ else:
+ queryset = queryset.prefetch_related(
+ Prefetch("categories", queryset=Category.objects.filter(is_active=True))
+ )
+
+ return queryset
+
+ @action(
+ detail=True,
+ methods=["get"],
+ url_path="meta",
+ permission_classes=[
+ AllowAny,
+ ],
+ )
+ def seo_meta(self, request, **kwargs):
+ brand = self.get_object()
+
+ title = f"{brand.name} | {config.PROJECT_NAME}"
+ description = (brand.description or "")[:180]
+ canonical = f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/brand/{brand.slug}"
+
+ logo_url = (
+ request.build_absolute_uri(brand.big_logo.url)
+ if getattr(brand, "big_logo", None)
+ else request.build_absolute_uri(brand.small_logo.url)
+ if getattr(brand, "small_logo", None)
+ else ""
+ )
+
+ og = {
+ "title": title,
+ "description": description,
+ "type": "website",
+ "url": canonical,
+ "image": logo_url,
+ }
+ tw = {"card": "summary_large_image", "title": title, "description": description}
+
+ crumbs = [
+ ("Home", f"https://{config.BASE_DOMAIN}/"),
+ (brand.name, canonical),
+ ]
+
+ json_ld = [
+ org_schema(),
+ website_schema(),
+ breadcrumb_schema(crumbs),
+ brand_schema(brand, canonical, logo_url=logo_url),
+ ]
+
+ payload = {
+ "title": title,
+ "description": description,
+ "canonical": canonical,
+ "robots": "index,follow",
+ "open_graph": og,
+ "twitter": tw,
+ "json_ld": json_ld,
+ }
+ return Response(SeoSnapshotSerializer(payload).data)
@extend_schema_view(**PRODUCT_SCHEMA)
class ProductViewSet(EvibesViewSet):
+ """
+ Manages operations related to the `Product` model in the system.
+
+ This class provides a viewset for managing products, including their filtering, serialization,
+ and operations on specific instances. It extends from `EvibesViewSet` to use common
+ functionality and integrates with the Django REST framework for RESTful API operations.
+ Includes methods for retrieving product details, applying permissions, and accessing
+ related feedback of a product.
+
+ Attributes:
+ queryset: The base queryset to retrieve `Product` objects with prefetch optimization.
+ filter_backends: Specifies the filtering mechanism for the list views.
+ filterset_class: Defines the filter class to be used for filtering products.
+ serializer_class: The default serializer class for product details.
+ action_serializer_classes: Specific serializer mappings for action methods.
+ lookup_field: Field representing the object's lookup value in URLs.
+ lookup_url_kwarg: Field key used to extract the object's lookup value from URL.
+
+ Methods:
+ get_queryset: Retrieves the queryset with user-specific filtering applied.
+ get_object: Fetches a single object based on its identifier, applying permissions.
+ feedbacks: Fetches feedback associated with a specific product.
+ """
+
queryset = Product.objects.prefetch_related("tags", "attributes", "stocks", "images").all()
filter_backends = [DjangoFilterBackend]
filterset_class = ProductFilter
@@ -191,12 +534,18 @@ class ProductViewSet(EvibesViewSet):
}
lookup_field = "lookup_value"
lookup_url_kwarg = "lookup_value"
+ additional = {"seo_meta": "ALLOW"}
def get_queryset(self):
qs = super().get_queryset()
if self.request.user.has_perm("core.view_product"):
return qs
- return qs.filter(is_active=True)
+ return qs.filter(
+ is_active=True,
+ brand__is_active=True,
+ category__is_active=True,
+ stocks__vendor__is_active=True,
+ )
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
@@ -225,18 +574,85 @@ class ProductViewSet(EvibesViewSet):
lookup_val = kwargs.get(self.lookup_field)
try:
product = Product.objects.get(uuid=lookup_val)
- feedbacks: QuerySet[Feedback] = ( # type: ignore
+ feedbacks = (
Feedback.objects.filter(order_product__product=product)
if request.user.has_perm("core.view_feedback")
else Feedback.objects.filter(order_product__product=product, is_active=True)
)
+ # noinspection PyTypeChecker
return Response(data=FeedbackDetailSerializer(feedbacks, many=True).data)
except Product.DoesNotExist:
name = "Product"
return Response(status=status.HTTP_404_NOT_FOUND, data={"detail": _(f"{name} does not exist: {uuid}")})
+ @action(
+ detail=True,
+ methods=["get"],
+ url_path="meta",
+ permission_classes=[
+ AllowAny,
+ ],
+ )
+ def seo_meta(self, request, **kwargs):
+ p = self.get_object()
+ images = list(p.images.all()[:6])
+ rating = {"value": p.rating, "count": p.feedbacks_count}
+ title = f"{p.name} | {config.PROJECT_NAME}"
+ description = (p.description or "")[:180]
+ canonical = f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/product/{p.slug}"
+ og = {
+ "title": title,
+ "description": description,
+ "type": "product",
+ "url": canonical,
+ "image": request.build_absolute_uri(images[0].image.url) if images else "",
+ }
+ tw = {"card": "summary_large_image", "title": title, "description": description}
+
+ crumbs = [("Home", f"https://{config.BASE_DOMAIN}/")]
+ if p.category:
+ for c in p.category.get_ancestors(include_self=True):
+ crumbs.append((c.name, f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/catalog/{c.slug}"))
+ crumbs.append((p.name, canonical))
+
+ json_ld = [org_schema(), website_schema()]
+ if crumbs:
+ json_ld.append(breadcrumb_schema(crumbs))
+ json_ld.append(product_schema(p, images, rating=rating))
+
+ payload = {
+ "title": title,
+ "description": description,
+ "canonical": canonical,
+ "robots": "index,follow",
+ "open_graph": og,
+ "twitter": tw,
+ "json_ld": json_ld,
+ }
+ return Response(SeoSnapshotSerializer(payload).data)
+
class VendorViewSet(EvibesViewSet):
+ """
+ Represents a viewset for managing Vendor objects.
+
+ This viewset allows fetching, filtering, and serializing Vendor data.
+ It defines the queryset, filter configurations, and serializer classes
+ used to handle different actions. The purpose of this class is to
+ provide streamlined access to Vendor-related resources through the
+ Django REST framework.
+
+ Attributes:
+ queryset: A QuerySet containing all Vendor objects.
+ filter_backends: A list containing configured filter backends.
+ filterset_fields: A list of fields that can be used for filtering
+ Vendor records.
+ serializer_class: The default serializer class used for this
+ viewset.
+ action_serializer_classes: A dictionary mapping specific actions
+ (e.g., "list") to custom serializer classes for those actions.
+ """
+
queryset = Vendor.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["name", "markup_percent", "is_active"]
@@ -248,6 +664,27 @@ class VendorViewSet(EvibesViewSet):
@extend_schema_view(**FEEDBACK_SCHEMA)
class FeedbackViewSet(EvibesViewSet):
+ """
+ Representation of a view set handling Feedback objects.
+
+ This class manages operations related to Feedback objects, including listing,
+ filtering, and retrieving details. The purpose of this view set is to provide
+ different serializers for different actions and implement permission-based
+ handling of accessible Feedback objects. It extends the base `EvibesViewSet`
+ and makes use of Django's filtering system for querying data.
+
+ Attributes:
+ queryset: The base queryset for Feedback objects used in this view set.
+ filter_backends: List of filter backends to apply, specifically
+ `DjangoFilterBackend` for this view set.
+ filterset_class: Class specifying the filter set used for querying
+ Feedback objects.
+ serializer_class: Default serializer class used for this view set.
+ action_serializer_classes: A dictionary mapping action names to specific
+ serializer classes. For example, the "list" action uses
+ `FeedbackSimpleSerializer`.
+ """
+
queryset = Feedback.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_class = FeedbackFilter
@@ -265,6 +702,52 @@ class FeedbackViewSet(EvibesViewSet):
@extend_schema_view(**ORDER_SCHEMA)
class OrderViewSet(EvibesViewSet):
+ """
+ ViewSet for managing orders and related operations.
+
+ This class provides functionality to retrieve, modify, and manage order objects.
+ It includes various endpoints for handling order operations such as adding or
+ removing products, performing purchases for registered as well as unregistered
+ users, and retrieving the current authenticated user's pending orders.
+
+ The ViewSet uses multiple serializers based on the specific action being
+ performed and enforces permissions accordingly while interacting with order data.
+
+ Attributes:
+ lookup_field (str): Field name used for performing object lookup.
+ lookup_url_kwarg (str): URL keyword argument used for object lookup. Defaults
+ to `lookup_field`.
+ queryset (QuerySet): Default queryset for retrieving order objects, with
+ prefetched related order products.
+ filter_backends (list): List of backends applied for filtering the queryset.
+ filterset_class (type): Filtering class applied to the queryset for request-based
+ customizations.
+ serializer_class (type): Default serializer used if no specific serializer is
+ defined for an action.
+ action_serializer_classes (dict): Mapping of actions to their respective serializers.
+ Used to determine the serializer dynamically based on the requested action.
+ additional (dict): Additional settings for specific actions.
+
+ Methods:
+ get_serializer_class: Returns the serializer class based on the specific
+ action being requested.
+ get_queryset: Adjusts the queryset based on the request user's permissions,
+ favoring anonymous or limited query access for unauthenticated users.
+ get_object: Retrieves a specific order object based on the lookup value, either
+ its UUID or a human-readable ID.
+ current: Retrieves the authenticated user's current pending order.
+ buy: Processes an order purchase for an authenticated user with optional parameters
+ such as balance and payment overrides, promocodes, and billing/shipping addresses.
+ buy_unregistered: Processes an order purchase for unauthenticated users with product,
+ customer details, and payment information.
+ add_order_product: Adds a product, with optional attributes, to an order specified by UUID.
+ remove_order_product: Removes a product, with optional attributes, from an order specified
+ by UUID.
+ bulk_add_order_products: Adds multiple products with optional attributes to an order.
+ bulk_remove_order_products: Removes multiple products with optional attributes from
+ an order.
+ """
+
lookup_field = "lookup_value"
lookup_url_kwarg = "lookup_value"
queryset = Order.objects.prefetch_related("order_products").all()
@@ -331,6 +814,7 @@ class OrderViewSet(EvibesViewSet):
promocode_uuid=serializer.validated_data.get("promocode_uuid"),
shipping_address=serializer.validated_data.get("shipping_address_uuid"),
billing_address=serializer.validated_data.get("billing_address_uuid"),
+ chosen_products=serializer.validated_data.get("chosen_products"),
)
match str(type(instance)):
case "":
@@ -404,7 +888,7 @@ class OrderViewSet(EvibesViewSet):
serializer.is_valid(raise_exception=True)
lookup_val = kwargs.get(self.lookup_field)
try:
- order = Order.objects.get(uuid=lookup_val)
+ order = Order.objects.get(uuid=str(lookup_val))
if not (request.user.has_perm("core.add_orderproduct") or request.user == order.user):
raise PermissionDenied(permission_denied_message)
@@ -435,6 +919,34 @@ class OrderViewSet(EvibesViewSet):
@extend_schema_view(**ORDER_PRODUCT_SCHEMA)
class OrderProductViewSet(EvibesViewSet):
+ """
+ Provides a viewset for managing OrderProduct entities.
+
+ This viewset enables CRUD operations and custom actions specific to the
+ OrderProduct model. It includes filtering, permission checks, and
+ serializer switching based on the requested action. Additionally, it
+ provides a detailed action for handling feedback on OrderProduct
+ instances.
+
+ Attributes:
+ queryset (QuerySet): The base queryset for OrderProduct objects.
+ filter_backends (list): Backends responsible for handling filtering
+ mechanisms.
+ filterset_fields (list[str]): Fields available for API filtering.
+ serializer_class (Serializer): Default serializer class for CRUD
+ operations.
+ action_serializer_classes (dict[str, Serializer]): Mapping of
+ specific actions to their corresponding serializer classes.
+
+ Methods:
+ get_queryset: Overrides the default queryset to enforce user
+ permissions.
+
+ Actions:
+ do_feedback: Custom action to add, remove, or manage feedback for
+ an OrderProduct instance.
+ """
+
queryset = OrderProduct.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["order", "product", "status", "is_active"]
@@ -478,6 +990,28 @@ class OrderProductViewSet(EvibesViewSet):
class ProductImageViewSet(EvibesViewSet):
+ """
+ Manages operations related to Product images in the application.
+
+ This class-based view set provides endpoints to manage and access ProductImage
+ objects. It supports filtering, serialization, and customized serializers for
+ different actions to handle ProductImage data.
+
+ Attributes:
+ queryset (QuerySet): A Django QuerySet consisting of all ProductImage
+ instances within the system.
+ filter_backends (list): A list of filter backends that determine the
+ filtering behavior on querysets. Set to [DjangoFilterBackend].
+ filterset_fields (list): Fields that can be used for filtering data.
+ Includes "product", "priority", and "is_active".
+ serializer_class (Serializer): The default serializer class used for
+ serializing and deserializing ProductImage data. Set to
+ ProductImageDetailSerializer.
+ action_serializer_classes (dict): A mapping of action names to specific
+ serializer classes. For the "list" action, ProductImageSimpleSerializer
+ is used.
+ """
+
queryset = ProductImage.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["product", "priority", "is_active"]
@@ -488,6 +1022,26 @@ class ProductImageViewSet(EvibesViewSet):
class PromoCodeViewSet(EvibesViewSet):
+ """
+ Manages the retrieval and handling of PromoCode instances through various
+ API actions.
+
+ This class extends the functionality of the EvibesViewSet to provide a
+ customized view set for PromoCode objects. It includes filtering capabilities,
+ uses specific serializers for different actions, and limits data access
+ based on user permissions. The primary purpose is to enable API operations
+ related to PromoCodes while enforcing security and filtering.
+
+ Attributes:
+ queryset: A queryset of all PromoCode objects in the database.
+ filter_backends: Backend classes responsible for filtering queryset data.
+ filterset_fields: Fields supported for filtering PromoCode data.
+ serializer_class: The default serializer class used for instances when no
+ specific action-based serializer is defined.
+ action_serializer_classes: A dictionary mapping specific actions (like
+ "list") to their corresponding serializer classes.
+ """
+
queryset = PromoCode.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["code", "discount_amount", "discount_percent", "start_time", "end_time", "used_on", "is_active"]
@@ -507,6 +1061,15 @@ class PromoCodeViewSet(EvibesViewSet):
class PromotionViewSet(EvibesViewSet):
+ """
+ Represents a view set for managing promotions.
+
+ This class provides operations to handle retrieval, filtering, and serialization
+ of promotion objects. It leverages Django REST framework capabilities such as
+ queryset management, filter backends, and serializer customization for handling
+ different views or actions efficiently.
+ """
+
queryset = Promotion.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["name", "discount_percent", "is_active"]
@@ -517,6 +1080,27 @@ class PromotionViewSet(EvibesViewSet):
class StockViewSet(EvibesViewSet):
+ """
+ Handles operations related to Stock data in the system.
+
+ The StockViewSet class is a viewset that provides methods for retrieving,
+ filtering, and serializing Stock data. It uses Django's filter
+ backends to enable filtering based on specified fields and supports
+ custom serializers for different actions.
+
+ Attributes:
+ queryset (QuerySet): A queryset of all Stock objects.
+ filter_backends (list): A list of filter backends to be applied.
+ filterset_fields (list of str): Fields on which the filtering
+ is permitted. These fields include "vendor", "product", "sku",
+ and "is_active".
+ serializer_class (Serializer): The primary serializer used
+ for Stock detail representation.
+ action_serializer_classes (dict): A dictionary mapping action names
+ to their respective serializers. For the "list" action,
+ StockSimpleSerializer is used.
+ """
+
queryset = Stock.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["vendor", "product", "sku", "is_active"]
@@ -528,6 +1112,45 @@ class StockViewSet(EvibesViewSet):
@extend_schema_view(**WISHLIST_SCHEMA)
class WishlistViewSet(EvibesViewSet):
+ """
+ ViewSet for managing Wishlist operations.
+
+ The WishlistViewSet provides endpoints for interacting with a user's wish list,
+ allowing for the retrieval, modification, and customization of products within
+ the wish list. This ViewSet facilitates functionality such as adding, removing,
+ and bulk actions for wishlist products. Permission checks are integrated to
+ ensure that users can only manage their own wishlists unless explicit permissions
+ are granted.
+
+ Attributes
+ ----------
+ queryset : QuerySet
+ The base queryset for retrieving wishlist objects.
+ filter_backends : list
+ List of backend filters to apply to the queryset.
+ filterset_fields : list
+ Fields for which filtering is allowed in queries.
+ serializer_class : Serializer
+ The default serializer class used for wishlist objects.
+ action_serializer_classes : dict
+ A map of serializers used for specific actions.
+
+ Methods
+ -------
+ get_queryset()
+ Retrieves the queryset, filtered based on the user's permissions.
+ current(request)
+ Retrieves the currently authenticated user's wishlist.
+ add_wishlist_product(request, **kwargs)
+ Adds a product to a specific wishlist.
+ remove_wishlist_product(request, **kwargs)
+ Removes a product from a specific wishlist.
+ bulk_add_wishlist_products(request, **kwargs)
+ Adds multiple products to a specific wishlist.
+ bulk_remove_wishlist_products(request, **kwargs)
+ Removes multiple products from a specific wishlist.
+ """
+
queryset = Wishlist.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["user", "is_active"]
@@ -628,6 +1251,22 @@ class WishlistViewSet(EvibesViewSet):
@extend_schema_view(**ADDRESS_SCHEMA)
class AddressViewSet(EvibesViewSet):
+ """
+ This class provides viewset functionality for managing `Address` objects.
+
+ The AddressViewSet class enables CRUD operations, filtering, and custom actions
+ related to address entities. It includes specialized behaviors for different HTTP
+ methods, serializer overrides, and permission handling based on the request context.
+
+ Attributes:
+ pagination_class: Specifies pagination class for the viewset, set to None.
+ filter_backends: List of backend classes for filtering querysets.
+ filterset_class: Specifies the filter class for filtering address objects.
+ queryset: Default queryset containing all Address objects.
+ serializer_class: Default serializer class for address objects.
+ additional: Dictionary of additional options for this viewset.
+ """
+
pagination_class = None
filter_backends = [DjangoFilterBackend]
filterset_class = AddressFilter
@@ -687,6 +1326,27 @@ class AddressViewSet(EvibesViewSet):
class ProductTagViewSet(EvibesViewSet):
+ """
+ Handles operations related to Product Tags within the application.
+
+ This class provides functionality for retrieving, filtering, and serializing
+ Product Tag objects. It supports flexible filtering on specific attributes
+ using the specified filter backend and dynamically uses different serializers
+ based on the action being performed.
+
+ Attributes:
+ queryset: The base queryset containing all ProductTag objects.
+ filter_backends: A list of backends used to filter the queryset.
+ filterset_fields: Fields available for filtering the queryset. Includes
+ 'tag_name' for filtering by the name of the tag, and 'is_active' for
+ filtering active/inactive tags.
+ serializer_class: The default serializer class is used when no specific
+ serializer is defined for an action.
+ action_serializer_classes: A dictionary mapping specific actions (e.g.,
+ 'list') to custom serializers. Uses ProductTagSimpleSerializer
+ for the 'list' action.
+ """
+
queryset = ProductTag.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["tag_name", "is_active"]
diff --git a/docker-compose.yml b/docker-compose.yml
index f880c9ab..7e5b89d0 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -136,7 +136,38 @@ services:
- .env
environment:
- BROKER_URL=${CELERY_BROKER_URL}
+ - TZ=${TIME_ZONE}
depends_on:
+ database:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ elasticsearch:
+ condition: service_healthy
+ logging: *default-logging
+ healthcheck:
+ test: [ "CMD-SHELL", "celery -A evibes status | grep -q 'OK'" ]
+ interval: 30s
+ timeout: 10s
+ retries: 5
+ start_period: 15s
+
+ stock_updater:
+ container_name: stock_updater
+ build:
+ context: .
+ dockerfile: ./Dockerfiles/Dockerfile.stock_updater
+ restart: always
+ volumes:
+ - .:/app
+ env_file:
+ - .env
+ environment:
+ - BROKER_URL=${CELERY_BROKER_URL}
+ - TZ=${TIME_ZONE}
+ depends_on:
+ database:
+ condition: service_healthy
redis:
condition: service_healthy
elasticsearch:
@@ -159,8 +190,11 @@ services:
- .:/app
env_file:
- .env
+ environment:
+ - BROKER_URL=${CELERY_BROKER_URL}
+ - TZ=${TIME_ZONE}
depends_on:
- worker:
+ database:
condition: service_healthy
logging: *default-logging
healthcheck:
diff --git a/evibes/api_urls.py b/evibes/api_urls.py
index 683bbae6..016efca4 100644
--- a/evibes/api_urls.py
+++ b/evibes/api_urls.py
@@ -17,12 +17,9 @@ from core.views import (
from evibes.settings import SPECTACULAR_PLATFORM_SETTINGS
urlpatterns = [
- path(r"health/", include("health_check.urls")),
+ path(r"health/", include("health_check.urls", namespace="health_check")),
path("prometheus/", include("django_prometheus.urls")),
- path(
- r"graphql/",
- csrf_exempt(CustomGraphQLView.as_view(graphiql=True, schema=schema)),
- ),
+ path(r"graphql/", csrf_exempt(CustomGraphQLView.as_view(graphiql=True, schema=schema)), name="graphql-platform"),
path(
r"docs/",
SpectacularAPIView.as_view(urlconf="evibes.api_urls", custom_settings=SPECTACULAR_PLATFORM_SETTINGS),
@@ -42,10 +39,11 @@ urlpatterns = [
path(r"i18n/", include("django.conf.urls.i18n")),
path(r"favicon.ico", favicon_view),
path(r"", index),
- path(r"", include("core.api_urls")),
- path(r"auth/", include("vibes_auth.urls")),
- path(r"payments/", include("payments.urls")),
- path(r"blog/", include("blog.urls")),
+ path(r"", include("core.api_urls", namespace="core")),
+ path(r"auth/", include("vibes_auth.urls", namespace="vibes_auth")),
+ path(r"payments/", include("payments.urls", namespace="payments")),
+ path(r"blog/", include("blog.urls", namespace="blog")),
+ path("admin/doc/", include("django.contrib.admindocs.urls")),
] + i18n_patterns(path("admin/", admin.site.urls))
if settings.DEBUG:
diff --git a/evibes/b2b_urls.py b/evibes/b2b_urls.py
index 8bd89af0..aeeeee23 100644
--- a/evibes/b2b_urls.py
+++ b/evibes/b2b_urls.py
@@ -7,8 +7,6 @@ from core.views import CustomRedocView, CustomSwaggerView, favicon_view
from evibes.settings import SPECTACULAR_B2B_SETTINGS
urlpatterns = [
- # path(r'graphql/', csrf_exempt(CustomGraphQLView.as_view(graphiql=True, schema=schema))),
- path("prometheus/", include("django_prometheus.urls")),
path(
r"docs/",
SpectacularAPIView.as_view(urlconf="evibes.b2b_urls", custom_settings=SPECTACULAR_B2B_SETTINGS),
@@ -17,7 +15,7 @@ urlpatterns = [
path(r"docs/swagger/", CustomSwaggerView.as_view(url_name="schema-b2b"), name="swagger-ui-b2b"),
path(r"docs/redoc/", CustomRedocView.as_view(url_name="schema-b2b"), name="redoc-ui-b2b"),
path(r"favicon.ico", favicon_view),
- path(r"", include("core.b2b_urls")),
+ path(r"", include("core.b2b_urls", namespace="core_b2b")),
]
if settings.DEBUG:
diff --git a/evibes/celery.py b/evibes/celery.py
index d0479561..5ddabb48 100644
--- a/evibes/celery.py
+++ b/evibes/celery.py
@@ -2,37 +2,27 @@ import os
from celery import Celery
-from evibes.settings import REDIS_PASSWORD, TIME_ZONE
-
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "evibes.settings")
app = Celery("evibes")
app.conf.update(
- broker_url=f"redis://:{REDIS_PASSWORD}@redis:6379/0",
- result_backend=f"redis://:{REDIS_PASSWORD}@redis:6379/0",
worker_hijack_root_logger=False,
worker_log_format="[%(asctime)s: %(levelname)s/%(processName)s] %(name)s: %(message)s",
worker_task_log_format="[%(asctime)s: %(levelname)s/%(processName)s] %(name)s: %(message)s",
- worker_autoscale=(10, 3),
broker_connection_retry_on_startup=True,
- timezone=TIME_ZONE,
task_serializer="json",
result_serializer="json",
result_compression="zlib",
accept_content=["json"],
- broker_transport_options={
- "retry_policy": {"interval_start": 0.1, "interval_step": 0.2, "max_retries": 5},
- "visibility_timeout": 3600,
- },
task_acks_late=True,
task_reject_on_worker_lost=True,
- worker_prefetch_multiplier=1,
- worker_max_tasks_per_child=100,
- task_soft_time_limit=10800,
- task_time_limit=21600,
)
+app.conf.task_routes = {
+ "core.tasks.update_products_task": {"queue": "stock_updater"},
+}
+
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
diff --git a/evibes/ftpstorage.py b/evibes/ftpstorage.py
new file mode 100644
index 00000000..7e87e0f6
--- /dev/null
+++ b/evibes/ftpstorage.py
@@ -0,0 +1,13 @@
+from urllib.parse import urlparse
+
+from storages.backends.ftp import FTPStorage
+
+
+class AbsoluteFTPStorage(FTPStorage): # type: ignore
+ # noinspection PyProtectedMember
+
+ def _get_config(self):
+ cfg = super()._get_config()
+ url = urlparse(self.location)
+ cfg["path"] = url.path or cfg["path"]
+ return cfg
diff --git a/evibes/locale/ar_AR/LC_MESSAGES/django.mo b/evibes/locale/ar_AR/LC_MESSAGES/django.mo
index 0fc354f2..401478ad 100644
Binary files a/evibes/locale/ar_AR/LC_MESSAGES/django.mo and b/evibes/locale/ar_AR/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/ar_AR/LC_MESSAGES/django.po b/evibes/locale/ar_AR/LC_MESSAGES/django.po
index 9a7d8f60..14eecf75 100644
--- a/evibes/locale/ar_AR/LC_MESSAGES/django.po
+++ b/evibes/locale/ar_AR/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: ar-ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "اسم المشروع"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "اسم نطاق الواجهة الأمامية"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "اسم النطاق الأساسي"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "اسم الشركة"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "عنوان الشركة"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "رقم هاتف الشركة"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "مضيف SMTP"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "منفذ SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "استخدام TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "استخدام SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "اسم مستخدم SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "كلمة مرور SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "عنوان مرسل البريد الإلكتروني"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "عنوان URL لبوابة الدفع"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "الرمز المميز لبوابة الدفع"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "الحد الأدنى لمبلغ بوابة الدفع"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "الحد الأقصى لمبلغ بوابة الدفع"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "مفتاح API لسعر الصرف"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "عنوان URL لواجهة برمجة تطبيقات OpenStreetMap Nominatim"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "مفتاح واجهة برمجة تطبيقات OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "مفتاح واجهة برمجة التطبيقات المجردة"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "وكيل HTTP"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "تعطيل وظيفة الشراء"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "كيان لتخزين بيانات الإعلانات"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "كيان لتخزين بيانات التحليلات"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "الخيارات العامة"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "خيارات البريد الإلكتروني"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "خيارات بوابة الدفع"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "خيارات الميزات"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "خيارات تحسين محركات البحث"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "الصفحة الرئيسية"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "واجهة المتجر"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "مستندات GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "مستندات النظام الأساسي REST"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "مستندات B2B REST"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "الدعم"
diff --git a/evibes/locale/cs_CZ/LC_MESSAGES/django.mo b/evibes/locale/cs_CZ/LC_MESSAGES/django.mo
index 0fc354f2..e6d117e7 100644
Binary files a/evibes/locale/cs_CZ/LC_MESSAGES/django.mo and b/evibes/locale/cs_CZ/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/cs_CZ/LC_MESSAGES/django.po b/evibes/locale/cs_CZ/LC_MESSAGES/django.po
index 9a7d8f60..068ab567 100644
--- a/evibes/locale/cs_CZ/LC_MESSAGES/django.po
+++ b/evibes/locale/cs_CZ/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: cs-cz\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Název projektu"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Název domény frontendu"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Název základní domény"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Název společnosti"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Adresa společnosti"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Telefonní číslo společnosti"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP host"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "Port SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Použití protokolu TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Použití protokolu SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Uživatelské jméno SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Heslo SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Adresa odesílatele e-mailů"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "Adresa URL platební brány"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Token platební brány"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Minimální částka platební brány"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Maximální částka platební brány"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Klíč API pro směnný kurz"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "URL rozhraní API OpenStreetMap Nominatim"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "Klíč API OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Abstraktní klíč API"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "Proxy server HTTP"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Zakázat funkci nákupu"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Subjekt pro ukládání dat inzerátů"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Subjekt pro ukládání analytických dat"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Obecné možnosti"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Možnosti e-mailu"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Možnosti platební brány"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Možnosti funkcí"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Možnosti SEO"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Home"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Výloha"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Dokumenty GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Dokumenty platformy REST"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "Dokumenty B2B REST"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Podpora"
diff --git a/evibes/locale/da_DK/LC_MESSAGES/django.mo b/evibes/locale/da_DK/LC_MESSAGES/django.mo
index 0fc354f2..3c8570fa 100644
Binary files a/evibes/locale/da_DK/LC_MESSAGES/django.mo and b/evibes/locale/da_DK/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/da_DK/LC_MESSAGES/django.po b/evibes/locale/da_DK/LC_MESSAGES/django.po
index 9a7d8f60..617b3c79 100644
--- a/evibes/locale/da_DK/LC_MESSAGES/django.po
+++ b/evibes/locale/da_DK/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: da-dk\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Projektets navn"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Frontend-domænenavn"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Basisdomænenavn"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Virksomhedens navn"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Virksomhedens adresse"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Virksomhedens telefonnummer"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP-vært"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTP-port"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Brug TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Brug SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "SMTP-brugernavn"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "SMTP-adgangskode"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Adressen på e-mailens afsender"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL til betalingsgateway"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Token til betalingsgateway"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Minimumsbeløb for betalingsgateway"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Betalingsgatewayens maksimale beløb"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "API-nøgle til valutakurs"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI API-nøgle"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Abstrakt API-nøgle"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP-proxy"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Deaktiver købsfunktionalitet"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "En enhed til lagring af annonceringsdata"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "En enhed til lagring af analysedata"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Generelle indstillinger"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Indstillinger for e-mail"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Muligheder for betalingsgateway"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Funktioner Indstillinger"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "SEO-muligheder"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Hjem"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Butiksfacade"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "GraphQL-dokumenter"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Platform REST-dokumenter"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST-dokumenter"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Støtte"
diff --git a/evibes/locale/de_DE/LC_MESSAGES/django.mo b/evibes/locale/de_DE/LC_MESSAGES/django.mo
index 0fc354f2..b53a8e0f 100644
Binary files a/evibes/locale/de_DE/LC_MESSAGES/django.mo and b/evibes/locale/de_DE/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/de_DE/LC_MESSAGES/django.po b/evibes/locale/de_DE/LC_MESSAGES/django.po
index 9a7d8f60..fbd0b63c 100644
--- a/evibes/locale/de_DE/LC_MESSAGES/django.po
+++ b/evibes/locale/de_DE/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: de-de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Name des Projekts"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Frontend-Domain-Name"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Basis-Domainname"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Name des Unternehmens"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Anschrift des Unternehmens"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Telefonnummer des Unternehmens"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP-Host"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTP-Port"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Use TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Use SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "SMTP-Benutzername"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "SMTP-Kennwort"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Die Adresse des Absenders der E-Mail"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL des Zahlungsgateways"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Zahlungsgateway-Token"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Mindestbetrag für das Zahlungsgateway"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Höchstbetrag des Zahlungsgateways"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Wechselkurs-API-Schlüssel"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI API Key"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Abstrakter API-Schlüssel"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP-Proxy"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Kauffunktionalität deaktivieren"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Eine Einheit zur Speicherung von Werbedaten"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Eine Einheit zur Speicherung von Analysedaten"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Allgemeine Optionen"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "E-Mail-Optionen"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Zahlungs-Gateway-Optionen"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Merkmale Optionen"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "SEO-Optionen"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Startseite"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Schaufenster"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "GraphQL Docs"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Plattform REST Docs"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST-Dokumente"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Unterstützung"
diff --git a/evibes/locale/en_GB/LC_MESSAGES/django.mo b/evibes/locale/en_GB/LC_MESSAGES/django.mo
index 63f7d7fb..467d627b 100644
Binary files a/evibes/locale/en_GB/LC_MESSAGES/django.mo and b/evibes/locale/en_GB/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/en_GB/LC_MESSAGES/django.po b/evibes/locale/en_GB/LC_MESSAGES/django.po
index 9c62dda9..5b4fbabf 100644
--- a/evibes/locale/en_GB/LC_MESSAGES/django.po
+++ b/evibes/locale/en_GB/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -17,186 +17,146 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
-
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Name of the project"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Frontend domain name"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Base domain name"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Name of the company"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Address of the company"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Phone number of the company"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP host"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTP port"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Use TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Use SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "SMTP username"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "SMTP password"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "The address of the emails sender"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "Payment gateway URL"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Payment gateway token"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Payment gateway minimum amount"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Payment gateway maximum amount"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Exchange rate API key"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI API Key"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Abstract API Key"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP Proxy"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Disable buy functionality"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "An entity for storing advertisiment data"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "An entity for storing analytics data"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "General Options"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Email Options"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Payment Gateway Options"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Features Options"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "SEO Options"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Home"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Storefront"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "GraphQL Docs"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Platform REST Docs"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST Docs"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Support"
diff --git a/evibes/locale/en_US/LC_MESSAGES/django.mo b/evibes/locale/en_US/LC_MESSAGES/django.mo
index 0fc354f2..04719d61 100644
Binary files a/evibes/locale/en_US/LC_MESSAGES/django.mo and b/evibes/locale/en_US/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/en_US/LC_MESSAGES/django.po b/evibes/locale/en_US/LC_MESSAGES/django.po
index 9a7d8f60..4aba66ba 100644
--- a/evibes/locale/en_US/LC_MESSAGES/django.po
+++ b/evibes/locale/en_US/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: en-us\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Name of the project"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Frontend domain name"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Base domain name"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Name of the company"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Address of the company"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Phone number of the company"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP host"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTP port"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Use TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Use SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "SMTP username"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "SMTP password"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "The address of the emails sender"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "Payment gateway URL"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Payment gateway token"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Payment gateway minimum amount"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Payment gateway maximum amount"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Exchange rate API key"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI API Key"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Abstract API Key"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP Proxy"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Disable buy functionality"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "An entity for storing advertisiment data"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "An entity for storing analytics data"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "General Options"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Email Options"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Payment Gateway Options"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Features Options"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "SEO Options"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Home"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Storefront"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "GraphQL Docs"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Platform REST Docs"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST Docs"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Support"
diff --git a/evibes/locale/es_ES/LC_MESSAGES/django.mo b/evibes/locale/es_ES/LC_MESSAGES/django.mo
index 0fc354f2..7f49ac2b 100644
Binary files a/evibes/locale/es_ES/LC_MESSAGES/django.mo and b/evibes/locale/es_ES/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/es_ES/LC_MESSAGES/django.po b/evibes/locale/es_ES/LC_MESSAGES/django.po
index 9a7d8f60..0ceb55a6 100644
--- a/evibes/locale/es_ES/LC_MESSAGES/django.po
+++ b/evibes/locale/es_ES/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: es-es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Nombre del proyecto"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Nombre de dominio frontend"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Nombre de dominio base"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Nombre de la empresa"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Dirección de la empresa"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Número de teléfono de la empresa"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "Host SMTP"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "Puerto SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Utilizar TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Utilizar SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Nombre de usuario SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Contraseña SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Dirección del remitente del correo electrónico"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL de la pasarela de pago"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Token de pasarela de pago"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Importe mínimo de la pasarela de pago"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Importe máximo de la pasarela de pago"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Clave API de tipo de cambio"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "URL de la API Nominatim de OpenStreetMap"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "Clave API de OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Clave API abstracta"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "Proxy HTTP"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Desactivar la función de compra"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Una entidad para almacenar datos publicitarios"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Una entidad para almacenar datos analíticos"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Opciones generales"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Opciones de correo electrónico"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Opciones de pasarela de pago"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Características Opciones"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Opciones SEO"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Inicio"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Escaparate"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Documentos GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Plataforma REST Docs"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "Documentos B2B REST"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Ayuda"
diff --git a/evibes/locale/fr_FR/LC_MESSAGES/django.mo b/evibes/locale/fr_FR/LC_MESSAGES/django.mo
index 0fc354f2..0152adfe 100644
Binary files a/evibes/locale/fr_FR/LC_MESSAGES/django.mo and b/evibes/locale/fr_FR/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/fr_FR/LC_MESSAGES/django.po b/evibes/locale/fr_FR/LC_MESSAGES/django.po
index 9a7d8f60..29e11c2b 100644
--- a/evibes/locale/fr_FR/LC_MESSAGES/django.po
+++ b/evibes/locale/fr_FR/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: fr-fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Nom du projet"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Nom de domaine du frontend"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Nom de domaine de base"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Nom de l'entreprise"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Adresse de l'entreprise"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Numéro de téléphone de l'entreprise"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "Hôte SMTP"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTP port"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Utiliser TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Use SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Nom d'utilisateur SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Mot de passe SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "L'adresse de l'expéditeur du courrier électronique"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL de la passerelle de paiement"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Jeton de passerelle de paiement"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Montant minimum de la passerelle de paiement"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Montant maximum de la passerelle de paiement"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Clé API pour le taux de change"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "URL de l'API OpenStreetMap Nominatim"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI API Key"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Clé API abstraite"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP Proxy"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Désactiver la fonctionnalité d'achat"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Une entité pour stocker des données publicitaires"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Une entité pour stocker des données analytiques"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Options générales"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Options de courrier électronique"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Options de passerelle de paiement"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Caractéristiques Options"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Options de référencement"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Accueil"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Vitrine"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Docs GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Docs REST de la plateforme"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST Docs"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Soutien"
diff --git a/evibes/locale/hi_IN/LC_MESSAGES/django.mo b/evibes/locale/hi_IN/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/evibes/locale/hi_IN/LC_MESSAGES/django.mo and b/evibes/locale/hi_IN/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/hi_IN/LC_MESSAGES/django.po b/evibes/locale/hi_IN/LC_MESSAGES/django.po
index 9a7d8f60..75d54335 100644
--- a/evibes/locale/hi_IN/LC_MESSAGES/django.po
+++ b/evibes/locale/hi_IN/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -16,34 +16,30 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: evibes/settings/constance.py:18
+#: evibes/settings/constance.py:22
msgid "Name of the project"
msgstr ""
-#: evibes/settings/constance.py:19
+#: evibes/settings/constance.py:23
msgid "Frontend domain name"
msgstr ""
-#: evibes/settings/constance.py:20
+#: evibes/settings/constance.py:24
msgid "Base domain name"
msgstr ""
-#: evibes/settings/constance.py:21
+#: evibes/settings/constance.py:25
msgid "Name of the company"
msgstr ""
-#: evibes/settings/constance.py:22
+#: evibes/settings/constance.py:26
msgid "Address of the company"
msgstr ""
-#: evibes/settings/constance.py:23
+#: evibes/settings/constance.py:27
msgid "Phone number of the company"
msgstr ""
-#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
-
#: evibes/settings/constance.py:28
msgid "SMTP host"
msgstr ""
@@ -53,11 +49,11 @@ msgid "SMTP port"
msgstr ""
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
+msgid "Use TLS (0=No, 1=Yes)"
msgstr ""
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
+msgid "Use SSL (0=No, 1=Yes)"
msgstr ""
#: evibes/settings/constance.py:32
@@ -100,102 +96,66 @@ msgstr ""
msgid "OpenAI API Key"
msgstr ""
-#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
msgstr ""
-#: evibes/settings/constance.py:46
+#: evibes/settings/constance.py:43
msgid "HTTP Proxy"
msgstr ""
-#: evibes/settings/constance.py:47
+#: evibes/settings/constance.py:44
msgid "Disable buy functionality"
msgstr ""
-#: evibes/settings/constance.py:50
+#: evibes/settings/constance.py:47
msgid "An entity for storing advertisiment data"
msgstr ""
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
msgstr ""
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
+#: evibes/settings/constance.py:54
+msgid "General Options"
msgstr ""
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr ""
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr ""
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr ""
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
msgstr ""
diff --git a/evibes/locale/it_IT/LC_MESSAGES/django.mo b/evibes/locale/it_IT/LC_MESSAGES/django.mo
index 0fc354f2..1b5bccda 100644
Binary files a/evibes/locale/it_IT/LC_MESSAGES/django.mo and b/evibes/locale/it_IT/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/it_IT/LC_MESSAGES/django.po b/evibes/locale/it_IT/LC_MESSAGES/django.po
index 9a7d8f60..5a19bfb8 100644
--- a/evibes/locale/it_IT/LC_MESSAGES/django.po
+++ b/evibes/locale/it_IT/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: it-it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Nome del progetto"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Nome di dominio del frontend"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Nome di dominio di base"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Nome della società"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Indirizzo dell'azienda"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Numero di telefono dell'azienda"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "Host SMTP"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "Porta SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Utilizzare TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Utilizzare SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Nome utente SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Password SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "L'indirizzo del mittente dell'e-mail"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL del gateway di pagamento"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Token del gateway di pagamento"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Importo minimo del gateway di pagamento"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Importo massimo del gateway di pagamento"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Chiave API del tasso di cambio"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "URL dell'API OpenStreetMap Nominatim"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "Chiave API OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Chiave API astratta"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "Proxy HTTP"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Disattivare la funzionalità di acquisto"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Un'entità per la memorizzazione dei dati pubblicitari"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Un'entità per la memorizzazione dei dati analitici"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Opzioni generali"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Opzioni e-mail"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Opzioni di gateway di pagamento"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Caratteristiche Opzioni"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Opzioni SEO"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Casa"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Storefront"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Documenti GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Documenti della piattaforma REST"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "Documenti REST B2B"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Supporto"
diff --git a/evibes/locale/ja_JP/LC_MESSAGES/django.mo b/evibes/locale/ja_JP/LC_MESSAGES/django.mo
index 0fc354f2..992ead43 100644
Binary files a/evibes/locale/ja_JP/LC_MESSAGES/django.mo and b/evibes/locale/ja_JP/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/ja_JP/LC_MESSAGES/django.po b/evibes/locale/ja_JP/LC_MESSAGES/django.po
index 9a7d8f60..00db5aac 100644
--- a/evibes/locale/ja_JP/LC_MESSAGES/django.po
+++ b/evibes/locale/ja_JP/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: ja-jp\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "プロジェクト名"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "フロントエンド・ドメイン名"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "ベースドメイン名"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "会社名"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "会社住所"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "会社の電話番号"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTPホスト"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTPポート"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "TLSを使用する"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "SSLの使用"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "SMTPユーザー名"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "SMTPパスワード"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "メール送信者のアドレス"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "決済ゲートウェイURL"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "ペイメントゲートウェイ・トークン"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "ペイメントゲートウェイの最低金額"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "支払ゲートウェイ上限額"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "為替レートAPIキー"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI APIキー"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "抽象APIキー"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTPプロキシ"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "購入機能を無効にする"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "広告データを保存するエンティティ"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "分析データを保存するエンティティ"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "一般オプション"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Eメールオプション"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "ペイメントゲートウェイオプション"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "機能オプション"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "SEOオプション"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "ホーム"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "ストアフロント"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "GraphQLドキュメント"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "プラットフォームRESTドキュメント"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST ドキュメント"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "サポート"
diff --git a/evibes/locale/kk_KZ/LC_MESSAGES/django.mo b/evibes/locale/kk_KZ/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/evibes/locale/kk_KZ/LC_MESSAGES/django.mo and b/evibes/locale/kk_KZ/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/kk_KZ/LC_MESSAGES/django.po b/evibes/locale/kk_KZ/LC_MESSAGES/django.po
index 9a7d8f60..75d54335 100644
--- a/evibes/locale/kk_KZ/LC_MESSAGES/django.po
+++ b/evibes/locale/kk_KZ/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -16,34 +16,30 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: evibes/settings/constance.py:18
+#: evibes/settings/constance.py:22
msgid "Name of the project"
msgstr ""
-#: evibes/settings/constance.py:19
+#: evibes/settings/constance.py:23
msgid "Frontend domain name"
msgstr ""
-#: evibes/settings/constance.py:20
+#: evibes/settings/constance.py:24
msgid "Base domain name"
msgstr ""
-#: evibes/settings/constance.py:21
+#: evibes/settings/constance.py:25
msgid "Name of the company"
msgstr ""
-#: evibes/settings/constance.py:22
+#: evibes/settings/constance.py:26
msgid "Address of the company"
msgstr ""
-#: evibes/settings/constance.py:23
+#: evibes/settings/constance.py:27
msgid "Phone number of the company"
msgstr ""
-#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
-
#: evibes/settings/constance.py:28
msgid "SMTP host"
msgstr ""
@@ -53,11 +49,11 @@ msgid "SMTP port"
msgstr ""
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
+msgid "Use TLS (0=No, 1=Yes)"
msgstr ""
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
+msgid "Use SSL (0=No, 1=Yes)"
msgstr ""
#: evibes/settings/constance.py:32
@@ -100,102 +96,66 @@ msgstr ""
msgid "OpenAI API Key"
msgstr ""
-#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
msgstr ""
-#: evibes/settings/constance.py:46
+#: evibes/settings/constance.py:43
msgid "HTTP Proxy"
msgstr ""
-#: evibes/settings/constance.py:47
+#: evibes/settings/constance.py:44
msgid "Disable buy functionality"
msgstr ""
-#: evibes/settings/constance.py:50
+#: evibes/settings/constance.py:47
msgid "An entity for storing advertisiment data"
msgstr ""
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
msgstr ""
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
+#: evibes/settings/constance.py:54
+msgid "General Options"
msgstr ""
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr ""
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr ""
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr ""
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr ""
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
msgstr ""
diff --git a/evibes/locale/nl_NL/LC_MESSAGES/django.mo b/evibes/locale/nl_NL/LC_MESSAGES/django.mo
index 0fc354f2..b51078fc 100644
Binary files a/evibes/locale/nl_NL/LC_MESSAGES/django.mo and b/evibes/locale/nl_NL/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/nl_NL/LC_MESSAGES/django.po b/evibes/locale/nl_NL/LC_MESSAGES/django.po
index 9a7d8f60..60e90e40 100644
--- a/evibes/locale/nl_NL/LC_MESSAGES/django.po
+++ b/evibes/locale/nl_NL/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: nl-nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Naam van het project"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Frontend domeinnaam"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Basis domeinnaam"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Naam van het bedrijf"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Adres van het bedrijf"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Telefoonnummer van het bedrijf"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP host"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTP poort"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "TLS gebruiken"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "SSL gebruiken"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "SMTP gebruikersnaam"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "SMTP wachtwoord"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Het adres van de afzender van de e-mail"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL betalingsgateway"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Betaal gateway token"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Minimumbedrag betalingsgateway"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Maximumbedrag betalingsgateway"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Wisselkoers API sleutel"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI API sleutel"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Abstracte API-sleutel"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP-proxy"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Koopfunctie uitschakelen"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Een entiteit voor het opslaan van adverteerdersgegevens"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Een entiteit voor het opslaan van analytische gegevens"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Algemene opties"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "E-mailopties"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Opties voor betalingsgateways"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Functies Opties"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "SEO Opties"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Home"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Winkelpui"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "GraphQL-documenten"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Platform REST-documenten"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST-documenten"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Ondersteuning"
diff --git a/evibes/locale/pl_PL/LC_MESSAGES/django.mo b/evibes/locale/pl_PL/LC_MESSAGES/django.mo
index 0fc354f2..17cfa98f 100644
Binary files a/evibes/locale/pl_PL/LC_MESSAGES/django.mo and b/evibes/locale/pl_PL/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/pl_PL/LC_MESSAGES/django.po b/evibes/locale/pl_PL/LC_MESSAGES/django.po
index 9a7d8f60..50f7619c 100644
--- a/evibes/locale/pl_PL/LC_MESSAGES/django.po
+++ b/evibes/locale/pl_PL/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: pl-pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Nazwa projektu"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Nazwa domeny frontendu"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Nazwa domeny podstawowej"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Nazwa firmy"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Adres spółki"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Numer telefonu firmy"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "Host SMTP"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "Port SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Używanie TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Używanie protokołu SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Nazwa użytkownika SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Hasło SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Adres nadawcy wiadomości e-mail"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "Adres URL bramki płatności"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Token bramki płatności"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Minimalna kwota bramki płatności"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Maksymalna kwota bramki płatności"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Klucz API kursu wymiany"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "Adres URL interfejsu API OpenStreetMap Nominatim"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "Klucz API OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Abstrakcyjny klucz API"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "Serwer proxy HTTP"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Wyłączenie funkcji kupowania"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Jednostka do przechowywania danych reklamowych"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Jednostka do przechowywania danych analitycznych"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Opcje ogólne"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Opcje e-mail"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Opcje bramki płatności"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Opcje funkcji"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Opcje SEO"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Strona główna"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Witryna sklepowa"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Dokumenty GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Dokumenty platformy REST"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "Dokumenty B2B REST"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Wsparcie"
diff --git a/evibes/locale/pt_BR/LC_MESSAGES/django.mo b/evibes/locale/pt_BR/LC_MESSAGES/django.mo
index e7d918d9..8c3c4184 100644
Binary files a/evibes/locale/pt_BR/LC_MESSAGES/django.mo and b/evibes/locale/pt_BR/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/pt_BR/LC_MESSAGES/django.po b/evibes/locale/pt_BR/LC_MESSAGES/django.po
index b841007d..0dc4779e 100644
--- a/evibes/locale/pt_BR/LC_MESSAGES/django.po
+++ b/evibes/locale/pt_BR/LC_MESSAGES/django.po
@@ -1,202 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: pt-br\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Nome do projeto"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Nome de domínio de front-end"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Nome de domínio básico"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Nome da empresa"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Endereço da empresa"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Número de telefone da empresa"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "Host SMTP"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "Porta SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Usar TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Usar SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Nome de usuário SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Senha SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "O endereço do remetente do e-mail"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL do gateway de pagamento"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Token de gateway de pagamento"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Valor mínimo do gateway de pagamento"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Valor máximo do gateway de pagamento"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Chave da API de taxa de câmbio"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "URL da API do OpenStreetMap Nominatim"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "Chave da API da OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Chave abstrata da API"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "Proxy HTTP"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Desativar a funcionalidade de compra"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Uma entidade para armazenar dados de propaganda"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Uma entidade para armazenar dados analíticos"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Opções gerais"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Opções de e-mail"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Opções de gateway de pagamento"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Opções de recursos"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Opções de SEO"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Início"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Vitrine"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Documentos do GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Documentos REST da plataforma"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "Documentos B2B REST"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Suporte"
diff --git a/evibes/locale/ro_RO/LC_MESSAGES/django.mo b/evibes/locale/ro_RO/LC_MESSAGES/django.mo
index 0fc354f2..6f0b3b4b 100644
Binary files a/evibes/locale/ro_RO/LC_MESSAGES/django.mo and b/evibes/locale/ro_RO/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/ro_RO/LC_MESSAGES/django.po b/evibes/locale/ro_RO/LC_MESSAGES/django.po
index 9a7d8f60..4fc0b953 100644
--- a/evibes/locale/ro_RO/LC_MESSAGES/django.po
+++ b/evibes/locale/ro_RO/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: ro-ro\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Denumirea proiectului"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Nume de domeniu Frontend"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Numele domeniului de bază"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Denumirea societății"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Adresa societății"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Numărul de telefon al societății"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "Gazdă SMTP"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "Portul SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Utilizați TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Utilizați SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Nume utilizator SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Parola SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Adresa expeditorului e-mailurilor"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL-ul gateway-ului de plată"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Token pentru gateway-ul de plată"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Suma minimă a gateway-ului de plată"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Suma maximă a gateway-ului de plată"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Cheie API pentru rata de schimb"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "Cheie API OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Cheie API abstractă"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "Proxy HTTP"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Dezactivați funcționalitatea de cumpărare"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "O entitate pentru stocarea datelor privind publicitatea"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "O entitate pentru stocarea datelor analitice"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Opțiuni generale"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Opțiuni de e-mail"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Opțiuni pentru portalul de plăți"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Caracteristici Opțiuni"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Opțiuni SEO"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Acasă"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Vitrină"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Docuri GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Platforma REST Docs"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "Docuri B2B REST"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Sprijin"
diff --git a/evibes/locale/ru_RU/LC_MESSAGES/django.mo b/evibes/locale/ru_RU/LC_MESSAGES/django.mo
index 0fc354f2..b70b4f28 100644
Binary files a/evibes/locale/ru_RU/LC_MESSAGES/django.mo and b/evibes/locale/ru_RU/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/ru_RU/LC_MESSAGES/django.po b/evibes/locale/ru_RU/LC_MESSAGES/django.po
index 9a7d8f60..57270c24 100644
--- a/evibes/locale/ru_RU/LC_MESSAGES/django.po
+++ b/evibes/locale/ru_RU/LC_MESSAGES/django.po
@@ -1,201 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: ru-ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "Название проекта"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "Доменное имя фронтенд-приложения"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "Базовое доменное имя"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "Название компании"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "Адрес компании"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "Номер телефона компании"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP-хост"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "Порт SMTP"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "Используйте TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "Используйте SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "Имя пользователя SMTP"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "Пароль SMTP"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "Адрес отправителя электронного письма"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "URL-адрес платежного шлюза"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "Токен платежного шлюза"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "Минимальная сумма платежного шлюза"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "Максимальная сумма платежного шлюза"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "Ключ API обменного курса"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "URL-адрес API OpenStreetMap Nominatim"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "Ключ API OpenAI"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "Абстрактный ключ API"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP-прокси"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "Отключить функцию покупки"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "Устройство для хранения данных о рекламе"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "Сущность для хранения аналитических данных"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "Общие параметры"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "Параметры электронной почты"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "Варианты платежных шлюзов"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "Особенности Опции"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "Параметры SEO"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "Главная"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "Витрина"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "Документация по GraphQL"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "Документация по REST"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "Документация по B2B REST"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "Поддержка"
diff --git a/evibes/locale/zh_Hans/LC_MESSAGES/django.mo b/evibes/locale/zh_Hans/LC_MESSAGES/django.mo
index ed31f42b..ad32b734 100644
Binary files a/evibes/locale/zh_Hans/LC_MESSAGES/django.mo and b/evibes/locale/zh_Hans/LC_MESSAGES/django.mo differ
diff --git a/evibes/locale/zh_Hans/LC_MESSAGES/django.po b/evibes/locale/zh_Hans/LC_MESSAGES/django.po
index 1380a17d..5fc42118 100644
--- a/evibes/locale/zh_Hans/LC_MESSAGES/django.po
+++ b/evibes/locale/zh_Hans/LC_MESSAGES/django.po
@@ -1,202 +1,158 @@
-# EVIBES GETTEXT TRANSLATIONS
-# Copyright (C) 2025 EGOR GORBUNOV
-# This file is distributed under the same license as the EVIBES package.
-# EGOR GORBUNOV , 2025.
#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-18 08:39+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
-"Language: \n"
+"Language: zh-hans\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-
-#: evibes/settings/constance.py:18
-msgid "Name of the project"
-msgstr ""
-
-#: evibes/settings/constance.py:19
-msgid "Frontend domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:20
-msgid "Base domain name"
-msgstr ""
-
-#: evibes/settings/constance.py:21
-msgid "Name of the company"
-msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: evibes/settings/constance.py:22
-msgid "Address of the company"
-msgstr ""
+msgid "Name of the project"
+msgstr "项目名称"
#: evibes/settings/constance.py:23
-msgid "Phone number of the company"
-msgstr ""
+msgid "Frontend domain name"
+msgstr "前台域名"
+
+#: evibes/settings/constance.py:24
+msgid "Base domain name"
+msgstr "基础域名"
+
+#: evibes/settings/constance.py:25
+msgid "Name of the company"
+msgstr "公司名称"
#: evibes/settings/constance.py:26
-msgid "Designates whether every product has one stock or not"
-msgstr ""
+msgid "Address of the company"
+msgstr "公司地址"
+
+#: evibes/settings/constance.py:27
+msgid "Phone number of the company"
+msgstr "公司电话号码"
#: evibes/settings/constance.py:28
msgid "SMTP host"
-msgstr ""
+msgstr "SMTP 主机"
#: evibes/settings/constance.py:29
msgid "SMTP port"
-msgstr ""
+msgstr "SMTP 端口"
#: evibes/settings/constance.py:30
-msgid "Use TLS (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use TLS (0=No, 1=Yes)"
+msgstr "使用 TLS"
#: evibes/settings/constance.py:31
-msgid "Use SSL (Specify 0 for No and 1 for Yes)"
-msgstr ""
+msgid "Use SSL (0=No, 1=Yes)"
+msgstr "使用 SSL"
#: evibes/settings/constance.py:32
msgid "SMTP username"
-msgstr ""
+msgstr "SMTP 用户名"
#: evibes/settings/constance.py:33
msgid "SMTP password"
-msgstr ""
+msgstr "SMTP 密码"
#: evibes/settings/constance.py:34
msgid "Mail from option"
-msgstr ""
+msgstr "邮件发件人地址"
#: evibes/settings/constance.py:35
msgid "Payment gateway URL"
-msgstr ""
+msgstr "付款网关 URL"
#: evibes/settings/constance.py:36
msgid "Payment gateway token"
-msgstr ""
+msgstr "支付网关令牌"
#: evibes/settings/constance.py:37
msgid "Payment gateway minimum amount"
-msgstr ""
+msgstr "支付网关最低金额"
#: evibes/settings/constance.py:38
msgid "Payment gateway maximum amount"
-msgstr ""
+msgstr "支付网关最高限额"
#: evibes/settings/constance.py:39
msgid "Exchange rate API key"
-msgstr ""
+msgstr "汇率 API 密钥"
#: evibes/settings/constance.py:40
msgid "OpenStreetMap Nominatim API URL"
-msgstr ""
+msgstr "OpenStreetMap Nominatim API URL"
#: evibes/settings/constance.py:41
msgid "OpenAI API Key"
-msgstr ""
+msgstr "OpenAI API 密钥"
+
+#: evibes/settings/constance.py:42
+msgid "Abstract API Key"
+msgstr "抽象应用程序接口密钥"
+
+#: evibes/settings/constance.py:43
+msgid "HTTP Proxy"
+msgstr "HTTP 代理服务器"
#: evibes/settings/constance.py:44
-msgid "Abstract API Key, if empty - no Abstract features provided"
-msgstr ""
-
-#: evibes/settings/constance.py:46
-msgid "HTTP Proxy"
-msgstr ""
+msgid "Disable buy functionality"
+msgstr "禁用购买功能"
#: evibes/settings/constance.py:47
-msgid "Disable buy functionality"
-msgstr ""
-
-#: evibes/settings/constance.py:50
msgid "An entity for storing advertisiment data"
-msgstr ""
+msgstr "存储广告数据的实体"
-#: evibes/settings/constance.py:55
+#: evibes/settings/constance.py:49
msgid "An entity for storing analytics data"
-msgstr ""
+msgstr "存储分析数据的实体"
-#: evibes/settings/drf.py:49
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} B2B API is designed to "
-"provide seamless integration for merchants selling a wide range of "
-"electronics. Through this API, partnered merchants can manage products, "
-"orders, and inventory with ease, while accessing real-time stock levels.\n"
-"\n"
-"## Key Features\n"
-"- **Product Management:** Easily create, update, and manage your product "
-"listings with detailed specifications.\n"
-"- **Order Processing:** Handle bulk orders efficiently with streamlined "
-"operations for merchants.\n"
-"- **Inventory Management:** Keep track of stock levels in real-time, "
-"ensuring smooth fulfillment.\n"
-"- **Secure Transactions:** Secure and encrypted transactions to protect "
-"sensitive business information.\n"
-"- **Multi-Currency Support:** Expand your market reach with multi-currency "
-"transactions.\n"
-"- **Real-Time Notifications:** Stay updated with instant alerts on stock "
-"changes and order statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via your merchant token. Include the token in "
-"the `X-EVIBES-B2B-AUTH` header of your requests in the format `Bearer "
-"`.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:54
+msgid "General Options"
+msgstr "一般选项"
-#: evibes/settings/drf.py:74
-msgid ""
-"\n"
-"Welcome to the {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} Platform API "
-"documentation.\n"
-"\n"
-"The {CONSTANCE_CONFIG.get(\"PROJECT_NAME\")[0]} API is the central hub for "
-"managing product listings, monitoring orders, and accessing analytics for "
-"your electronics store. It provides RESTful endpoints for managing your "
-"store’s backend operations and includes both REST and GraphQL options.\n"
-"\n"
-"## Key Features\n"
-"- **Product Catalog:** Manage product details, pricing, and availability.\n"
-"- **Order Management:** Access detailed order information and process "
-"customer requests efficiently.\n"
-"- **User Roles & Permissions:** Set user roles and permissions for internal "
-"management.\n"
-"- **Custom Integrations:** Connect your system with external platforms "
-"through powerful APIs.\n"
-"- **Detailed Reporting:** Generate comprehensive reports on orders, sales "
-"performance, and product data.\n"
-"- **Real-Time Data:** Get live updates on inventory, pricing, and order "
-"statuses.\n"
-"\n"
-"## Authentication\n"
-"- Authentication is handled via JWT tokens. Include the token in the `X-"
-"EVIBES-AUTH` header of your requests in the format `Bearer `.\n"
-"- Access token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 60 if not DEBUG else 3600} {\"minutes\" if not DEBUG else "
-"\"hours\"}.\n"
-"- Refresh token lifetime is {SIMPLE_JWT.get(\"ACCESS_TOKEN_LIFETIME\")."
-"total_seconds() // 3600} hours.\n"
-"- Refresh tokens are automatically invalidated after usage.\n"
-"\n"
-"## I18N\n"
-"- Apply an `Accept-Language` header to use non-default language. A list of "
-"all languages is available at `/app/languages/`.\n"
-"\n"
-"## Version\n"
-"Current API version: {EVIBES_VERSION}\n"
-msgstr ""
+#: evibes/settings/constance.py:62
+msgid "Email Options"
+msgstr "电子邮件选项"
+
+#: evibes/settings/constance.py:71
+msgid "Payment Gateway Options"
+msgstr "支付网关选项"
+
+#: evibes/settings/constance.py:78
+msgid "Features Options"
+msgstr "功能选项"
+
+#: evibes/settings/constance.py:85
+msgid "SEO Options"
+msgstr "搜索引擎优化选项"
+
+#: evibes/settings/jazzmin.py:20
+msgid "Home"
+msgstr "首页"
+
+#: evibes/settings/jazzmin.py:21
+msgid "Storefront"
+msgstr "店面"
+
+#: evibes/settings/jazzmin.py:24
+msgid "GraphQL Docs"
+msgstr "GraphQL 文档"
+
+#: evibes/settings/jazzmin.py:29
+msgid "Platform REST Docs"
+msgstr "平台 REST 文档"
+
+#: evibes/settings/jazzmin.py:34
+msgid "B2B REST Docs"
+msgstr "B2B REST 文档"
+
+#: evibes/settings/jazzmin.py:38
+msgid "Support"
+msgstr "支持"
diff --git a/evibes/middleware.py b/evibes/middleware.py
index 56e21545..b411eb05 100644
--- a/evibes/middleware.py
+++ b/evibes/middleware.py
@@ -4,7 +4,7 @@ from os import getenv
from constance import config
from django.contrib.auth.models import AnonymousUser
-from django.core.exceptions import BadRequest, DisallowedHost
+from django.core.exceptions import BadRequest, DisallowedHost, PermissionDenied, ValidationError
from django.http import HttpResponseForbidden
from django.middleware.common import CommonMiddleware
from django.middleware.locale import LocaleMiddleware
@@ -16,7 +16,7 @@ from sentry_sdk import capture_exception
from evibes.settings import DEBUG
-logger = logging.getLogger("django.request")
+logger = logging.getLogger("django")
class CustomCommonMiddleware(CommonMiddleware):
@@ -95,12 +95,21 @@ class BlockInvalidHostMiddleware:
# noinspection PyShadowingBuiltins
class GrapheneLoggingErrorsDebugMiddleware:
+ WARNING_ONLY_ERRORS = [
+ BadRequest,
+ PermissionDenied,
+ DisallowedHost,
+ ValidationError,
+ ]
+
def resolve(self, next, root, info, **args):
try:
return next(root, info, **args)
except Exception as e:
- logger.error("Error occurred in GraphQL execution:", exc_info=True)
- if bool(int(getenv("DEBUG"))):
+ if any(isinstance(e, error_type) for error_type in self.WARNING_ONLY_ERRORS):
+ logger.warning(str(e))
+ else:
+ logger.error(str(e))
logger.error(traceback.format_exc())
- capture_exception(e)
+ capture_exception(e)
raise e
diff --git a/evibes/models.png b/evibes/models.png
new file mode 100644
index 00000000..5c2377e5
Binary files /dev/null and b/evibes/models.png differ
diff --git a/evibes/pagination.py b/evibes/pagination.py
index be486861..99a9bd17 100644
--- a/evibes/pagination.py
+++ b/evibes/pagination.py
@@ -10,9 +10,9 @@ class CustomPagination(PageNumberPagination):
{
"links": {"forward": self.get_next_link(), "backward": self.get_previous_link()},
"counts": {
- "total_pages": None or self.page.paginator.num_pages, # type: ignore
- "page_size": None or self.page_size, # type: ignore
- "total_items": None or self.page.paginator.count, # type: ignore
+ "total_pages": None or self.page.paginator.num_pages, # type: ignore [union-attr]
+ "page_size": None or self.page_size,
+ "total_items": None or self.page.paginator.count, # type: ignore [union-attr]
},
"data": data,
}
diff --git a/evibes/settings/__init__.py b/evibes/settings/__init__.py
index 74696a6d..86adbb63 100644
--- a/evibes/settings/__init__.py
+++ b/evibes/settings/__init__.py
@@ -2,7 +2,6 @@ from .caches import * # noqa: F403
from .celery import * # noqa: F403
from .constance import * # noqa: F403
from .csp import * # noqa: F403
-from .daisy import * # noqa: F403
from .database import * # noqa: F403
from .dbbackup import * # noqa: F403
from .drf import * # noqa: F403
@@ -10,5 +9,6 @@ from .elasticsearch import * # noqa: F403
from .emailing import * # noqa: F403
from .extensions import * # noqa: F403
from .graphene import * # noqa: F403
+from .jazzmin import * # noqa: F403
from .logconfig import * # noqa: F403
from .summernote import * # noqa: F403
diff --git a/evibes/settings/base.py b/evibes/settings/base.py
index 300a0b66..651e850c 100644
--- a/evibes/settings/base.py
+++ b/evibes/settings/base.py
@@ -1,15 +1,15 @@
import logging
-from os import getenv
+from os import getenv, name
from pathlib import Path
-EVIBES_VERSION = "2.8.10"
+EVIBES_VERSION = "2.9.2"
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = getenv("SECRET_KEY", "SUPER_SECRET_KEY")
DEBUG = bool(int(getenv("DEBUG", "1")))
-ALLOWED_HOSTS = {
+ALLOWED_HOSTS: set = {
"app",
"worker",
"beat",
@@ -27,9 +27,9 @@ else:
for entry in getenv("ALLOWED_HOSTS", "").split(" "):
ALLOWED_HOSTS.add(entry)
-ALLOWED_HOSTS = tuple(ALLOWED_HOSTS) # type: ignore
+ALLOWED_HOSTS: tuple = tuple(ALLOWED_HOSTS)
-CSRF_TRUSTED_ORIGINS = {
+CSRF_TRUSTED_ORIGINS: set = {
"http://127.0.0.1",
"http://api.localhost",
"http://b2b.localhost",
@@ -38,12 +38,12 @@ CSRF_TRUSTED_ORIGINS = {
for entry in getenv("CSRF_TRUSTED_ORIGINS", "").split(" "):
CSRF_TRUSTED_ORIGINS.add(entry)
-CSRF_TRUSTED_ORIGINS = tuple(CSRF_TRUSTED_ORIGINS) # type: ignore
+CSRF_TRUSTED_ORIGINS: tuple = tuple(CSRF_TRUSTED_ORIGINS)
if DEBUG:
CORS_ALLOW_ALL_ORIGINS = True
else:
- CORS_ALLOWED_ORIGINS = {
+ CORS_ALLOWED_ORIGINS: set = {
"http://127.0.0.1",
"http://api.localhost",
"http://b2b.localhost",
@@ -51,7 +51,7 @@ else:
for entry in getenv("CORS_ALLOWED_ORIGINS", "").split(" "):
CORS_ALLOWED_ORIGINS.add(entry)
- CORS_ALLOWED_ORIGINS = tuple(CORS_ALLOWED_ORIGINS) # type: ignore
+ CORS_ALLOWED_ORIGINS: tuple = tuple(CORS_ALLOWED_ORIGINS)
CORS_ALLOW_METHODS = (
"DELETE",
@@ -96,9 +96,10 @@ SITE_ID: int = 1
INSTALLED_APPS: list[str] = [
"django_prometheus",
"constance",
- "django_daisy",
+ "jazzmin",
"modeltranslation",
"django.contrib.admin",
+ "django.contrib.admindocs",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
@@ -112,8 +113,11 @@ INSTALLED_APPS: list[str] = [
"health_check.cache",
"health_check.storage",
"health_check.contrib.migrations",
+ "health_check.contrib.celery_ping",
"health_check.contrib.psutil",
+ "health_check.contrib.redis",
"health_check.contrib.db_heartbeat",
+ "health_check.contrib.mail",
"cacheops",
"django_hosts",
"django_celery_beat",
@@ -152,6 +156,7 @@ MIDDLEWARE: list[str] = [
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
+ "django.contrib.admindocs.middleware.XViewMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"evibes.middleware.CustomLocaleMiddleware",
"django_hosts.middleware.HostsResponseMiddleware",
@@ -225,7 +230,7 @@ CURRENCIES: tuple[tuple[str, str], ...] = (
("zh-hans", "CNY"),
)
-CURRENCY_CODE: str | None = dict(CURRENCIES).get(LANGUAGE_CODE)
+CURRENCY_CODE: str = dict(CURRENCIES).get(LANGUAGE_CODE) # type: ignore [assignment]
MODELTRANSLATION_FALLBACK_LANGUAGES: tuple = (LANGUAGE_CODE, "en-us", "de-de")
@@ -267,6 +272,7 @@ APPEND_SLASH: bool = True
ROOT_HOSTCONF: str = "evibes.hosts"
DEFAULT_HOST: str = "api"
REDIS_PASSWORD: str = getenv("REDIS_PASSWORD", default="")
+REDIS_URL: str = f"redis://:{REDIS_PASSWORD}@redis:6379/0"
INTERNAL_IPS: list[str] = [
"127.0.0.1",
@@ -279,28 +285,32 @@ if getenv("SENTRY_DSN"):
from sentry_sdk.integrations.logging import LoggingIntegration
from sentry_sdk.integrations.redis import RedisIntegration
- ignore_errors: list[str] = [
- "django.http.response.Http404",
- "django.core.exceptions.PermissionDenied",
- "django.core.exceptions.BadRequest",
- "django.db.utils.OperationalError",
- "billiard.exceptions.SoftTimeLimitExceeded", # This is a handled exception
- "billiard.exceptions.WorkerLostError", # This is a handled exception
- "core.models.Attribute.DoesNotExist",
- "core.models.AttributeGroup.DoesNotExist",
- "core.models.AttributeValue.DoesNotExist",
- "core.models.Product.DoesNotExist",
- "core.models.Category.DoesNotExist",
- "core.models.Brand.DoesNotExist",
- "core.models.Stock.DoesNotExist",
- "core.models.ProductImage.DoesNotExist",
- "blog.models.Post.DoesNotExist",
- ]
+ def scrub_sensitive(data):
+ if isinstance(data, dict):
+ cleaned = {}
+ for key, value in data.items():
+ if key.lower() in ("password", "confirm_password"):
+ cleaned[key] = "[FILTERED]"
+ else:
+ cleaned[key] = scrub_sensitive(value)
+ return cleaned
+ if isinstance(data, list):
+ return [scrub_sensitive(item) for item in data]
+ return data
+
+ def before_send(event, hint):
+ if hint:
+ pass
+ request = event.get("request", {})
+ if "data" in request:
+ request["data"] = scrub_sensitive(request["data"])
+ event["request"] = request
+ return event
+
+ ignore_errors: list[str] = []
sentry_sdk.init(
dsn=getenv("SENTRY_DSN"),
- traces_sample_rate=1.0 if DEBUG else 0.2,
- profiles_sample_rate=1.0 if DEBUG else 0.1,
integrations=[
DjangoIntegration(),
LoggingIntegration(level=logging.INFO, event_level=logging.ERROR),
@@ -308,9 +318,13 @@ if getenv("SENTRY_DSN"):
RedisIntegration(),
],
environment="development" if DEBUG else "production",
- debug=False,
release=f"evibes@{EVIBES_VERSION}",
+ traces_sample_rate=1.0 if DEBUG else 0.2,
+ profiles_sample_rate=1.0 if DEBUG else 0.1,
+ max_request_body_size="always",
+ before_send=before_send,
ignore_errors=ignore_errors,
+ debug=False,
)
SESSION_COOKIE_HTTPONLY: bool = True
@@ -332,3 +346,7 @@ STORAGES: dict[str, dict[str, str | int | bool | None]] = {
"BACKEND": "django.core.files.storage.FileSystemStorage",
},
}
+
+if name == "nt":
+ GDAL_LIBRARY_PATH = r"C:\OSGeo4W\bin\gdal311.dll"
+ GEOS_LIBRARY_PATH = r"C:\OSGeo4W\bin\geos_c.dll"
diff --git a/evibes/settings/celery.py b/evibes/settings/celery.py
index 94f0c08b..6ff53d01 100644
--- a/evibes/settings/celery.py
+++ b/evibes/settings/celery.py
@@ -1,9 +1,26 @@
from datetime import timedelta
-from evibes.settings import REDIS_PASSWORD
+from evibes.settings.base import REDIS_PASSWORD, TIME_ZONE
-CELERY_BROKER_URL = f"redis://:{REDIS_PASSWORD + '@'}redis:6379/0"
-CELERY_RESULT_BACKEND = f"redis://:{REDIS_PASSWORD + '@'}redis:6379/0"
+CELERY_ENABLE_UTC = False
+CELERY_TIMEZONE = TIME_ZONE
+
+CELERY_BROKER_URL = f"redis://:{REDIS_PASSWORD}@redis:6379/0"
+
+CELERY_BROKER_HEARTBEAT = 10
+CELERY_BROKER_HEARTBEAT_CHECKRATE = 2
+
+CELERY_BROKER_POOL_LIMIT = 10
+CELERY_BROKER_TRANSPORT_OPTIONS = {
+ "visibility_timeout": 3600,
+ "retry_policy": {"interval_start": 0.1, "interval_step": 0.2, "max_retries": 5},
+ "socket_keepalive": True,
+ "socket_timeout": 30,
+ "socket_connect_timeout": 30,
+ "retry_on_timeout": True,
+}
+
+CELERY_RESULT_BACKEND = CELERY_BROKER_URL
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers.DatabaseScheduler"
@@ -11,21 +28,26 @@ CELERY_BEAT_SCHEDULE = {
"update_products_task": {
"task": "core.tasks.update_products_task",
"schedule": timedelta(minutes=60),
+ "options": {"queue": "stock_updater"},
},
"update_orderproducts_task": {
"task": "core.tasks.update_orderproducts_task",
"schedule": timedelta(minutes=1),
+ "options": {"queue": "default"},
},
"set_default_caches_task": {
"task": "core.tasks.set_default_caches_task",
"schedule": timedelta(hours=4),
+ "options": {"queue": "default"},
},
"remove_stale_product_images": {
"task": "core.tasks.remove_stale_product_images",
"schedule": timedelta(days=1),
+ "options": {"queue": "default"},
},
"process_promotions": {
"task": "core.tasks.process_promotions",
"schedule": timedelta(hours=2),
+ "options": {"queue": "default"},
},
}
diff --git a/evibes/settings/constance.py b/evibes/settings/constance.py
index e108ced7..69b12293 100644
--- a/evibes/settings/constance.py
+++ b/evibes/settings/constance.py
@@ -1,8 +1,11 @@
-from django.utils.translation import gettext_lazy as _
+from collections import OrderedDict
+
+from django.utils.translation import gettext_lazy as _, gettext_noop
from evibes.settings.base import getenv
-CONSTANCE_BACKEND = "constance.backends.database.DatabaseBackend" # Or "constance.backends.redis.RedisBackend"
+CONSTANCE_BACKEND = "constance.backends.database.DatabaseBackend"
+CONSTANCE_SUPERUSER_ONLY = False
CONSTANCE_ADDITIONAL_FIELDS = {
"json": [
@@ -14,48 +17,78 @@ CONSTANCE_ADDITIONAL_FIELDS = {
],
}
-CONSTANCE_CONFIG = {
- "PROJECT_NAME": (getenv("EVIBES_PROJECT_NAME"), _("Name of the project")),
- "FRONTEND_DOMAIN": (getenv("EVIBES_FRONTEND_DOMAIN"), _("Frontend domain name")),
- "BASE_DOMAIN": (getenv("EVIBES_BASE_DOMAIN"), _("Base domain name")),
- "COMPANY_NAME": (getenv("COMPANY_NAME"), _("Name of the company")),
- "COMPANY_ADDRESS": (getenv("COMPANY_ADDRESS"), _("Address of the company")),
- "COMPANY_PHONE_NUMBER": (getenv("COMPANY_PHONE_NUMBER"), _("Phone number of the company")),
- "STOCKS_ARE_SINGLE": (
- getenv("STOCKS_ARE_SINGLE", True),
- _("Designates whether every product has one stock or not"),
- ),
- "EMAIL_HOST": (getenv("EMAIL_HOST", "smtp.404.org"), _("SMTP host")),
- "EMAIL_PORT": (int(getenv("EMAIL_PORT", "465")), _("SMTP port")),
- "EMAIL_USE_TLS": (bool(int(getenv("EMAIL_USE_TLS", 0))), _("Use TLS (Specify 0 for No and 1 for Yes)")),
- "EMAIL_USE_SSL": (bool(int(getenv("EMAIL_USE_SSL", 1))), _("Use SSL (Specify 0 for No and 1 for Yes)")),
- "EMAIL_HOST_USER": (getenv("EMAIL_HOST_USER", "no-user@fix.this"), _("SMTP username")),
- "EMAIL_HOST_PASSWORD": (getenv("EMAIL_HOST_PASSWORD", "SUPERsecretPASSWORD"), _("SMTP password")),
- "EMAIL_FROM": (getenv("EMAIL_FROM", "eVibes"), _("Mail from option")),
- "PAYMENT_GATEWAY_URL": (getenv("PAYMENT_GATEWAY_URL", "http://404.org"), _("Payment gateway URL")),
- "PAYMENT_GATEWAY_TOKEN": (getenv("PAYMENT_GATEWAY_TOKEN", "example token"), _("Payment gateway token")),
- "PAYMENT_GATEWAY_MINIMUM": (getenv("PAYMENT_GATEWAY_MINIMUM", 5.0), _("Payment gateway minimum amount")),
- "PAYMENT_GATEWAY_MAXIMUM": (getenv("PAYMENT_GATEWAY_MAXIMUM", 500.0), _("Payment gateway maximum amount")),
- "EXCHANGE_RATE_API_KEY": (getenv("EXCHANGE_RATE_API_KEY", "example token"), _("Exchange rate API key")),
- "NOMINATIM_URL": (getenv("NOMINATIM_URL", ""), _("OpenStreetMap Nominatim API URL")),
- "OPENAI_API_KEY": (getenv("OPENAI_API_KEY", "example key"), _("OpenAI API Key")),
- "ABSTRACT_API_KEY": (
- getenv("ABSTRACT_API_KEY", "example key"),
- _("Abstract API Key, if empty - no Abstract features provided"),
- ),
- "HTTP_PROXY": (getenv("DJANGO_HTTP_PROXY", "http://username:password@proxy_address:port"), _("HTTP Proxy")),
- "DISABLED_COMMERCE": (getenv("DISABLED_COMMERCE", False), _("Disable buy functionality")),
- "ADVERTISEMENT_DATA": (
- getenv("EVIBES_ADVERTISEMENT_DATA", ""),
- _("An entity for storing advertisiment data"),
- "json",
- ),
- "ANALYTICS_DATA": (
- getenv("EVIBES_ANALYTICS_DATA", ""),
- _("An entity for storing analytics data"),
- "json",
- ),
-}
+CONSTANCE_CONFIG = OrderedDict(
+ [
+ ("PROJECT_NAME", (getenv("EVIBES_PROJECT_NAME"), _("Name of the project"))),
+ ("FRONTEND_DOMAIN", (getenv("EVIBES_FRONTEND_DOMAIN"), _("Frontend domain name"))),
+ ("BASE_DOMAIN", (getenv("EVIBES_BASE_DOMAIN"), _("Base domain name"))),
+ ("COMPANY_NAME", (getenv("COMPANY_NAME"), _("Name of the company"))),
+ ("COMPANY_ADDRESS", (getenv("COMPANY_ADDRESS"), _("Address of the company"))),
+ ("COMPANY_PHONE_NUMBER", (getenv("COMPANY_PHONE_NUMBER"), _("Phone number of the company"))),
+ ("EMAIL_HOST", (getenv("EMAIL_HOST", "smtp.404.org"), _("SMTP host"))),
+ ("EMAIL_PORT", (int(getenv("EMAIL_PORT", "465")), _("SMTP port"))),
+ ("EMAIL_USE_TLS", (bool(int(getenv("EMAIL_USE_TLS", 0))), _("Use TLS (0=No, 1=Yes)"))),
+ ("EMAIL_USE_SSL", (bool(int(getenv("EMAIL_USE_SSL", 1))), _("Use SSL (0=No, 1=Yes)"))),
+ ("EMAIL_HOST_USER", (getenv("EMAIL_HOST_USER", "no-user@fix.this"), _("SMTP username"))),
+ ("EMAIL_HOST_PASSWORD", (getenv("EMAIL_HOST_PASSWORD", "SUPERsecretPASSWORD"), _("SMTP password"))),
+ ("EMAIL_FROM", (getenv("EMAIL_FROM", "eVibes"), _("Mail from option"))),
+ ("PAYMENT_GATEWAY_URL", (getenv("PAYMENT_GATEWAY_URL", "http://404.org"), _("Payment gateway URL"))),
+ ("PAYMENT_GATEWAY_TOKEN", (getenv("PAYMENT_GATEWAY_TOKEN", "example token"), _("Payment gateway token"))),
+ ("PAYMENT_GATEWAY_MINIMUM", (getenv("PAYMENT_GATEWAY_MINIMUM", 5.0), _("Payment gateway minimum amount"))),
+ ("PAYMENT_GATEWAY_MAXIMUM", (getenv("PAYMENT_GATEWAY_MAXIMUM", 500.0), _("Payment gateway maximum amount"))),
+ ("EXCHANGE_RATE_API_KEY", (getenv("EXCHANGE_RATE_API_KEY", "example token"), _("Exchange rate API key"))),
+ ("NOMINATIM_URL", (getenv("NOMINATIM_URL", ""), _("OpenStreetMap Nominatim API URL"))),
+ ("OPENAI_API_KEY", (getenv("OPENAI_API_KEY", "example key"), _("OpenAI API Key"))),
+ ("ABSTRACT_API_KEY", (getenv("ABSTRACT_API_KEY", "example key"), _("Abstract API Key"))),
+ ("HTTP_PROXY", (getenv("DJANGO_HTTP_PROXY", "http://username:password@proxy_address:port"), _("HTTP Proxy"))),
+ ("DISABLED_COMMERCE", (getenv("DISABLED_COMMERCE", False), _("Disable buy functionality"))),
+ (
+ "ADVERTISEMENT_DATA",
+ (getenv("EVIBES_ADVERTISEMENT_DATA", ""), _("An entity for storing advertisiment data"), "json"),
+ ),
+ ("ANALYTICS_DATA", (getenv("EVIBES_ANALYTICS_DATA", ""), _("An entity for storing analytics data"), "json")),
+ ]
+)
+
+CONSTANCE_CONFIG_FIELDSETS = OrderedDict(
+ {
+ gettext_noop("General Options"): (
+ "PROJECT_NAME",
+ "FRONTEND_DOMAIN",
+ "BASE_DOMAIN",
+ "COMPANY_NAME",
+ "COMPANY_ADDRESS",
+ "COMPANY_PHONE_NUMBER",
+ ),
+ gettext_noop("Email Options"): (
+ "EMAIL_HOST",
+ "EMAIL_PORT",
+ "EMAIL_USE_TLS",
+ "EMAIL_USE_SSL",
+ "EMAIL_HOST_USER",
+ "EMAIL_HOST_PASSWORD",
+ "EMAIL_FROM",
+ ),
+ gettext_noop("Payment Gateway Options"): (
+ "PAYMENT_GATEWAY_URL",
+ "PAYMENT_GATEWAY_TOKEN",
+ "EXCHANGE_RATE_API_KEY",
+ "PAYMENT_GATEWAY_MINIMUM",
+ "PAYMENT_GATEWAY_MAXIMUM",
+ ),
+ gettext_noop("Features Options"): (
+ "DISABLED_COMMERCE",
+ "NOMINATIM_URL",
+ "OPENAI_API_KEY",
+ "ABSTRACT_API_KEY",
+ "HTTP_PROXY",
+ ),
+ gettext_noop("SEO Options"): (
+ "ADVERTISEMENT_DATA",
+ "ANALYTICS_DATA",
+ ),
+ }
+)
EXPOSABLE_KEYS = [
"PROJECT_NAME",
diff --git a/evibes/settings/daisy.py b/evibes/settings/daisy.py
deleted file mode 100644
index 7e4c8192..00000000
--- a/evibes/settings/daisy.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from evibes.settings.base import EVIBES_VERSION
-from evibes.settings.constance import CONSTANCE_CONFIG
-
-DAISY_SETTINGS: dict = {
- "SITE_LOGO": "/static/favicon.ico",
- "EXTRA_STYLES": [
- f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/static/css/constance.css", # type: ignore
- ],
- "EXTRA_SCRIPTS": [],
- "SHOW_CHANGELIST_FILTER": True,
- "DONT_SUPPORT_ME": True,
- "SIDEBAR_FOOTNOTE": f"eVibes {EVIBES_VERSION} by Wiseless",
- "LOAD_FULL_STYLES": True,
- "APPS_REORDER": {
- "django_celery_results": {
- "hide": True,
- "app": "django_celery_results",
- },
- "django_celery_beat": {
- "icon": "fa fa-solid fa-timeline",
- "hide": False,
- "app": "django_celery_beat",
- "priority": 1,
- },
- "django_mailbox": {
- "icon": "fa fa-solid fa-envelope",
- "hide": False,
- "app": "django_mailbox",
- "priority": 2,
- },
- "django_summernote": {
- "icon": "fa fa-solid fa-note-sticky",
- "hide": False,
- "app": "django_summernote",
- "priority": 3,
- },
- },
-}
diff --git a/evibes/settings/database.py b/evibes/settings/database.py
index 3036c70c..80a8858f 100644
--- a/evibes/settings/database.py
+++ b/evibes/settings/database.py
@@ -1,11 +1,11 @@
-from evibes.settings.base import * # noqa: F403
+from os import getenv
DATABASES = {
"default": {
"ENGINE": "django_prometheus.db.backends.postgis",
- "NAME": getenv("POSTGRES_DB"), # noqa: F405
- "USER": getenv("POSTGRES_USER"), # noqa: F405
- "PASSWORD": getenv("POSTGRES_PASSWORD"), # noqa: F405
+ "NAME": getenv("POSTGRES_DB"),
+ "USER": getenv("POSTGRES_USER"),
+ "PASSWORD": getenv("POSTGRES_PASSWORD"),
"HOST": "database",
"PORT": 5432,
}
diff --git a/evibes/settings/dbbackup.py b/evibes/settings/dbbackup.py
index fa86b908..fca73a7e 100644
--- a/evibes/settings/dbbackup.py
+++ b/evibes/settings/dbbackup.py
@@ -1,4 +1,5 @@
-from evibes.settings.base import getenv
+from os import getenv
+from django.core.exceptions import ImproperlyConfigured
DBBACKUP_CONNECTORS = {
"default": {
@@ -8,21 +9,44 @@ DBBACKUP_CONNECTORS = {
}
}
-if getenv("DBBACKUP_SFTP_HOST") and getenv("DBBACKUP_SFTP_USER") and getenv("DBBACKUP_SFTP_PASS"):
- DBBACKUP_STORAGE = "storages.backends.sftpstorage.SFTPStorage"
- DBBACKUP_STORAGE_OPTIONS = {
- "host": getenv("DBBACKUP_SFTP_HOST"),
- "root_path": "/db_backups/",
- "params": {
- "username": getenv("DBBACKUP_SFTP_USER"),
- "password": getenv("DBBACKUP_SFTP_PASS"),
- "allow_agent": False,
- "look_for_keys": False,
- },
- "interactive": False,
- "file_mode": 0o600,
- "dir_mode": 0o700,
- }
+if getenv("DBBACKUP_HOST") and getenv("DBBACKUP_USER") and getenv("DBBACKUP_PASS"):
+ dbbackup_server_type = getenv("DBBACKUP_TYPE", "sftp")
+ project_name = getenv("EVIBES_PROJECT_NAME", "evibes_common").lower().replace(" ", "_")
+
+ raw_path = getenv("DBBACKUP_PATH", f"/backups/{project_name}/")
+ cleaned = raw_path.strip("/")
+ remote_dir = f"{cleaned}/"
+
+ match dbbackup_server_type:
+ case "sftp":
+ DBBACKUP_STORAGE = "storages.backends.sftpstorage.SFTPStorage"
+ DBBACKUP_STORAGE_OPTIONS = {
+ "host": getenv("DBBACKUP_HOST"),
+ "root_path": f"/{remote_dir}",
+ "params": {
+ "username": getenv("DBBACKUP_USER"),
+ "password": getenv("DBBACKUP_PASS"),
+ "allow_agent": False,
+ "look_for_keys": False,
+ },
+ "interactive": False,
+ "file_mode": 0o600,
+ "dir_mode": 0o700,
+ }
+
+ case "ftp":
+ DBBACKUP_STORAGE = "evibes.ftpstorage.AbsoluteFTPStorage"
+ DBBACKUP_STORAGE_OPTIONS = {
+ "location": (
+ f"ftp://{getenv('DBBACKUP_USER')}:{getenv('DBBACKUP_PASS')}@{getenv('DBBACKUP_HOST')}:21/{raw_path}"
+ ),
+ }
+
+ case _:
+ raise ImproperlyConfigured(f"Invalid DBBACKUP_TYPE: {dbbackup_server_type}")
+
else:
DBBACKUP_STORAGE = "django.core.files.storage.FileSystemStorage"
- DBBACKUP_STORAGE_OPTIONS = {"location": "/app/db_backups/"}
+ DBBACKUP_STORAGE_OPTIONS = {
+ "location": "/app/backups/",
+ }
diff --git a/evibes/settings/drf.py b/evibes/settings/drf.py
index 393acec0..afd4ab65 100644
--- a/evibes/settings/drf.py
+++ b/evibes/settings/drf.py
@@ -1,9 +1,7 @@
-# mypy: ignore-errors
from datetime import timedelta
+from os import getenv
-from django.utils.translation import gettext_lazy as _
-
-from evibes.settings.base import * # noqa: F403
+from evibes.settings.base import DEBUG, EVIBES_VERSION, SECRET_KEY
from evibes.settings.constance import CONSTANCE_CONFIG
REST_FRAMEWORK: dict = {
@@ -21,6 +19,8 @@ REST_FRAMEWORK: dict = {
"DEFAULT_PARSER_CLASSES": (
"djangorestframework_camel_case.parser.CamelCaseJSONParser",
"djangorestframework_camel_case.parser.CamelCaseMultiPartParser",
+ "rest_framework.parsers.FormParser",
+ "rest_framework.parsers.MultiPartParser",
"rest_framework_xml.parsers.XMLParser",
"rest_framework_yaml.parsers.YAMLParser",
),
@@ -45,11 +45,15 @@ SIMPLE_JWT: dict[str, timedelta | str | bool] = {
"AUTH_HEADER_NAME": "HTTP_X_EVIBES_AUTH",
}
-# type: ignore
-SPECTACULAR_B2B_DESCRIPTION = _(f"""
-Welcome to the {CONSTANCE_CONFIG.get("PROJECT_NAME")[0]} B2B API documentation.
+SPECTACULAR_B2B_DESCRIPTION = ( # type: ignore [index]
+ f"""
+Welcome to the {
+ CONSTANCE_CONFIG.get("PROJECT_NAME")[0] # type: ignore [index]
+ } B2B API documentation.
-The {CONSTANCE_CONFIG.get("PROJECT_NAME")[0]} B2B API is designed to provide seamless integration for merchants selling a wide range of electronics. Through this API, partnered merchants can manage products, orders, and inventory with ease, while accessing real-time stock levels.
+The {
+ CONSTANCE_CONFIG.get("PROJECT_NAME")[0] # type: ignore [index]
+ } B2B API is designed to provide seamless integration for merchants selling a wide range of electronics. Through this API, partnered merchants can manage products, orders, and inventory with ease, while accessing real-time stock levels.
## Key Features
- **Product Management:** Easily create, update, and manage your product listings with detailed specifications.
@@ -67,14 +71,17 @@ The {CONSTANCE_CONFIG.get("PROJECT_NAME")[0]} B2B API is designed to provide sea
## Version
Current API version: {EVIBES_VERSION}
-""") # noqa: E501, F405
+"""
+) # noqa: E501, F405
-# type: ignore
-# noinspection Mypy
-SPECTACULAR_PLATFORM_DESCRIPTION = _(f"""
-Welcome to the {CONSTANCE_CONFIG.get("PROJECT_NAME")[0]} Platform API documentation.
+SPECTACULAR_PLATFORM_DESCRIPTION = f"""
+Welcome to the {
+ CONSTANCE_CONFIG.get("PROJECT_NAME")[0] # type: ignore [index]
+} Platform API documentation.
-The {CONSTANCE_CONFIG.get("PROJECT_NAME")[0]} API is the central hub for managing product listings, monitoring orders, and accessing analytics for your electronics store. It provides RESTful endpoints for managing your store’s backend operations and includes both REST and GraphQL options.
+The {
+ CONSTANCE_CONFIG.get("PROJECT_NAME")[0] # type: ignore [index]
+} API is the central hub for managing product listings, monitoring orders, and accessing analytics for your electronics store. It provides RESTful endpoints for managing your store’s backend operations and includes both REST and GraphQL options.
## Key Features
- **Product Catalog:** Manage product details, pricing, and availability.
@@ -86,8 +93,12 @@ The {CONSTANCE_CONFIG.get("PROJECT_NAME")[0]} API is the central hub for managin
## Authentication
- Authentication is handled via JWT tokens. Include the token in the `X-EVIBES-AUTH` header of your requests in the format `Bearer `.
-- Access token lifetime is {SIMPLE_JWT.get("ACCESS_TOKEN_LIFETIME").total_seconds() // 60 if not DEBUG else 3600} {"minutes" if not DEBUG else "hours"}.
-- Refresh token lifetime is {SIMPLE_JWT.get("ACCESS_TOKEN_LIFETIME").total_seconds() // 3600} hours.
+- Access token lifetime is {
+ SIMPLE_JWT.get("ACCESS_TOKEN_LIFETIME").total_seconds() // 60 if not DEBUG else 3600 # type: ignore [union-attr]
+} {"minutes" if not DEBUG else "hours"}.
+- Refresh token lifetime is {
+ SIMPLE_JWT.get("REFRESH_TOKEN_LIFETIME").total_seconds() // 3600 # type: ignore [union-attr]
+} hours.
- Refresh tokens are automatically invalidated after usage.
## I18N
@@ -95,10 +106,10 @@ The {CONSTANCE_CONFIG.get("PROJECT_NAME")[0]} API is the central hub for managin
## Version
Current API version: {EVIBES_VERSION}
-""") # noqa: E501, F405
+""" # noqa: E501, F405
SPECTACULAR_PLATFORM_SETTINGS = {
- "TITLE": f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]} API",
+ "TITLE": f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]} API", # type: ignore [index]
"DESCRIPTION": SPECTACULAR_PLATFORM_DESCRIPTION,
"VERSION": EVIBES_VERSION, # noqa: F405
"TOS": "https://wiseless.xyz/evibes/terms-of-service",
@@ -136,7 +147,7 @@ SPECTACULAR_PLATFORM_SETTINGS = {
},
"SERVERS": [
{
- "url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/",
+ "url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/", # type: ignore [index]
"description": "Production Server",
},
{"url": "http://api.localhost:8000/", "description": "Development Server"},
@@ -150,7 +161,7 @@ SPECTACULAR_PLATFORM_SETTINGS = {
# noinspection Mypy
SPECTACULAR_B2B_SETTINGS = {
- "TITLE": f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]} API",
+ "TITLE": f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]} API", # type: ignore [index]
"DESCRIPTION": SPECTACULAR_B2B_DESCRIPTION,
"VERSION": EVIBES_VERSION, # noqa: F405
"TOS": "https://wiseless.xyz/evibes/terms-of-service",
@@ -188,17 +199,17 @@ SPECTACULAR_B2B_SETTINGS = {
},
"SERVERS": [
{
- "url": f"https://b2b.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/",
+ "url": f"https://b2b.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/", # type: ignore [index]
"description": "Production Server",
},
{
- "url": f"https://beta.b2b.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/",
+ "url": f"https://beta.b2b.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/", # type: ignore [index]
"description": "Beta Solutions Server",
},
],
"CONTACT": {
- "name": f"{CONSTANCE_CONFIG.get('COMPANY_NAME')[0]}",
- "email": f"{CONSTANCE_CONFIG.get('EMAIL_HOST_USER')[0]}",
- "URL": f"https://www.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/help",
+ "name": f"{CONSTANCE_CONFIG.get('COMPANY_NAME')[0]}", # type: ignore [index]
+ "email": f"{CONSTANCE_CONFIG.get('EMAIL_HOST_USER')[0]}", # type: ignore [index]
+ "URL": f"https://www.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/help", # type: ignore [index]
},
}
diff --git a/evibes/settings/elasticsearch.py b/evibes/settings/elasticsearch.py
index 171208e3..257262a3 100644
--- a/evibes/settings/elasticsearch.py
+++ b/evibes/settings/elasticsearch.py
@@ -1,9 +1,11 @@
-from evibes.settings.base import * # noqa: F403
+from os import getenv
+
+from evibes.settings import DEBUG
ELASTICSEARCH_DSL = {
"default": {
"hosts": ["http://elasticsearch:9200"],
- "http_auth": ("elastic", getenv("ELASTIC_PASSWORD")), # noqa: F405
+ "http_auth": ("elastic", getenv("ELASTIC_PASSWORD")),
"verify_certs": False,
"timeout": 30,
"ssl_show_warn": False,
@@ -12,6 +14,6 @@ ELASTICSEARCH_DSL = {
},
}
-ELASTICSEARCH_DSL_AUTOSYNC = DEBUG # noqa: F405
+ELASTICSEARCH_DSL_AUTOSYNC = DEBUG
ELASTICSEARCH_DSL_PARALLEL = True
ELASTICSEARCH_DSL_SIGNAL_PROCESSOR = "django_elasticsearch_dsl.signals.CelerySignalProcessor"
diff --git a/evibes/settings/emailing.py b/evibes/settings/emailing.py
index c2eccc79..82dbcd65 100644
--- a/evibes/settings/emailing.py
+++ b/evibes/settings/emailing.py
@@ -1,9 +1,9 @@
from evibes.settings import CONSTANCE_CONFIG
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
-EMAIL_HOST = CONSTANCE_CONFIG.get("EMAIL_HOST")[0] # type: ignore
-EMAIL_PORT = CONSTANCE_CONFIG.get("EMAIL_PORT")[0] # type: ignore
-EMAIL_USE_TLS = CONSTANCE_CONFIG.get("EMAIL_USE_TLS")[0] # type: ignore
-EMAIL_USE_SSL = CONSTANCE_CONFIG.get("EMAIL_USE_SSL")[0] # type: ignore
-EMAIL_HOST_USER = CONSTANCE_CONFIG.get("EMAIL_HOST_USER")[0] # type: ignore
-EMAIL_HOST_PASSWORD = CONSTANCE_CONFIG.get("EMAIL_HOST_PASSWORD")[0] # type: ignore
+EMAIL_HOST = CONSTANCE_CONFIG.get("EMAIL_HOST")[0] # type: ignore [index]
+EMAIL_PORT = CONSTANCE_CONFIG.get("EMAIL_PORT")[0] # type: ignore [index]
+EMAIL_USE_TLS = CONSTANCE_CONFIG.get("EMAIL_USE_TLS")[0] # type: ignore [index]
+EMAIL_USE_SSL = CONSTANCE_CONFIG.get("EMAIL_USE_SSL")[0] # type: ignore [index]
+EMAIL_HOST_USER = CONSTANCE_CONFIG.get("EMAIL_HOST_USER")[0] # type: ignore [index]
+EMAIL_HOST_PASSWORD = CONSTANCE_CONFIG.get("EMAIL_HOST_PASSWORD")[0] # type: ignore [index]
diff --git a/evibes/settings/extensions.py b/evibes/settings/extensions.py
index 44adc7b2..eed9c571 100644
--- a/evibes/settings/extensions.py
+++ b/evibes/settings/extensions.py
@@ -1,6 +1,12 @@
+# noinspection PyUnresolvedReferences
+from evibes.settings.base import * # noqa: F403
+
GRAPH_MODELS = {
"all_applications": True,
"group_models": True,
}
EXTENSIONS_MAX_UNIQUE_QUERY_ATTEMPTS = 500
+
+HEALTHCHECK_CELERY_RESULT_TIMEOUT = 5
+HEALTHCHECK_CELERY_QUEUE_TIMEOUT = 5
diff --git a/evibes/settings/graphene.py b/evibes/settings/graphene.py
index 376a410c..e46bd3e7 100644
--- a/evibes/settings/graphene.py
+++ b/evibes/settings/graphene.py
@@ -1,11 +1,11 @@
-from evibes.settings.base import * # noqa: F403
+from evibes.settings.base import DEBUG
GRAPHENE = {
"MIDDLEWARE": [
"evibes.middleware.GrapheneLoggingErrorsDebugMiddleware",
"evibes.middleware.GrapheneJWTAuthorizationMiddleware",
]
- if DEBUG # noqa: F405
+ if DEBUG
else [
"evibes.middleware.GrapheneJWTAuthorizationMiddleware",
],
diff --git a/evibes/settings/jazzmin.py b/evibes/settings/jazzmin.py
new file mode 100644
index 00000000..a15ceb1e
--- /dev/null
+++ b/evibes/settings/jazzmin.py
@@ -0,0 +1,63 @@
+from django.utils.translation import gettext_lazy as _
+
+from evibes.settings.base import EVIBES_VERSION
+from evibes.settings.constance import CONSTANCE_CONFIG
+
+JAZZMIN_SETTINGS = {
+ "site_title": f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]} Admin", # type: ignore [index]
+ "site_header": str(CONSTANCE_CONFIG.get("PROJECT_NAME")[0]), # type: ignore [index]
+ "site_brand": str(CONSTANCE_CONFIG.get("PROJECT_NAME")[0]), # type: ignore [index]
+ "site_logo": "logo.png",
+ "login_logo": "logo.png",
+ "login_logo_dark": "logo.png",
+ "site_logo_classes": "",
+ "site_icon": "favicon.ico",
+ "welcome_sign": "Whoa! Only admins allowed here!",
+ "copyright": f"eVibes {EVIBES_VERSION} by Wiseless",
+ "search_model": None,
+ "user_avatar": "avatar",
+ "topmenu_links": [
+ {"name": _("Home"), "url": "admin:index"},
+ {"name": _("Storefront"), "url": f"https://{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}", "new_window": True}, # type: ignore [index]
+ {"name": "GitLab", "url": "https://gitlab.com/wiseless/evibes", "new_window": True},
+ {
+ "name": _("GraphQL Docs"),
+ "url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/graphql", # type: ignore [index]
+ "new_window": True,
+ },
+ {
+ "name": _("Platform REST Docs"),
+ "url": f"https://api.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/docs/swagger", # type: ignore [index]
+ "new_window": True,
+ },
+ {
+ "name": _("B2B REST Docs"),
+ "url": f"https://b2b.{CONSTANCE_CONFIG.get('BASE_DOMAIN')[0]}/docs/swagger", # type: ignore [index]
+ "new_window": True,
+ },
+ {"name": _("Support"), "url": "https://t.me/fureunoir", "new_window": True},
+ ],
+ "usermenu_links": [],
+ "show_sidebar": True,
+ "navigation_expanded": True,
+ "hide_apps": ["django_celery_results", ""],
+ "hide_models": [],
+ "order_with_respect_to": ["vibes_auth", "core", "payments", "blog"],
+ "icons": {
+ "auth": "fas fa-users-cog",
+ "auth.user": "fas fa-user",
+ "auth.Group": "fas fa-users",
+ },
+ "default_icon_parents": "fas fa-chevron-circle-right",
+ "default_icon_children": "fas fa-circle",
+ "related_modal_active": False,
+ "use_google_fonts_cdn": True,
+ "show_ui_builder": True,
+ "changeform_format": "horizontal_tabs",
+ "language_chooser": True,
+}
+
+JAZZMIN_UI_TWEAKS = {
+ "theme": "cyborg",
+ "dark_mode_theme": "cyborg",
+}
diff --git a/evibes/settings/logconfig.py b/evibes/settings/logconfig.py
index 2168802b..7505042f 100644
--- a/evibes/settings/logconfig.py
+++ b/evibes/settings/logconfig.py
@@ -1,4 +1,22 @@
-from evibes.settings.base import * # noqa: F403
+import logging
+
+from evibes.settings.base import DEBUG
+
+
+class SkipVariableDoesNotExistFilter(logging.Filter):
+ def filter(self, record: logging.LogRecord) -> bool:
+ if record.exc_info:
+ exc_type, exc_instance, _ = record.exc_info
+ try:
+ if exc_type is not None:
+ if exc_type.__name__ == "VariableDoesNotExist":
+ return False
+ else:
+ return True
+ except AttributeError:
+ return True
+ return "VariableDoesNotExist" not in record.getMessage()
+
LOGGING = {
"version": 1,
@@ -22,67 +40,96 @@ LOGGING = {
},
},
"filters": {
+ "require_debug_false": {
+ "()": "django.utils.log.RequireDebugFalse",
+ },
"require_debug_true": {
"()": "django.utils.log.RequireDebugTrue",
},
+ "skip_variable_doesnotexist": {
+ "()": "evibes.settings.logconfig.SkipVariableDoesNotExistFilter",
+ },
},
"handlers": {
- "console_debug": {
- "level": "DEBUG",
- "filters": ["require_debug_true"],
- "class": "logging.StreamHandler",
- "formatter": "color",
- },
- "console_production": {
- "level": "WARNING",
+ "console": {
"class": "logging.StreamHandler",
"formatter": "color",
},
"mail_admins": {
"level": "ERROR",
+ "filters": ["require_debug_false"],
"class": "django.utils.log.AdminEmailHandler",
- "include_html": True,
- "formatter": "plain",
},
},
"loggers": {
"django": {
- "handlers": ["console_debug", "console_production"],
- "level": "DEBUG" if DEBUG else "INFO", # noqa: F405
+ "handlers": [
+ "console",
+ "mail_admins",
+ ],
+ "level": "DEBUG" if DEBUG else "INFO",
"propagate": True,
},
- "django.request": {
- "handlers": ["console_debug", "mail_admins"],
- "level": "DEBUG" if DEBUG else "INFO", # noqa: F405
+ "django.server": {
+ "level": "INFO",
"propagate": False,
},
"django.db.backends": {
- "handlers": ["console_debug" if DEBUG else "console_production"], # noqa: F405
+ "handlers": [
+ "console",
+ "mail_admins",
+ ],
"level": "WARNING",
"propagate": False,
},
- "core": {
- "handlers": ["console_debug" if DEBUG else "console_production"], # noqa: F405
- "level": "DEBUG" if DEBUG else "WARNING", # noqa: F405
+ "django.template": {
+ "handlers": [
+ "console",
+ "mail_admins",
+ ],
+ "level": "DEBUG" if DEBUG else "ERROR",
"propagate": True,
+ "filters": ["skip_variable_doesnotexist"],
+ },
+ "gunicorn.access": {
+ "handlers": [
+ "console",
+ ],
+ "level": "DEBUG" if DEBUG else "INFO",
+ "propagate": False,
+ },
+ "gunicorn.error": {
+ "handlers": [
+ "console",
+ ],
+ "level": "WARNING",
+ "propagate": False,
},
"django_elasticsearch_dsl": {
- "handlers": ["console_debug" if DEBUG else "console_production"], # noqa: F405
+ "handlers": [
+ "console",
+ ],
"level": "WARNING",
"propagate": False,
},
"celery.app.trace": {
- "handlers": ["console_debug" if DEBUG else "console_production"], # noqa: F405
- "level": "DEBUG" if DEBUG else "INFO", # noqa: F405
+ "handlers": [
+ "console",
+ ],
+ "level": "DEBUG" if DEBUG else "INFO",
"propagate": False,
},
"celery.worker.strategy": {
- "handlers": ["console_debug" if DEBUG else "console_production"], # noqa: F405
- "level": "DEBUG" if DEBUG else "INFO", # noqa: F405
+ "handlers": [
+ "console",
+ ],
+ "level": "DEBUG" if DEBUG else "INFO",
"propagate": False,
},
"elastic_transport.transport": {
- "handlers": ["console_debug" if DEBUG else "console_production"], # noqa: F405
+ "handlers": [
+ "console",
+ ],
"level": "ERROR",
"propagate": False,
},
diff --git a/evibes/utils/__init__.py b/evibes/utils/__init__.py
index 603e85df..d72283bc 100644
--- a/evibes/utils/__init__.py
+++ b/evibes/utils/__init__.py
@@ -34,5 +34,5 @@ def evibes_summernote_upload_to_func(instance, filename: str) -> str:
filename = f"{uuid.uuid4()}.{ext}"
today = datetime.now().strftime("%Y-%m-%d")
if instance:
- return os.path.join('evibes-summernote', today, filename)
- return os.path.join('evibes-summernote', today)
+ return os.path.join("evibes-summernote", today, filename)
+ return os.path.join("evibes-summernote", today)
diff --git a/payments/admin.py b/payments/admin.py
index 9de87f4b..d53f51b8 100644
--- a/payments/admin.py
+++ b/payments/admin.py
@@ -1,8 +1,8 @@
-# noinspection PyUnresolvedReferences
from django.contrib import admin
+from django.contrib.admin import ModelAdmin, register
from django.utils.translation import gettext_lazy as _
-from core.admin import BasicModelAdmin
+from core.admin import ActivationActionsMixin
from payments.forms import TransactionForm
from payments.models import Balance, Transaction
@@ -20,7 +20,8 @@ class TransactionInline(admin.TabularInline):
return qs.select_related("order")
-class BalanceAdmin(BasicModelAdmin):
+@register(Balance)
+class BalanceAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
inlines = (TransactionInline,)
list_display = ("user", "amount")
search_fields = ("user__email",)
@@ -31,13 +32,10 @@ class BalanceAdmin(BasicModelAdmin):
return qs.prefetch_related("transactions", "user")
-class TransactionAdmin(BasicModelAdmin):
- list_display = ("balance", "amount", "currency", "payment_method", "order")
+@register(Transaction)
+class TransactionAdmin(ActivationActionsMixin, ModelAdmin): # type: ignore [misc]
+ list_display = ("balance", "amount", "order", "modified", "created")
search_fields = ("balance__user__email", "currency", "payment_method")
list_filter = ("currency", "payment_method")
ordering = ("balance",)
form = TransactionForm
-
-
-admin.site.register(Balance, BalanceAdmin)
-admin.site.register(Transaction, TransactionAdmin)
diff --git a/payments/graphene/object_types.py b/payments/graphene/object_types.py
index 69d59408..c39091a3 100644
--- a/payments/graphene/object_types.py
+++ b/payments/graphene/object_types.py
@@ -11,8 +11,9 @@ class TransactionType(DjangoObjectType):
process = GenericScalar()
def resolve_process(self: Transaction, info) -> dict:
- if info.context.user == self.balance.user:
- return self.process
+ if self.balance is not None:
+ if info.context.user == self.balance.user:
+ return self.process
return {}
class Meta:
diff --git a/payments/locale/ar_AR/LC_MESSAGES/django.mo b/payments/locale/ar_AR/LC_MESSAGES/django.mo
index f4ff31c0..fc2d8807 100644
Binary files a/payments/locale/ar_AR/LC_MESSAGES/django.mo and b/payments/locale/ar_AR/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/ar_AR/LC_MESSAGES/django.po b/payments/locale/ar_AR/LC_MESSAGES/django.po
index 5a8dfcc9..736fd372 100644
--- a/payments/locale/ar_AR/LC_MESSAGES/django.po
+++ b/payments/locale/ar_AR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "المعاملات"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "المعاملات"
@@ -41,15 +41,15 @@ msgstr "الإيداع في الرصيد"
msgid "deposit some money to balance"
msgstr "إيداع بعض الأموال لتحقيق التوازن"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "طلب المعالجة بعد الدفع"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "تفاصيل المعالجة"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"يجب أن يتناسب مبلغ المعاملة مع "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "الرصيد"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "الموازين"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "إيداع الرصيد"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "الشعار"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "مرحباً %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"لقد نجحنا في إيداع رصيد حسابك في %(amount)s. رصيدك الحالي\n"
" رصيدك الحالي هو %(balance)s__."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"إذا كان لديك أي أسئلة، فلا تتردد في الاتصال بدعمنا على\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "مع أطيب تحياتي،
فريق%(project_name)s"
+msgstr "مع أطيب تحياتي،
فريق %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "جميع الحقوق محفوظة"
@@ -114,9 +114,9 @@ msgstr "مطلوب مزود للحصول على الأسعار من"
#: payments/utils/__init__.py:15
#, python-brace-format
msgid "couldn't find provider {provider}"
-msgstr "تعذّر العثور على الموفر {provider}"
+msgstr "تعذر العثور على مزود {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | إيداع الرصيد"
diff --git a/payments/locale/cs_CZ/LC_MESSAGES/django.mo b/payments/locale/cs_CZ/LC_MESSAGES/django.mo
index 56456447..32cd1d95 100644
Binary files a/payments/locale/cs_CZ/LC_MESSAGES/django.mo and b/payments/locale/cs_CZ/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/cs_CZ/LC_MESSAGES/django.po b/payments/locale/cs_CZ/LC_MESSAGES/django.po
index e7ed0f46..7cb81ebe 100644
--- a/payments/locale/cs_CZ/LC_MESSAGES/django.po
+++ b/payments/locale/cs_CZ/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transakce"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transakce"
@@ -41,15 +41,15 @@ msgstr "Vklad do zůstatku"
msgid "deposit some money to balance"
msgstr "Vložte nějaké peníze na účet"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Objednávka ke zpracování po zaplacení"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Podrobnosti o zpracování"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Částka transakce se musí vejít do rozmezí "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}."
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Bilance"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Váhy"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Zůstatková záloha"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Ahoj %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Na váš účet jsme úspěšně připsali %(amount)s. Váš aktuální\n"
" je %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Pokud máte jakékoli dotazy, neváhejte kontaktovat naši podporu na adrese\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "S pozdravem,
tým %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Všechna práva vyhrazena"
@@ -116,7 +116,7 @@ msgstr "Je třeba mít poskytovatele, od kterého lze získat sazby"
msgid "couldn't find provider {provider}"
msgstr "Nepodařilo se najít poskytovatele {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Zůstatek vkladu"
diff --git a/payments/locale/da_DK/LC_MESSAGES/django.mo b/payments/locale/da_DK/LC_MESSAGES/django.mo
index a6f7f29b..e7504b30 100644
Binary files a/payments/locale/da_DK/LC_MESSAGES/django.mo and b/payments/locale/da_DK/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/da_DK/LC_MESSAGES/django.po b/payments/locale/da_DK/LC_MESSAGES/django.po
index b57ddfa8..0bb3bc3c 100644
--- a/payments/locale/da_DK/LC_MESSAGES/django.po
+++ b/payments/locale/da_DK/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transaktion"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transaktioner"
@@ -41,15 +41,15 @@ msgstr "Indbetaling til saldo"
msgid "deposit some money to balance"
msgstr "Sæt nogle penge ind på saldoen"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Ordre til behandling efter betaling"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Behandling af detaljer"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Transaktionsbeløbet skal passe ind i "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}."
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Balance"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Vægte"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Saldoindbetaling"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hej %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Vi har krediteret din konto med %(amount)s. Din nuværende\n"
" saldo er %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Hvis du har spørgsmål, er du velkommen til at kontakte vores support på\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Med venlig hilsen,
teamet %(project_name)s."
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Alle rettigheder forbeholdes"
@@ -114,9 +114,9 @@ msgstr "Der er brug for en udbyder at få priser fra"
#: payments/utils/__init__.py:15
#, python-brace-format
msgid "couldn't find provider {provider}"
-msgstr "Kunne ikke finde udbyder {provider}"
+msgstr "Kunne ikke finde udbyder {provider}."
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Saldoindbetaling"
diff --git a/payments/locale/de_DE/LC_MESSAGES/django.mo b/payments/locale/de_DE/LC_MESSAGES/django.mo
index 60228123..b2262d8f 100644
Binary files a/payments/locale/de_DE/LC_MESSAGES/django.mo and b/payments/locale/de_DE/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/de_DE/LC_MESSAGES/django.po b/payments/locale/de_DE/LC_MESSAGES/django.po
index 15de2683..a8c78ad8 100644
--- a/payments/locale/de_DE/LC_MESSAGES/django.po
+++ b/payments/locale/de_DE/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transaktion"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transaktionen"
@@ -41,15 +41,15 @@ msgstr "Einzahlung auf den Saldo"
msgid "deposit some money to balance"
msgstr "Einzahlung von Geld zum Ausgleich"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Auftrag zur Bearbeitung nach Bezahlung"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Details zur Verarbeitung"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Der Transaktionsbetrag muss zwischen "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM} liegen"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Waage"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Waagen"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Balance Deposit"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hallo %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Wir haben Ihrem Konto erfolgreich %(amount)s gutgeschrieben. Ihr aktuelles\n"
" Saldo beträgt %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Wenn Sie Fragen haben, wenden Sie sich bitte an unseren Support unter\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Mit freundlichen Grüßen,
das %(project_name)s-Team"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Alle Rechte vorbehalten"
@@ -116,7 +116,7 @@ msgstr "Sie benötigen einen Anbieter, bei dem Sie die Preise erfragen können."
msgid "couldn't find provider {provider}"
msgstr "Anbieter {provider} konnte nicht gefunden werden"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Saldo Einzahlung"
diff --git a/payments/locale/en_GB/LC_MESSAGES/django.mo b/payments/locale/en_GB/LC_MESSAGES/django.mo
index 00eb93a4..c40f51f0 100644
Binary files a/payments/locale/en_GB/LC_MESSAGES/django.mo and b/payments/locale/en_GB/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/en_GB/LC_MESSAGES/django.po b/payments/locale/en_GB/LC_MESSAGES/django.po
index c6bb4455..2268b1e3 100644
--- a/payments/locale/en_GB/LC_MESSAGES/django.po
+++ b/payments/locale/en_GB/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -17,11 +17,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transaction"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transactions"
@@ -45,46 +45,46 @@ msgstr "Deposit to balance"
msgid "deposit some money to balance"
msgstr "Deposit some money to balance"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Order to process after paid"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Processing details"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
-"transaction amount must fit into {config.PAYMENT_GATEWAY_MINIMUM}-{config."
-"PAYMENT_GATEWAY_MAXIMUM}"
+"transaction amount must fit into "
+"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
msgstr ""
-"Transaction amount must fit into {config.PAYMENT_GATEWAY_MINIMUM}-{config."
-"PAYMENT_GATEWAY_MAXIMUM}"
+"Transaction amount must fit into "
+"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Balance"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Balances"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Balance Deposit"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hello %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -93,7 +93,7 @@ msgstr ""
"We have successfully credited your account with %(amount)s. Your current\n"
" balance is %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -102,12 +102,12 @@ msgstr ""
"If you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Best regards,
the %(project_name)s team"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "All rights reserved"
@@ -120,7 +120,7 @@ msgstr "A provider to get rates from is required"
msgid "couldn't find provider {provider}"
msgstr "Couldn't find provider {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Balance Deposit"
diff --git a/payments/locale/en_US/LC_MESSAGES/django.mo b/payments/locale/en_US/LC_MESSAGES/django.mo
index b5d49a6e..caeca9cb 100644
Binary files a/payments/locale/en_US/LC_MESSAGES/django.mo and b/payments/locale/en_US/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/en_US/LC_MESSAGES/django.po b/payments/locale/en_US/LC_MESSAGES/django.po
index f6465785..4afec807 100644
--- a/payments/locale/en_US/LC_MESSAGES/django.po
+++ b/payments/locale/en_US/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transaction"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transactions"
@@ -41,15 +41,15 @@ msgstr "Deposit to balance"
msgid "deposit some money to balance"
msgstr "Deposit some money to balance"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Order to process after paid"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Processing details"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Transaction amount must fit into "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Balance"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Scales"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Balance Deposit"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hello %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"We have successfully credited your account with %(amount)s. Your current\n"
" balance is %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"If you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Best regards,
the %(project_name)s team"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "All rights reserved"
@@ -116,7 +116,7 @@ msgstr "A provider to get rates from is required"
msgid "couldn't find provider {provider}"
msgstr "Couldn't find provider {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Balance Deposit"
diff --git a/payments/locale/es_ES/LC_MESSAGES/django.mo b/payments/locale/es_ES/LC_MESSAGES/django.mo
index 7829282b..8d3f7a8a 100644
Binary files a/payments/locale/es_ES/LC_MESSAGES/django.mo and b/payments/locale/es_ES/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/es_ES/LC_MESSAGES/django.po b/payments/locale/es_ES/LC_MESSAGES/django.po
index 1de2abb2..22e9be2d 100644
--- a/payments/locale/es_ES/LC_MESSAGES/django.po
+++ b/payments/locale/es_ES/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transacción"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transacciones"
@@ -41,15 +41,15 @@ msgstr "Depósito a cuenta"
msgid "deposit some money to balance"
msgstr "Depositar dinero para equilibrar"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Orden a tramitar una vez pagada"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Detalles del proceso"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"El importe de la transacción debe ajustarse a "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Saldo"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Escalas"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Depósito de saldo"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logotipo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hola %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Hemos ingresado correctamente %(amount)s en su cuenta. Su saldo\n"
" actual es de %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Si tiene alguna pregunta, no dude en ponerse en contacto con nuestro servicio de asistencia en\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Saludos cordiales,
el equipo %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Todos los derechos reservados"
@@ -114,9 +114,9 @@ msgstr "Se necesita un proveedor del que obtener tarifas"
#: payments/utils/__init__.py:15
#, python-brace-format
msgid "couldn't find provider {provider}"
-msgstr "No se ha podido encontrar el proveedor {provider}"
+msgstr "No se pudo encontrar el proveedor {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Depósito de saldo"
diff --git a/payments/locale/fr_FR/LC_MESSAGES/django.mo b/payments/locale/fr_FR/LC_MESSAGES/django.mo
index d8d54560..b154dd0c 100644
Binary files a/payments/locale/fr_FR/LC_MESSAGES/django.mo and b/payments/locale/fr_FR/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/fr_FR/LC_MESSAGES/django.po b/payments/locale/fr_FR/LC_MESSAGES/django.po
index 2319678c..faafb50b 100644
--- a/payments/locale/fr_FR/LC_MESSAGES/django.po
+++ b/payments/locale/fr_FR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transaction"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transactions"
@@ -41,15 +41,15 @@ msgstr "Dépôt au solde"
msgid "deposit some money to balance"
msgstr "Déposer de l'argent sur le compte"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Commande à traiter après paiement"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Détails du traitement"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Le montant de la transaction doit être compris entre "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}."
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Balance"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Balances"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Balance Deposit"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Bonjour %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Nous avons crédité votre compte de %(amount)s. Votre solde\n"
" est de %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Si vous avez des questions, n'hésitez pas à contacter notre service d'assistance à l'adresse suivante\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Meilleures salutations,
l'équipe %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Tous droits réservés"
@@ -117,7 +117,7 @@ msgstr ""
msgid "couldn't find provider {provider}"
msgstr "Impossible de trouver le fournisseur {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Dépôt de solde"
diff --git a/payments/locale/hi_IN/LC_MESSAGES/django.mo b/payments/locale/hi_IN/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/payments/locale/hi_IN/LC_MESSAGES/django.mo and b/payments/locale/hi_IN/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/hi_IN/LC_MESSAGES/django.po b/payments/locale/hi_IN/LC_MESSAGES/django.po
index c93e735e..879b9332 100644
--- a/payments/locale/hi_IN/LC_MESSAGES/django.po
+++ b/payments/locale/hi_IN/LC_MESSAGES/django.po
@@ -2,12 +2,12 @@
# Copyright (C) 2025 EGOR GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV , 2025.
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:40+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -16,11 +16,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr ""
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr ""
@@ -44,63 +44,63 @@ msgstr ""
msgid "deposit some money to balance"
msgstr ""
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr ""
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr ""
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into {config.PAYMENT_GATEWAY_MINIMUM}-{config."
"PAYMENT_GATEWAY_MAXIMUM}"
msgstr ""
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr ""
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr ""
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr ""
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr ""
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr ""
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
" balance is %(balance)s."
msgstr ""
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
msgstr ""
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr ""
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr ""
@@ -113,7 +113,7 @@ msgstr ""
msgid "couldn't find provider {provider}"
msgstr ""
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr ""
diff --git a/payments/locale/it_IT/LC_MESSAGES/django.mo b/payments/locale/it_IT/LC_MESSAGES/django.mo
index 021e8f7b..06bc4086 100644
Binary files a/payments/locale/it_IT/LC_MESSAGES/django.mo and b/payments/locale/it_IT/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/it_IT/LC_MESSAGES/django.po b/payments/locale/it_IT/LC_MESSAGES/django.po
index 50d12ae9..f3998be7 100644
--- a/payments/locale/it_IT/LC_MESSAGES/django.po
+++ b/payments/locale/it_IT/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transazione"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transazioni"
@@ -41,15 +41,15 @@ msgstr "Deposito a saldo"
msgid "deposit some money to balance"
msgstr "Depositare del denaro per bilanciare"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Ordine da elaborare dopo il pagamento"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Dettagli di elaborazione"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"L'importo della transazione deve rientrare in "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Equilibrio"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Bilance"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Saldo Deposito"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hello %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Abbiamo accreditato il vostro conto con %(amount)s. Il suo saldo attuale\n"
" saldo è %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"In caso di domande, non esitate a contattare il nostro supporto all'indirizzo\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Cordiali saluti,
il team %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Tutti i diritti riservati"
@@ -116,7 +116,7 @@ msgstr "È necessario un fornitore da cui ottenere le tariffe"
msgid "couldn't find provider {provider}"
msgstr "Impossibile trovare il fornitore {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Deposito a saldo"
diff --git a/payments/locale/ja_JP/LC_MESSAGES/django.mo b/payments/locale/ja_JP/LC_MESSAGES/django.mo
index e37cf94c..595b2e3e 100644
Binary files a/payments/locale/ja_JP/LC_MESSAGES/django.mo and b/payments/locale/ja_JP/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/ja_JP/LC_MESSAGES/django.po b/payments/locale/ja_JP/LC_MESSAGES/django.po
index 4c8d5b7d..8eecbd21 100644
--- a/payments/locale/ja_JP/LC_MESSAGES/django.po
+++ b/payments/locale/ja_JP/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "トランザクション"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "トランザクション"
@@ -41,15 +41,15 @@ msgstr "預金残高"
msgid "deposit some money to balance"
msgstr "預金残高を増やす"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "支払い後の処理順序"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "加工内容"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -57,29 +57,29 @@ msgid ""
msgstr ""
"取引金額は{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}に収まる必要があります。"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "バランス"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "体重計"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "預金残高"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "ロゴ"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "こんにちは%(user_first_name)s、"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -88,7 +88,7 @@ msgstr ""
"お客様の口座に%(amount)sが入金されました。あなたの現在の\n"
" 現在の残高は%(balance)sです。"
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -97,12 +97,12 @@ msgstr ""
"ご不明な点がございましたら、お気軽に下記までお問い合わせください。\n"
" %(contact_email)s。"
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "よろしくお願いします、
%(project_name)sチーム"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "無断複写・転載を禁じます。"
@@ -113,9 +113,9 @@ msgstr "レートを取得するプロバイダーが必要"
#: payments/utils/__init__.py:15
#, python-brace-format
msgid "couldn't find provider {provider}"
-msgstr "{provider}プロバイダーが見つかりません。"
+msgstr "プロバイダーが見つかりませんでした {provider} 。"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME}| 預金残高"
diff --git a/payments/locale/kk_KZ/LC_MESSAGES/django.mo b/payments/locale/kk_KZ/LC_MESSAGES/django.mo
index 0fc354f2..47c1f925 100644
Binary files a/payments/locale/kk_KZ/LC_MESSAGES/django.mo and b/payments/locale/kk_KZ/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/kk_KZ/LC_MESSAGES/django.po b/payments/locale/kk_KZ/LC_MESSAGES/django.po
index c93e735e..879b9332 100644
--- a/payments/locale/kk_KZ/LC_MESSAGES/django.po
+++ b/payments/locale/kk_KZ/LC_MESSAGES/django.po
@@ -2,12 +2,12 @@
# Copyright (C) 2025 EGOR GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV , 2025.
-#
+#
msgid ""
msgstr ""
-"Project-Id-Version: EVIBES 2.8.10\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:40+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: LANGUAGE \n"
@@ -16,11 +16,11 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr ""
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr ""
@@ -44,63 +44,63 @@ msgstr ""
msgid "deposit some money to balance"
msgstr ""
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr ""
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr ""
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into {config.PAYMENT_GATEWAY_MINIMUM}-{config."
"PAYMENT_GATEWAY_MAXIMUM}"
msgstr ""
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr ""
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr ""
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr ""
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr ""
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr ""
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
" balance is %(balance)s."
msgstr ""
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
" %(contact_email)s."
msgstr ""
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr ""
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr ""
@@ -113,7 +113,7 @@ msgstr ""
msgid "couldn't find provider {provider}"
msgstr ""
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr ""
diff --git a/payments/locale/nl_NL/LC_MESSAGES/django.mo b/payments/locale/nl_NL/LC_MESSAGES/django.mo
index 660b9a17..9788cbe8 100644
Binary files a/payments/locale/nl_NL/LC_MESSAGES/django.mo and b/payments/locale/nl_NL/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/nl_NL/LC_MESSAGES/django.po b/payments/locale/nl_NL/LC_MESSAGES/django.po
index 76999271..b047c098 100644
--- a/payments/locale/nl_NL/LC_MESSAGES/django.po
+++ b/payments/locale/nl_NL/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transactie"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transacties"
@@ -41,15 +41,15 @@ msgstr "Storting op saldo"
msgid "deposit some money to balance"
msgstr "Stort wat geld om te balanceren"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Order te verwerken na betaling"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Verwerkingsdetails"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Het transactiebedrag moet passen binnen "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}."
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Saldo"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Weegschaal"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Saldo Storting"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Hallo %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"We hebben uw rekening succesvol gecrediteerd met %(amount)s. Uw huidige\n"
" saldo is %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Als u vragen hebt, kunt u contact opnemen met onze klantenservice op\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Vriendelijke groeten,
het %(project_name)s team"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Alle rechten voorbehouden"
@@ -114,9 +114,9 @@ msgstr "Een provider om tarieven van te krijgen is vereist"
#: payments/utils/__init__.py:15
#, python-brace-format
msgid "couldn't find provider {provider}"
-msgstr "Kon provider {provider} niet vinden"
+msgstr "Kon provider {provider} niet vinden."
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Saldo storting"
diff --git a/payments/locale/pl_PL/LC_MESSAGES/django.mo b/payments/locale/pl_PL/LC_MESSAGES/django.mo
index 6134527e..0e386c06 100644
Binary files a/payments/locale/pl_PL/LC_MESSAGES/django.mo and b/payments/locale/pl_PL/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/pl_PL/LC_MESSAGES/django.po b/payments/locale/pl_PL/LC_MESSAGES/django.po
index 3e8005d4..f59fb8fd 100644
--- a/payments/locale/pl_PL/LC_MESSAGES/django.po
+++ b/payments/locale/pl_PL/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transakcja"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transakcje"
@@ -41,15 +41,15 @@ msgstr "Wpłata na saldo"
msgid "deposit some money to balance"
msgstr "Wpłać trochę pieniędzy na saldo"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Zamówienie do przetworzenia po opłaceniu"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Szczegóły przetwarzania"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Kwota transakcji musi mieścić się w przedziale "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}."
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Równowaga"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Wagi"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Saldo depozytu"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Witaj %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Twoje konto zostało pomyślnie zasilone kwotą %(amount)s. Aktualne\n"
" wynosi %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Jeśli masz jakiekolwiek pytania, skontaktuj się z naszym działem pomocy technicznej pod adresem\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Najlepsze pozdrowienia,
zespół %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Wszelkie prawa zastrzeżone"
@@ -114,9 +114,9 @@ msgstr "Wymagany jest dostawca, od którego można uzyskać stawki"
#: payments/utils/__init__.py:15
#, python-brace-format
msgid "couldn't find provider {provider}"
-msgstr "Nie można znaleźć dostawcy {provider}."
+msgstr "Nie można znaleźć dostawcy {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Wpłata salda"
diff --git a/payments/locale/pt_BR/LC_MESSAGES/django.mo b/payments/locale/pt_BR/LC_MESSAGES/django.mo
index a4c815ff..6ec393d6 100644
Binary files a/payments/locale/pt_BR/LC_MESSAGES/django.mo and b/payments/locale/pt_BR/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/pt_BR/LC_MESSAGES/django.po b/payments/locale/pt_BR/LC_MESSAGES/django.po
index 9ca89ceb..9a078627 100644
--- a/payments/locale/pt_BR/LC_MESSAGES/django.po
+++ b/payments/locale/pt_BR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Transação"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Transações"
@@ -41,15 +41,15 @@ msgstr "Depósito no saldo"
msgid "deposit some money to balance"
msgstr "Depositar algum dinheiro no saldo"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Ordem a ser processada após o pagamento"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Detalhes do processamento"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"O valor da transação deve se enquadrar em "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Equilíbrio"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Balanças"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Depósito de saldo"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logotipo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Olá %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Creditamos sua conta com %(amount)s com sucesso. Seu saldo atual\n"
" saldo atual é %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Se tiver alguma dúvida, entre em contato com o nosso suporte em\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Atenciosamente,
a equipe %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Todos os direitos reservados"
@@ -116,7 +116,7 @@ msgstr "É necessário um provedor para obter as tarifas"
msgid "couldn't find provider {provider}"
msgstr "Não foi possível encontrar o provedor {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Depósito de saldo"
diff --git a/payments/locale/ro_RO/LC_MESSAGES/django.mo b/payments/locale/ro_RO/LC_MESSAGES/django.mo
index c68e1d82..06d0094e 100644
Binary files a/payments/locale/ro_RO/LC_MESSAGES/django.mo and b/payments/locale/ro_RO/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/ro_RO/LC_MESSAGES/django.po b/payments/locale/ro_RO/LC_MESSAGES/django.po
index 6c4601d8..9a98693c 100644
--- a/payments/locale/ro_RO/LC_MESSAGES/django.po
+++ b/payments/locale/ro_RO/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Tranzacție"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Tranzacții"
@@ -41,15 +41,15 @@ msgstr "Depozit la sold"
msgid "deposit some money to balance"
msgstr "Depuneți niște bani la sold"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Ordin de procesare după plată"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Detalii de prelucrare"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Valoarea tranzacției trebuie să se încadreze în "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Echilibru"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "Balanță"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Sold Depozit"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Logo"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Bună ziua %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Am creditat cu succes contul dvs. cu %(amount)s. Soldul dvs. actual\n"
" actual este %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Dacă aveți întrebări, nu ezitați să contactați asistența noastră la\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "Cele mai bune salutări,
echipa %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Toate drepturile rezervate"
@@ -116,7 +116,7 @@ msgstr "Este necesar un furnizor de la care să se obțină tarife"
msgid "couldn't find provider {provider}"
msgstr "Nu am putut găsi furnizorul {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Depozit sold"
diff --git a/payments/locale/ru_RU/LC_MESSAGES/django.mo b/payments/locale/ru_RU/LC_MESSAGES/django.mo
index 19bd0d56..b22307d9 100644
Binary files a/payments/locale/ru_RU/LC_MESSAGES/django.mo and b/payments/locale/ru_RU/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/ru_RU/LC_MESSAGES/django.po b/payments/locale/ru_RU/LC_MESSAGES/django.po
index 57dfa416..ce969f65 100644
--- a/payments/locale/ru_RU/LC_MESSAGES/django.po
+++ b/payments/locale/ru_RU/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "Транзакция"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "Транзакции"
@@ -41,15 +41,15 @@ msgstr "Депозит на баланс"
msgid "deposit some money to balance"
msgstr "Внесите немного денег на баланс"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "Заказ на обработку после оплаты"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "Детали обработки"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"Сумма транзакции должна вписываться в "
"{config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM}"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "Баланс"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
-msgstr "Весы"
+msgstr "Балансы"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "Балансовый депозит"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "Логотип"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "Привет %(user_first_name)s,"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"Мы успешно зачислили на ваш счет %(amount)s. Ваш текущий\n"
" баланс составляет %(balance)s."
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"Если у вас возникнут вопросы, обращайтесь в нашу службу поддержки по адресу\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "С наилучшими пожеланиями,
команда %(project_name)s"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "Все права защищены"
@@ -116,7 +116,7 @@ msgstr "Требуется поставщик, у которого можно п
msgid "couldn't find provider {provider}"
msgstr "Не удалось найти провайдера {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME} | Депозит баланса"
diff --git a/payments/locale/zh_Hans/LC_MESSAGES/django.mo b/payments/locale/zh_Hans/LC_MESSAGES/django.mo
index fc816df9..46df8adf 100644
Binary files a/payments/locale/zh_Hans/LC_MESSAGES/django.mo and b/payments/locale/zh_Hans/LC_MESSAGES/django.mo differ
diff --git a/payments/locale/zh_Hans/LC_MESSAGES/django.po b/payments/locale/zh_Hans/LC_MESSAGES/django.po
index 3f639b94..2c9e8f9e 100644
--- a/payments/locale/zh_Hans/LC_MESSAGES/django.po
+++ b/payments/locale/zh_Hans/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-22 18:07+0100\n"
+"POT-Creation-Date: 2025-07-03 18:33+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -13,11 +13,11 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: payments/admin.py:15 payments/models.py:43
+#: payments/admin.py:15 payments/models.py:41
msgid "transaction"
msgstr "交易"
-#: payments/admin.py:16 payments/models.py:44
+#: payments/admin.py:16 payments/models.py:42
msgid "transactions"
msgstr "交易"
@@ -41,15 +41,15 @@ msgstr "余额存款"
msgid "deposit some money to balance"
msgstr "为余额存入一些钱"
-#: payments/models.py:21
+#: payments/models.py:19
msgid "order to process after paid"
msgstr "付款后处理订单"
-#: payments/models.py:24
+#: payments/models.py:22
msgid "processing details"
msgstr "处理细节"
-#: payments/models.py:39
+#: payments/models.py:37
#, python-brace-format
msgid ""
"transaction amount must fit into "
@@ -58,29 +58,29 @@ msgstr ""
"交易金额必须符合 {config.PAYMENT_GATEWAY_MINIMUM}-{config.PAYMENT_GATEWAY_MAXIMUM} "
"的规定。"
-#: payments/models.py:61
+#: payments/models.py:59
msgid "balance"
msgstr "平衡"
-#: payments/models.py:62
+#: payments/models.py:60
msgid "balances"
msgstr "天平"
-#: payments/templates/balance_deposit_email.html:7
-#: payments/templates/balance_deposit_email.html:100
+#: payments/templates/balance_deposit_email.html:6
+#: payments/templates/balance_deposit_email.html:93
msgid "balance deposit"
msgstr "余额存款"
-#: payments/templates/balance_deposit_email.html:95
+#: payments/templates/balance_deposit_email.html:88
msgid "logo"
msgstr "标志"
-#: payments/templates/balance_deposit_email.html:101
+#: payments/templates/balance_deposit_email.html:94
#, python-format
msgid "hello %(user_first_name)s,"
msgstr "你好%(user_first_name)s_、"
-#: payments/templates/balance_deposit_email.html:102
+#: payments/templates/balance_deposit_email.html:95
#, python-format
msgid ""
"we have successfully credited your account with %(amount)s. your current\n"
@@ -89,7 +89,7 @@ msgstr ""
"我们已成功地将 %(amount)s_记入您的账户。您目前的\n"
" 余额为%(balance)s_。"
-#: payments/templates/balance_deposit_email.html:105
+#: payments/templates/balance_deposit_email.html:98
#, python-format
msgid ""
"if you have any questions, feel free to contact our support at\n"
@@ -98,12 +98,12 @@ msgstr ""
"如果您有任何问题,请随时通过以下方式联系我们的支持人员\n"
" %(contact_email)s."
-#: payments/templates/balance_deposit_email.html:107
+#: payments/templates/balance_deposit_email.html:100
#, python-format
msgid "best regards,
the %(project_name)s team"
msgstr "致以最诚挚的问候,
%(project_name)s_团队"
-#: payments/templates/balance_deposit_email.html:113
+#: payments/templates/balance_deposit_email.html:106
msgid "all rights reserved"
msgstr "保留所有权利"
@@ -114,9 +114,9 @@ msgstr "需要提供商提供费率"
#: payments/utils/__init__.py:15
#, python-brace-format
msgid "couldn't find provider {provider}"
-msgstr "找不到提供方 {provider}"
+msgstr "找不到提供商 {provider}"
-#: payments/utils/emailing.py:27
+#: payments/utils/emailing.py:31
#, python-brace-format
msgid "{config.PROJECT_NAME} | balance deposit"
msgstr "{config.PROJECT_NAME}| 余额存款"
diff --git a/payments/migrations/0001_initial.py b/payments/migrations/0001_initial.py
index 1dd62ba0..06280b64 100644
--- a/payments/migrations/0001_initial.py
+++ b/payments/migrations/0001_initial.py
@@ -9,55 +9,96 @@ from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
- dependencies = [
- ]
+ dependencies = []
operations = [
migrations.CreateModel(
- name='Balance',
+ name="Balance",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('amount', models.FloatField(default=0)),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ ("amount", models.FloatField(default=0)),
],
options={
- 'verbose_name': 'balance',
- 'verbose_name_plural': 'balances',
+ "verbose_name": "balance",
+ "verbose_name_plural": "balances",
},
),
migrations.CreateModel(
- name='Transaction',
+ name="Transaction",
fields=[
- ('uuid', models.UUIDField(default=uuid.uuid4, editable=False,
- help_text='unique id is used to surely identify any database object',
- primary_key=True, serialize=False, verbose_name='unique id')),
- ('is_active', models.BooleanField(default=True,
- help_text="if set to false, this object can't be seen by users without needed permission",
- verbose_name='is active')),
- ('created', django_extensions.db.fields.CreationDateTimeField(auto_now_add=True,
- help_text='when the object first appeared on the database',
- verbose_name='created')),
- ('modified', django_extensions.db.fields.ModificationDateTimeField(auto_now=True,
- help_text='when the object was last modified',
- verbose_name='modified')),
- ('amount', models.FloatField()),
- ('currency', models.CharField(max_length=3)),
- ('payment_method', models.CharField(max_length=20)),
- ('process', models.JSONField(default=dict, verbose_name='processing details')),
+ (
+ "uuid",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ help_text="unique id is used to surely identify any database object",
+ primary_key=True,
+ serialize=False,
+ verbose_name="unique id",
+ ),
+ ),
+ (
+ "is_active",
+ models.BooleanField(
+ default=True,
+ help_text="if set to false, this object can't be seen by users without needed permission",
+ verbose_name="is active",
+ ),
+ ),
+ (
+ "created",
+ django_extensions.db.fields.CreationDateTimeField(
+ auto_now_add=True,
+ help_text="when the object first appeared on the database",
+ verbose_name="created",
+ ),
+ ),
+ (
+ "modified",
+ django_extensions.db.fields.ModificationDateTimeField(
+ auto_now=True, help_text="when the object was last modified", verbose_name="modified"
+ ),
+ ),
+ ("amount", models.FloatField()),
+ ("currency", models.CharField(max_length=3)),
+ ("payment_method", models.CharField(max_length=20)),
+ ("process", models.JSONField(default=dict, verbose_name="processing details")),
],
options={
- 'verbose_name': 'transaction',
- 'verbose_name_plural': 'transactions',
+ "verbose_name": "transaction",
+ "verbose_name_plural": "transactions",
},
),
]
diff --git a/payments/migrations/0002_initial.py b/payments/migrations/0002_initial.py
index d9618a27..480ec9b6 100644
--- a/payments/migrations/0002_initial.py
+++ b/payments/migrations/0002_initial.py
@@ -10,32 +10,42 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
- ('core', '0002_initial'),
- ('payments', '0001_initial'),
+ ("core", "0002_initial"),
+ ("payments", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
- model_name='balance',
- name='user',
- field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='payments_balance',
- to=settings.AUTH_USER_MODEL, blank=True, null=True),
+ model_name="balance",
+ name="user",
+ field=models.OneToOneField(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="payments_balance",
+ to=settings.AUTH_USER_MODEL,
+ blank=True,
+ null=True,
+ ),
),
migrations.AddField(
- model_name='transaction',
- name='balance',
- field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='payments.balance'),
+ model_name="transaction",
+ name="balance",
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="payments.balance"),
),
migrations.AddField(
- model_name='transaction',
- name='order',
- field=models.ForeignKey(blank=True, help_text='order to process after paid', null=True,
- on_delete=django.db.models.deletion.CASCADE, related_name='payments_transactions',
- to='core.order'),
+ model_name="transaction",
+ name="order",
+ field=models.ForeignKey(
+ blank=True,
+ help_text="order to process after paid",
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="payments_transactions",
+ to="core.order",
+ ),
),
migrations.AddIndex(
- model_name='transaction',
- index=django.contrib.postgres.indexes.GinIndex(fields=['process'], name='payments_tr_process_d5b008_gin'),
+ model_name="transaction",
+ index=django.contrib.postgres.indexes.GinIndex(fields=["process"], name="payments_tr_process_d5b008_gin"),
),
]
diff --git a/payments/migrations/0003_alter_transaction_balance.py b/payments/migrations/0003_alter_transaction_balance.py
index ea6bdece..029e2448 100644
--- a/payments/migrations/0003_alter_transaction_balance.py
+++ b/payments/migrations/0003_alter_transaction_balance.py
@@ -5,15 +5,20 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('payments', '0002_initial'),
+ ("payments", "0002_initial"),
]
operations = [
migrations.AlterField(
- model_name='transaction',
- name='balance',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transactions', to='payments.balance'),
+ model_name="transaction",
+ name="balance",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="transactions",
+ to="payments.balance",
+ ),
),
]
diff --git a/payments/migrations/0004_alter_transaction_payment_method.py b/payments/migrations/0004_alter_transaction_payment_method.py
index 241ecc4a..978c5214 100644
--- a/payments/migrations/0004_alter_transaction_payment_method.py
+++ b/payments/migrations/0004_alter_transaction_payment_method.py
@@ -4,15 +4,14 @@ from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('payments', '0003_alter_transaction_balance'),
+ ("payments", "0003_alter_transaction_balance"),
]
operations = [
migrations.AlterField(
- model_name='transaction',
- name='payment_method',
+ model_name="transaction",
+ name="payment_method",
field=models.CharField(blank=True, max_length=20, null=True),
),
]
diff --git a/payments/models.py b/payments/models.py
index 14eeeaaf..6678715b 100644
--- a/payments/models.py
+++ b/payments/models.py
@@ -7,13 +7,11 @@ from core.abstract import NiceModel
class Transaction(NiceModel):
- amount: float = FloatField(null=False, blank=False) # type: ignore
- balance: "Balance" = ForeignKey(
- "payments.Balance", on_delete=CASCADE, blank=True, null=True, related_name="transactions"
- ) # type: ignore
- currency: str = CharField(max_length=3, null=False, blank=False) # type: ignore
- payment_method: str = CharField(max_length=20, null=True, blank=True) # type: ignore
- order = ForeignKey( # type: ignore
+ amount = FloatField(null=False, blank=False)
+ balance = ForeignKey("payments.Balance", on_delete=CASCADE, blank=True, null=True, related_name="transactions")
+ currency = CharField(max_length=3, null=False, blank=False)
+ payment_method = CharField(max_length=20, null=True, blank=True)
+ order = ForeignKey(
"core.Order",
on_delete=CASCADE,
blank=True,
@@ -21,7 +19,7 @@ class Transaction(NiceModel):
help_text=_("order to process after paid"),
related_name="payments_transactions",
)
- process: dict = JSONField(verbose_name=_("processing details"), default=dict) # type: ignore
+ process = JSONField(verbose_name=_("processing details"), default=dict)
def __str__(self):
return f"{self.balance.user.email} | {self.amount}"
@@ -48,8 +46,8 @@ class Transaction(NiceModel):
class Balance(NiceModel):
- amount: float = FloatField(null=False, blank=False, default=0) # type: ignore
- user = OneToOneField( # type: ignore
+ amount = FloatField(null=False, blank=False, default=0)
+ user = OneToOneField(
to="vibes_auth.User", on_delete=CASCADE, blank=True, null=True, related_name="payments_balance"
)
transactions: QuerySet["Transaction"]
diff --git a/payments/serializers.py b/payments/serializers.py
index 47f953a0..faa92d4c 100644
--- a/payments/serializers.py
+++ b/payments/serializers.py
@@ -19,11 +19,11 @@ class TransactionProcessSerializer(ModelSerializer):
order_hr_id = SerializerMethodField(read_only=True, required=False)
order_uuid = SerializerMethodField(read_only=True, required=False)
- def get_order_hr_id(self, obj: Transaction):
- return obj.order.human_readable_id if obj.order else None # type: ignore
+ def get_order_hr_id(self, obj: Transaction) -> str | None:
+ return obj.order.human_readable_id if obj.order else None
- def get_order_uuid(self, obj: Transaction):
- return obj.order.uuid if obj.order else None # type: ignore
+ def get_order_uuid(self, obj: Transaction) -> str | None:
+ return str(obj.order.uuid) if obj.order else None
class Meta:
model = Transaction
diff --git a/payments/signals.py b/payments/signals.py
index 7f94297a..9e9078b1 100644
--- a/payments/signals.py
+++ b/payments/signals.py
@@ -1,3 +1,6 @@
+import logging
+import traceback
+
from django.db.models.signals import post_save
from django.dispatch import receiver
@@ -6,6 +9,8 @@ from payments.models import Balance, Transaction
from payments.utils.emailing import balance_deposit_email
from vibes_auth.models import User
+logger = logging.getLogger("django")
+
@receiver(post_save, sender=User)
def create_balance_on_user_creation_signal(instance, created, **_kwargs):
@@ -17,12 +22,19 @@ def create_balance_on_user_creation_signal(instance, created, **_kwargs):
def process_transaction_changes(instance, created, **_kwargs):
if created:
try:
- gateway = AbstractGateway()
+ match instance.process.get("gateway", "default"):
+ case "gateway":
+ gateway = AbstractGateway()
+ case "default":
+ gateway = AbstractGateway()
+ case _:
+ gateway = AbstractGateway()
gateway.process_transaction(instance)
- except Exception as e: # noqa:
- instance.process = {"status": "NOGATEWAY", "error": str(e)}
+ except Exception as e:
+ instance.process = {"status": "ERRORED", "error": str(e)}
+ logger.error(f"Error processing transaction {instance.uuid}: {e}\n{traceback.format_exc()}")
if not created:
- status = instance.process.get("status", "").lower()
+ status = str(instance.process.get("status", "")).lower()
success = instance.process.get("success", False)
if ("success" in status or success) and (instance.process.get("notify", False)):
diff --git a/payments/templates/balance_deposit_email.html b/payments/templates/balance_deposit_email.html
index 509d0c06..004d95ce 100644
--- a/payments/templates/balance_deposit_email.html
+++ b/payments/templates/balance_deposit_email.html
@@ -1,5 +1,4 @@
{% load tz static i18n filters conditions %}
-
@@ -61,12 +60,6 @@
color: #888;
}
- .order-table {
- width: 100%;
- margin-top: 20px;
- border-collapse: collapse;
- }
-
.order-table th, .order-table td {
border: 1px solid #ddd;
padding: 8px;
@@ -91,7 +84,7 @@
diff --git a/payments/urls.py b/payments/urls.py
index 6f703c4a..4c567fde 100644
--- a/payments/urls.py
+++ b/payments/urls.py
@@ -4,6 +4,8 @@ from rest_framework.routers import DefaultRouter
from payments.views import CallbackAPIView, DepositView
from payments.viewsets import TransactionViewSet
+app_name = "payments"
+
payment_router = DefaultRouter()
payment_router.register(prefix=r"transactions", viewset=TransactionViewSet, basename="transactions")
diff --git a/payments/utils/emailing.py b/payments/utils/emailing.py
index d2a39266..34df0767 100644
--- a/payments/utils/emailing.py
+++ b/payments/utils/emailing.py
@@ -6,19 +6,23 @@ from django.core import mail
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.utils.translation import activate
+from django.utils.translation import gettext_lazy as _
from core.utils.constance import set_email_settings
from payments.models import Transaction
-@shared_task
+@shared_task(queue="default")
def balance_deposit_email(transaction_pk: str) -> tuple[bool, str]:
try:
transaction = Transaction.objects.get(pk=transaction_pk)
except Transaction.DoesNotExist:
return False, f"Transaction not found with the given pk: {transaction_pk}"
- activate(transaction.balance.user.language) # type: ignore
+ if not transaction.balance or not transaction.balance.user:
+ return False, f"Balance not found for the given transaction pk: {transaction_pk}"
+
+ activate(transaction.balance.user.language)
set_email_settings()
connection = mail.get_connection()
@@ -30,17 +34,17 @@ def balance_deposit_email(transaction_pk: str) -> tuple[bool, str]:
context={
"amount": transaction.amount,
"balance": transaction.balance.amount,
- "user_first_name": transaction.balance.user.first_name, # type: ignore
+ "user_first_name": transaction.balance.user.first_name,
"project_name": config.PROJECT_NAME,
"contact_email": config.EMAIL_FROM,
"today": datetime.today(),
},
),
- to=[transaction.balance.user.email], # type: ignore
+ to=[transaction.balance.user.email],
from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>",
connection=connection,
)
email.content_subtype = "html"
email.send()
- return True, str(order.uuid)
+ return True, str(transaction_pk)
diff --git a/payments/views.py b/payments/views.py
index 9d3a1c6b..ef83ba09 100644
--- a/payments/views.py
+++ b/payments/views.py
@@ -11,11 +11,27 @@ from payments.gateways import UnknownGatewayError
from payments.models import Transaction
from payments.serializers import DepositSerializer, TransactionProcessSerializer
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
@extend_schema_view(**DEPOSIT_SCHEMA)
class DepositView(APIView):
+ """Handles deposit operations.
+
+ This class provides an API endpoint to handle deposit transactions.
+ It supports the creation of a deposit transaction after validating the
+ provided data. If the user is not authenticated, an appropriate response
+ is returned. On successful validation and execution, a response
+ with the transaction details is provided.
+
+ Attributes:
+ No attributes are declared at the class-level for this view.
+
+ Methods:
+ post: Processes the deposit request, validates the request data, ensures
+ user authentication, and creates a transaction.
+ """
+
def post(self, request, *args, **kwargs):
logger.debug(request.__dict__)
serializer = DepositSerializer(data=request.data)
@@ -33,8 +49,26 @@ class DepositView(APIView):
@extend_schema(exclude=True)
class CallbackAPIView(APIView):
+ """
+ Handles incoming callback requests to the API.
+
+ This class processes and routes incoming HTTP POST requests to the appropriate
+ gateway handler based on the provided gateway parameter. It is designed to handle
+ callback events coming from external systems and provide an appropriate HTTP response
+ indicating success or failure.
+
+ Attributes:
+ No additional attributes are defined for this class beyond what is
+ inherited from APIView.
+
+ Methods:
+ post(request, *args, **kwargs): Processes POST requests and routes them
+ based on the specified gateway. Handles exceptions gracefully by returning
+ a server error response if an unknown gateway or other issues occur.
+ """
+
def post(self, request, *args, **kwargs):
- logger.debug(request.__dict__)
+ logger.debug(f"{request.__dict__}\n")
try:
gateway = kwargs.get("gateway", "")
# noinspection PyUnreachableCode
diff --git a/payments/viewsets.py b/payments/viewsets.py
index 0b7a141c..3342cecc 100644
--- a/payments/viewsets.py
+++ b/payments/viewsets.py
@@ -5,5 +5,21 @@ from payments.serializers import TransactionSerializer
class TransactionViewSet(ReadOnlyModelViewSet):
+ """
+ ViewSet for handling read-only operations on the Transaction model.
+
+ This class provides a read-only interface for interacting with transaction
+ data. It uses the TransactionSerializer for serializing and deserializing
+ the data. The class ensures that only authorized users, who meet specific
+ permissions, can access the transactions.
+
+ Attributes:
+ serializer_class: Specifies the serializer class to be used for
+ serializing transaction data.
+ permission_classes: A tuple specifying the permissions required to access
+ the data. Includes custom permissions to restrict access based
+ on ownership and other criteria.
+ """
+
serializer_class = TransactionSerializer
permission_classes = (EvibesPermission, IsOwner)
diff --git a/poetry.lock b/poetry.lock
index 7b663f20..e2edbd85 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -727,13 +727,13 @@ click = ">=7"
[[package]]
name = "click-plugins"
-version = "1.1.1"
+version = "1.1.1.2"
description = "An extension module for click to enable registering CLI commands via setuptools entry-points."
optional = false
python-versions = "*"
files = [
- {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"},
- {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"},
+ {file = "click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6"},
+ {file = "click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261"},
]
[package.dependencies]
@@ -1135,20 +1135,6 @@ files = [
asgiref = ">=3.6"
django = ">=4.2"
-[[package]]
-name = "django-daisy"
-version = "1.0.26"
-description = "A modern Django dashboard built with DaisyUI"
-optional = false
-python-versions = "*"
-files = [
- {file = "django_daisy-1.0.26-py3-none-any.whl", hash = "sha256:3c2dd94264beded68f8ed3399f919bd0ae29cb93f03badb7b5694dc6f4736ddb"},
- {file = "django_daisy-1.0.26.tar.gz", hash = "sha256:6fbafb5c4d15f0ca6b5d724e98c731e647a940c0270636ef363fc09ce1fa78cb"},
-]
-
-[package.dependencies]
-Django = ">=3.2"
-
[[package]]
name = "django-dbbackup"
version = "4.3.0"
@@ -1259,6 +1245,20 @@ files = [
{file = "django_hosts-6.0-py3-none-any.whl", hash = "sha256:34a97a183b3fb8a00de3e0a8af5355a25ff5203019d2e213edd8f12c330cc303"},
]
+[[package]]
+name = "django-jazzmin"
+version = "3.0.1"
+description = "Drop-in theme for django admin, that utilises AdminLTE 3 & Bootstrap 4 to make yo' admin look jazzy"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "django_jazzmin-3.0.1-py3-none-any.whl", hash = "sha256:12a0a4c1d4fd09c2eef22acf6a1f03112b515ba695c59faa8ea80efc81c1f21b"},
+ {file = "django_jazzmin-3.0.1.tar.gz", hash = "sha256:67ae148bade41267a09ca8e4352ddefa6121795ebbac238bb9a6564ff841eb1b"},
+]
+
+[package.dependencies]
+django = ">=4.2"
+
[[package]]
name = "django-js-asset"
version = "3.1.2"
@@ -1644,6 +1644,17 @@ dev = ["Django (>=1.6)", "djangorestframework (>=2.4.3)", "flake8", "mkdocs (>=0
docs = ["mkdocs (>=0.11.1)"]
tests = ["Django (>=1.6)", "djangorestframework (>=2.4.3)", "flake8", "pytest", "pytest-django"]
+[[package]]
+name = "docutils"
+version = "0.21.2"
+description = "Docutils -- Python Documentation Utilities"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"},
+ {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"},
+]
+
[[package]]
name = "drf-spectacular"
version = "0.28.0"
@@ -1670,13 +1681,13 @@ sidecar = ["drf-spectacular-sidecar"]
[[package]]
name = "drf-spectacular-sidecar"
-version = "2025.6.1"
+version = "2025.7.1"
description = "Serve self-contained distribution builds of Swagger UI and Redoc with Django"
optional = false
python-versions = ">=3.6"
files = [
- {file = "drf_spectacular_sidecar-2025.6.1-py3-none-any.whl", hash = "sha256:c7c4768c03faa3d2f7afacd1464f67732e7d6866d2cf2e8f649175c27318745c"},
- {file = "drf_spectacular_sidecar-2025.6.1.tar.gz", hash = "sha256:ee6752c73d712265a61b9e2ca6f71c3b2bd89f30f39cf9f8cda98e7f371fcbcf"},
+ {file = "drf_spectacular_sidecar-2025.7.1-py3-none-any.whl", hash = "sha256:efe33ba696ba25f28c32ead75b56e3ef68f167b9ed7468f8d16322bfe8e304e7"},
+ {file = "drf_spectacular_sidecar-2025.7.1.tar.gz", hash = "sha256:03b4a9f2062115f69ce24509d855b180244d58ef45edd67ea8bcb214c7021e10"},
]
[package.dependencies]
@@ -2114,13 +2125,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio
[[package]]
name = "ipython"
-version = "9.3.0"
+version = "9.4.0"
description = "IPython: Productive Interactive Computing"
optional = true
python-versions = ">=3.11"
files = [
- {file = "ipython-9.3.0-py3-none-any.whl", hash = "sha256:1a0b6dd9221a1f5dddf725b57ac0cb6fddc7b5f470576231ae9162b9b3455a04"},
- {file = "ipython-9.3.0.tar.gz", hash = "sha256:79eb896f9f23f50ad16c3bc205f686f6e030ad246cc309c6279a242b14afe9d8"},
+ {file = "ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066"},
+ {file = "ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270"},
]
[package.dependencies]
@@ -2590,13 +2601,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (>
[[package]]
name = "jupyterlab"
-version = "4.4.3"
+version = "4.4.4"
description = "JupyterLab computational environment"
optional = true
python-versions = ">=3.9"
files = [
- {file = "jupyterlab-4.4.3-py3-none-any.whl", hash = "sha256:164302f6d4b6c44773dfc38d585665a4db401a16e5296c37df5cba63904fbdea"},
- {file = "jupyterlab-4.4.3.tar.gz", hash = "sha256:a94c32fd7f8b93e82a49dc70a6ec45a5c18281ca2a7228d12765e4e210e5bca2"},
+ {file = "jupyterlab-4.4.4-py3-none-any.whl", hash = "sha256:711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd"},
+ {file = "jupyterlab-4.4.4.tar.gz", hash = "sha256:163fee1ef702e0a057f75d2eed3ed1da8a986d59eb002cbeb6f0c2779e6cd153"},
]
[package.dependencies]
@@ -2705,143 +2716,86 @@ zookeeper = ["kazoo (>=2.8.0)"]
[[package]]
name = "lxml"
-version = "5.4.0"
+version = "6.0.0"
description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
files = [
- {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c"},
- {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c"},
- {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b"},
- {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b"},
- {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563"},
- {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5"},
- {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776"},
- {file = "lxml-5.4.0-cp310-cp310-win32.whl", hash = "sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7"},
- {file = "lxml-5.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250"},
- {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9"},
- {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8"},
- {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86"},
- {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056"},
- {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7"},
- {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd"},
- {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751"},
- {file = "lxml-5.4.0-cp311-cp311-win32.whl", hash = "sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4"},
- {file = "lxml-5.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539"},
- {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4"},
- {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7"},
- {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079"},
- {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20"},
- {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8"},
- {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f"},
- {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc"},
- {file = "lxml-5.4.0-cp312-cp312-win32.whl", hash = "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f"},
- {file = "lxml-5.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2"},
- {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0"},
- {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8"},
- {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982"},
- {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61"},
- {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54"},
- {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b"},
- {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a"},
- {file = "lxml-5.4.0-cp313-cp313-win32.whl", hash = "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82"},
- {file = "lxml-5.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f"},
- {file = "lxml-5.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7be701c24e7f843e6788353c055d806e8bd8466b52907bafe5d13ec6a6dbaecd"},
- {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb54f7c6bafaa808f27166569b1511fc42701a7713858dddc08afdde9746849e"},
- {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97dac543661e84a284502e0cf8a67b5c711b0ad5fb661d1bd505c02f8cf716d7"},
- {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:c70e93fba207106cb16bf852e421c37bbded92acd5964390aad07cb50d60f5cf"},
- {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9c886b481aefdf818ad44846145f6eaf373a20d200b5ce1a5c8e1bc2d8745410"},
- {file = "lxml-5.4.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:fa0e294046de09acd6146be0ed6727d1f42ded4ce3ea1e9a19c11b6774eea27c"},
- {file = "lxml-5.4.0-cp36-cp36m-win32.whl", hash = "sha256:61c7bbf432f09ee44b1ccaa24896d21075e533cd01477966a5ff5a71d88b2f56"},
- {file = "lxml-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121"},
- {file = "lxml-5.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872"},
- {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e"},
- {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f7f991a68d20c75cb13c5c9142b2a3f9eb161f1f12a9489c82172d1f133c0"},
- {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92"},
- {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:ac7ba71f9561cd7d7b55e1ea5511543c0282e2b6450f122672a2694621d63b7e"},
- {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5"},
- {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:ce31158630a6ac85bddd6b830cffd46085ff90498b397bd0a259f59d27a12188"},
- {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6"},
- {file = "lxml-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063"},
- {file = "lxml-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49"},
- {file = "lxml-5.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eaf24066ad0b30917186420d51e2e3edf4b0e2ea68d8cd885b14dc8afdcf6556"},
- {file = "lxml-5.4.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b31a3a77501d86d8ade128abb01082724c0dfd9524f542f2f07d693c9f1175f"},
- {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e108352e203c7afd0eb91d782582f00a0b16a948d204d4dec8565024fafeea5"},
- {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11a96c3b3f7551c8a8109aa65e8594e551d5a84c76bf950da33d0fb6dfafab7"},
- {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:ca755eebf0d9e62d6cb013f1261e510317a41bf4650f22963474a663fdfe02aa"},
- {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4cd915c0fb1bed47b5e6d6edd424ac25856252f09120e3e8ba5154b6b921860e"},
- {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:226046e386556a45ebc787871d6d2467b32c37ce76c2680f5c608e25823ffc84"},
- {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b108134b9667bcd71236c5a02aad5ddd073e372fb5d48ea74853e009fe38acb6"},
- {file = "lxml-5.4.0-cp38-cp38-win32.whl", hash = "sha256:1320091caa89805df7dcb9e908add28166113dcd062590668514dbd510798c88"},
- {file = "lxml-5.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:073eb6dcdf1f587d9b88c8c93528b57eccda40209cf9be549d469b942b41d70b"},
- {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bda3ea44c39eb74e2488297bb39d47186ed01342f0022c8ff407c250ac3f498e"},
- {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9ceaf423b50ecfc23ca00b7f50b64baba85fb3fb91c53e2c9d00bc86150c7e40"},
- {file = "lxml-5.4.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:664cdc733bc87449fe781dbb1f309090966c11cc0c0cd7b84af956a02a8a4729"},
- {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67ed8a40665b84d161bae3181aa2763beea3747f748bca5874b4af4d75998f87"},
- {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4a3bd174cc9cdaa1afbc4620c049038b441d6ba07629d89a83b408e54c35cd"},
- {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:b0989737a3ba6cf2a16efb857fb0dfa20bc5c542737fddb6d893fde48be45433"},
- {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:dc0af80267edc68adf85f2a5d9be1cdf062f973db6790c1d065e45025fa26140"},
- {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:639978bccb04c42677db43c79bdaa23785dc7f9b83bfd87570da8207872f1ce5"},
- {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a99d86351f9c15e4a901fc56404b485b1462039db59288b203f8c629260a142"},
- {file = "lxml-5.4.0-cp39-cp39-win32.whl", hash = "sha256:3e6d5557989cdc3ebb5302bbdc42b439733a841891762ded9514e74f60319ad6"},
- {file = "lxml-5.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:a8c9b7f16b63e65bbba889acb436a1034a82d34fa09752d754f88d708eca80e1"},
- {file = "lxml-5.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55"},
- {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740"},
- {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5"},
- {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37"},
- {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571"},
- {file = "lxml-5.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4"},
- {file = "lxml-5.4.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5f11a1526ebd0dee85e7b1e39e39a0cc0d9d03fb527f56d8457f6df48a10dc0c"},
- {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b4afaf38bf79109bb060d9016fad014a9a48fb244e11b94f74ae366a64d252"},
- {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de6f6bb8a7840c7bf216fb83eec4e2f79f7325eca8858167b68708b929ab2172"},
- {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5cca36a194a4eb4e2ed6be36923d3cffd03dcdf477515dea687185506583d4c9"},
- {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b7c86884ad23d61b025989d99bfdd92a7351de956e01c61307cb87035960bcb1"},
- {file = "lxml-5.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:53d9469ab5460402c19553b56c3648746774ecd0681b1b27ea74d5d8a3ef5590"},
- {file = "lxml-5.4.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:56dbdbab0551532bb26c19c914848d7251d73edb507c3079d6805fa8bba5b706"},
- {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14479c2ad1cb08b62bb941ba8e0e05938524ee3c3114644df905d2331c76cd57"},
- {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32697d2ea994e0db19c1df9e40275ffe84973e4232b5c274f47e7c1ec9763cdd"},
- {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:24f6df5f24fc3385f622c0c9d63fe34604893bc1a5bdbb2dbf5870f85f9a404a"},
- {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:151d6c40bc9db11e960619d2bf2ec5829f0aaffb10b41dcf6ad2ce0f3c0b2325"},
- {file = "lxml-5.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4025bf2884ac4370a3243c5aa8d66d3cb9e15d3ddd0af2d796eccc5f0244390e"},
- {file = "lxml-5.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9459e6892f59ecea2e2584ee1058f5d8f629446eab52ba2305ae13a32a059530"},
- {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47fb24cc0f052f0576ea382872b3fc7e1f7e3028e53299ea751839418ade92a6"},
- {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50441c9de951a153c698b9b99992e806b71c1f36d14b154592580ff4a9d0d877"},
- {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ab339536aa798b1e17750733663d272038bf28069761d5be57cb4a9b0137b4f8"},
- {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9776af1aad5a4b4a1317242ee2bea51da54b2a7b7b48674be736d463c999f37d"},
- {file = "lxml-5.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:63e7968ff83da2eb6fdda967483a7a023aa497d85ad8f05c3ad9b1f2e8c84987"},
- {file = "lxml-5.4.0.tar.gz", hash = "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd"},
+ {file = "lxml-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:35bc626eec405f745199200ccb5c6b36f202675d204aa29bb52e27ba2b71dea8"},
+ {file = "lxml-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:246b40f8a4aec341cbbf52617cad8ab7c888d944bfe12a6abd2b1f6cfb6f6082"},
+ {file = "lxml-6.0.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:2793a627e95d119e9f1e19720730472f5543a6d84c50ea33313ce328d870f2dd"},
+ {file = "lxml-6.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e2030956cf4886b10be9a0285c6802e078ec2391e1dd7ff3eb509c2c95a69b76"},
+ {file = "lxml-6.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d23854ecf381ab1facc8f353dcd9adeddef3652268ee75297c1164c987c11dc"},
+ {file = "lxml-6.0.0-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:43fe5af2d590bf4691531b1d9a2495d7aab2090547eaacd224a3afec95706d76"},
+ {file = "lxml-6.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74e748012f8c19b47f7d6321ac929a9a94ee92ef12bc4298c47e8b7219b26541"},
+ {file = "lxml-6.0.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:43cfbb7db02b30ad3926e8fceaef260ba2fb7df787e38fa2df890c1ca7966c3b"},
+ {file = "lxml-6.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:34190a1ec4f1e84af256495436b2d196529c3f2094f0af80202947567fdbf2e7"},
+ {file = "lxml-6.0.0-cp310-cp310-win32.whl", hash = "sha256:5967fe415b1920a3877a4195e9a2b779249630ee49ece22021c690320ff07452"},
+ {file = "lxml-6.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:f3389924581d9a770c6caa4df4e74b606180869043b9073e2cec324bad6e306e"},
+ {file = "lxml-6.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:522fe7abb41309e9543b0d9b8b434f2b630c5fdaf6482bee642b34c8c70079c8"},
+ {file = "lxml-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ee56288d0df919e4aac43b539dd0e34bb55d6a12a6562038e8d6f3ed07f9e36"},
+ {file = "lxml-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b8dd6dd0e9c1992613ccda2bcb74fc9d49159dbe0f0ca4753f37527749885c25"},
+ {file = "lxml-6.0.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:d7ae472f74afcc47320238b5dbfd363aba111a525943c8a34a1b657c6be934c3"},
+ {file = "lxml-6.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f720a14aa102a38907c6d5030e3d66b3b680c3e6f6bc95473931ea3c00c59967"},
+ {file = "lxml-6.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2a5e8d207311a0170aca0eb6b160af91adc29ec121832e4ac151a57743a1e1e"},
+ {file = "lxml-6.0.0-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:2dd1cc3ea7e60bfb31ff32cafe07e24839df573a5e7c2d33304082a5019bcd58"},
+ {file = "lxml-6.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cfcf84f1defed7e5798ef4f88aa25fcc52d279be731ce904789aa7ccfb7e8d2"},
+ {file = "lxml-6.0.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a52a4704811e2623b0324a18d41ad4b9fabf43ce5ff99b14e40a520e2190c851"},
+ {file = "lxml-6.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c16304bba98f48a28ae10e32a8e75c349dd742c45156f297e16eeb1ba9287a1f"},
+ {file = "lxml-6.0.0-cp311-cp311-win32.whl", hash = "sha256:f8d19565ae3eb956d84da3ef367aa7def14a2735d05bd275cd54c0301f0d0d6c"},
+ {file = "lxml-6.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b2d71cdefda9424adff9a3607ba5bbfc60ee972d73c21c7e3c19e71037574816"},
+ {file = "lxml-6.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:8a2e76efbf8772add72d002d67a4c3d0958638696f541734304c7f28217a9cab"},
+ {file = "lxml-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78718d8454a6e928470d511bf8ac93f469283a45c354995f7d19e77292f26108"},
+ {file = "lxml-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:84ef591495ffd3f9dcabffd6391db7bb70d7230b5c35ef5148354a134f56f2be"},
+ {file = "lxml-6.0.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:2930aa001a3776c3e2601cb8e0a15d21b8270528d89cc308be4843ade546b9ab"},
+ {file = "lxml-6.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:390240baeb9f415a82eefc2e13285016f9c8b5ad71ec80574ae8fa9605093cd7"},
+ {file = "lxml-6.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ca50bd612438258a91b5b3788c6621c1f05c8c478e7951899f492be42defc0da"},
+ {file = "lxml-6.0.0-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:c24b8efd9c0f62bad0439283c2c795ef916c5a6b75f03c17799775c7ae3c0c9e"},
+ {file = "lxml-6.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:afd27d8629ae94c5d863e32ab0e1d5590371d296b87dae0a751fb22bf3685741"},
+ {file = "lxml-6.0.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:54c4855eabd9fc29707d30141be99e5cd1102e7d2258d2892314cf4c110726c3"},
+ {file = "lxml-6.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36531f81c8214e293097cd2b7873f178997dae33d3667caaae8bdfb9666b76c0"},
+ {file = "lxml-6.0.0-cp312-cp312-win32.whl", hash = "sha256:690b20e3388a7ec98e899fd54c924e50ba6693874aa65ef9cb53de7f7de9d64a"},
+ {file = "lxml-6.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:310b719b695b3dd442cdfbbe64936b2f2e231bb91d998e99e6f0daf991a3eba3"},
+ {file = "lxml-6.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:8cb26f51c82d77483cdcd2b4a53cda55bbee29b3c2f3ddeb47182a2a9064e4eb"},
+ {file = "lxml-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6da7cd4f405fd7db56e51e96bff0865b9853ae70df0e6720624049da76bde2da"},
+ {file = "lxml-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b34339898bb556a2351a1830f88f751679f343eabf9cf05841c95b165152c9e7"},
+ {file = "lxml-6.0.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:51a5e4c61a4541bd1cd3ba74766d0c9b6c12d6a1a4964ef60026832aac8e79b3"},
+ {file = "lxml-6.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f4b481b6cc3a897adb4279216695150bbe7a44c03daba3c894f49d2037e0a24"},
+ {file = "lxml-6.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae06fbab4f1bb7db4f7c8ca9897dc8db4447d1a2b9bee78474ad403437bcc29"},
+ {file = "lxml-6.0.0-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:1fa377b827ca2023244a06554c6e7dc6828a10aaf74ca41965c5d8a4925aebb4"},
+ {file = "lxml-6.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1676b56d48048a62ef77a250428d1f31f610763636e0784ba67a9740823988ca"},
+ {file = "lxml-6.0.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:0e32698462aacc5c1cf6bdfebc9c781821b7e74c79f13e5ffc8bfe27c42b1abf"},
+ {file = "lxml-6.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7488a43033c958637b1a08cddc9188eb06d3ad36582cebc7d4815980b47e27ef"},
+ {file = "lxml-6.0.0-cp313-cp313-win32.whl", hash = "sha256:5fcd7d3b1d8ecb91445bd71b9c88bdbeae528fefee4f379895becfc72298d181"},
+ {file = "lxml-6.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:2f34687222b78fff795feeb799a7d44eca2477c3d9d3a46ce17d51a4f383e32e"},
+ {file = "lxml-6.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:21db1ec5525780fd07251636eb5f7acb84003e9382c72c18c542a87c416ade03"},
+ {file = "lxml-6.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4eb114a0754fd00075c12648d991ec7a4357f9cb873042cc9a77bf3a7e30c9db"},
+ {file = "lxml-6.0.0-cp38-cp38-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:7da298e1659e45d151b4028ad5c7974917e108afb48731f4ed785d02b6818994"},
+ {file = "lxml-6.0.0-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63b634facdfbad421d4b61c90735688465d4ab3a8853ac22c76ccac2baf98d97"},
+ {file = "lxml-6.0.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:e380e85b93f148ad28ac15f8117e2fd8e5437aa7732d65e260134f83ce67911b"},
+ {file = "lxml-6.0.0-cp38-cp38-win32.whl", hash = "sha256:185efc2fed89cdd97552585c624d3c908f0464090f4b91f7d92f8ed2f3b18f54"},
+ {file = "lxml-6.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:f97487996a39cb18278ca33f7be98198f278d0bc3c5d0fd4d7b3d63646ca3c8a"},
+ {file = "lxml-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85b14a4689d5cff426c12eefe750738648706ea2753b20c2f973b2a000d3d261"},
+ {file = "lxml-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f64ccf593916e93b8d36ed55401bb7fe9c7d5de3180ce2e10b08f82a8f397316"},
+ {file = "lxml-6.0.0-cp39-cp39-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:b372d10d17a701b0945f67be58fae4664fd056b85e0ff0fbc1e6c951cdbc0512"},
+ {file = "lxml-6.0.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:048a930eb4572829604982e39a0c7289ab5dc8abc7fc9f5aabd6fbc08c154e93"},
+ {file = "lxml-6.0.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0b5fa5eda84057a4f1bbb4bb77a8c28ff20ae7ce211588d698ae453e13c6281"},
+ {file = "lxml-6.0.0-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:c352fc8f36f7e9727db17adbf93f82499457b3d7e5511368569b4c5bd155a922"},
+ {file = "lxml-6.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8db5dc617cb937ae17ff3403c3a70a7de9df4852a046f93e71edaec678f721d0"},
+ {file = "lxml-6.0.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:2181e4b1d07dde53986023482673c0f1fba5178ef800f9ab95ad791e8bdded6a"},
+ {file = "lxml-6.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b3c98d5b24c6095e89e03d65d5c574705be3d49c0d8ca10c17a8a4b5201b72f5"},
+ {file = "lxml-6.0.0-cp39-cp39-win32.whl", hash = "sha256:04d67ceee6db4bcb92987ccb16e53bef6b42ced872509f333c04fb58a3315256"},
+ {file = "lxml-6.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:e0b1520ef900e9ef62e392dd3d7ae4f5fa224d1dd62897a792cf353eb20b6cae"},
+ {file = "lxml-6.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:e35e8aaaf3981489f42884b59726693de32dabfc438ac10ef4eb3409961fd402"},
+ {file = "lxml-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:dbdd7679a6f4f08152818043dbb39491d1af3332128b3752c3ec5cebc0011a72"},
+ {file = "lxml-6.0.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ab542c91f5a47aaa58abdd8ea84b498e8e49fe4b883d67800017757a3eb78e8"},
+ {file = "lxml-6.0.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:013090383863b72c62a702d07678b658fa2567aa58d373d963cca245b017e065"},
+ {file = "lxml-6.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c86df1c9af35d903d2b52d22ea3e66db8058d21dc0f59842ca5deb0595921141"},
+ {file = "lxml-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4337e4aec93b7c011f7ee2e357b0d30562edd1955620fdd4aeab6aacd90d43c5"},
+ {file = "lxml-6.0.0-pp39-pypy39_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f090a9bc0ce8da51a5632092f98a7e7f84bca26f33d161a98b57f7fb0004ca"},
+ {file = "lxml-6.0.0-pp39-pypy39_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9da022c14baeec36edfcc8daf0e281e2f55b950249a455776f0d1adeeada4734"},
+ {file = "lxml-6.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a55da151d0b0c6ab176b4e761670ac0e2667817a1e0dadd04a01d0561a219349"},
+ {file = "lxml-6.0.0.tar.gz", hash = "sha256:032e65120339d44cdc3efc326c9f660f5f7205f3a535c1fdbf898b29ea01fb72"},
]
[package.extras]
@@ -2849,7 +2803,6 @@ cssselect = ["cssselect (>=0.7)"]
html-clean = ["lxml_html_clean"]
html5 = ["html5lib"]
htmlsoup = ["BeautifulSoup4"]
-source = ["Cython (>=3.0.11,<3.1.0)"]
[[package]]
name = "markdown"
@@ -3174,18 +3127,18 @@ files = [
[[package]]
name = "notebook"
-version = "7.4.3"
+version = "7.4.4"
description = "Jupyter Notebook - A web-based notebook environment for interactive computing"
optional = true
python-versions = ">=3.8"
files = [
- {file = "notebook-7.4.3-py3-none-any.whl", hash = "sha256:9cdeee954e04101cadb195d90e2ab62b7c9286c1d4f858bf3bb54e40df16c0c3"},
- {file = "notebook-7.4.3.tar.gz", hash = "sha256:a1567481cd3853f2610ee0ecf5dfa12bb508e878ee8f92152c134ef7f0568a76"},
+ {file = "notebook-7.4.4-py3-none-any.whl", hash = "sha256:32840f7f777b6bff79bb101159336e9b332bdbfba1495b8739e34d1d65cbc1c0"},
+ {file = "notebook-7.4.4.tar.gz", hash = "sha256:392fd501e266f2fb3466c6fcd3331163a2184968cb5c5accf90292e01dfe528c"},
]
[package.dependencies]
jupyter-server = ">=2.4.0,<3"
-jupyterlab = ">=4.4.3,<4.5"
+jupyterlab = ">=4.4.4,<4.5"
jupyterlab-server = ">=2.27.1,<3"
notebook-shim = ">=0.2,<0.3"
tornado = ">=6.2.0"
@@ -4387,128 +4340,155 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "rpds-py"
-version = "0.25.1"
+version = "0.26.0"
description = "Python bindings to Rust's persistent data structures (rpds)"
optional = false
python-versions = ">=3.9"
files = [
- {file = "rpds_py-0.25.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f4ad628b5174d5315761b67f212774a32f5bad5e61396d38108bd801c0a8f5d9"},
- {file = "rpds_py-0.25.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c742af695f7525e559c16f1562cf2323db0e3f0fbdcabdf6865b095256b2d40"},
- {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:605ffe7769e24b1800b4d024d24034405d9404f0bc2f55b6db3362cd34145a6f"},
- {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc6f3ddef93243538be76f8e47045b4aad7a66a212cd3a0f23e34469473d36b"},
- {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f70316f760174ca04492b5ab01be631a8ae30cadab1d1081035136ba12738cfa"},
- {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1dafef8df605fdb46edcc0bf1573dea0d6d7b01ba87f85cd04dc855b2b4479e"},
- {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0701942049095741a8aeb298a31b203e735d1c61f4423511d2b1a41dcd8a16da"},
- {file = "rpds_py-0.25.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e87798852ae0b37c88babb7f7bbbb3e3fecc562a1c340195b44c7e24d403e380"},
- {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3bcce0edc1488906c2d4c75c94c70a0417e83920dd4c88fec1078c94843a6ce9"},
- {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e2f6a2347d3440ae789505693a02836383426249d5293541cd712e07e7aecf54"},
- {file = "rpds_py-0.25.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4fd52d3455a0aa997734f3835cbc4c9f32571345143960e7d7ebfe7b5fbfa3b2"},
- {file = "rpds_py-0.25.1-cp310-cp310-win32.whl", hash = "sha256:3f0b1798cae2bbbc9b9db44ee068c556d4737911ad53a4e5093d09d04b3bbc24"},
- {file = "rpds_py-0.25.1-cp310-cp310-win_amd64.whl", hash = "sha256:3ebd879ab996537fc510a2be58c59915b5dd63bccb06d1ef514fee787e05984a"},
- {file = "rpds_py-0.25.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5f048bbf18b1f9120685c6d6bb70cc1a52c8cc11bdd04e643d28d3be0baf666d"},
- {file = "rpds_py-0.25.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4fbb0dbba559959fcb5d0735a0f87cdbca9e95dac87982e9b95c0f8f7ad10255"},
- {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4ca54b9cf9d80b4016a67a0193ebe0bcf29f6b0a96f09db942087e294d3d4c2"},
- {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ee3e26eb83d39b886d2cb6e06ea701bba82ef30a0de044d34626ede51ec98b0"},
- {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89706d0683c73a26f76a5315d893c051324d771196ae8b13e6ffa1ffaf5e574f"},
- {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2013ee878c76269c7b557a9a9c042335d732e89d482606990b70a839635feb7"},
- {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45e484db65e5380804afbec784522de84fa95e6bb92ef1bd3325d33d13efaebd"},
- {file = "rpds_py-0.25.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:48d64155d02127c249695abb87d39f0faf410733428d499867606be138161d65"},
- {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:048893e902132fd6548a2e661fb38bf4896a89eea95ac5816cf443524a85556f"},
- {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0317177b1e8691ab5879f4f33f4b6dc55ad3b344399e23df2e499de7b10a548d"},
- {file = "rpds_py-0.25.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bffcf57826d77a4151962bf1701374e0fc87f536e56ec46f1abdd6a903354042"},
- {file = "rpds_py-0.25.1-cp311-cp311-win32.whl", hash = "sha256:cda776f1967cb304816173b30994faaf2fd5bcb37e73118a47964a02c348e1bc"},
- {file = "rpds_py-0.25.1-cp311-cp311-win_amd64.whl", hash = "sha256:dc3c1ff0abc91444cd20ec643d0f805df9a3661fcacf9c95000329f3ddf268a4"},
- {file = "rpds_py-0.25.1-cp311-cp311-win_arm64.whl", hash = "sha256:5a3ddb74b0985c4387719fc536faced33cadf2172769540c62e2a94b7b9be1c4"},
- {file = "rpds_py-0.25.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5ffe453cde61f73fea9430223c81d29e2fbf412a6073951102146c84e19e34c"},
- {file = "rpds_py-0.25.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:115874ae5e2fdcfc16b2aedc95b5eef4aebe91b28e7e21951eda8a5dc0d3461b"},
- {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a714bf6e5e81b0e570d01f56e0c89c6375101b8463999ead3a93a5d2a4af91fa"},
- {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35634369325906bcd01577da4c19e3b9541a15e99f31e91a02d010816b49bfda"},
- {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4cb2b3ddc16710548801c6fcc0cfcdeeff9dafbc983f77265877793f2660309"},
- {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9ceca1cf097ed77e1a51f1dbc8d174d10cb5931c188a4505ff9f3e119dfe519b"},
- {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c2cd1a4b0c2b8c5e31ffff50d09f39906fe351389ba143c195566056c13a7ea"},
- {file = "rpds_py-0.25.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1de336a4b164c9188cb23f3703adb74a7623ab32d20090d0e9bf499a2203ad65"},
- {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9fca84a15333e925dd59ce01da0ffe2ffe0d6e5d29a9eeba2148916d1824948c"},
- {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88ec04afe0c59fa64e2f6ea0dd9657e04fc83e38de90f6de201954b4d4eb59bd"},
- {file = "rpds_py-0.25.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8bd2f19e312ce3e1d2c635618e8a8d8132892bb746a7cf74780a489f0f6cdcb"},
- {file = "rpds_py-0.25.1-cp312-cp312-win32.whl", hash = "sha256:e5e2f7280d8d0d3ef06f3ec1b4fd598d386cc6f0721e54f09109a8132182fbfe"},
- {file = "rpds_py-0.25.1-cp312-cp312-win_amd64.whl", hash = "sha256:db58483f71c5db67d643857404da360dce3573031586034b7d59f245144cc192"},
- {file = "rpds_py-0.25.1-cp312-cp312-win_arm64.whl", hash = "sha256:6d50841c425d16faf3206ddbba44c21aa3310a0cebc3c1cdfc3e3f4f9f6f5728"},
- {file = "rpds_py-0.25.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:659d87430a8c8c704d52d094f5ba6fa72ef13b4d385b7e542a08fc240cb4a559"},
- {file = "rpds_py-0.25.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68f6f060f0bbdfb0245267da014d3a6da9be127fe3e8cc4a68c6f833f8a23bb1"},
- {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:083a9513a33e0b92cf6e7a6366036c6bb43ea595332c1ab5c8ae329e4bcc0a9c"},
- {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:816568614ecb22b18a010c7a12559c19f6fe993526af88e95a76d5a60b8b75fb"},
- {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c6564c0947a7f52e4792983f8e6cf9bac140438ebf81f527a21d944f2fd0a40"},
- {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c4a128527fe415d73cf1f70a9a688d06130d5810be69f3b553bf7b45e8acf79"},
- {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e1d7a4978ed554f095430b89ecc23f42014a50ac385eb0c4d163ce213c325"},
- {file = "rpds_py-0.25.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d74ec9bc0e2feb81d3f16946b005748119c0f52a153f6db6a29e8cd68636f295"},
- {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3af5b4cc10fa41e5bc64e5c198a1b2d2864337f8fcbb9a67e747e34002ce812b"},
- {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:79dc317a5f1c51fd9c6a0c4f48209c6b8526d0524a6904fc1076476e79b00f98"},
- {file = "rpds_py-0.25.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1521031351865e0181bc585147624d66b3b00a84109b57fcb7a779c3ec3772cd"},
- {file = "rpds_py-0.25.1-cp313-cp313-win32.whl", hash = "sha256:5d473be2b13600b93a5675d78f59e63b51b1ba2d0476893415dfbb5477e65b31"},
- {file = "rpds_py-0.25.1-cp313-cp313-win_amd64.whl", hash = "sha256:a7b74e92a3b212390bdce1d93da9f6488c3878c1d434c5e751cbc202c5e09500"},
- {file = "rpds_py-0.25.1-cp313-cp313-win_arm64.whl", hash = "sha256:dd326a81afe332ede08eb39ab75b301d5676802cdffd3a8f287a5f0b694dc3f5"},
- {file = "rpds_py-0.25.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:a58d1ed49a94d4183483a3ce0af22f20318d4a1434acee255d683ad90bf78129"},
- {file = "rpds_py-0.25.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f251bf23deb8332823aef1da169d5d89fa84c89f67bdfb566c49dea1fccfd50d"},
- {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dbd586bfa270c1103ece2109314dd423df1fa3d9719928b5d09e4840cec0d72"},
- {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6d273f136e912aa101a9274c3145dcbddbe4bac560e77e6d5b3c9f6e0ed06d34"},
- {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:666fa7b1bd0a3810a7f18f6d3a25ccd8866291fbbc3c9b912b917a6715874bb9"},
- {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:921954d7fbf3fccc7de8f717799304b14b6d9a45bbeec5a8d7408ccbf531faf5"},
- {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d86373ff19ca0441ebeb696ef64cb58b8b5cbacffcda5a0ec2f3911732a194"},
- {file = "rpds_py-0.25.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8980cde3bb8575e7c956a530f2c217c1d6aac453474bf3ea0f9c89868b531b6"},
- {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8eb8c84ecea987a2523e057c0d950bcb3f789696c0499290b8d7b3107a719d78"},
- {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e43a005671a9ed5a650f3bc39e4dbccd6d4326b24fb5ea8be5f3a43a6f576c72"},
- {file = "rpds_py-0.25.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58f77c60956501a4a627749a6dcb78dac522f249dd96b5c9f1c6af29bfacfb66"},
- {file = "rpds_py-0.25.1-cp313-cp313t-win32.whl", hash = "sha256:2cb9e5b5e26fc02c8a4345048cd9998c2aca7c2712bd1b36da0c72ee969a3523"},
- {file = "rpds_py-0.25.1-cp313-cp313t-win_amd64.whl", hash = "sha256:401ca1c4a20cc0510d3435d89c069fe0a9ae2ee6495135ac46bdd49ec0495763"},
- {file = "rpds_py-0.25.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ce4c8e485a3c59593f1a6f683cf0ea5ab1c1dc94d11eea5619e4fb5228b40fbd"},
- {file = "rpds_py-0.25.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d8222acdb51a22929c3b2ddb236b69c59c72af4019d2cba961e2f9add9b6e634"},
- {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4593c4eae9b27d22df41cde518b4b9e4464d139e4322e2127daa9b5b981b76be"},
- {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd035756830c712b64725a76327ce80e82ed12ebab361d3a1cdc0f51ea21acb0"},
- {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:114a07e85f32b125404f28f2ed0ba431685151c037a26032b213c882f26eb908"},
- {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dec21e02e6cc932538b5203d3a8bd6aa1480c98c4914cb88eea064ecdbc6396a"},
- {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09eab132f41bf792c7a0ea1578e55df3f3e7f61888e340779b06050a9a3f16e9"},
- {file = "rpds_py-0.25.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c98f126c4fc697b84c423e387337d5b07e4a61e9feac494362a59fd7a2d9ed80"},
- {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0e6a327af8ebf6baba1c10fadd04964c1965d375d318f4435d5f3f9651550f4a"},
- {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc120d1132cff853ff617754196d0ac0ae63befe7c8498bd67731ba368abe451"},
- {file = "rpds_py-0.25.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:140f61d9bed7839446bdd44852e30195c8e520f81329b4201ceead4d64eb3a9f"},
- {file = "rpds_py-0.25.1-cp39-cp39-win32.whl", hash = "sha256:9c006f3aadeda131b438c3092124bd196b66312f0caa5823ef09585a669cf449"},
- {file = "rpds_py-0.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:a61d0b2c7c9a0ae45732a77844917b427ff16ad5464b4d4f5e4adb955f582890"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b24bf3cd93d5b6ecfbedec73b15f143596c88ee249fa98cefa9a9dc9d92c6f28"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:0eb90e94f43e5085623932b68840b6f379f26db7b5c2e6bcef3179bd83c9330f"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d50e4864498a9ab639d6d8854b25e80642bd362ff104312d9770b05d66e5fb13"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c9409b47ba0650544b0bb3c188243b83654dfe55dcc173a86832314e1a6a35d"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:796ad874c89127c91970652a4ee8b00d56368b7e00d3477f4415fe78164c8000"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85608eb70a659bf4c1142b2781083d4b7c0c4e2c90eff11856a9754e965b2540"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4feb9211d15d9160bc85fa72fed46432cdc143eb9cf6d5ca377335a921ac37b"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ccfa689b9246c48947d31dd9d8b16d89a0ecc8e0e26ea5253068efb6c542b76e"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:3c5b317ecbd8226887994852e85de562f7177add602514d4ac40f87de3ae45a8"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:454601988aab2c6e8fd49e7634c65476b2b919647626208e376afcd22019eeb8"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:1c0c434a53714358532d13539272db75a5ed9df75a4a090a753ac7173ec14e11"},
- {file = "rpds_py-0.25.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f73ce1512e04fbe2bc97836e89830d6b4314c171587a99688082d090f934d20a"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee86d81551ec68a5c25373c5643d343150cc54672b5e9a0cafc93c1870a53954"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:89c24300cd4a8e4a51e55c31a8ff3918e6651b241ee8876a42cc2b2a078533ba"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:771c16060ff4e79584dc48902a91ba79fd93eade3aa3a12d6d2a4aadaf7d542b"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:785ffacd0ee61c3e60bdfde93baa6d7c10d86f15655bd706c89da08068dc5038"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a40046a529cc15cef88ac5ab589f83f739e2d332cb4d7399072242400ed68c9"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:85fc223d9c76cabe5d0bff82214459189720dc135db45f9f66aa7cffbf9ff6c1"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0be9965f93c222fb9b4cc254235b3b2b215796c03ef5ee64f995b1b69af0762"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8378fa4a940f3fb509c081e06cb7f7f2adae8cf46ef258b0e0ed7519facd573e"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:33358883a4490287e67a2c391dfaea4d9359860281db3292b6886bf0be3d8692"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1d1fadd539298e70cac2f2cb36f5b8a65f742b9b9f1014dd4ea1f7785e2470bf"},
- {file = "rpds_py-0.25.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a46c2fb2545e21181445515960006e85d22025bd2fe6db23e76daec6eb689fe"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:50f2c501a89c9a5f4e454b126193c5495b9fb441a75b298c60591d8a2eb92e1b"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d779b325cc8238227c47fbc53964c8cc9a941d5dbae87aa007a1f08f2f77b23"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:036ded36bedb727beeabc16dc1dad7cb154b3fa444e936a03b67a86dc6a5066e"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:245550f5a1ac98504147cba96ffec8fabc22b610742e9150138e5d60774686d7"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff7c23ba0a88cb7b104281a99476cccadf29de2a0ef5ce864959a52675b1ca83"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e37caa8cdb3b7cf24786451a0bdb853f6347b8b92005eeb64225ae1db54d1c2b"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2f48ab00181600ee266a095fe815134eb456163f7d6699f525dee471f312cf"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e5fc7484fa7dce57e25063b0ec9638ff02a908304f861d81ea49273e43838c1"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d3c10228d6cf6fe2b63d2e7985e94f6916fa46940df46b70449e9ff9297bd3d1"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:5d9e40f32745db28c1ef7aad23f6fc458dc1e29945bd6781060f0d15628b8ddf"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:35a8d1a24b5936b35c5003313bc177403d8bdef0f8b24f28b1c4a255f94ea992"},
- {file = "rpds_py-0.25.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6099263f526efff9cf3883dfef505518730f7a7a93049b1d90d42e50a22b4793"},
- {file = "rpds_py-0.25.1.tar.gz", hash = "sha256:8960b6dac09b62dac26e75d7e2c4a22efb835d827a7278c34f72b2b84fa160e3"},
+ {file = "rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37"},
+ {file = "rpds_py-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:777c62479d12395bfb932944e61e915741e364c843afc3196b694db3d669fcd0"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec671691e72dff75817386aa02d81e708b5a7ec0dec6669ec05213ff6b77e1bd"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a1cb5d6ce81379401bbb7f6dbe3d56de537fb8235979843f0d53bc2e9815a79"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f789e32fa1fb6a7bf890e0124e7b42d1e60d28ebff57fe806719abb75f0e9a3"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c55b0a669976cf258afd718de3d9ad1b7d1fe0a91cd1ab36f38b03d4d4aeaaf"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70d9ec912802ecfd6cd390dadb34a9578b04f9bcb8e863d0a7598ba5e9e7ccc"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3021933c2cb7def39d927b9862292e0f4c75a13d7de70eb0ab06efed4c508c19"},
+ {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a7898b6ca3b7d6659e55cdac825a2e58c638cbf335cde41f4619e290dd0ad11"},
+ {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:12bff2ad9447188377f1b2794772f91fe68bb4bbfa5a39d7941fbebdbf8c500f"},
+ {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:191aa858f7d4902e975d4cf2f2d9243816c91e9605070aeb09c0a800d187e323"},
+ {file = "rpds_py-0.26.0-cp310-cp310-win32.whl", hash = "sha256:b37a04d9f52cb76b6b78f35109b513f6519efb481d8ca4c321f6a3b9580b3f45"},
+ {file = "rpds_py-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:38721d4c9edd3eb6670437d8d5e2070063f305bfa2d5aa4278c51cedcd508a84"},
+ {file = "rpds_py-0.26.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e8cb77286025bdb21be2941d64ac6ca016130bfdcd228739e8ab137eb4406ed"},
+ {file = "rpds_py-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e09330b21d98adc8ccb2dbb9fc6cb434e8908d4c119aeaa772cb1caab5440a0"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9c1b92b774b2e68d11193dc39620d62fd8ab33f0a3c77ecdabe19c179cdbc1"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:824e6d3503ab990d7090768e4dfd9e840837bae057f212ff9f4f05ec6d1975e7"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ad7fd2258228bf288f2331f0a6148ad0186b2e3643055ed0db30990e59817a6"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dc23bbb3e06ec1ea72d515fb572c1fea59695aefbffb106501138762e1e915e"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d80bf832ac7b1920ee29a426cdca335f96a2b5caa839811803e999b41ba9030d"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0919f38f5542c0a87e7b4afcafab6fd2c15386632d249e9a087498571250abe3"},
+ {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d422b945683e409000c888e384546dbab9009bb92f7c0b456e217988cf316107"},
+ {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a7711fa562ba2da1aa757e11024ad6d93bad6ad7ede5afb9af144623e5f76a"},
+ {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238e8c8610cb7c29460e37184f6799547f7e09e6a9bdbdab4e8edb90986a2318"},
+ {file = "rpds_py-0.26.0-cp311-cp311-win32.whl", hash = "sha256:893b022bfbdf26d7bedb083efeea624e8550ca6eb98bf7fea30211ce95b9201a"},
+ {file = "rpds_py-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:87a5531de9f71aceb8af041d72fc4cab4943648d91875ed56d2e629bef6d4c03"},
+ {file = "rpds_py-0.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:de2713f48c1ad57f89ac25b3cb7daed2156d8e822cf0eca9b96a6f990718cc41"},
+ {file = "rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d"},
+ {file = "rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323"},
+ {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158"},
+ {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3"},
+ {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2"},
+ {file = "rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44"},
+ {file = "rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c"},
+ {file = "rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8"},
+ {file = "rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d"},
+ {file = "rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1"},
+ {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9"},
+ {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9"},
+ {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba"},
+ {file = "rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b"},
+ {file = "rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5"},
+ {file = "rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9"},
+ {file = "rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a"},
+ {file = "rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387"},
+ {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af"},
+ {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33"},
+ {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953"},
+ {file = "rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9"},
+ {file = "rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37"},
+ {file = "rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7"},
+ {file = "rpds_py-0.26.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:7a48af25d9b3c15684059d0d1fc0bc30e8eee5ca521030e2bffddcab5be40226"},
+ {file = "rpds_py-0.26.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c71c2f6bf36e61ee5c47b2b9b5d47e4d1baad6426bfed9eea3e858fc6ee8806"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d815d48b1804ed7867b539236b6dd62997850ca1c91cad187f2ddb1b7bbef19"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84cfbd4d4d2cdeb2be61a057a258d26b22877266dd905809e94172dff01a42ae"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbaa70553ca116c77717f513e08815aec458e6b69a028d4028d403b3bc84ff37"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39bfea47c375f379d8e87ab4bb9eb2c836e4f2069f0f65731d85e55d74666387"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1533b7eb683fb5f38c1d68a3c78f5fdd8f1412fa6b9bf03b40f450785a0ab915"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5ab0ee51f560d179b057555b4f601b7df909ed31312d301b99f8b9fc6028284"},
+ {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e5162afc9e0d1f9cae3b577d9c29ddbab3505ab39012cb794d94a005825bde21"},
+ {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:43f10b007033f359bc3fa9cd5e6c1e76723f056ffa9a6b5c117cc35720a80292"},
+ {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3730a48e5622e598293eee0762b09cff34dd3f271530f47b0894891281f051d"},
+ {file = "rpds_py-0.26.0-cp39-cp39-win32.whl", hash = "sha256:4b1f66eb81eab2e0ff5775a3a312e5e2e16bf758f7b06be82fb0d04078c7ac51"},
+ {file = "rpds_py-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:519067e29f67b5c90e64fb1a6b6e9d2ec0ba28705c51956637bac23a2f4ddae1"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3c0909c5234543ada2515c05dc08595b08d621ba919629e94427e8e03539c958"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c1fb0cda2abcc0ac62f64e2ea4b4e64c57dfd6b885e693095460c61bde7bb18e"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d142d2d6cf9b31c12aa4878d82ed3b2324226270b89b676ac62ccd7df52d08"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a547e21c5610b7e9093d870be50682a6a6cf180d6da0f42c47c306073bfdbbf6"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35e9a70a0f335371275cdcd08bc5b8051ac494dd58bff3bbfb421038220dc871"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dfa6115c6def37905344d56fb54c03afc49104e2ca473d5dedec0f6606913b4"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:313cfcd6af1a55a286a3c9a25f64af6d0e46cf60bc5798f1db152d97a216ff6f"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7bf2496fa563c046d05e4d232d7b7fd61346e2402052064b773e5c378bf6f73"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:aa81873e2c8c5aa616ab8e017a481a96742fdf9313c40f14338ca7dbf50cb55f"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:68ffcf982715f5b5b7686bdd349ff75d422e8f22551000c24b30eaa1b7f7ae84"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6188de70e190847bb6db3dc3981cbadff87d27d6fe9b4f0e18726d55795cee9b"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1c962145c7473723df9722ba4c058de12eb5ebedcb4e27e7d902920aa3831ee8"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f61a9326f80ca59214d1cceb0a09bb2ece5b2563d4e0cd37bfd5515c28510674"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:183f857a53bcf4b1b42ef0f57ca553ab56bdd170e49d8091e96c51c3d69ca696"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:941c1cfdf4799d623cf3aa1d326a6b4fdb7a5799ee2687f3516738216d2262fb"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72a8d9564a717ee291f554eeb4bfeafe2309d5ec0aa6c475170bdab0f9ee8e88"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:511d15193cbe013619dd05414c35a7dedf2088fcee93c6bbb7c77859765bd4e8"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aea1f9741b603a8d8fedb0ed5502c2bc0accbc51f43e2ad1337fe7259c2b77a5"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4019a9d473c708cf2f16415688ef0b4639e07abaa569d72f74745bbeffafa2c7"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:093d63b4b0f52d98ebae33b8c50900d3d67e0666094b1be7a12fffd7f65de74b"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2abe21d8ba64cded53a2a677e149ceb76dcf44284202d737178afe7ba540c1eb"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:4feb7511c29f8442cbbc28149a92093d32e815a28aa2c50d333826ad2a20fdf0"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e99685fc95d386da368013e7fb4269dd39c30d99f812a8372d62f244f662709c"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a90a13408a7a856b87be8a9f008fff53c5080eea4e4180f6c2e546e4a972fb5d"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ac51b65e8dc76cf4949419c54c5528adb24fc721df722fd452e5fbc236f5c40"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b2093224a18c6508d95cfdeba8db9cbfd6f3494e94793b58972933fcee4c6d"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f01a5d6444a3258b00dc07b6ea4733e26f8072b788bef750baa37b370266137"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6e2c12160c72aeda9d1283e612f68804621f448145a210f1bf1d79151c47090"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb28c1f569f8d33b2b5dcd05d0e6ef7005d8639c54c2f0be824f05aedf715255"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1766b5724c3f779317d5321664a343c07773c8c5fd1532e4039e6cc7d1a815be"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b6d9e5a2ed9c4988c8f9b28b3bc0e3e5b1aaa10c28d210a594ff3a8c02742daf"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b5f7a446ddaf6ca0fad9a5535b56fbfc29998bf0e0b450d174bbec0d600e1d72"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:eed5ac260dd545fbc20da5f4f15e7efe36a55e0e7cf706e4ec005b491a9546a0"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:582462833ba7cee52e968b0341b85e392ae53d44c0f9af6a5927c80e539a8b67"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69a607203441e07e9a8a529cff1d5b73f6a160f22db1097211e6212a68567d11"},
+ {file = "rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0"},
]
[[package]]
@@ -5183,4 +5163,4 @@ worker = ["celery", "celery-prometheus-exporter", "django-celery-beat", "django-
[metadata]
lock-version = "2.0"
python-versions = ">=3.12,<3.13"
-content-hash = "659721d93224050ebe572b017a80d45826b288764427c24bd07fbd35b704fa48"
+content-hash = "58d67f7b6c2313bdb117965a9c9555319bbb059db043e5723d39a27c36695939"
diff --git a/pyproject.toml b/pyproject.toml
index 0ed53114..c84498a5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "eVibes"
-version = "2.8.10"
+version = "2.9.2"
description = "eVibes is an open-source eCommerce backend service built with Django. It’s designed for flexibility, making it ideal for various use cases and learning Django skills. The project is easy to customize, allowing for straightforward editing and extension."
authors = ["fureunoir "]
readme = "README.md"
@@ -19,7 +19,6 @@ django-celery-beat = { version = "2.8.1", optional = true }
django-celery-results = { version = "2.6.0", optional = true }
django-constance = "4.3.2"
django-cors-headers = "4.7.0"
-django-daisy = "1.0.26"
django-dbbackup = "4.3.0"
django-elasticsearch-dsl = "8.0"
django-elasticsearch-dsl-drf = "0.22.5"
@@ -27,6 +26,7 @@ django-extensions = "4.1"
django-filter = "25.1"
django-health-check = "3.20.0"
django-hosts = "6.0"
+django-jazzmin = "3.0.1"
django-json-widget = "2.0.1"
django-mailbox = "4.10.1"
django-model-utils = "5.0.0"
@@ -47,6 +47,7 @@ djangorestframework-simplejwt = { extras = ["crypto"], version = "5.5.0" }
djangorestframework-stubs = "3.16.0"
djangorestframework-xml = "2.0.0"
djangorestframework-yaml = "2.0.0"
+docutils = "0.21.2"
drf-spectacular = { extras = ["sidecar"], version = "0.28.0" }
elasticsearch = "8.18.1"
elasticsearch-dsl = "8.18.0"
@@ -102,22 +103,22 @@ testing = ["pytest", "pytest-django", "coverage"]
linting = ["black", "isort", "flake8", "bandit"]
[tool.mypy]
-disable_error_code = ["import-untyped", "misc"]
-exclude = ["*/migrations/*", "./evibes/settings/drf.py"]
+disable_error_code = ["no-redef", "import-untyped"]
+exclude = ["*/migrations/*", "storefront/*"]
+plugins = ["mypy_django_plugin.main", "mypy_drf_plugin.main"]
+
+[tool.django-stubs]
+django_settings_module = "evibes.settings"
[tool.ruff]
line-length = 120
target-version = "py312"
-exclude = ["migrations", "media", "static", "storefront"]
+exclude = ["media", "static", "storefront"]
[tool.ruff.lint]
-select = ["E", "W", "F", "B", "I", "RUF", "UP", "N", "A", "COM", "C4", "DJ001", "RSE", "SIM", "ISC", "TID252", "PGH004"]
-ignore = ["B904", "RUF001", "RUF002", "RUF003", "RUF005", "RUF012", "A003", "A002", "COM812", "S603"]
-per-file-ignores = { "__init__.py" = ["E402", "F401"] }
+select = ["E4", "E7", "E9", "F", "B", "Q"]
+ignore = ["RUF012", "A002", "A003"]
[tool.ruff.format]
quote-style = "double"
-indent-style = "space"
-
-[tool.yapf]
-based_on_style = "pep8"
\ No newline at end of file
+indent-style = "space"
\ No newline at end of file
diff --git a/scripts/Docker/app-entrypoint.sh b/scripts/Docker/app-entrypoint.sh
index 73fb6d95..05ddd61e 100644
--- a/scripts/Docker/app-entrypoint.sh
+++ b/scripts/Docker/app-entrypoint.sh
@@ -1,4 +1,4 @@
-#!/usr/bin/env sh
+#!/usr/bin/bash
set -e
# wait for auxiliary services
@@ -18,4 +18,4 @@ else
--bind 0.0.0.0:8000 \
--workers 12 \
--timeout 120
-fi
\ No newline at end of file
+fi
diff --git a/scripts/Docker/beat-entrypoint.sh b/scripts/Docker/beat-entrypoint.sh
index f0db32d5..d1779697 100644
--- a/scripts/Docker/beat-entrypoint.sh
+++ b/scripts/Docker/beat-entrypoint.sh
@@ -1,8 +1,8 @@
-#!/usr/bin/env sh
+#!/usr/bin/bash
set -e
# wait for auxiliary services
poetry run python manage.py await_services
# run beat
-poetry run celery -A evibes beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
\ No newline at end of file
+poetry run celery -A evibes beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler
diff --git a/scripts/Docker/stock-updater-entrypoint.sh b/scripts/Docker/stock-updater-entrypoint.sh
new file mode 100644
index 00000000..1686cd32
--- /dev/null
+++ b/scripts/Docker/stock-updater-entrypoint.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/bash
+set -e
+
+# wait for auxiliary services
+poetry run python manage.py await_services
+
+# run stock_updater
+poetry run celery -A evibes worker --pool=prefork --concurrency=1 --queues=stock_updater --loglevel=info --max-tasks-per-child=1
diff --git a/scripts/Docker/worker-entrypoint.sh b/scripts/Docker/worker-entrypoint.sh
index 9c81ffdc..f811766f 100644
--- a/scripts/Docker/worker-entrypoint.sh
+++ b/scripts/Docker/worker-entrypoint.sh
@@ -1,8 +1,8 @@
-#!/usr/bin/env sh
+#!/usr/bin/bash
set -e
# wait for auxiliary services
poetry run python manage.py await_services
-# run workers and metrics exporter
-poetry run celery -A evibes worker --loglevel=info -E --concurrency=4 --autoscale=4,2 --max-tasks-per-child=100 --max-memory-per-child=512000 --soft-time-limit=10800 --time-limit=21600 & /usr/local/bin/celery-prometheus-exporter
\ No newline at end of file
+# run worker and metrics exporter
+poetry run celery -A evibes worker --pool=prefork --concurrency=8 --loglevel=info -E --queues=default --prefetch-multiplier=1 --max-tasks-per-child=100 --max-memory-per-child=512000 --soft-time-limit=3600 --time-limit=7200 & /usr/local/bin/celery-prometheus-exporter
diff --git a/scripts/Unix/generate-environment-file.sh b/scripts/Unix/generate-environment-file.sh
index dfa3618d..47703cdf 100755
--- a/scripts/Unix/generate-environment-file.sh
+++ b/scripts/Unix/generate-environment-file.sh
@@ -38,6 +38,7 @@ FRONTEND_DOMAIN=$(prompt_default EVIBES_FRONTEND_DOMAIN evibes.com)
BASE_DOMAIN=$(prompt_default EVIBES_BASE_DOMAIN evibes.com)
SENTRY_DSN=$(prompt_default SENTRY_DSN "")
DEBUG=$(prompt_default DEBUG 1)
+TIME_ZONE=$(prompt_default TIME_ZONE "Europe/London")
SECRET_KEY=$(prompt_autogen SECRET_KEY 32)
JWT_SIGNING_KEY=$(prompt_autogen JWT_SIGNING_KEY 64)
@@ -50,9 +51,10 @@ POSTGRES_DB=$(prompt_default POSTGRES_DB evibes)
POSTGRES_USER=$(prompt_default POSTGRES_USER evibes_user)
POSTGRES_PASSWORD=$(prompt_autogen POSTGRES_PASSWORD 16)
-DBBACKUP_SFTP_HOST=$(prompt_default DBBACKUP_SFTP_HOST "Your SFTP backup host")
-DBBACKUP_SFTP_USER=$(prompt_default DBBACKUP_SFTP_USER "The username to use to log in to that host")
-DBBACKUP_SFTP_PASS=$(prompt_default DBBACKUP_SFTP_PASS "The password to use to log in to that host")
+DBBACKUP_TYPE=$(prompt_default DBBACKUP_TYPE "Your backup connection type")
+DBBACKUP_HOST=$(prompt_default DBBACKUP_HOST "Your SFTP backup host")
+DBBACKUP_USER=$(prompt_default DBBACKUP_USER "The username to use to log in to that host")
+DBBACKUP_PASS=$(prompt_default DBBACKUP_PASS "The password to use to log in to that host")
ELASTIC_PASSWORD=$(prompt_autogen ELASTIC_PASSWORD 16)
REDIS_PASSWORD=$(prompt_autogen REDIS_PASSWORD 16)
diff --git a/scripts/Unix/reboot.sh b/scripts/Unix/reboot.sh
index 7f855a12..ea45fd1f 100755
--- a/scripts/Unix/reboot.sh
+++ b/scripts/Unix/reboot.sh
@@ -16,7 +16,7 @@ docker compose exec app poetry run python manage.py migrate --no-input --verbosi
echo "Migrations applied successfully!"
echo "Collecting static files..."
-docker compose exec app poetry run python manage.py collectstatic --no-input --verbosity 0
+docker compose exec app poetry run python manage.py collectstatic --clear --no-input --verbosity 0
echo "Static files collected successfully!"
echo "Setting default caches..."
diff --git a/scripts/Unix/run.sh b/scripts/Unix/run.sh
index 99c9507f..efdd2882 100755
--- a/scripts/Unix/run.sh
+++ b/scripts/Unix/run.sh
@@ -22,7 +22,7 @@ docker compose exec app poetry run python manage.py migrate --no-input
echo "Migrations applied successfully!"
echo "Collecting static files…"
-docker compose exec app poetry run python manage.py collectstatic --no-input
+docker compose exec app poetry run python manage.py collectstatic --clear --no-input
echo "Static files collected successfully!"
echo "Setting default caches…"
diff --git a/scripts/Windows/backup.ps1 b/scripts/Windows/backup.ps1
index cc12a11b..bf890dd7 100644
--- a/scripts/Windows/backup.ps1
+++ b/scripts/Windows/backup.ps1
@@ -3,11 +3,20 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Starting database backup process..." -ForegroundColor Magenta
docker compose exec app poetry run python manage.py dbbackup
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Database backup created under ./dbbackup" -ForegroundColor Green
Write-Host "Starting media backup process..." -ForegroundColor Magenta
docker compose exec app poetry run python manage.py mediabackup
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Media backup created under ./dbbackup" -ForegroundColor Green
\ No newline at end of file
diff --git a/scripts/Windows/compile-messages.ps1 b/scripts/Windows/compile-messages.ps1
new file mode 100644
index 00000000..c80b9c9a
--- /dev/null
+++ b/scripts/Windows/compile-messages.ps1
@@ -0,0 +1,27 @@
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+
+if (-not (Test-Path '.env'))
+{
+ Write-Warning ".env file not found. Exiting without running Docker steps."
+ exit 0
+}
+
+Write-Host "Checking placeholders in PO files..." -ForegroundColor Magenta
+docker compose exec app poetry run python manage.py check_translated -l en-GB -l ar-AR -l cs-CZ -l da-DK -l de-DE -l en-US -l es-ES -l fr-FR -l hi-IN -l it-IT -l ja-JP -l kk-KZ -l nl-NL -l pl-PL -l pt-BR -l ro-RO -l ru-RU -l zh-hans -a core -a geo -a payments -a vibes_auth -a blog -a root
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+Write-Host "PO files have no placeholder issues!" -ForegroundColor Green
+
+Write-Host "Compiling PO files into MO files..." -ForegroundColor Magenta
+docker compose exec app poetry run python manage.py compilemessages -l en_GB -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_US -l es_ES -l fr_FR -l hi_IN -l it_IT -l ja_JP -l kk_KZ -l nl_NL -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l zh_Hans
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+Write-Host "Compiled successfully!" -ForegroundColor Green
diff --git a/scripts/Windows/export-environment-file.ps1 b/scripts/Windows/export-environment-file.ps1
index 010d44b0..402cba9e 100644
--- a/scripts/Windows/export-environment-file.ps1
+++ b/scripts/Windows/export-environment-file.ps1
@@ -3,6 +3,9 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
$envFile = '.env'
diff --git a/scripts/Windows/generate-environment-file.ps1 b/scripts/Windows/generate-environment-file.ps1
index 62c1410a..7499cffd 100644
--- a/scripts/Windows/generate-environment-file.ps1
+++ b/scripts/Windows/generate-environment-file.ps1
@@ -2,6 +2,9 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
function Get-RandomHex
{
@@ -46,55 +49,57 @@ if (Test-Path '.env')
Read-Host "Press Enter to continue or Ctrl+C to abort"
}
-$PROJECT_NAME = Prompt-Default 'EVIBES_PROJECT_NAME' 'eVibes'
-$FRONTEND_DOMAIN = Prompt-Default 'EVIBES_FRONTEND_DOMAIN' 'evibes.com'
-$BASE_DOMAIN = Prompt-Default 'EVIBES_BASE_DOMAIN' 'evibes.com'
-$SENTRY_DSN = Prompt-Default 'SENTRY_DSN' ''
-$DEBUG = Prompt-Default 'DEBUG' '1'
+$EVIBES_PROJECT_NAME = Prompt-Default 'EVIBES_PROJECT_NAME' 'eVibes'
+$EVIBES_FRONTEND_DOMAIN = Prompt-Default 'EVIBES_FRONTEND_DOMAIN' 'evibes.com'
+$EVIBES_BASE_DOMAIN = Prompt-Default 'EVIBES_BASE_DOMAIN' 'evibes.com'
+$SENTRY_DSN = Prompt-Default 'SENTRY_DSN' ''
+$DEBUG = Prompt-Default 'DEBUG' '1'
+$TIME_ZONE = Prompt-Default 'TIME_ZONE' 'Europe/London'
-$SECRET_KEY = Prompt-AutoGen 'SECRET_KEY' 32
-$JWT_SIGNING_KEY = Prompt-AutoGen 'JWT_SIGNING_KEY' 64
+$SECRET_KEY = Prompt-AutoGen 'SECRET_KEY' 32
+$JWT_SIGNING_KEY = Prompt-AutoGen 'JWT_SIGNING_KEY' 64
-$ALLOWED_HOSTS = Prompt-Default 'ALLOWED_HOSTS' 'evibes.com api.evibes.com b2b.evibes.com'
+$ALLOWED_HOSTS = Prompt-Default 'ALLOWED_HOSTS' 'evibes.com api.evibes.com b2b.evibes.com'
$CSRF_TRUSTED_ORIGINS = Prompt-Default 'CSRF_TRUSTED_ORIGINS' 'https://evibes.com https://api.evibes.com https://www.evibes.com https://b2b.evibes.com'
$CORS_ALLOWED_ORIGINS = Prompt-Default 'CORS_ALLOWED_ORIGINS' $CSRF_TRUSTED_ORIGINS
-$POSTGRES_DB = Prompt-Default 'POSTGRES_DB' 'evibes'
-$POSTGRES_USER = Prompt-Default 'POSTGRES_USER' 'evibes_user'
-$POSTGRES_PASSWORD = Prompt-AutoGen 'POSTGRES_PASSWORD' 16
+$POSTGRES_DB = Prompt-Default 'POSTGRES_DB' 'evibes'
+$POSTGRES_USER = Prompt-Default 'POSTGRES_USER' 'evibes_user'
+$POSTGRES_PASSWORD = Prompt-AutoGen 'POSTGRES_PASSWORD' 16
-$DBBACKUP_SFTP_HOST = Prompt-Default 'DBBACKUP_SFTP_HOST' 'Your SFTP backup host'
-$DBBACKUP_SFTP_USER = Prompt-Default 'DBBACKUP_SFTP_USER' 'The username to use to log in to that host'
-$DBBACKUP_SFTP_PASS = Prompt-Default 'DBBACKUP_SFTP_PASS' 'The password to use to log in to that host'
+$DBBACKUP_TYPE = Prompt-Default 'DBBACKUP_TYPE' 'Your backup connection type'
+$DBBACKUP_HOST = Prompt-Default 'DBBACKUP_HOST' 'Your SFTP backup host'
+$DBBACKUP_USER = Prompt-Default 'DBBACKUP_USER' 'The username to use to log in to that host'
+$DBBACKUP_PASS = Prompt-Default 'DBBACKUP_PASS' 'The password to use to log in to that host'
-$ELASTIC_PASSWORD = Prompt-AutoGen 'ELASTIC_PASSWORD' 16
+$ELASTIC_PASSWORD = Prompt-AutoGen 'ELASTIC_PASSWORD' 16
-$REDIS_PASSWORD = Prompt-AutoGen 'REDIS_PASSWORD' 16
+$REDIS_PASSWORD = Prompt-AutoGen 'REDIS_PASSWORD' 16
-$PROMETHEUS_USER = Prompt-Default 'PROMETHEUS_USER' 'evibes'
+$PROMETHEUS_USER = Prompt-Default 'PROMETHEUS_USER' 'evibes'
$PROMETHEUS_PASSWORD = Prompt-AutoGen 'PROMETHEUS_PASSWORD' 16
-$EMAIL_BACKEND = Prompt-Default 'EMAIL_BACKEND' 'django.core.mail.backends.smtp.EmailBackend'
-$EMAIL_HOST = Prompt-Default 'EMAIL_HOST' 'smtp.whatever.evibes.com'
-$EMAIL_PORT = Prompt-Default 'EMAIL_PORT' '465'
-$EMAIL_USE_TLS = Prompt-Default 'EMAIL_USE_TLS' '0'
-$EMAIL_USE_SSL = Prompt-Default 'EMAIL_USE_SSL' '1'
-$EMAIL_HOST_USER = Prompt-Default 'EMAIL_HOST_USER' 'your-email-user@whatever.evibes.com'
-$EMAIL_FROM = Prompt-Default 'EMAIL_FROM' $EMAIL_HOST_USER
+$EMAIL_BACKEND = Prompt-Default 'EMAIL_BACKEND' 'django.core.mail.backends.smtp.EmailBackend'
+$EMAIL_HOST = Prompt-Default 'EMAIL_HOST' 'smtp.whatever.evibes.com'
+$EMAIL_PORT = Prompt-Default 'EMAIL_PORT' '465'
+$EMAIL_USE_TLS = Prompt-Default 'EMAIL_USE_TLS' '0'
+$EMAIL_USE_SSL = Prompt-Default 'EMAIL_USE_SSL' '1'
+$EMAIL_HOST_USER = Prompt-Default 'EMAIL_HOST_USER' 'your-email-user@whatever.evibes.com'
+$EMAIL_FROM = Prompt-Default 'EMAIL_FROM' $EMAIL_HOST_USER
$EMAIL_HOST_PASSWORD = Prompt-Default 'EMAIL_HOST_PASSWORD' 'SUPERSECRETEMAILHOSTPASSWORD'
-$COMPANY_NAME = Prompt-Default 'COMPANY_NAME' 'eVibes, Inc.'
-$COMPANY_PHONE_NUMBER = Prompt-Default 'COMPANY_PHONE_NUMBER' '+888888888888'
-$COMPANY_ADDRESS = Prompt-Default 'COMPANY_ADDRESS' 'The place that does not exist'
+$COMPANY_NAME = Prompt-Default 'COMPANY_NAME' 'eVibes, Inc.'
+$COMPANY_PHONE_NUMBER = Prompt-Default 'COMPANY_PHONE_NUMBER' '+888888888888'
+$COMPANY_ADDRESS = Prompt-Default 'COMPANY_ADDRESS' 'The place that does not exist'
-$OPENAI_API_KEY = Prompt-Default 'OPENAI_API_KEY' 'Haha, really?'
-$ABSTRACT_API_KEY = Prompt-Default 'ABSTRACT_API_KEY' 'Haha, really? x2'
-$DEEPL_AUTH_KEY = Prompt-Default 'DEEPL_AUTH_KEY' 'Haha, really? x3'
+$OPENAI_API_KEY = Prompt-Default 'OPENAI_API_KEY' 'Haha, really?'
+$ABSTRACT_API_KEY = Prompt-Default 'ABSTRACT_API_KEY' 'Haha, really? x2'
+$DEEPL_AUTH_KEY = Prompt-Default 'DEEPL_AUTH_KEY' 'Haha, really? x3'
$lines = @(
- "EVIBES_PROJECT_NAME=""$PROJECT_NAME"""
- "EVIBES_FRONTEND_DOMAIN=""$FRONTEND_DOMAIN"""
- "EVIBES_BASE_DOMAIN=""$BASE_DOMAIN"""
+ "EVIBES_PROJECT_NAME=""$EVIBES_PROJECT_NAME"""
+ "EVIBES_FRONTEND_DOMAIN=""$EVIBES_FRONTEND_DOMAIN"""
+ "EVIBES_BASE_DOMAIN=""$EVIBES_BASE_DOMAIN"""
"SENTRY_DSN=""$SENTRY_DSN"""
"DEBUG=$DEBUG"
""
@@ -109,9 +114,10 @@ $lines = @(
"POSTGRES_USER=""$POSTGRES_USER"""
"POSTGRES_PASSWORD=""$POSTGRES_PASSWORD"""
""
- "DBBACKUP_SFTP_HOST=""$DBBACKUP_SFTP_HOST"""
- "DBBACKUP_SFTP_USER=""$DBBACKUP_SFTP_USER"""
- "DBBACKUP_SFTP_PASS=""$DBBACKUP_SFTP_PASS"""
+ "DBBACKUP_TYPE=""$DBBACKUP_TYPE"""
+ "DBBACKUP_HOST=""$DBBACKUP_HOST"""
+ "DBBACKUP_USER=""$DBBACKUP_USER"""
+ "DBBACKUP_PASS=""$DBBACKUP_PASS"""
""
"ELASTIC_PASSWORD=""$ELASTIC_PASSWORD"""
""
diff --git a/scripts/Windows/install.ps1 b/scripts/Windows/install.ps1
index c0d49dca..0df9aec8 100644
--- a/scripts/Windows/install.ps1
+++ b/scripts/Windows/install.ps1
@@ -2,6 +2,9 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
if (-not (Test-Path '.env'))
{
diff --git a/scripts/Windows/make-messages.ps1 b/scripts/Windows/make-messages.ps1
new file mode 100644
index 00000000..c7ca8997
--- /dev/null
+++ b/scripts/Windows/make-messages.ps1
@@ -0,0 +1,44 @@
+Set-StrictMode -Version Latest
+$ErrorActionPreference = 'Stop'
+
+.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+
+if (-not (Test-Path '.env'))
+{
+ Write-Warning ".env file not found. Exiting without running Docker steps."
+ exit 0
+}
+
+Write-Host "Remove old fuzzy entries..." -ForegroundColor Magenta
+docker compose exec app poetry run python manage.py fix_fuzzy
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+Write-Host "Old fuzzy entries removed successfully!" -ForegroundColor Green
+
+Write-Host "Updating PO files..." -ForegroundColor Magenta
+docker compose exec app poetry run python manage.py makemessages -l en_GB -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_US -l es_ES -l fr_FR -l hi_IN -l it_IT -l ja_JP -l kk_KZ -l nl_NL -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l zh_Hans
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+Write-Host "PO files updated successfully!" -ForegroundColor Green
+
+Write-Host "Fixing new fuzzy entries..." -ForegroundColor Magenta
+docker compose exec app poetry run python manage.py fix_fuzzy
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+Write-Host "New fuzzy entries fixed successfully!" -ForegroundColor Green
+
+Write-Host "Translating with DeepL..." -ForegroundColor Magenta
+docker compose exec app poetry run python manage.py deepl_translate -l en-gb -l ar-ar -l cs-cz -l da-dk -l de-de -l en-us -l es-es -l fr-fr -l hi-in -l it-it -l ja-jp -l kk-kz -l nl-nl -l pl-pl -l pt-br -l ro-ro -l ru-ru -l zh-hans -a core -a geo -a payments -a vibes_auth -a blog -a root
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+Write-Host "Translated successfully!" -ForegroundColor Green
+
+Write-Host ""
+Write-Host "You can now use compile-messages.ps1 script." -ForegroundColor Cyan
diff --git a/scripts/Windows/reboot.ps1 b/scripts/Windows/reboot.ps1
index a6f48430..ec0e2f2c 100644
--- a/scripts/Windows/reboot.ps1
+++ b/scripts/Windows/reboot.ps1
@@ -2,30 +2,51 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Shutting down..." -ForegroundColor Magenta
docker compose down
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Services were shut down successfully!" -ForegroundColor Green
Write-Host "Spinning services up..." -ForegroundColor Magenta
docker compose up -d --build --wait
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Services are up and healthy!" -ForegroundColor Green
Write-Host "Applying migrations..." -ForegroundColor Magenta
docker compose exec app poetry run python manage.py migrate --no-input --verbosity 0
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Migrations applied successfully!" -ForegroundColor Green
Write-Host "Collecting static files..." -ForegroundColor Magenta
-docker compose exec app poetry run python manage.py collectstatic --no-input --verbosity 0
+docker compose exec app poetry run python manage.py collectstatic --clear --no-input --verbosity 0
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Static files collected successfully!" -ForegroundColor Green
Write-Host "Setting default caches..." -ForegroundColor Magenta
docker compose exec app poetry run python manage.py set_default_caches
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Default caches set successfully!" -ForegroundColor Green
Write-Host "Cleaning up unused Docker data..." -ForegroundColor Magenta
docker system prune -f
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Unused Docker data cleaned successfully!" -ForegroundColor Green
Write-Host "All done! eVibes is up and running!" -ForegroundColor Cyan
diff --git a/scripts/Windows/run.ps1 b/scripts/Windows/run.ps1
index e43b7a9c..38f756aa 100644
--- a/scripts/Windows/run.ps1
+++ b/scripts/Windows/run.ps1
@@ -2,6 +2,9 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Verifying all images are present…" -ForegroundColor Green
@@ -29,22 +32,37 @@ foreach ($prop in $config.services.PSObject.Properties)
Write-Host "Spinning services up..." -ForegroundColor Magenta
docker compose up --no-build --detach --wait
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Services are up and healthy!" -ForegroundColor Green
Write-Host "Applying migrations..." -ForegroundColor Magenta
docker compose exec app poetry run python manage.py migrate --no-input
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Migrations applied successfully!" -ForegroundColor Green
Write-Host "Collecting static files..." -ForegroundColor Magenta
-docker compose exec app poetry run python manage.py collectstatic --no-input
+docker compose exec app poetry run python manage.py collectstatic --clear --no-input
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Static files collected successfully!" -ForegroundColor Green
Write-Host "Setting default caches..." -ForegroundColor Magenta
docker compose exec app poetry run python manage.py set_default_caches
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Default caches set successfully!" -ForegroundColor Green
Write-Host "Cleaning unused Docker data..." -ForegroundColor Magenta
docker system prune -f
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Unused Docker data cleaned successfully!" -ForegroundColor Green
Write-Host "All done! eVibes is up and running!" -ForegroundColor Cyan
diff --git a/scripts/Windows/starter.ps1 b/scripts/Windows/starter.ps1
index dc4914f5..7a847b58 100644
--- a/scripts/Windows/starter.ps1
+++ b/scripts/Windows/starter.ps1
@@ -18,4 +18,5 @@ if (-not (Test-Path $artPath))
}
Get-Content -Raw -Path $artPath | ForEach-Object { Write-Host "$purple$_$reset" }
-Write-Host "`n by WISELESS TEAM`n" -ForegroundColor Gray
\ No newline at end of file
+Write-Host "`n by WISELESS TEAM`n" -ForegroundColor Gray
+exit 0
\ No newline at end of file
diff --git a/scripts/Windows/uninstall.ps1 b/scripts/Windows/uninstall.ps1
index bee7d3a4..2ef36b9f 100644
--- a/scripts/Windows/uninstall.ps1
+++ b/scripts/Windows/uninstall.ps1
@@ -2,18 +2,33 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
.\scripts\Windows\starter.ps1
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Shutting down..." -ForegroundColor Magenta
docker compose down
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Services were shut down successfully!" -ForegroundColor Green
Write-Host "Removing volumes..." -ForegroundColor Magenta
docker volume remove -f evibes_prometheus-data
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
docker volume remove -f evibes_es-data
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Volumes were removed successfully!" -ForegroundColor Green
Write-Host "Cleaning up unused Docker data..." -ForegroundColor Magenta
docker system prune -a -f --volumes
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
Write-Host "Unused Docker data cleaned successfully!" -ForegroundColor Green
Write-Host "Removing related files..." -ForegroundColor Magenta
diff --git a/storefront/.gitkeep b/storefront/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/vibes_auth/admin.py b/vibes_auth/admin.py
index 3c1fc286..7dc34ba1 100644
--- a/vibes_auth/admin.py
+++ b/vibes_auth/admin.py
@@ -22,7 +22,7 @@ from rest_framework_simplejwt.token_blacklist.models import (
OutstandingToken as BaseOutstandingToken,
)
-from core.admin import BasicModelAdmin
+from core.admin import ActivationActionsMixin
from core.models import Order
from payments.models import Balance
from vibes_auth.forms import UserForm
@@ -48,7 +48,7 @@ class OrderInline(admin.TabularInline):
icon = "fa-solid fa-cart-shopping"
-class UserAdmin(BaseUserAdmin, BasicModelAdmin):
+class UserAdmin(ActivationActionsMixin, BaseUserAdmin): # type: ignore [misc]
inlines = (BalanceInline, OrderInline)
fieldsets = (
(None, {"fields": ("email", "password")}),
@@ -110,15 +110,15 @@ class UserAdmin(BaseUserAdmin, BasicModelAdmin):
super().save_model(request, obj, form, change)
-class GroupAdmin(BaseGroupAdmin, BasicModelAdmin):
+class GroupAdmin(BaseGroupAdmin):
pass
-class BlacklistedTokenAdmin(BaseBlacklistedTokenAdmin, BasicModelAdmin):
+class BlacklistedTokenAdmin(BaseBlacklistedTokenAdmin):
pass
-class OutstandingTokenAdmin(BaseOutstandingTokenAdmin, BasicModelAdmin):
+class OutstandingTokenAdmin(BaseOutstandingTokenAdmin):
pass
diff --git a/vibes_auth/graphene/mutations.py b/vibes_auth/graphene/mutations.py
index 9c7fe76a..c72d7379 100644
--- a/vibes_auth/graphene/mutations.py
+++ b/vibes_auth/graphene/mutations.py
@@ -25,7 +25,7 @@ from vibes_auth.serializers import (
from vibes_auth.utils.emailing import send_reset_password_email_task
from vibes_auth.validators import is_valid_email, is_valid_phone_number
-logger = logging.getLogger(__name__)
+logger = logging.getLogger("django")
class CreateUser(BaseMutation):
@@ -102,9 +102,9 @@ class UpdateUser(BaseMutation):
try:
user = User.objects.get(uuid=uuid)
- except User.DoesNotExist:
+ except User.DoesNotExist as dne:
name = "User"
- raise Http404(_(f"{name} does not exist: {uuid}"))
+ raise Http404(_(f"{name} does not exist: {uuid}")) from dne
if not (info.context.user.has_perm("vibes_auth.change_user") or info.context.user == user):
raise PermissionDenied(permission_denied_message)
@@ -176,8 +176,8 @@ class DeleteUser(BaseMutation):
else:
raise BadRequest("uuid or email must be specified")
return DeleteUser(success=True)
- except User.DoesNotExist:
- raise Http404(f"User with the given uuid: {uuid} or email: {email} does not exist.")
+ except User.DoesNotExist as dne:
+ raise Http404(f"User with the given uuid: {uuid} or email: {email} does not exist.") from dne
raise PermissionDenied(permission_denied_message)
@@ -201,7 +201,7 @@ class ObtainJSONWebToken(BaseMutation):
access_token=serializer.validated_data["access"],
)
except Exception as e:
- raise PermissionDenied(f"invalid credentials provided: {e!s}")
+ raise PermissionDenied(f"invalid credentials provided: {e!s}") from e
class RefreshJSONWebToken(BaseMutation):
@@ -222,7 +222,7 @@ class RefreshJSONWebToken(BaseMutation):
user=User.objects.get(uuid=serializer.validated_data["user"]["uuid"]),
)
except Exception as e:
- raise PermissionDenied(f"invalid refresh token provided: {e!s}")
+ raise PermissionDenied(f"invalid refresh token provided: {e!s}") from e
class VerifyJSONWebToken(BaseMutation):
@@ -270,7 +270,7 @@ class ActivateUser(BaseMutation):
user.save()
except (TypeError, ValueError, OverflowError, User.DoesNotExist) as e:
- raise BadRequest(_(f"something went wrong: {e!s}"))
+ raise BadRequest(_(f"something went wrong: {e!s}")) from e
return ActivateUser(success=True)
@@ -322,23 +322,24 @@ class ConfirmResetPassword(BaseMutation):
return ConfirmResetPassword(success=True)
except (TypeError, ValueError, OverflowError, ValidationError, User.DoesNotExist) as e:
- raise BadRequest(_(f"something went wrong: {e!s}"))
+ raise BadRequest(_(f"something went wrong: {e!s}")) from e
class UploadAvatar(BaseMutation):
class Arguments:
- avatar = Upload(required=True)
+ file = Upload(required=True)
user = Field(UserType)
- def mutate(self, info, avatar):
+ def mutate(self, info, file):
if not info.context.user.is_authenticated:
raise PermissionDenied(permission_denied_message)
try:
- info.context.user.avatar = avatar
+ info.context.user.avatar = file
info.context.user.save()
+ info.context.user.refresh_from_db()
except Exception as e:
- raise BadRequest(str(e))
+ raise BadRequest(str(e)) from e
return UploadAvatar(user=info.context.user)
diff --git a/vibes_auth/graphene/object_types.py b/vibes_auth/graphene/object_types.py
index 5eeced8f..71c32035 100644
--- a/vibes_auth/graphene/object_types.py
+++ b/vibes_auth/graphene/object_types.py
@@ -5,7 +5,7 @@ from graphene.types.generic import GenericScalar
from graphene_django import DjangoObjectType
from graphql_relay.connection.array_connection import connection_from_array
-from core.graphene.object_types import OrderType, ProductType, WishlistType
+from core.graphene.object_types import OrderType, ProductType, WishlistType, AddressType
from core.models import Product, Wishlist
from evibes.settings import LANGUAGE_CODE, LANGUAGES
from payments.graphene.object_types import BalanceType
@@ -47,6 +47,7 @@ class UserType(DjangoObjectType):
avatar = String(description=_("avatar"))
attributes = GenericScalar(description=_("attributes may be used to store custom data"))
language = String(description=_(f"language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"))
+ addresses = Field(lambda: AddressType, source="address_set", description=_("address set"))
class Meta:
model = User
@@ -97,7 +98,12 @@ class UserType(DjangoObjectType):
def resolve_avatar(self: User, info) -> str:
if self.avatar:
- return info.context.build_absolute_uri(self.avatar.url)
+ if hasattr(self.avatar, "url"):
+ return info.context.build_absolute_uri(self.avatar.url)
+ elif hasattr(self.avatar, "name"):
+ return info.context.build_absolute_uri(f"/media/{self.avatar.name}")
+ else:
+ return info.context.build_absolute_uri(f"/media/{self.avatar}")
else:
return ""
diff --git a/vibes_auth/locale/ar_AR/LC_MESSAGES/django.mo b/vibes_auth/locale/ar_AR/LC_MESSAGES/django.mo
index ce885860..f4be54c5 100644
Binary files a/vibes_auth/locale/ar_AR/LC_MESSAGES/django.mo and b/vibes_auth/locale/ar_AR/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/ar_AR/LC_MESSAGES/django.po b/vibes_auth/locale/ar_AR/LC_MESSAGES/django.po
index 269fa4db..dfdf1521 100644
--- a/vibes_auth/locale/ar_AR/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/ar_AR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -18,27 +18,27 @@ msgstr ""
msgid "balance"
msgstr "الرصيد"
-#: vibes_auth/admin.py:44
+#: vibes_auth/admin.py:45
msgid "order"
msgstr "الطلب"
-#: vibes_auth/admin.py:45 vibes_auth/graphene/object_types.py:44
+#: vibes_auth/admin.py:46 vibes_auth/graphene/object_types.py:44
msgid "orders"
msgstr "الطلبات"
-#: vibes_auth/admin.py:54
+#: vibes_auth/admin.py:56
msgid "personal info"
msgstr "معلومات شخصية"
-#: vibes_auth/admin.py:58 vibes_auth/graphene/object_types.py:43
+#: vibes_auth/admin.py:60 vibes_auth/graphene/object_types.py:43
msgid "permissions"
msgstr "الأذونات"
-#: vibes_auth/admin.py:71
+#: vibes_auth/admin.py:73
msgid "important dates"
msgstr "تواريخ مهمة"
-#: vibes_auth/admin.py:72
+#: vibes_auth/admin.py:74
msgid "additional info"
msgstr "معلومات إضافية"
@@ -70,7 +70,7 @@ msgstr "التحقق من الرمز المميز"
msgid "Verify a token (refresh or access)."
msgstr "التحقق من الرمز المميز (التحديث أو الوصول)."
-#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:55
+#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:115
msgid "the token is valid"
msgstr "الرمز المميز صالح"
@@ -93,8 +93,8 @@ msgstr "حذف مستخدم"
#: vibes_auth/docs/drf/viewsets.py:33
msgid "reset a user's password by sending a reset password email"
msgstr ""
-"إعادة تعيين كلمة مرور المستخدم عن طريق إرسال بريد إلكتروني لإعادة تعيين كلمة "
-"المرور"
+"إعادة تعيين كلمة مرور المستخدم عن طريق إرسال بريد إلكتروني لإعادة تعيين كلمة"
+" المرور"
#: vibes_auth/docs/drf/viewsets.py:38
msgid "handle avatar upload for a user"
@@ -105,7 +105,7 @@ msgid "confirm a user's password reset"
msgstr "تأكيد إعادة تعيين كلمة مرور المستخدم"
#: vibes_auth/docs/drf/viewsets.py:57 vibes_auth/graphene/mutations.py:307
-#: vibes_auth/viewsets.py:73
+#: vibes_auth/viewsets.py:114
msgid "passwords do not match"
msgstr "كلمات المرور غير متطابقة"
@@ -132,7 +132,7 @@ msgstr "كلمة المرور ضعيفة جداً"
#: vibes_auth/graphene/mutations.py:107
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} غير موجود: {uuid}"
+msgstr "{name} غير موجود: {uuid}!"
#: vibes_auth/graphene/mutations.py:115
msgid "malformed email"
@@ -141,15 +141,15 @@ msgstr "بريد إلكتروني مشوه"
#: vibes_auth/graphene/mutations.py:120
#, python-brace-format
msgid "malformed phone number: {phone_number}"
-msgstr "رقم هاتف مشوّه: {phone_number}"
+msgstr "رقم هاتف مشوه: {phone_number}!"
#: vibes_auth/graphene/mutations.py:142
#, python-brace-format
msgid "Invalid attribute format: {attribute_pair}"
-msgstr "تنسيق السمة غير صالح: {attribute_pair}"
+msgstr "تنسيق السمة غير صالح: {attribute_pair}!"
-#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:116
-#: vibes_auth/viewsets.py:135
+#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:157
+#: vibes_auth/viewsets.py:176
msgid "activation link is invalid!"
msgstr "رابط التفعيل غير صالح!"
@@ -161,18 +161,18 @@ msgstr "تم تفعيل الحساب بالفعل..."
msgid "something went wrong: {e!s}"
msgstr "حدث خطأ ما: {e!s}"
-#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:84
+#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:125
msgid "token is invalid!"
msgstr "الرمز غير صالح!"
#: vibes_auth/graphene/object_types.py:40
msgid ""
-"the products this user has viewed most recently (max 48), in reverse‐"
-"chronological order"
+"the products this user has viewed most recently (max 48), in "
+"reverse‐chronological order"
msgstr ""
"المنتجات التي شاهدها هذا المستخدم مؤخرًا (بحد أقصى 48)، بترتيب زمني عكسي."
-#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:117
+#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:180
msgid "groups"
msgstr "المجموعات"
@@ -180,7 +180,7 @@ msgstr "المجموعات"
msgid "wishlist"
msgstr "قائمة الرغبات"
-#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:53
+#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:102
msgid "avatar"
msgstr "الصورة الرمزية"
@@ -193,111 +193,120 @@ msgstr "يمكن استخدام السمات لتخزين البيانات ال
msgid "language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
msgstr "اللغة هي واحدة من {LANGUAGES} مع {LANGUAGE_CODE} الافتراضي"
-#: vibes_auth/models.py:36
+#: vibes_auth/graphene/object_types.py:50
+msgid "address set"
+msgstr "العناوين"
+
+#: vibes_auth/models.py:85
msgid "email"
msgstr "البريد الإلكتروني"
-#: vibes_auth/models.py:36
+#: vibes_auth/models.py:85
msgid "user email address"
msgstr "عنوان البريد الإلكتروني للمستخدم"
-#: vibes_auth/models.py:38
+#: vibes_auth/models.py:87
msgid "phone_number"
msgstr "رقم الهاتف"
-#: vibes_auth/models.py:43
+#: vibes_auth/models.py:92
msgid "user phone number"
msgstr "رقم هاتف المستخدم"
-#: vibes_auth/models.py:49
+#: vibes_auth/models.py:98
msgid "first_name"
msgstr "الاسم الأول"
-#: vibes_auth/models.py:50
+#: vibes_auth/models.py:99
msgid "last_name"
msgstr "اسم العائلة"
-#: vibes_auth/models.py:56
+#: vibes_auth/models.py:105
msgid "user profile image"
msgstr "صورة ملف تعريف المستخدم"
-#: vibes_auth/models.py:61
+#: vibes_auth/models.py:110
msgid "is verified"
msgstr "تم التحقق"
-#: vibes_auth/models.py:62
+#: vibes_auth/models.py:111
msgid "user verification status"
msgstr "حالة التحقق من المستخدم"
-#: vibes_auth/models.py:65
+#: vibes_auth/models.py:114
msgid "is_active"
msgstr "نشط"
-#: vibes_auth/models.py:67
+#: vibes_auth/models.py:116
msgid "unselect this instead of deleting accounts"
msgstr "قم بإلغاء تحديد هذا بدلاً من حذف الحسابات"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "is_subscribed"
msgstr "مشترك"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "user's newsletter subscription status"
msgstr "حالة اشتراك المستخدم في النشرة الإخبارية"
-#: vibes_auth/models.py:73
+#: vibes_auth/models.py:122
msgid "activation token"
msgstr "رمز التفعيل"
-#: vibes_auth/models.py:75
+#: vibes_auth/models.py:124
msgid "attributes"
msgstr "السمات"
-#: vibes_auth/models.py:109
+#: vibes_auth/models.py:158
msgid "user"
msgstr "المستخدم"
-#: vibes_auth/models.py:110
+#: vibes_auth/models.py:159
msgid "users"
msgstr "المستخدمون"
-#: vibes_auth/models.py:116
+#: vibes_auth/models.py:179
msgid "group"
msgstr "المجموعة"
-#: vibes_auth/models.py:123
+#: vibes_auth/models.py:196
msgid "outstanding token"
msgstr "الرمز المميز"
-#: vibes_auth/models.py:124
+#: vibes_auth/models.py:197
msgid "outstanding tokens"
msgstr "الرموز المميزة المعلقة"
-#: vibes_auth/models.py:130
+#: vibes_auth/models.py:215
msgid "blacklisted token"
msgstr "الرمز المميز المدرج في القائمة السوداء"
-#: vibes_auth/models.py:131
+#: vibes_auth/models.py:216
msgid "blacklisted tokens"
msgstr "الرموز المميزة المدرجة في القائمة السوداء"
-#: vibes_auth/serializers.py:112 vibes_auth/serializers.py:134
+#: vibes_auth/serializers.py:110 vibes_auth/serializers.py:132
+#: vibes_auth/serializers.py:154 vibes_auth/serializers.py:166
msgid "no active account"
msgstr "لم يتم العثور على حساب نشط"
-#: vibes_auth/serializers.py:205
+#: vibes_auth/serializers.py:142
+msgid "must set token_class attribute on class."
+msgstr "يجب تعيين سمة token_class على الفئة!"
+
+#: vibes_auth/serializers.py:214
msgid "token_blacklisted"
msgstr "تم إدراج الرمز المميز في القائمة السوداء"
-#: vibes_auth/serializers.py:210
+#: vibes_auth/serializers.py:219
msgid "invalid token"
msgstr "رمز غير صالح"
-#: vibes_auth/serializers.py:216
+#: vibes_auth/serializers.py:225
msgid "no user uuid claim present in token"
msgstr "لا توجد مطالبة معرف المستخدم في الرمز المميز"
-#: vibes_auth/serializers.py:218
+#: vibes_auth/serializers.py:227
msgid "user does not exist"
msgstr "المستخدم غير موجود"
@@ -322,8 +331,7 @@ msgstr "مرحباً %(user_first_name)s,"
#: vibes_auth/templates/user_reset_password_email.html:92
msgid ""
-"we have received a request to reset your password. please reset your "
-"password\n"
+"we have received a request to reset your password. please reset your password\n"
" by clicking the button below:"
msgstr ""
"لقد تلقينا طلباً لإعادة تعيين كلمة المرور الخاصة بك. يرجى إعادة تعيين كلمة "
@@ -357,7 +365,7 @@ msgstr ""
#: vibes_auth/templates/user_reset_password_email.html:103
#, python-format
msgid "best regards,
The %(project_name)s team"
-msgstr "مع أطيب تحياتي،
فريق عمل %(project_name)s"
+msgstr "مع أطيب التحيات,
فريق %(project_name)s"
#: vibes_auth/templates/user_reset_password_email.html:109
#: vibes_auth/templates/user_verification_email.html:108
@@ -389,7 +397,7 @@ msgstr ""
#: vibes_auth/templates/user_verification_email.html:102
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "مع أطيب التحيات، فريق عمل %(project_name)s"
+msgstr "مع أطيب تحياتي،
فريق %(project_name)s"
#: vibes_auth/utils/emailing.py:27
#, python-brace-format
@@ -409,17 +417,14 @@ msgstr ""
"تنسيق رقم الهاتف غير صالح. يجب إدخال الرقم بالصيغة: \"+999999999\". يُسمح "
"بإدخال 15 رقماً كحد أقصى."
-#: vibes_auth/views.py:57
+#: vibes_auth/views.py:117
msgid "the token is invalid"
msgstr "الرمز المميز غير صالح"
-#: vibes_auth/viewsets.py:88
+#: vibes_auth/viewsets.py:129
msgid "password reset successfully"
msgstr "تمت إعادة تعيين كلمة المرور بنجاح!"
-#: vibes_auth/viewsets.py:121
+#: vibes_auth/viewsets.py:162
msgid "account already activated!"
msgstr "لقد قمت بتفعيل الحساب بالفعل..."
-
-#~ msgid "eVibes Auth"
-#~ msgstr "مصادقة eVibes Auth"
diff --git a/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.mo b/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.mo
index 85955205..14060184 100644
Binary files a/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.mo and b/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.po b/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.po
index 463f8e62..b901bc0c 100644
--- a/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/cs_CZ/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -18,27 +18,27 @@ msgstr ""
msgid "balance"
msgstr "Bilance"
-#: vibes_auth/admin.py:44
+#: vibes_auth/admin.py:45
msgid "order"
msgstr "Objednávka"
-#: vibes_auth/admin.py:45 vibes_auth/graphene/object_types.py:44
+#: vibes_auth/admin.py:46 vibes_auth/graphene/object_types.py:44
msgid "orders"
msgstr "Objednávky"
-#: vibes_auth/admin.py:54
+#: vibes_auth/admin.py:56
msgid "personal info"
msgstr "Osobní informace"
-#: vibes_auth/admin.py:58 vibes_auth/graphene/object_types.py:43
+#: vibes_auth/admin.py:60 vibes_auth/graphene/object_types.py:43
msgid "permissions"
msgstr "Oprávnění"
-#: vibes_auth/admin.py:71
+#: vibes_auth/admin.py:73
msgid "important dates"
msgstr "Důležitá data"
-#: vibes_auth/admin.py:72
+#: vibes_auth/admin.py:74
msgid "additional info"
msgstr "Další informace"
@@ -70,7 +70,7 @@ msgstr "Ověření tokenu"
msgid "Verify a token (refresh or access)."
msgstr "Ověření tokenu (obnovení nebo přístup)."
-#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:55
+#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:115
msgid "the token is valid"
msgstr "Token je platný"
@@ -103,7 +103,7 @@ msgid "confirm a user's password reset"
msgstr "Potvrzení obnovení hesla uživatele"
#: vibes_auth/docs/drf/viewsets.py:57 vibes_auth/graphene/mutations.py:307
-#: vibes_auth/viewsets.py:73
+#: vibes_auth/viewsets.py:114
msgid "passwords do not match"
msgstr "Hesla se neshodují"
@@ -130,7 +130,7 @@ msgstr "Heslo je příliš slabé"
#: vibes_auth/graphene/mutations.py:107
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} neexistuje: {uuid}"
+msgstr "{name} neexistuje: {uuid}!"
#: vibes_auth/graphene/mutations.py:115
msgid "malformed email"
@@ -139,15 +139,15 @@ msgstr "Špatně formulovaný e-mail"
#: vibes_auth/graphene/mutations.py:120
#, python-brace-format
msgid "malformed phone number: {phone_number}"
-msgstr "Chybně zadané telefonní číslo: {phone_number}"
+msgstr "Chybně zadané telefonní číslo: {phone_number}!"
#: vibes_auth/graphene/mutations.py:142
#, python-brace-format
msgid "Invalid attribute format: {attribute_pair}"
-msgstr "Nesprávný formát atributu: {attribute_pair}"
+msgstr "Nesprávný formát atributu: {attribute_pair}!"
-#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:116
-#: vibes_auth/viewsets.py:135
+#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:157
+#: vibes_auth/viewsets.py:176
msgid "activation link is invalid!"
msgstr "Aktivační odkaz je neplatný!"
@@ -159,19 +159,19 @@ msgstr "Účet byl již aktivován..."
msgid "something went wrong: {e!s}"
msgstr "Něco se pokazilo: {e!s}"
-#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:84
+#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:125
msgid "token is invalid!"
msgstr "Token je neplatný!"
#: vibes_auth/graphene/object_types.py:40
msgid ""
-"the products this user has viewed most recently (max 48), in reverse‐"
-"chronological order"
+"the products this user has viewed most recently (max 48), in "
+"reverse‐chronological order"
msgstr ""
"Produkty, které si tento uživatel prohlížel naposledy (max. 48), seřazené v "
"opačném pořadí."
-#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:117
+#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:180
msgid "groups"
msgstr "Skupiny"
@@ -179,7 +179,7 @@ msgstr "Skupiny"
msgid "wishlist"
msgstr "Seznam přání"
-#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:53
+#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:102
msgid "avatar"
msgstr "Avatar"
@@ -190,113 +190,122 @@ msgstr "Atributy lze použít k uložení vlastních dat."
#: vibes_auth/graphene/object_types.py:49
#, python-brace-format
msgid "language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
-msgstr "Jazyk je jeden z {LANGUAGES} s výchozím {LANGUAGE_CODE}."
+msgstr "Jazyk je jeden z {LANGUAGES} s výchozím {LANGUAGE_CODE}"
-#: vibes_auth/models.py:36
+#: vibes_auth/graphene/object_types.py:50
+msgid "address set"
+msgstr "Adresy"
+
+#: vibes_auth/models.py:85
msgid "email"
msgstr "E-mail"
-#: vibes_auth/models.py:36
+#: vibes_auth/models.py:85
msgid "user email address"
msgstr "E-mailová adresa uživatele"
-#: vibes_auth/models.py:38
+#: vibes_auth/models.py:87
msgid "phone_number"
msgstr "Telefonní číslo"
-#: vibes_auth/models.py:43
+#: vibes_auth/models.py:92
msgid "user phone number"
msgstr "Telefonní číslo uživatele"
-#: vibes_auth/models.py:49
+#: vibes_auth/models.py:98
msgid "first_name"
msgstr "Křestní jméno"
-#: vibes_auth/models.py:50
+#: vibes_auth/models.py:99
msgid "last_name"
msgstr "Příjmení"
-#: vibes_auth/models.py:56
+#: vibes_auth/models.py:105
msgid "user profile image"
msgstr "Obrázek profilu uživatele"
-#: vibes_auth/models.py:61
+#: vibes_auth/models.py:110
msgid "is verified"
msgstr "Je ověřeno"
-#: vibes_auth/models.py:62
+#: vibes_auth/models.py:111
msgid "user verification status"
msgstr "Stav ověření uživatele"
-#: vibes_auth/models.py:65
+#: vibes_auth/models.py:114
msgid "is_active"
msgstr "Je aktivní"
-#: vibes_auth/models.py:67
+#: vibes_auth/models.py:116
msgid "unselect this instead of deleting accounts"
msgstr "Zrušení výběru této možnosti místo odstranění účtů"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "is_subscribed"
msgstr "Je přihlášena k odběru"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "user's newsletter subscription status"
msgstr "Stav odběru newsletteru uživatele"
-#: vibes_auth/models.py:73
+#: vibes_auth/models.py:122
msgid "activation token"
msgstr "Aktivační token"
-#: vibes_auth/models.py:75
+#: vibes_auth/models.py:124
msgid "attributes"
msgstr "Atributy"
-#: vibes_auth/models.py:109
+#: vibes_auth/models.py:158
msgid "user"
msgstr "Uživatel"
-#: vibes_auth/models.py:110
+#: vibes_auth/models.py:159
msgid "users"
msgstr "Uživatelé"
-#: vibes_auth/models.py:116
+#: vibes_auth/models.py:179
msgid "group"
msgstr "Skupina"
-#: vibes_auth/models.py:123
+#: vibes_auth/models.py:196
msgid "outstanding token"
msgstr "Vynikající žeton"
-#: vibes_auth/models.py:124
+#: vibes_auth/models.py:197
msgid "outstanding tokens"
msgstr "Nevyplacené žetony"
-#: vibes_auth/models.py:130
+#: vibes_auth/models.py:215
msgid "blacklisted token"
msgstr "Token na černé listině"
-#: vibes_auth/models.py:131
+#: vibes_auth/models.py:216
msgid "blacklisted tokens"
msgstr "Tokeny na černé listině"
-#: vibes_auth/serializers.py:112 vibes_auth/serializers.py:134
+#: vibes_auth/serializers.py:110 vibes_auth/serializers.py:132
+#: vibes_auth/serializers.py:154 vibes_auth/serializers.py:166
msgid "no active account"
msgstr "Nebyl nalezen žádný aktivní účet"
-#: vibes_auth/serializers.py:205
+#: vibes_auth/serializers.py:142
+msgid "must set token_class attribute on class."
+msgstr "Musí být nastaven atribut token_class na třídě!"
+
+#: vibes_auth/serializers.py:214
msgid "token_blacklisted"
msgstr "Token na černé listině"
-#: vibes_auth/serializers.py:210
+#: vibes_auth/serializers.py:219
msgid "invalid token"
msgstr "Neplatný token"
-#: vibes_auth/serializers.py:216
+#: vibes_auth/serializers.py:225
msgid "no user uuid claim present in token"
msgstr "V tokenu není deklarace uuid uživatele"
-#: vibes_auth/serializers.py:218
+#: vibes_auth/serializers.py:227
msgid "user does not exist"
msgstr "Uživatel neexistuje"
@@ -321,8 +330,7 @@ msgstr "Ahoj %(user_first_name)s,"
#: vibes_auth/templates/user_reset_password_email.html:92
msgid ""
-"we have received a request to reset your password. please reset your "
-"password\n"
+"we have received a request to reset your password. please reset your password\n"
" by clicking the button below:"
msgstr ""
"Obdrželi jsme žádost o obnovení vašeho hesla. Kliknutím na níže uvedené "
@@ -342,8 +350,7 @@ msgid ""
"if the button above does not work, please copy and paste the following URL\n"
" into your web browser:"
msgstr ""
-"Pokud výše uvedené tlačítko nefunguje, zkopírujte a vložte následující "
-"adresu URL\n"
+"Pokud výše uvedené tlačítko nefunguje, zkopírujte a vložte následující adresu URL\n"
" do webového prohlížeče:"
#: vibes_auth/templates/user_reset_password_email.html:101
@@ -409,17 +416,14 @@ msgstr ""
"Nesprávný formát telefonního čísla. Číslo musí být zadáno ve formátu: "
"\"+999999999\". Povoleno je až 15 číslic."
-#: vibes_auth/views.py:57
+#: vibes_auth/views.py:117
msgid "the token is invalid"
msgstr "Token je neplatný"
-#: vibes_auth/viewsets.py:88
+#: vibes_auth/viewsets.py:129
msgid "password reset successfully"
msgstr "Heslo bylo úspěšně resetováno!"
-#: vibes_auth/viewsets.py:121
+#: vibes_auth/viewsets.py:162
msgid "account already activated!"
msgstr "Účet jste již aktivovali..."
-
-#~ msgid "eVibes Auth"
-#~ msgstr "eVibes Auth"
diff --git a/vibes_auth/locale/da_DK/LC_MESSAGES/django.mo b/vibes_auth/locale/da_DK/LC_MESSAGES/django.mo
index 53aeb3e3..7380dad2 100644
Binary files a/vibes_auth/locale/da_DK/LC_MESSAGES/django.mo and b/vibes_auth/locale/da_DK/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/da_DK/LC_MESSAGES/django.po b/vibes_auth/locale/da_DK/LC_MESSAGES/django.po
index a045f38f..dd76906d 100644
--- a/vibes_auth/locale/da_DK/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/da_DK/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -18,27 +18,27 @@ msgstr ""
msgid "balance"
msgstr "Balance"
-#: vibes_auth/admin.py:44
+#: vibes_auth/admin.py:45
msgid "order"
msgstr "Bestil"
-#: vibes_auth/admin.py:45 vibes_auth/graphene/object_types.py:44
+#: vibes_auth/admin.py:46 vibes_auth/graphene/object_types.py:44
msgid "orders"
msgstr "Bestillinger"
-#: vibes_auth/admin.py:54
+#: vibes_auth/admin.py:56
msgid "personal info"
msgstr "Personlig information"
-#: vibes_auth/admin.py:58 vibes_auth/graphene/object_types.py:43
+#: vibes_auth/admin.py:60 vibes_auth/graphene/object_types.py:43
msgid "permissions"
msgstr "Tilladelser"
-#: vibes_auth/admin.py:71
+#: vibes_auth/admin.py:73
msgid "important dates"
msgstr "Vigtige datoer"
-#: vibes_auth/admin.py:72
+#: vibes_auth/admin.py:74
msgid "additional info"
msgstr "Yderligere information"
@@ -70,7 +70,7 @@ msgstr "Bekræft et token"
msgid "Verify a token (refresh or access)."
msgstr "Bekræft et token (opdatering eller adgang)."
-#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:55
+#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:115
msgid "the token is valid"
msgstr "Tokenet er gyldigt"
@@ -105,7 +105,7 @@ msgid "confirm a user's password reset"
msgstr "Bekræft nulstilling af en brugers adgangskode"
#: vibes_auth/docs/drf/viewsets.py:57 vibes_auth/graphene/mutations.py:307
-#: vibes_auth/viewsets.py:73
+#: vibes_auth/viewsets.py:114
msgid "passwords do not match"
msgstr "Adgangskoderne stemmer ikke overens"
@@ -132,7 +132,7 @@ msgstr "Adgangskoden er for svag"
#: vibes_auth/graphene/mutations.py:107
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} findes ikke: {uuid}"
+msgstr "{name} findes ikke: {uuid}!"
#: vibes_auth/graphene/mutations.py:115
msgid "malformed email"
@@ -141,15 +141,15 @@ msgstr "Misdannet e-mail"
#: vibes_auth/graphene/mutations.py:120
#, python-brace-format
msgid "malformed phone number: {phone_number}"
-msgstr "Misdannet telefonnummer: {phone_number}."
+msgstr "Misdannet telefonnummer: {phone_number}!"
#: vibes_auth/graphene/mutations.py:142
#, python-brace-format
msgid "Invalid attribute format: {attribute_pair}"
-msgstr "Ugyldigt attributformat: {attribute_pair}"
+msgstr "Ugyldigt attributformat: {attribute_pair}!"
-#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:116
-#: vibes_auth/viewsets.py:135
+#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:157
+#: vibes_auth/viewsets.py:176
msgid "activation link is invalid!"
msgstr "Aktiveringslinket er ugyldigt!"
@@ -161,19 +161,19 @@ msgstr "Kontoen er allerede aktiveret..."
msgid "something went wrong: {e!s}"
msgstr "Noget gik galt: {e!s}"
-#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:84
+#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:125
msgid "token is invalid!"
msgstr "Token er ugyldig!"
#: vibes_auth/graphene/object_types.py:40
msgid ""
-"the products this user has viewed most recently (max 48), in reverse‐"
-"chronological order"
+"the products this user has viewed most recently (max 48), in "
+"reverse‐chronological order"
msgstr ""
"De produkter, som denne bruger har set for nylig (maks. 48), i omvendt "
"kronologisk rækkefølge."
-#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:117
+#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:180
msgid "groups"
msgstr "Grupper"
@@ -181,7 +181,7 @@ msgstr "Grupper"
msgid "wishlist"
msgstr "Ønskeliste"
-#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:53
+#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:102
msgid "avatar"
msgstr "Avatar"
@@ -192,113 +192,122 @@ msgstr "Attributter kan bruges til at gemme brugerdefinerede data"
#: vibes_auth/graphene/object_types.py:49
#, python-brace-format
msgid "language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
-msgstr "Sprog er et af {LANGUAGES} med standard {LANGUAGE_CODE}."
+msgstr "Sprog er en af {LANGUAGES} med standard {LANGUAGE_CODE}."
-#: vibes_auth/models.py:36
+#: vibes_auth/graphene/object_types.py:50
+msgid "address set"
+msgstr "Adresser"
+
+#: vibes_auth/models.py:85
msgid "email"
msgstr "E-mail"
-#: vibes_auth/models.py:36
+#: vibes_auth/models.py:85
msgid "user email address"
msgstr "Brugerens e-mailadresse"
-#: vibes_auth/models.py:38
+#: vibes_auth/models.py:87
msgid "phone_number"
msgstr "Telefonnummer"
-#: vibes_auth/models.py:43
+#: vibes_auth/models.py:92
msgid "user phone number"
msgstr "Brugerens telefonnummer"
-#: vibes_auth/models.py:49
+#: vibes_auth/models.py:98
msgid "first_name"
msgstr "Fornavn"
-#: vibes_auth/models.py:50
+#: vibes_auth/models.py:99
msgid "last_name"
msgstr "Efternavn"
-#: vibes_auth/models.py:56
+#: vibes_auth/models.py:105
msgid "user profile image"
msgstr "Billede af brugerprofil"
-#: vibes_auth/models.py:61
+#: vibes_auth/models.py:110
msgid "is verified"
msgstr "Er verificeret"
-#: vibes_auth/models.py:62
+#: vibes_auth/models.py:111
msgid "user verification status"
msgstr "Brugerens verifikationsstatus"
-#: vibes_auth/models.py:65
+#: vibes_auth/models.py:114
msgid "is_active"
msgstr "Er aktiv"
-#: vibes_auth/models.py:67
+#: vibes_auth/models.py:116
msgid "unselect this instead of deleting accounts"
msgstr "Fravælg dette i stedet for at slette konti"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "is_subscribed"
msgstr "Er tilmeldt"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "user's newsletter subscription status"
msgstr "Status for brugerens abonnement på nyhedsbrev"
-#: vibes_auth/models.py:73
+#: vibes_auth/models.py:122
msgid "activation token"
msgstr "Aktiveringstoken"
-#: vibes_auth/models.py:75
+#: vibes_auth/models.py:124
msgid "attributes"
msgstr "Egenskaber"
-#: vibes_auth/models.py:109
+#: vibes_auth/models.py:158
msgid "user"
msgstr "Bruger"
-#: vibes_auth/models.py:110
+#: vibes_auth/models.py:159
msgid "users"
msgstr "Brugere"
-#: vibes_auth/models.py:116
+#: vibes_auth/models.py:179
msgid "group"
msgstr "Gruppe"
-#: vibes_auth/models.py:123
+#: vibes_auth/models.py:196
msgid "outstanding token"
msgstr "Enestående token"
-#: vibes_auth/models.py:124
+#: vibes_auth/models.py:197
msgid "outstanding tokens"
msgstr "Udestående tokens"
-#: vibes_auth/models.py:130
+#: vibes_auth/models.py:215
msgid "blacklisted token"
msgstr "Sortlistet token"
-#: vibes_auth/models.py:131
+#: vibes_auth/models.py:216
msgid "blacklisted tokens"
msgstr "Sortlistede tokens"
-#: vibes_auth/serializers.py:112 vibes_auth/serializers.py:134
+#: vibes_auth/serializers.py:110 vibes_auth/serializers.py:132
+#: vibes_auth/serializers.py:154 vibes_auth/serializers.py:166
msgid "no active account"
msgstr "Ingen aktiv konto fundet"
-#: vibes_auth/serializers.py:205
+#: vibes_auth/serializers.py:142
+msgid "must set token_class attribute on class."
+msgstr "Skal sætte token_class-attributten på klassen!"
+
+#: vibes_auth/serializers.py:214
msgid "token_blacklisted"
msgstr "Token blacklistet"
-#: vibes_auth/serializers.py:210
+#: vibes_auth/serializers.py:219
msgid "invalid token"
msgstr "Ugyldigt token"
-#: vibes_auth/serializers.py:216
+#: vibes_auth/serializers.py:225
msgid "no user uuid claim present in token"
msgstr "Ingen bruger-uuid-krav til stede i token"
-#: vibes_auth/serializers.py:218
+#: vibes_auth/serializers.py:227
msgid "user does not exist"
msgstr "Brugeren findes ikke"
@@ -323,8 +332,7 @@ msgstr "Hej %(user_first_name)s,"
#: vibes_auth/templates/user_reset_password_email.html:92
msgid ""
-"we have received a request to reset your password. please reset your "
-"password\n"
+"we have received a request to reset your password. please reset your password\n"
" by clicking the button below:"
msgstr ""
"Vi har modtaget en anmodning om at nulstille din adgangskode. Nulstil "
@@ -344,8 +352,7 @@ msgid ""
"if the button above does not work, please copy and paste the following URL\n"
" into your web browser:"
msgstr ""
-"Hvis ovenstående knap ikke virker, bedes du kopiere og indsætte følgende "
-"URL\n"
+"Hvis ovenstående knap ikke virker, bedes du kopiere og indsætte følgende URL\n"
" i din webbrowser:"
#: vibes_auth/templates/user_reset_password_email.html:101
@@ -358,7 +365,7 @@ msgstr ""
#: vibes_auth/templates/user_reset_password_email.html:103
#, python-format
msgid "best regards,
The %(project_name)s team"
-msgstr "Med venlig hilsen,
%(project_name)s team"
+msgstr "Bedste hilsner,
The %(project_name)s team"
#: vibes_auth/templates/user_reset_password_email.html:109
#: vibes_auth/templates/user_verification_email.html:108
@@ -390,7 +397,7 @@ msgstr ""
#: vibes_auth/templates/user_verification_email.html:102
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Med venlig hilsen,
%(project_name)s team"
+msgstr "Med venlig hilsen,
teamet %(project_name)s."
#: vibes_auth/utils/emailing.py:27
#, python-brace-format
@@ -410,17 +417,14 @@ msgstr ""
"Ugyldigt telefonnummerformat. Nummeret skal indtastes i formatet: "
"\"+999999999\". Op til 15 cifre er tilladt."
-#: vibes_auth/views.py:57
+#: vibes_auth/views.py:117
msgid "the token is invalid"
msgstr "Tokenet er ugyldigt"
-#: vibes_auth/viewsets.py:88
+#: vibes_auth/viewsets.py:129
msgid "password reset successfully"
msgstr "Adgangskoden er blevet nulstillet med succes!"
-#: vibes_auth/viewsets.py:121
+#: vibes_auth/viewsets.py:162
msgid "account already activated!"
msgstr "Du har allerede aktiveret kontoen..."
-
-#~ msgid "eVibes Auth"
-#~ msgstr "eVibes Auth"
diff --git a/vibes_auth/locale/de_DE/LC_MESSAGES/django.mo b/vibes_auth/locale/de_DE/LC_MESSAGES/django.mo
index 5873aab8..7c5c9893 100644
Binary files a/vibes_auth/locale/de_DE/LC_MESSAGES/django.mo and b/vibes_auth/locale/de_DE/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/de_DE/LC_MESSAGES/django.po b/vibes_auth/locale/de_DE/LC_MESSAGES/django.po
index 8d2a35b5..10c66cc0 100644
--- a/vibes_auth/locale/de_DE/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/de_DE/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -18,27 +18,27 @@ msgstr ""
msgid "balance"
msgstr "Waage"
-#: vibes_auth/admin.py:44
+#: vibes_auth/admin.py:45
msgid "order"
msgstr "Bestellung"
-#: vibes_auth/admin.py:45 vibes_auth/graphene/object_types.py:44
+#: vibes_auth/admin.py:46 vibes_auth/graphene/object_types.py:44
msgid "orders"
msgstr "Bestellungen"
-#: vibes_auth/admin.py:54
+#: vibes_auth/admin.py:56
msgid "personal info"
msgstr "Persönliche Informationen"
-#: vibes_auth/admin.py:58 vibes_auth/graphene/object_types.py:43
+#: vibes_auth/admin.py:60 vibes_auth/graphene/object_types.py:43
msgid "permissions"
msgstr "Erlaubnisse"
-#: vibes_auth/admin.py:71
+#: vibes_auth/admin.py:73
msgid "important dates"
msgstr "Wichtige Termine"
-#: vibes_auth/admin.py:72
+#: vibes_auth/admin.py:74
msgid "additional info"
msgstr "Zusätzliche Informationen"
@@ -71,7 +71,7 @@ msgstr "Überprüfen eines Tokens"
msgid "Verify a token (refresh or access)."
msgstr "Überprüfen eines Tokens (Aktualisierung oder Zugriff)."
-#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:55
+#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:115
msgid "the token is valid"
msgstr "Das Token ist gültig"
@@ -106,7 +106,7 @@ msgid "confirm a user's password reset"
msgstr "Bestätigen Sie das Zurücksetzen des Passworts eines Benutzers"
#: vibes_auth/docs/drf/viewsets.py:57 vibes_auth/graphene/mutations.py:307
-#: vibes_auth/viewsets.py:73
+#: vibes_auth/viewsets.py:114
msgid "passwords do not match"
msgstr "Passwörter stimmen nicht überein"
@@ -126,8 +126,8 @@ msgstr ""
#: vibes_auth/graphene/mutations.py:41
msgid "the user's b64-encoded uuid who referred the new user to us."
msgstr ""
-"Die b64-kodierte uuid des Benutzers, der den neuen Benutzer an uns verwiesen "
-"hat."
+"Die b64-kodierte uuid des Benutzers, der den neuen Benutzer an uns verwiesen"
+" hat."
#: vibes_auth/graphene/mutations.py:61
msgid "password too weak"
@@ -136,7 +136,7 @@ msgstr "Das Passwort ist zu schwach"
#: vibes_auth/graphene/mutations.py:107
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} existiert nicht: {uuid}"
+msgstr "{name} existiert nicht: {uuid}!"
#: vibes_auth/graphene/mutations.py:115
msgid "malformed email"
@@ -145,15 +145,15 @@ msgstr "Fehlerhafte E-Mail"
#: vibes_auth/graphene/mutations.py:120
#, python-brace-format
msgid "malformed phone number: {phone_number}"
-msgstr "Fehlerhafte Telefonnummer: {phone_number}"
+msgstr "Missgebildete Telefonnummer: {phone_number}!"
#: vibes_auth/graphene/mutations.py:142
#, python-brace-format
msgid "Invalid attribute format: {attribute_pair}"
-msgstr "Ungültiges Attributformat: {attribute_pair}"
+msgstr "Ungültiges Attributformat: {attribute_pair}!"
-#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:116
-#: vibes_auth/viewsets.py:135
+#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:157
+#: vibes_auth/viewsets.py:176
msgid "activation link is invalid!"
msgstr "Der Aktivierungslink ist ungültig!"
@@ -165,19 +165,19 @@ msgstr "Das Konto wurde bereits aktiviert..."
msgid "something went wrong: {e!s}"
msgstr "Etwas ist schief gelaufen: {e!s}"
-#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:84
+#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:125
msgid "token is invalid!"
msgstr "Token ist ungültig!"
#: vibes_auth/graphene/object_types.py:40
msgid ""
-"the products this user has viewed most recently (max 48), in reverse‐"
-"chronological order"
+"the products this user has viewed most recently (max 48), in "
+"reverse‐chronological order"
msgstr ""
"Die Produkte, die dieser Benutzer zuletzt angesehen hat (maximal 48), in "
"umgekehrter chronologischer Reihenfolge."
-#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:117
+#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:180
msgid "groups"
msgstr "Gruppen"
@@ -185,7 +185,7 @@ msgstr "Gruppen"
msgid "wishlist"
msgstr "Wunschzettel"
-#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:53
+#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:102
msgid "avatar"
msgstr "Avatar"
@@ -197,113 +197,122 @@ msgstr ""
#: vibes_auth/graphene/object_types.py:49
#, python-brace-format
msgid "language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
-msgstr "Sprache ist eine der {LANGUAGES} mit Standard {LANGUAGE_CODE}"
+msgstr "Sprache ist eine der {LANGUAGES} mit Voreinstellung {LANGUAGE_CODE}"
-#: vibes_auth/models.py:36
+#: vibes_auth/graphene/object_types.py:50
+msgid "address set"
+msgstr "Adressen"
+
+#: vibes_auth/models.py:85
msgid "email"
msgstr "E-Mail"
-#: vibes_auth/models.py:36
+#: vibes_auth/models.py:85
msgid "user email address"
msgstr "E-Mail Adresse des Benutzers"
-#: vibes_auth/models.py:38
+#: vibes_auth/models.py:87
msgid "phone_number"
msgstr "Rufnummer"
-#: vibes_auth/models.py:43
+#: vibes_auth/models.py:92
msgid "user phone number"
msgstr "Rufnummer des Benutzers"
-#: vibes_auth/models.py:49
+#: vibes_auth/models.py:98
msgid "first_name"
msgstr "Vornamen"
-#: vibes_auth/models.py:50
+#: vibes_auth/models.py:99
msgid "last_name"
msgstr "Nachname"
-#: vibes_auth/models.py:56
+#: vibes_auth/models.py:105
msgid "user profile image"
msgstr "Bild des Benutzerprofils"
-#: vibes_auth/models.py:61
+#: vibes_auth/models.py:110
msgid "is verified"
msgstr "Wird überprüft"
-#: vibes_auth/models.py:62
+#: vibes_auth/models.py:111
msgid "user verification status"
msgstr "Verifizierungsstatus des Benutzers"
-#: vibes_auth/models.py:65
+#: vibes_auth/models.py:114
msgid "is_active"
msgstr "Ist aktiv"
-#: vibes_auth/models.py:67
+#: vibes_auth/models.py:116
msgid "unselect this instead of deleting accounts"
msgstr "Deaktivieren Sie diese Option, anstatt Konten zu löschen"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "is_subscribed"
msgstr "Ist abonniert"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "user's newsletter subscription status"
msgstr "Status des Newsletter-Abonnements des Benutzers"
-#: vibes_auth/models.py:73
+#: vibes_auth/models.py:122
msgid "activation token"
msgstr "Aktivierungs-Token"
-#: vibes_auth/models.py:75
+#: vibes_auth/models.py:124
msgid "attributes"
msgstr "Attribute"
-#: vibes_auth/models.py:109
+#: vibes_auth/models.py:158
msgid "user"
msgstr "Benutzer"
-#: vibes_auth/models.py:110
+#: vibes_auth/models.py:159
msgid "users"
msgstr "Benutzer"
-#: vibes_auth/models.py:116
+#: vibes_auth/models.py:179
msgid "group"
msgstr "Gruppe"
-#: vibes_auth/models.py:123
+#: vibes_auth/models.py:196
msgid "outstanding token"
msgstr "Hervorragende Wertmarke"
-#: vibes_auth/models.py:124
+#: vibes_auth/models.py:197
msgid "outstanding tokens"
msgstr "Ausstehende Wertmarken"
-#: vibes_auth/models.py:130
+#: vibes_auth/models.py:215
msgid "blacklisted token"
msgstr "Token auf der schwarzen Liste"
-#: vibes_auth/models.py:131
+#: vibes_auth/models.py:216
msgid "blacklisted tokens"
msgstr "Token auf der schwarzen Liste"
-#: vibes_auth/serializers.py:112 vibes_auth/serializers.py:134
+#: vibes_auth/serializers.py:110 vibes_auth/serializers.py:132
+#: vibes_auth/serializers.py:154 vibes_auth/serializers.py:166
msgid "no active account"
msgstr "Kein aktives Konto gefunden"
-#: vibes_auth/serializers.py:205
+#: vibes_auth/serializers.py:142
+msgid "must set token_class attribute on class."
+msgstr "Das Attribut token_class muss auf class gesetzt werden!"
+
+#: vibes_auth/serializers.py:214
msgid "token_blacklisted"
msgstr "Token auf der schwarzen Liste"
-#: vibes_auth/serializers.py:210
+#: vibes_auth/serializers.py:219
msgid "invalid token"
msgstr "Ungültiges Token"
-#: vibes_auth/serializers.py:216
+#: vibes_auth/serializers.py:225
msgid "no user uuid claim present in token"
msgstr "Kein Benutzer uuid-Anspruch im Token vorhanden"
-#: vibes_auth/serializers.py:218
+#: vibes_auth/serializers.py:227
msgid "user does not exist"
msgstr "Benutzer existiert nicht"
@@ -328,8 +337,7 @@ msgstr "Hallo %(user_first_name)s,"
#: vibes_auth/templates/user_reset_password_email.html:92
msgid ""
-"we have received a request to reset your password. please reset your "
-"password\n"
+"we have received a request to reset your password. please reset your password\n"
" by clicking the button below:"
msgstr ""
"Wir haben eine Anfrage erhalten, Ihr Passwort zurückzusetzen. Bitte setzen "
@@ -349,8 +357,7 @@ msgid ""
"if the button above does not work, please copy and paste the following URL\n"
" into your web browser:"
msgstr ""
-"Wenn die obige Schaltfläche nicht funktioniert, kopieren Sie bitte die "
-"folgende URL und fügen Sie sie in Ihren Browser ein\n"
+"Wenn die obige Schaltfläche nicht funktioniert, kopieren Sie bitte die folgende URL und fügen Sie sie in Ihren Browser ein\n"
" in Ihren Webbrowser ein:"
#: vibes_auth/templates/user_reset_password_email.html:101
@@ -358,13 +365,13 @@ msgid ""
"if you did not send this request, please ignore this\n"
" email."
msgstr ""
-"Wenn Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese E-"
-"Mail."
+"Wenn Sie diese Anfrage nicht gesendet haben, ignorieren Sie bitte diese "
+"E-Mail."
#: vibes_auth/templates/user_reset_password_email.html:103
#, python-format
msgid "best regards,
The %(project_name)s team"
-msgstr "Mit freundlichen Grüßen,
Das Team von %(project_name)s"
+msgstr "Mit freundlichen Grüßen,
Das %(project_name)s-Team"
#: vibes_auth/templates/user_reset_password_email.html:109
#: vibes_auth/templates/user_verification_email.html:108
@@ -396,12 +403,12 @@ msgstr ""
#: vibes_auth/templates/user_verification_email.html:102
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Mit freundlichen Grüßen,
das %(project_name)s Team"
+msgstr "Mit freundlichen Grüßen,
das %(project_name)s-Team"
#: vibes_auth/utils/emailing.py:27
#, python-brace-format
msgid "{config.PROJECT_NAME} | Activate Account"
-msgstr "{config.PROJECT_NAME} | Konto aktivieren"
+msgstr "{config.PROJECT_NAME} | Konto freischalten"
#: vibes_auth/utils/emailing.py:69
#, python-brace-format
@@ -416,17 +423,14 @@ msgstr ""
"Ungültiges Telefonnummernformat. Die Nummer muss in dem Format eingegeben "
"werden: \"+999999999\". Bis zu 15 Ziffern sind erlaubt."
-#: vibes_auth/views.py:57
+#: vibes_auth/views.py:117
msgid "the token is invalid"
msgstr "Das Token ist ungültig"
-#: vibes_auth/viewsets.py:88
+#: vibes_auth/viewsets.py:129
msgid "password reset successfully"
msgstr "Das Passwort wurde erfolgreich zurückgesetzt!"
-#: vibes_auth/viewsets.py:121
+#: vibes_auth/viewsets.py:162
msgid "account already activated!"
msgstr "Sie haben das Konto bereits aktiviert..."
-
-#~ msgid "eVibes Auth"
-#~ msgstr "eVibes Auth"
diff --git a/vibes_auth/locale/en_GB/LC_MESSAGES/django.mo b/vibes_auth/locale/en_GB/LC_MESSAGES/django.mo
index 3bd5e573..5b5288c3 100644
Binary files a/vibes_auth/locale/en_GB/LC_MESSAGES/django.mo and b/vibes_auth/locale/en_GB/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/en_GB/LC_MESSAGES/django.po b/vibes_auth/locale/en_GB/LC_MESSAGES/django.po
index 69c069f4..409ecaef 100644
--- a/vibes_auth/locale/en_GB/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/en_GB/LC_MESSAGES/django.po
@@ -5,9 +5,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -22,27 +22,27 @@ msgstr ""
msgid "balance"
msgstr "Balance"
-#: vibes_auth/admin.py:44
+#: vibes_auth/admin.py:45
msgid "order"
msgstr "Order"
-#: vibes_auth/admin.py:45 vibes_auth/graphene/object_types.py:44
+#: vibes_auth/admin.py:46 vibes_auth/graphene/object_types.py:44
msgid "orders"
msgstr "Orders"
-#: vibes_auth/admin.py:54
+#: vibes_auth/admin.py:56
msgid "personal info"
msgstr "Personal Info"
-#: vibes_auth/admin.py:58 vibes_auth/graphene/object_types.py:43
+#: vibes_auth/admin.py:60 vibes_auth/graphene/object_types.py:43
msgid "permissions"
msgstr "Permissions"
-#: vibes_auth/admin.py:71
+#: vibes_auth/admin.py:73
msgid "important dates"
msgstr "Important dates"
-#: vibes_auth/admin.py:72
+#: vibes_auth/admin.py:74
msgid "additional info"
msgstr "Additional Info"
@@ -74,7 +74,7 @@ msgstr "Verify a token"
msgid "Verify a token (refresh or access)."
msgstr "Verify a token (refresh or access)."
-#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:55
+#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:115
msgid "the token is valid"
msgstr "The token is valid"
@@ -107,7 +107,7 @@ msgid "confirm a user's password reset"
msgstr "Confirm a user's password reset"
#: vibes_auth/docs/drf/viewsets.py:57 vibes_auth/graphene/mutations.py:307
-#: vibes_auth/viewsets.py:73
+#: vibes_auth/viewsets.py:114
msgid "passwords do not match"
msgstr "Passwords do not match"
@@ -134,7 +134,7 @@ msgstr "The password is too weak"
#: vibes_auth/graphene/mutations.py:107
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} does not exist: {uuid}"
+msgstr "{name} does not exist: {uuid}!"
#: vibes_auth/graphene/mutations.py:115
msgid "malformed email"
@@ -143,15 +143,15 @@ msgstr "Malformed email"
#: vibes_auth/graphene/mutations.py:120
#, python-brace-format
msgid "malformed phone number: {phone_number}"
-msgstr "Malformed phone number: {phone_number}"
+msgstr "Malformed phone number: {phone_number}!"
#: vibes_auth/graphene/mutations.py:142
#, python-brace-format
msgid "Invalid attribute format: {attribute_pair}"
-msgstr "Invalid attribute format: {attribute_pair}"
+msgstr "Invalid attribute format: {attribute_pair}!"
-#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:116
-#: vibes_auth/viewsets.py:135
+#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:157
+#: vibes_auth/viewsets.py:176
msgid "activation link is invalid!"
msgstr "Activation link is invalid!"
@@ -163,19 +163,19 @@ msgstr "Account has been already activated..."
msgid "something went wrong: {e!s}"
msgstr "Something went wrong: {e!s}"
-#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:84
+#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:125
msgid "token is invalid!"
msgstr "Token is invalid!"
#: vibes_auth/graphene/object_types.py:40
msgid ""
-"the products this user has viewed most recently (max 48), in reverse‐"
-"chronological order"
+"the products this user has viewed most recently (max 48), in "
+"reverse‐chronological order"
msgstr ""
"The products this user has viewed most recently (max 48), in reverse-"
"chronological order."
-#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:117
+#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:180
msgid "groups"
msgstr "Groups"
@@ -183,7 +183,7 @@ msgstr "Groups"
msgid "wishlist"
msgstr "Wishlist"
-#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:53
+#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:102
msgid "avatar"
msgstr "Avatar"
@@ -196,111 +196,120 @@ msgstr "Attributes may be used to store custom data"
msgid "language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
msgstr "Language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
-#: vibes_auth/models.py:36
+#: vibes_auth/graphene/object_types.py:50
+msgid "address set"
+msgstr "Adresses"
+
+#: vibes_auth/models.py:85
msgid "email"
msgstr "E-mail"
-#: vibes_auth/models.py:36
+#: vibes_auth/models.py:85
msgid "user email address"
msgstr "User's email address"
-#: vibes_auth/models.py:38
+#: vibes_auth/models.py:87
msgid "phone_number"
msgstr "Phone Number"
-#: vibes_auth/models.py:43
+#: vibes_auth/models.py:92
msgid "user phone number"
msgstr "User phone number"
-#: vibes_auth/models.py:49
+#: vibes_auth/models.py:98
msgid "first_name"
msgstr "First name"
-#: vibes_auth/models.py:50
+#: vibes_auth/models.py:99
msgid "last_name"
msgstr "Last name"
-#: vibes_auth/models.py:56
+#: vibes_auth/models.py:105
msgid "user profile image"
msgstr "User profile image"
-#: vibes_auth/models.py:61
+#: vibes_auth/models.py:110
msgid "is verified"
msgstr "Is verified"
-#: vibes_auth/models.py:62
+#: vibes_auth/models.py:111
msgid "user verification status"
msgstr "User's verification status"
-#: vibes_auth/models.py:65
+#: vibes_auth/models.py:114
msgid "is_active"
msgstr "Is active"
-#: vibes_auth/models.py:67
+#: vibes_auth/models.py:116
msgid "unselect this instead of deleting accounts"
msgstr "Unselect this instead of deleting accounts"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "is_subscribed"
msgstr "Is subscribed"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "user's newsletter subscription status"
msgstr "User's newsletter subscription status"
-#: vibes_auth/models.py:73
+#: vibes_auth/models.py:122
msgid "activation token"
msgstr "Activation token"
-#: vibes_auth/models.py:75
+#: vibes_auth/models.py:124
msgid "attributes"
msgstr "Attributes"
-#: vibes_auth/models.py:109
+#: vibes_auth/models.py:158
msgid "user"
msgstr "User"
-#: vibes_auth/models.py:110
+#: vibes_auth/models.py:159
msgid "users"
msgstr "Users"
-#: vibes_auth/models.py:116
+#: vibes_auth/models.py:179
msgid "group"
msgstr "Group"
-#: vibes_auth/models.py:123
+#: vibes_auth/models.py:196
msgid "outstanding token"
msgstr "Outstanding token"
-#: vibes_auth/models.py:124
+#: vibes_auth/models.py:197
msgid "outstanding tokens"
msgstr "Outstanding tokens"
-#: vibes_auth/models.py:130
+#: vibes_auth/models.py:215
msgid "blacklisted token"
msgstr "Blacklisted token"
-#: vibes_auth/models.py:131
+#: vibes_auth/models.py:216
msgid "blacklisted tokens"
msgstr "Blacklisted tokens"
-#: vibes_auth/serializers.py:112 vibes_auth/serializers.py:134
+#: vibes_auth/serializers.py:110 vibes_auth/serializers.py:132
+#: vibes_auth/serializers.py:154 vibes_auth/serializers.py:166
msgid "no active account"
msgstr "No active account found"
-#: vibes_auth/serializers.py:205
+#: vibes_auth/serializers.py:142
+msgid "must set token_class attribute on class."
+msgstr "Must set token_class attribute on class!"
+
+#: vibes_auth/serializers.py:214
msgid "token_blacklisted"
msgstr "Token blacklisted"
-#: vibes_auth/serializers.py:210
+#: vibes_auth/serializers.py:219
msgid "invalid token"
msgstr "Invalid token"
-#: vibes_auth/serializers.py:216
+#: vibes_auth/serializers.py:225
msgid "no user uuid claim present in token"
msgstr "No user uuid claim present in token"
-#: vibes_auth/serializers.py:218
+#: vibes_auth/serializers.py:227
msgid "user does not exist"
msgstr "User does not exist"
@@ -325,8 +334,7 @@ msgstr "Hello %(user_first_name)s,"
#: vibes_auth/templates/user_reset_password_email.html:92
msgid ""
-"we have received a request to reset your password. please reset your "
-"password\n"
+"we have received a request to reset your password. please reset your password\n"
" by clicking the button below:"
msgstr ""
"We have received a request to reset your password. Please reset your "
@@ -412,37 +420,14 @@ msgstr ""
"Invalid phone number format. The number must be entered in the format: "
"\"+999999999\". Up to 15 digits allowed."
-#: vibes_auth/views.py:57
+#: vibes_auth/views.py:117
msgid "the token is invalid"
msgstr "The token is invalid"
-#: vibes_auth/viewsets.py:88
+#: vibes_auth/viewsets.py:129
msgid "password reset successfully"
msgstr "Password has been reset successfully!"
-#: vibes_auth/viewsets.py:121
+#: vibes_auth/viewsets.py:162
msgid "account already activated!"
msgstr "You have already activated the account..."
-
-#~ msgid "eVibes Auth"
-#~ msgstr "eVibes Auth"
-
-#~ msgid "reset password"
-#~ msgstr "Reset password"
-
-#~ msgid ""
-#~ "if the button above does not work, please copy and paste the following "
-#~ "URL into your web browser:"
-#~ msgstr ""
-#~ "If the button above does not work, please copy and paste the following "
-#~ "URL into your web browser:"
-
-#, python-brace-format
-#~ msgid "user not found with the given pk: {user_pk}"
-#~ msgstr "User not found with the given UUID: {user_pk}"
-
-#~ msgid "something went wrong while sending an email: {e!s}"
-#~ msgstr "Something went wrong while sending an email: {e!s}"
-
-#~ msgid "recently viwed"
-#~ msgstr "Recently viewed"
diff --git a/vibes_auth/locale/en_US/LC_MESSAGES/django.mo b/vibes_auth/locale/en_US/LC_MESSAGES/django.mo
index d083bc4b..b5c06dbf 100644
Binary files a/vibes_auth/locale/en_US/LC_MESSAGES/django.mo and b/vibes_auth/locale/en_US/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/en_US/LC_MESSAGES/django.po b/vibes_auth/locale/en_US/LC_MESSAGES/django.po
index cbf93d02..667df87e 100644
--- a/vibes_auth/locale/en_US/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/en_US/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -18,27 +18,27 @@ msgstr ""
msgid "balance"
msgstr "Balance"
-#: vibes_auth/admin.py:44
+#: vibes_auth/admin.py:45
msgid "order"
msgstr "Order"
-#: vibes_auth/admin.py:45 vibes_auth/graphene/object_types.py:44
+#: vibes_auth/admin.py:46 vibes_auth/graphene/object_types.py:44
msgid "orders"
msgstr "Orders"
-#: vibes_auth/admin.py:54
+#: vibes_auth/admin.py:56
msgid "personal info"
msgstr "Personal Info"
-#: vibes_auth/admin.py:58 vibes_auth/graphene/object_types.py:43
+#: vibes_auth/admin.py:60 vibes_auth/graphene/object_types.py:43
msgid "permissions"
msgstr "Permissions"
-#: vibes_auth/admin.py:71
+#: vibes_auth/admin.py:73
msgid "important dates"
msgstr "Important dates"
-#: vibes_auth/admin.py:72
+#: vibes_auth/admin.py:74
msgid "additional info"
msgstr "Additional Info"
@@ -70,7 +70,7 @@ msgstr "Verify a token"
msgid "Verify a token (refresh or access)."
msgstr "Verify a token (refresh or access)."
-#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:55
+#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:115
msgid "the token is valid"
msgstr "The token is valid"
@@ -103,7 +103,7 @@ msgid "confirm a user's password reset"
msgstr "Confirm a user's password reset"
#: vibes_auth/docs/drf/viewsets.py:57 vibes_auth/graphene/mutations.py:307
-#: vibes_auth/viewsets.py:73
+#: vibes_auth/viewsets.py:114
msgid "passwords do not match"
msgstr "Passwords do not match"
@@ -130,7 +130,7 @@ msgstr "The password is too weak"
#: vibes_auth/graphene/mutations.py:107
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} does not exist: {uuid}"
+msgstr "{name} does not exist: {uuid}!"
#: vibes_auth/graphene/mutations.py:115
msgid "malformed email"
@@ -139,15 +139,15 @@ msgstr "Malformed email"
#: vibes_auth/graphene/mutations.py:120
#, python-brace-format
msgid "malformed phone number: {phone_number}"
-msgstr "Malformed phone number: {phone_number}"
+msgstr "Malformed phone number: {phone_number}!"
#: vibes_auth/graphene/mutations.py:142
#, python-brace-format
msgid "Invalid attribute format: {attribute_pair}"
-msgstr "Invalid attribute format: {attribute_pair}"
+msgstr "Invalid attribute format: {attribute_pair}!"
-#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:116
-#: vibes_auth/viewsets.py:135
+#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:157
+#: vibes_auth/viewsets.py:176
msgid "activation link is invalid!"
msgstr "Activation link is invalid!"
@@ -159,19 +159,19 @@ msgstr "Account has been already activated..."
msgid "something went wrong: {e!s}"
msgstr "Something went wrong: {e!s}"
-#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:84
+#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:125
msgid "token is invalid!"
msgstr "Token is invalid!"
#: vibes_auth/graphene/object_types.py:40
msgid ""
-"the products this user has viewed most recently (max 48), in reverse‐"
-"chronological order"
+"the products this user has viewed most recently (max 48), in "
+"reverse‐chronological order"
msgstr ""
"The products this user has viewed most recently (max 48), in reverse-"
"chronological order."
-#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:117
+#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:180
msgid "groups"
msgstr "Groups"
@@ -179,7 +179,7 @@ msgstr "Groups"
msgid "wishlist"
msgstr "Wishlist"
-#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:53
+#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:102
msgid "avatar"
msgstr "Avatar"
@@ -192,111 +192,120 @@ msgstr "Attributes may be used to store custom data"
msgid "language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
msgstr "Language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
-#: vibes_auth/models.py:36
+#: vibes_auth/graphene/object_types.py:50
+msgid "address set"
+msgstr "Adresses"
+
+#: vibes_auth/models.py:85
msgid "email"
msgstr "Email"
-#: vibes_auth/models.py:36
+#: vibes_auth/models.py:85
msgid "user email address"
msgstr "User's email address"
-#: vibes_auth/models.py:38
+#: vibes_auth/models.py:87
msgid "phone_number"
msgstr "Phone Number"
-#: vibes_auth/models.py:43
+#: vibes_auth/models.py:92
msgid "user phone number"
msgstr "User phone number"
-#: vibes_auth/models.py:49
+#: vibes_auth/models.py:98
msgid "first_name"
msgstr "First name"
-#: vibes_auth/models.py:50
+#: vibes_auth/models.py:99
msgid "last_name"
msgstr "Last name"
-#: vibes_auth/models.py:56
+#: vibes_auth/models.py:105
msgid "user profile image"
msgstr "User profile image"
-#: vibes_auth/models.py:61
+#: vibes_auth/models.py:110
msgid "is verified"
msgstr "Is verified"
-#: vibes_auth/models.py:62
+#: vibes_auth/models.py:111
msgid "user verification status"
msgstr "User's verification status"
-#: vibes_auth/models.py:65
+#: vibes_auth/models.py:114
msgid "is_active"
msgstr "Is active"
-#: vibes_auth/models.py:67
+#: vibes_auth/models.py:116
msgid "unselect this instead of deleting accounts"
msgstr "Unselect this instead of deleting accounts"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "is_subscribed"
msgstr "Is subscribed"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "user's newsletter subscription status"
msgstr "User's newsletter subscription status"
-#: vibes_auth/models.py:73
+#: vibes_auth/models.py:122
msgid "activation token"
msgstr "Activation token"
-#: vibes_auth/models.py:75
+#: vibes_auth/models.py:124
msgid "attributes"
msgstr "Attributes"
-#: vibes_auth/models.py:109
+#: vibes_auth/models.py:158
msgid "user"
msgstr "User"
-#: vibes_auth/models.py:110
+#: vibes_auth/models.py:159
msgid "users"
msgstr "Users"
-#: vibes_auth/models.py:116
+#: vibes_auth/models.py:179
msgid "group"
msgstr "Group"
-#: vibes_auth/models.py:123
+#: vibes_auth/models.py:196
msgid "outstanding token"
msgstr "Outstanding token"
-#: vibes_auth/models.py:124
+#: vibes_auth/models.py:197
msgid "outstanding tokens"
msgstr "Outstanding tokens"
-#: vibes_auth/models.py:130
+#: vibes_auth/models.py:215
msgid "blacklisted token"
msgstr "Blacklisted token"
-#: vibes_auth/models.py:131
+#: vibes_auth/models.py:216
msgid "blacklisted tokens"
msgstr "Blacklisted tokens"
-#: vibes_auth/serializers.py:112 vibes_auth/serializers.py:134
+#: vibes_auth/serializers.py:110 vibes_auth/serializers.py:132
+#: vibes_auth/serializers.py:154 vibes_auth/serializers.py:166
msgid "no active account"
msgstr "No active account found"
-#: vibes_auth/serializers.py:205
+#: vibes_auth/serializers.py:142
+msgid "must set token_class attribute on class."
+msgstr "Must set token_class attribute on class!"
+
+#: vibes_auth/serializers.py:214
msgid "token_blacklisted"
msgstr "Token blacklisted"
-#: vibes_auth/serializers.py:210
+#: vibes_auth/serializers.py:219
msgid "invalid token"
msgstr "Invalid token"
-#: vibes_auth/serializers.py:216
+#: vibes_auth/serializers.py:225
msgid "no user uuid claim present in token"
msgstr "No user uuid claim present in token"
-#: vibes_auth/serializers.py:218
+#: vibes_auth/serializers.py:227
msgid "user does not exist"
msgstr "User does not exist"
@@ -321,8 +330,7 @@ msgstr "Hello %(user_first_name)s,"
#: vibes_auth/templates/user_reset_password_email.html:92
msgid ""
-"we have received a request to reset your password. please reset your "
-"password\n"
+"we have received a request to reset your password. please reset your password\n"
" by clicking the button below:"
msgstr ""
"We have received a request to reset your password. Please reset your "
@@ -408,17 +416,14 @@ msgstr ""
"Invalid phone number format. The number must be entered in the format: "
"\"+999999999\". Up to 15 digits allowed."
-#: vibes_auth/views.py:57
+#: vibes_auth/views.py:117
msgid "the token is invalid"
msgstr "The token is invalid"
-#: vibes_auth/viewsets.py:88
+#: vibes_auth/viewsets.py:129
msgid "password reset successfully"
msgstr "Password has been reset successfully!"
-#: vibes_auth/viewsets.py:121
+#: vibes_auth/viewsets.py:162
msgid "account already activated!"
msgstr "You have already activated the account..."
-
-#~ msgid "eVibes Auth"
-#~ msgstr "eVibes Auth"
diff --git a/vibes_auth/locale/es_ES/LC_MESSAGES/django.mo b/vibes_auth/locale/es_ES/LC_MESSAGES/django.mo
index f322f54f..cd06e2c8 100644
Binary files a/vibes_auth/locale/es_ES/LC_MESSAGES/django.mo and b/vibes_auth/locale/es_ES/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/es_ES/LC_MESSAGES/django.po b/vibes_auth/locale/es_ES/LC_MESSAGES/django.po
index f51db134..01ca6613 100644
--- a/vibes_auth/locale/es_ES/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/es_ES/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH \n"
@@ -18,27 +18,27 @@ msgstr ""
msgid "balance"
msgstr "Saldo"
-#: vibes_auth/admin.py:44
+#: vibes_auth/admin.py:45
msgid "order"
msgstr "Pida"
-#: vibes_auth/admin.py:45 vibes_auth/graphene/object_types.py:44
+#: vibes_auth/admin.py:46 vibes_auth/graphene/object_types.py:44
msgid "orders"
msgstr "Pedidos"
-#: vibes_auth/admin.py:54
+#: vibes_auth/admin.py:56
msgid "personal info"
msgstr "Información personal"
-#: vibes_auth/admin.py:58 vibes_auth/graphene/object_types.py:43
+#: vibes_auth/admin.py:60 vibes_auth/graphene/object_types.py:43
msgid "permissions"
msgstr "Permisos"
-#: vibes_auth/admin.py:71
+#: vibes_auth/admin.py:73
msgid "important dates"
msgstr "Fechas importantes"
-#: vibes_auth/admin.py:72
+#: vibes_auth/admin.py:74
msgid "additional info"
msgstr "Información adicional"
@@ -70,7 +70,7 @@ msgstr "Verificar un token"
msgid "Verify a token (refresh or access)."
msgstr "Verificar un token (actualización o acceso)."
-#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:55
+#: vibes_auth/docs/drf/views.py:62 vibes_auth/views.py:115
msgid "the token is valid"
msgstr "El token es válido"
@@ -105,7 +105,7 @@ msgid "confirm a user's password reset"
msgstr "Confirmar el restablecimiento de la contraseña de un usuario"
#: vibes_auth/docs/drf/viewsets.py:57 vibes_auth/graphene/mutations.py:307
-#: vibes_auth/viewsets.py:73
+#: vibes_auth/viewsets.py:114
msgid "passwords do not match"
msgstr "Las contraseñas no coinciden"
@@ -133,7 +133,7 @@ msgstr "La contraseña es demasiado débil"
#: vibes_auth/graphene/mutations.py:107
#, python-brace-format
msgid "{name} does not exist: {uuid}"
-msgstr "{name} no existe: {uuid}"
+msgstr "{name} no existe: ¡{uuid}!"
#: vibes_auth/graphene/mutations.py:115
msgid "malformed email"
@@ -142,15 +142,15 @@ msgstr "Correo electrónico malformado"
#: vibes_auth/graphene/mutations.py:120
#, python-brace-format
msgid "malformed phone number: {phone_number}"
-msgstr "Número de teléfono malformado: {phone_number}"
+msgstr "Número de teléfono malformado: ¡{phone_number}!"
#: vibes_auth/graphene/mutations.py:142
#, python-brace-format
msgid "Invalid attribute format: {attribute_pair}"
-msgstr "Formato de atributo no válido: {attribute_pair}"
+msgstr "Formato de atributo no válido: ¡{attribute_pair}!"
-#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:116
-#: vibes_auth/viewsets.py:135
+#: vibes_auth/graphene/mutations.py:263 vibes_auth/viewsets.py:157
+#: vibes_auth/viewsets.py:176
msgid "activation link is invalid!"
msgstr "El enlace de activación no es válido."
@@ -162,19 +162,19 @@ msgstr "La cuenta ya ha sido activada..."
msgid "something went wrong: {e!s}"
msgstr "Algo salió mal: {e!s}."
-#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:84
+#: vibes_auth/graphene/mutations.py:314 vibes_auth/viewsets.py:125
msgid "token is invalid!"
msgstr "¡La ficha no es válida!"
#: vibes_auth/graphene/object_types.py:40
msgid ""
-"the products this user has viewed most recently (max 48), in reverse‐"
-"chronological order"
+"the products this user has viewed most recently (max 48), in "
+"reverse‐chronological order"
msgstr ""
"Los productos que este usuario ha visto más recientemente (máx. 48), en "
"orden cronológico inverso."
-#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:117
+#: vibes_auth/graphene/object_types.py:42 vibes_auth/models.py:180
msgid "groups"
msgstr "Grupos"
@@ -182,7 +182,7 @@ msgstr "Grupos"
msgid "wishlist"
msgstr "Lista de deseos"
-#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:53
+#: vibes_auth/graphene/object_types.py:47 vibes_auth/models.py:102
msgid "avatar"
msgstr "Avatar"
@@ -193,113 +193,122 @@ msgstr "Los atributos pueden utilizarse para almacenar datos personalizados"
#: vibes_auth/graphene/object_types.py:49
#, python-brace-format
msgid "language is one of the {LANGUAGES} with default {LANGUAGE_CODE}"
-msgstr "El idioma es uno de los {LANGUAGES} con {LANGUAGE_CODE} por defecto."
+msgstr "El idioma es uno de los {LANGUAGES} con {LANGUAGE_CODE} por defecto"
-#: vibes_auth/models.py:36
+#: vibes_auth/graphene/object_types.py:50
+msgid "address set"
+msgstr "Direcciones"
+
+#: vibes_auth/models.py:85
msgid "email"
msgstr "Correo electrónico"
-#: vibes_auth/models.py:36
+#: vibes_auth/models.py:85
msgid "user email address"
msgstr "Dirección de correo electrónico del usuario"
-#: vibes_auth/models.py:38
+#: vibes_auth/models.py:87
msgid "phone_number"
msgstr "Número de teléfono"
-#: vibes_auth/models.py:43
+#: vibes_auth/models.py:92
msgid "user phone number"
msgstr "Número de teléfono del usuario"
-#: vibes_auth/models.py:49
+#: vibes_auth/models.py:98
msgid "first_name"
msgstr "Nombre"
-#: vibes_auth/models.py:50
+#: vibes_auth/models.py:99
msgid "last_name"
msgstr "Apellido"
-#: vibes_auth/models.py:56
+#: vibes_auth/models.py:105
msgid "user profile image"
msgstr "Imagen del perfil del usuario"
-#: vibes_auth/models.py:61
+#: vibes_auth/models.py:110
msgid "is verified"
msgstr "Se verifica"
-#: vibes_auth/models.py:62
+#: vibes_auth/models.py:111
msgid "user verification status"
msgstr "Estado de verificación del usuario"
-#: vibes_auth/models.py:65
+#: vibes_auth/models.py:114
msgid "is_active"
msgstr "Está activo"
-#: vibes_auth/models.py:67
+#: vibes_auth/models.py:116
msgid "unselect this instead of deleting accounts"
msgstr "Deseleccione esta opción en lugar de eliminar cuentas"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "is_subscribed"
msgstr "Está suscrito"
-#: vibes_auth/models.py:70
+#: vibes_auth/models.py:119
msgid "user's newsletter subscription status"
msgstr "Estado de suscripción del usuario al boletín"
-#: vibes_auth/models.py:73
+#: vibes_auth/models.py:122
msgid "activation token"
msgstr "Ficha de activación"
-#: vibes_auth/models.py:75
+#: vibes_auth/models.py:124
msgid "attributes"
msgstr "Atributos"
-#: vibes_auth/models.py:109
+#: vibes_auth/models.py:158
msgid "user"
msgstr "Usuario"
-#: vibes_auth/models.py:110
+#: vibes_auth/models.py:159
msgid "users"
msgstr "Usuarios"
-#: vibes_auth/models.py:116
+#: vibes_auth/models.py:179
msgid "group"
msgstr "Grupo"
-#: vibes_auth/models.py:123
+#: vibes_auth/models.py:196
msgid "outstanding token"
msgstr "Ficha pendiente"
-#: vibes_auth/models.py:124
+#: vibes_auth/models.py:197
msgid "outstanding tokens"
msgstr "Fichas pendientes"
-#: vibes_auth/models.py:130
+#: vibes_auth/models.py:215
msgid "blacklisted token"
msgstr "Ficha en la lista negra"
-#: vibes_auth/models.py:131
+#: vibes_auth/models.py:216
msgid "blacklisted tokens"
msgstr "Fichas en la lista negra"
-#: vibes_auth/serializers.py:112 vibes_auth/serializers.py:134
+#: vibes_auth/serializers.py:110 vibes_auth/serializers.py:132
+#: vibes_auth/serializers.py:154 vibes_auth/serializers.py:166
msgid "no active account"
msgstr "No se ha encontrado ninguna cuenta activa"
-#: vibes_auth/serializers.py:205
+#: vibes_auth/serializers.py:142
+msgid "must set token_class attribute on class."
+msgstr "Debe establecer el atributo token_class en la clase."
+
+#: vibes_auth/serializers.py:214
msgid "token_blacklisted"
msgstr "Ficha en la lista negra"
-#: vibes_auth/serializers.py:210
+#: vibes_auth/serializers.py:219
msgid "invalid token"
msgstr "Token no válido"
-#: vibes_auth/serializers.py:216
+#: vibes_auth/serializers.py:225
msgid "no user uuid claim present in token"
msgstr "No user uuid claim present in token"
-#: vibes_auth/serializers.py:218
+#: vibes_auth/serializers.py:227
msgid "user does not exist"
msgstr "El usuario no existe"
@@ -324,8 +333,7 @@ msgstr "Hola %(user_first_name)s,"
#: vibes_auth/templates/user_reset_password_email.html:92
msgid ""
-"we have received a request to reset your password. please reset your "
-"password\n"
+"we have received a request to reset your password. please reset your password\n"
" by clicking the button below:"
msgstr ""
"Hemos recibido una solicitud para restablecer su contraseña. Por favor, "
@@ -359,7 +367,7 @@ msgstr ""
#: vibes_auth/templates/user_reset_password_email.html:103
#, python-format
msgid "best regards,
The %(project_name)s team"
-msgstr "Saludos cordiales,
El equipo de %(project_name)s"
+msgstr "Saludos cordiales,
El equipo %(project_name)s"
#: vibes_auth/templates/user_reset_password_email.html:109
#: vibes_auth/templates/user_verification_email.html:108
@@ -391,7 +399,7 @@ msgstr ""
#: vibes_auth/templates/user_verification_email.html:102
#, python-format
msgid "best regards,
the %(project_name)s team"
-msgstr "Saludos cordiales,
el equipo de %(project_name)s"
+msgstr "Saludos cordiales,
el equipo %(project_name)s"
#: vibes_auth/utils/emailing.py:27
#, python-brace-format
@@ -411,17 +419,14 @@ msgstr ""
"Formato de número de teléfono no válido. El número debe introducirse con el "
"formato \"+999999999\". Se permiten hasta 15 dígitos."
-#: vibes_auth/views.py:57
+#: vibes_auth/views.py:117
msgid "the token is invalid"
msgstr "El token no es válido"
-#: vibes_auth/viewsets.py:88
+#: vibes_auth/viewsets.py:129
msgid "password reset successfully"
msgstr "La contraseña se ha restablecido correctamente."
-#: vibes_auth/viewsets.py:121
+#: vibes_auth/viewsets.py:162
msgid "account already activated!"
msgstr "Ya ha activado la cuenta..."
-
-#~ msgid "eVibes Auth"
-#~ msgstr "eVibes Auth"
diff --git a/vibes_auth/locale/fr_FR/LC_MESSAGES/django.mo b/vibes_auth/locale/fr_FR/LC_MESSAGES/django.mo
index 3cadc87d..31480c06 100644
Binary files a/vibes_auth/locale/fr_FR/LC_MESSAGES/django.mo and b/vibes_auth/locale/fr_FR/LC_MESSAGES/django.mo differ
diff --git a/vibes_auth/locale/fr_FR/LC_MESSAGES/django.po b/vibes_auth/locale/fr_FR/LC_MESSAGES/django.po
index ab1f4ec8..9ef1405c 100644
--- a/vibes_auth/locale/fr_FR/LC_MESSAGES/django.po
+++ b/vibes_auth/locale/fr_FR/LC_MESSAGES/django.po
@@ -1,9 +1,9 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: 1\n"
+"Project-Id-Version: EVIBES 2.9.2\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2025-06-21 22:42+0100\n"
+"POT-Creation-Date: 2025-07-14 15:36+0300\n"
"PO-Revision-Date: 2025-01-30 03:27+0000\n"
"Last-Translator: EGOR GORBUNOV \n"
"Language-Team: BRITISH ENGLISH