Merge branch 'main' into storefront-next

This commit is contained in:
Egor Pavlovich Gorbunov 2025-12-15 19:52:29 +03:00
commit 0b829d3b5f
876 changed files with 160393 additions and 73108 deletions

View file

@ -26,6 +26,7 @@ cython_debug/
# Python environments
.Python
.python-version
env/
env.bak/
venv/
@ -38,7 +39,6 @@ __pypackages__/
# Packaging and distribution
# ──────────────────────────────────────────────────────────────────────────
build/
dist/
dist-ssr/
*.egg
*.egg-info/
@ -69,14 +69,13 @@ pip-delete-this-directory.txt
# ──────────────────────────────────────────────────────────────────────────
storefront/Dockerfile
docker-compose.yml
db_backups/
services_data/
backups/
static/
media/
!core/static
!blog/static
!vibes_auth/static
!payments/static
!engine/core/static
!engine/blog/static
!engine/vibes_auth/static
!engine/payments/static
# Environment file
.env

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
*.sh text eol=lf

26
.gitignore vendored
View file

@ -27,6 +27,7 @@ venv.bak/
ENV/
.venv/
__pypackages__/
.python-version
# Local Django settings and database
local_settings.py
@ -35,7 +36,7 @@ db.sqlite3-journal
# Django backups and metadata
instance/
db_backups/
backups/
# ──────────────────────────────────────────────────────────────────────────
# Logs and reports
@ -50,6 +51,7 @@ coverage.*
*.cover
*.py,cover
nosetests.xml
tmp
# Coverage / test reports
htmlcov/
@ -90,6 +92,7 @@ share/python-wheels/
pip-log.txt
pip-delete-this-directory.txt
desktop.ini
*.iml
# Node build artifacts
npm-debug.log*
@ -106,22 +109,14 @@ static/
media/
# Allow checked-in static from apps
!core/static/
!payments/static/
!vibes_auth/static/
!blog/static/
!engine/core/static/
!engine/payments/static/
!engine/vibes_auth/static/
!engine/blog/static/
# Webassets
.webassets-cache/
# ──────────────────────────────────────────────────────────────────────────
# Docker & service data
# ──────────────────────────────────────────────────────────────────────────
# Local volume mounts
services_data/
services_data/postgres/
services_data/redis/
# ──────────────────────────────────────────────────────────────────────────
# Node dependencies
# ──────────────────────────────────────────────────────────────────────────
@ -145,6 +140,7 @@ cypress/screenshots/
!.idea/icon.svg
!.idea/externalDependencies.xml
!.idea/evibes.iml
!.idea/evibes.ico
# Microsoft
*.suo
@ -169,3 +165,7 @@ cypress/screenshots/
# Development stuff
test.ipynb
# Production stuff
.initialized
queries

View file

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="PyDocumentationSettings">
<option name="format" value="GOOGLE" />
<option name="myDocStringFormat" value="Google" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/blog/templates" />
</list>
</option>
</component>
</module>

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalDependencies">
<plugin id="Docker" />
<plugin id="Git4Idea" />
<plugin id="Pythonid" />
<plugin id="com.github.xepozz.gitcodeowners" />
<plugin id="com.intellij.python.django" />
<plugin id="com.koxudaxi.ruff" />
<plugin id="com.leinardi.pycharm.mypy" />
<plugin id="com.mallowigi" />
<plugin id="com.nasller.CodeGlancePro" />
<plugin id="dev.meanmail.plugin.nginx-intellij-plugin" />
<plugin id="mobi.hsz.idea.gitignore" />
<plugin id="org.jetbrains.plugins.astro" />
<plugin id="ru.adelf.idea.dotenv" />
</component>
</project>

View file

@ -10,7 +10,7 @@ docker-compose.yml @@maintainer
.dockerignore @@maintainer
nginx @@maintainer
pyproject.toml @fureunoir contact@fureunoir.com
poetry.lock @fureunoir contact@fureunoir.com
uv.lock @fureunoir contact@fureunoir.com
*.py @fureunoir contact@fureunoir.com
*.bat @fureunoir contact@fureunoir.com

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM python:3.12-bookworm
FROM python:3.12-slim-bookworm
LABEL authors="fureunoir"
ENV PYTHONDONTWRITEBYTECODE=1 \
@ -13,7 +13,7 @@ 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; \
apt-get install -y --no-install-recommends wget gnupg curl; \
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; \
@ -26,24 +26,32 @@ RUN set -eux; \
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
pip install --upgrade pip
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
RUN uv venv /opt/evibes-python
ENV VIRTUAL_ENV=/opt/evibes-python
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
COPY pyproject.toml pyproject.toml
COPY poetry.lock poetry.lock
COPY uv.lock uv.lock
RUN poetry config virtualenvs.create false
RUN poetry install --extras="graph worker openai testing" --no-interaction --no-ansi
RUN set -eux; \
uv sync --extra graph --extra worker --extra openai --locked
COPY ./scripts/Docker/app-entrypoint.sh /usr/local/bin/app-entrypoint.sh
RUN chmod +x /usr/local/bin/app-entrypoint.sh
COPY . .
ENTRYPOINT ["app-entrypoint.sh"]
ENTRYPOINT ["/usr/bin/bash", "app-entrypoint.sh"]

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM python:3.12-bookworm
FROM python:3.12-slim-bookworm
LABEL authors="fureunoir"
ENV PYTHONDONTWRITEBYTECODE=1 \
@ -13,7 +13,7 @@ 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; \
apt-get install -y --no-install-recommends wget gnupg curl; \
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; \
@ -26,24 +26,32 @@ RUN set -eux; \
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
pip install --upgrade pip
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
RUN uv venv /opt/evibes-python
ENV VIRTUAL_ENV=/opt/evibes-python
COPY pyproject.toml pyproject.toml
COPY poetry.lock poetry.lock
COPY uv.lock uv.lock
RUN poetry config virtualenvs.create false
RUN poetry install --extras="worker openai" --no-interaction --no-ansi
RUN set -eux; \
uv sync --extra worker --extra openai --locked
COPY ./scripts/Docker/beat-entrypoint.sh /usr/local/bin/beat-entrypoint.sh
RUN chmod +x /usr/local/bin/beat-entrypoint.sh
COPY . .
ENTRYPOINT ["beat-entrypoint.sh"]
ENTRYPOINT ["/usr/bin/bash", "beat-entrypoint.sh"]

View file

@ -0,0 +1,57 @@
# syntax=docker/dockerfile:1
FROM python:3.12-slim-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 curl; \
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
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
RUN uv venv /opt/evibes-python
ENV VIRTUAL_ENV=/opt/evibes-python
COPY pyproject.toml pyproject.toml
COPY uv.lock uv.lock
RUN set -eux; \
uv sync --extra worker --extra openai --locked
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"]

View file

@ -0,0 +1,38 @@
# syntax=docker/dockerfile:1
FROM node:22-bookworm-slim AS build
WORKDIR /app
ARG EVIBES_BASE_DOMAIN
ARG EVIBES_PROJECT_NAME
ENV EVIBES_BASE_DOMAIN=$EVIBES_BASE_DOMAIN
ENV EVIBES_PROJECT_NAME=$EVIBES_PROJECT_NAME
COPY ./supervisor/package.json ./supervisor/package-lock.json ./
RUN npm ci --include=optional
COPY ./supervisor ./
RUN npm run build
FROM node:22-bookworm-slim AS runtime
WORKDIR /app
ENV HOST=0.0.0.0
ENV PORT=7777
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
RUN addgroup --system --gid 1001 nodeapp \
&& adduser --system --uid 1001 --ingroup nodeapp --home /home/nodeapp nodeapp
USER nodeapp
COPY --from=build /app/.output/ ./
RUN install -d -m 0755 -o nodeapp -g nodeapp /home/nodeapp \
&& printf '#!/bin/sh\nif [ \"$DEBUG\" = \"1\" ]; then export NODE_ENV=development; else export NODE_ENV=production; fi\nexec node /app/server/index.mjs\n' > /home/nodeapp/start.sh \
&& chown nodeapp:nodeapp /home/nodeapp/start.sh \
&& chmod +x /home/nodeapp/start.sh
USER nodeapp
CMD ["sh", "/home/nodeapp/start.sh"]

View file

@ -1,5 +1,5 @@
# syntax=docker/dockerfile:1
FROM python:3.12-bookworm
FROM python:3.12-slim-bookworm
LABEL authors="fureunoir"
ENV PYTHONDONTWRITEBYTECODE=1 \
@ -13,7 +13,7 @@ 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; \
apt-get install -y --no-install-recommends wget gnupg curl; \
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; \
@ -26,24 +26,32 @@ RUN set -eux; \
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
pip install --upgrade pip
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:/root/.cargo/bin:$PATH"
RUN uv venv /opt/evibes-python
ENV VIRTUAL_ENV=/opt/evibes-python
ENV UV_PROJECT_ENVIRONMENT=/opt/evibes-python
ENV PATH="/opt/evibes-python/bin:/root/.local/bin:/root/.cargo/bin:$PATH"
COPY pyproject.toml pyproject.toml
COPY poetry.lock poetry.lock
COPY uv.lock uv.lock
RUN poetry config virtualenvs.create false
RUN poetry install --extras="worker openai" --no-interaction --no-ansi
RUN set -eux; \
uv sync --extra worker --extra openai --locked
COPY ./scripts/Docker/worker-entrypoint.sh /usr/local/bin/worker-entrypoint.sh
RUN chmod +x /usr/local/bin/worker-entrypoint.sh
COPY . .
ENTRYPOINT ["worker-entrypoint.sh"]
ENTRYPOINT ["/usr/bin/bash", "worker-entrypoint.sh"]

140
README.md
View file

@ -1,58 +1,56 @@
# eVibes
![LOGO](core/docs/images/evibes-big.png)
![LOGO](engine/core/docs/images/evibes-big.png)
eVibes is an eCommerce backend service built with Django. Its designed for flexibility, making it ideal for various use
cases and learning Django skills. The project is straightforward to customize, allowing for straightforward editing and
extension.
eVibes — a lightweight, production-ready ecommerce backend. Storefront, product catalog, cart, and orders work out of the box. Minimal complexity, maximum flexibility — install, adjust to your needs, and start selling.
- Public issues: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban
## Table of Contents
- [Features](#features)
- [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Configuration](#configuration)
- [Dockerfile](#Dockerfile)
- [nginx](#nginx)
- [.env](#env)
- [Usage](#usage)
- [Contact](#contact)
- Features
- Quick Start
- Prerequisites
- Installation
- Configuration
- Dockerfile
- nginx
- .env
- Usage
- Contributing
- Contact
- License
## Features
- **Modular Architecture**: Extend and customize the backend to fit your needs.
- **Dockerized Deployment**: Quick setup and deployment using Docker and Docker Compose.
- **Asynchronous Task Processing**: Integrated Celery workers and beat scheduler for background tasks.
- **GraphQL and REST APIs**: Supports both GraphQL and RESTful API endpoints.
- **Internationalization**: Multilingual support using modeltranslate.
- **Advanced Caching**: Utilizes Redis for caching and task queuing.
- **Security**: Implements JWT authentication and rate limiting.
- Modular backend, easy to extend and customize
- Dockerized deployment with Docker Compose
- Celery workers and beat for background tasks
- REST and GraphQL APIs
- Internationalization with modeltranslation
- Redis-based caching and queues
- JWT auth and rate limiting
## Getting Started
## Quick Start
### Prerequisites
- Docker and Docker Compose are installed on your machine.
- Docker and Docker Compose
### Installation
1. Clone the repository:
1. Clone the repository
```bash
git clone https://gitlab.com/wiseless.xyz/eVibes.git
cd eVibes
```
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.
2. Choose a storefront (optional). The `main` branch ships without a storefront. If you want one, pick a branch:
```bash
git checkout storefront-<options: nuxt, next, sk, qwik >
git checkout storefront-<nuxt|next|sk|qwik>
```
3. Generate your .env file. Check and confirm the contents afterward.
3. Generate your .env file and review its values
- Windows
```powershell
scripts\Windows\generate-environment-file.ps1
@ -62,8 +60,7 @@ Skip this step if you're OK with that and plan to only use API or develop your o
scripts/Unix/generate-environment-file.sh
```
4. Install all the dependencies.
4. Install dependencies
- Windows
```powershell
scripts\Windows\install.ps1
@ -73,8 +70,7 @@ Skip this step if you're OK with that and plan to only use API or develop your o
scripts/Unix/install.sh
```
5. Spin it up.
5. Run the stack
- Windows
```powershell
scripts\Windows\run.ps1
@ -84,71 +80,53 @@ Skip this step if you're OK with that and plan to only use API or develop your o
scripts/Unix/run.sh
```
6. Bring to production.
Include `nginx` file to your nginx configuration, you really want to install and
run [Certbot](https://certbot.eff.org/) afterward!
6. Production checklist
- Include `nginx.conf` into your Nginx setup
- Issue TLS certs with Certbot (https://certbot.eff.org/)
## Configuration
### Dockerfile
Remember to change the
`RUN sed -i 's|https://deb.debian.org/debian|https://ftp.<locale>.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources`
before running installment scripts
If you rely on locale mirrors, adjust Debian sources before running installation scripts:
```
RUN sed -i 's|https://deb.debian.org/debian|https://ftp.<locale>.debian.org/debian|g' /etc/apt/sources.list.d/debian.sources
```
### nginx
Please comment-out SSL-related lines, then apply necessary configurations, run `certbot --cert-only --nginx`,
decomment previously commented lines and enjoy eVibes over HTTPS!
- Comment out SSL-related lines
- Apply your domain-specific settings
- Run `certbot --cert-only --nginx`
- Uncomment SSL lines and reload Nginx
### .env
After .env file generation, you may want to edit some of its values, such as macroservices` API keys, database password,
redis password, etc.
After generation, review and update secrets and credentials (API keys, DB password, Redis password, etc.).
## Usage
- Add the necessary subdomains to DNS-settings of your domain, those are:
- DNS records youll typically want:
1. @.your-domain.com
2. www.your-domain.com
3. api.your-domain.com
4. b2b.your-domain.com
5. prometheus.your-domain.com
4. prometheus.your-domain.com
- Add these lines to your hosts-file to use django-hosts functionality on localhost(*DEVELOPMENT ONLY*):
- Once running, access:
- API root / Admin redirect: http://api.localhost:8000/
- REST docs: http://api.localhost:8000/docs/swagger or http://api.localhost:8000/docs/redoc
- GraphQL: http://api.localhost:8000/graphql/
```hosts
127.0.0.1 api.localhost
127.0.0.1 b2b.localhost
```
## Contributing
Once the services are up and running, you can access the application at
`http://api.your-domain.com`(http://api.localhost:8000).
- **Django Admin**: `http://api.your-domain.com/` (will redirect to admin)
- **API Docs**:
- REST API: `http://api.localhost:8000/docs/swagger` or `http://api.localhost:8000/docs/redoc`
- GraphQL API: `http://api.localhost:8000/graphql/`
## Uninstall eVibes
You are not planning to do that, aren't you?
- Windows
```powershell
scripts\Windows\uninstall.ps1
```
- Unix
```bash
scripts/Unix/uninstall.sh
```
- Track and report issues here: https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=list
- Pull requests are welcome. Please keep changes minimal and focused.
## Contact
- **Author**: Egor "fureunoir" Gorbunov
- Author: Egor "fureunoir" Gorbunov
- Email: contact@fureunoir.com
- Telegram: [@fureunoir](https://t.me/fureunoir)
- Telegram: https://t.me/fureunoir
![FAVICON](core/docs/images/evibes.png)
## License
This project is licensed under the terms of the LICENSE file included in this repository.
![FAVICON](engine/core/docs/images/evibes.png)

View file

@ -1,71 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: ar-ar\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"
#: blog/apps.py:8
msgid "blog"
msgstr "المدونة"
#: blog/models.py:17
msgid "post title"
msgstr "عنوان المنشور"
#: blog/models.py:17
msgid "title"
msgstr "العنوان"
#: blog/models.py:64
msgid "post"
msgstr "المنشور"
#: blog/models.py:65
msgid "posts"
msgstr "المنشورات"
#: blog/models.py:69
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"ملفات تخفيض السعر غير مدعومة Yer - استخدم محتوى تخفيض السعر بدلاً من ذلك!"
#: blog/models.py:71
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr "يجب توفير ملف ترميز أو محتوى ترميز مخفض - متنافيان"
#: blog/models.py:82
msgid "internal tag identifier for the post tag"
msgstr "معرّف العلامة الداخلي لعلامة المنشور"
#: blog/models.py:83
msgid "tag name"
msgstr "اسم العلامة"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "اسم سهل الاستخدام لعلامة المنشور"
#: blog/models.py:88
msgid "tag display name"
msgstr "اسم عرض العلامة"
#: blog/models.py:96
msgid "post tag"
msgstr "علامة المشاركة"
#: blog/models.py:97
msgid "post tags"
msgstr "علامات المشاركة"
#~ msgid "eVibes Engine"
#~ msgstr "محرك eVibes"

View file

@ -1,73 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: cs-cz\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Název příspěvku"
#: blog/models.py:17
msgid "title"
msgstr "Název"
#: blog/models.py:64
msgid "post"
msgstr "Příspěvek"
#: blog/models.py:65
msgid "posts"
msgstr "Příspěvky"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "interní identifikátor tagu pro tag příspěvku"
#: blog/models.py:83
msgid "tag name"
msgstr "Název štítku"
#: blog/models.py:87
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
msgid "tag display name"
msgstr "Zobrazení názvu štítku"
#: blog/models.py:96
msgid "post tag"
msgstr "Označení příspěvku"
#: blog/models.py:97
msgid "post tags"
msgstr "Štítky příspěvků"
#~ msgid "eVibes Engine"
#~ msgstr "Motor eVibes"

View file

@ -1,71 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: da-dk\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Indlæggets titel"
#: blog/models.py:17
msgid "title"
msgstr "Titel"
#: blog/models.py:64
msgid "post"
msgstr "Indlæg"
#: blog/models.py:65
msgid "posts"
msgstr "Indlæg"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "intern tag-identifikator for indlægs-tagget"
#: blog/models.py:83
msgid "tag name"
msgstr "Tag-navn"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Brugervenligt navn til posttagget"
#: blog/models.py:88
msgid "tag display name"
msgstr "Navn på tag-visning"
#: blog/models.py:96
msgid "post tag"
msgstr "Tag til indlæg"
#: blog/models.py:97
msgid "post tags"
msgstr "Tags til indlæg"
#~ msgid "eVibes Engine"
#~ msgstr "eVibes-motor"

View file

@ -1,74 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: de-de\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Titel des Beitrags"
#: blog/models.py:17
msgid "title"
msgstr "Titel"
#: blog/models.py:64
msgid "post"
msgstr "Beitrag"
#: blog/models.py:65
msgid "posts"
msgstr "Beiträge"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "interner Tag-Bezeichner für den Post-Tag"
#: blog/models.py:83
msgid "tag name"
msgstr "Tag name"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Benutzerfreundlicher Name für das Post-Tag"
#: blog/models.py:88
msgid "tag display name"
msgstr "Tag-Anzeigename"
#: blog/models.py:96
msgid "post tag"
msgstr "Tag eintragen"
#: blog/models.py:97
msgid "post tags"
msgstr "Tags eintragen"
#~ msgid "eVibes Engine"
#~ msgstr "eVibes Motor"

View file

@ -1,81 +0,0 @@
# EVIBES GETTEXT TRANSLATIONS
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: \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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Post's title"
#: blog/models.py:17
msgid "title"
msgstr "Title"
#: blog/models.py:64
msgid "post"
msgstr "Post"
#: blog/models.py:65
msgid "posts"
msgstr "Posts"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "internal tag identifier for the post tag"
#: blog/models.py:83
msgid "tag name"
msgstr "Tag name"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "User-friendly name for the post tag"
#: blog/models.py:88
msgid "tag display name"
msgstr "Tag display name"
#: blog/models.py:96
msgid "post tag"
msgstr "Post tag"
#: blog/models.py:97
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"

View file

@ -1,71 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: en-us\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Post's title"
#: blog/models.py:17
msgid "title"
msgstr "Title"
#: blog/models.py:64
msgid "post"
msgstr "Post"
#: blog/models.py:65
msgid "posts"
msgstr "Posts"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "internal tag identifier for the post tag"
#: blog/models.py:83
msgid "tag name"
msgstr "Tag name"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "User-friendly name for the post tag"
#: blog/models.py:88
msgid "tag display name"
msgstr "Tag display name"
#: blog/models.py:96
msgid "post tag"
msgstr "Post tag"
#: blog/models.py:97
msgid "post tags"
msgstr "Post tags"
#~ msgid "eVibes Engine"
#~ msgstr "eVibes Engine"

View file

@ -1,73 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: es-es\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Título del mensaje"
#: blog/models.py:17
msgid "title"
msgstr "Título"
#: blog/models.py:64
msgid "post"
msgstr "Publicar en"
#: blog/models.py:65
msgid "posts"
msgstr "Puestos"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "identificador interno de la etiqueta post"
#: blog/models.py:83
msgid "tag name"
msgstr "Nombre de la etiqueta"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Nombre fácil de usar para la etiqueta de la entrada"
#: blog/models.py:88
msgid "tag display name"
msgstr "Nombre de la etiqueta"
#: blog/models.py:96
msgid "post tag"
msgstr "Etiqueta postal"
#: blog/models.py:97
msgid "post tags"
msgstr "Etiquetas"
#~ msgid "eVibes Engine"
#~ msgstr "Motor eVibes"

View file

@ -1,74 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: fr-fr\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Titre du message"
#: blog/models.py:17
msgid "title"
msgstr "Titre"
#: blog/models.py:64
msgid "post"
msgstr "Poste"
#: blog/models.py:65
msgid "posts"
msgstr "Postes"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "identifiant interne de la balise post"
#: blog/models.py:83
msgid "tag name"
msgstr "Nom du jour"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Nom convivial pour la balise post"
#: blog/models.py:88
msgid "tag display name"
msgstr "Nom d'affichage de l'étiquette"
#: blog/models.py:96
msgid "post tag"
msgstr "Tag de poste"
#: blog/models.py:97
msgid "post tags"
msgstr "Tags de la poste"
#~ msgid "eVibes Engine"
#~ msgstr "Moteur eVibes"

View file

@ -1,70 +0,0 @@
# EVIBES GETTEXT TRANSLATIONS
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: blog/apps.py:8
msgid "blog"
msgstr ""
#: blog/models.py:17
msgid "post title"
msgstr ""
#: blog/models.py:17
msgid "title"
msgstr ""
#: blog/models.py:64
msgid "post"
msgstr ""
#: blog/models.py:65
msgid "posts"
msgstr ""
#: blog/models.py:69
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
#: blog/models.py:71
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
#: blog/models.py:82
msgid "internal tag identifier for the post tag"
msgstr ""
#: blog/models.py:83
msgid "tag name"
msgstr ""
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr ""
#: blog/models.py:88
msgid "tag display name"
msgstr ""
#: blog/models.py:96
msgid "post tag"
msgstr ""
#: blog/models.py:97
msgid "post tags"
msgstr ""

View file

@ -1,72 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: it-it\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Titolo del post"
#: blog/models.py:17
msgid "title"
msgstr "Titolo"
#: blog/models.py:64
msgid "post"
msgstr "Posta"
#: blog/models.py:65
msgid "posts"
msgstr "Messaggi"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "identificatore interno del tag post"
#: blog/models.py:83
msgid "tag name"
msgstr "Nome del tag"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Nome intuitivo per il tag del post"
#: blog/models.py:88
msgid "tag display name"
msgstr "Nome del tag"
#: blog/models.py:96
msgid "post tag"
msgstr "Post tag"
#: blog/models.py:97
msgid "post tags"
msgstr "Tag dei post"
#~ msgid "eVibes Engine"
#~ msgstr "Motore eVibes"

View file

@ -1,74 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: ja-jp\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"
#: blog/apps.py:8
msgid "blog"
msgstr "ブログ"
#: blog/models.py:17
msgid "post title"
msgstr "投稿タイトル"
#: blog/models.py:17
msgid "title"
msgstr "タイトル"
#: blog/models.py:64
msgid "post"
msgstr "ポスト"
#: blog/models.py:65
msgid "posts"
msgstr "投稿"
#: blog/models.py:69
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"マークダウン・ファイルはサポートされていません - 代わりにマークダウン・コンテ"
"ンツを使用してください!"
#: blog/models.py:71
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"マークダウン・ファイルまたはマークダウン・コンテンツを提供しなければならな"
"い。"
#: blog/models.py:82
msgid "internal tag identifier for the post tag"
msgstr "投稿タグの内部タグ識別子"
#: blog/models.py:83
msgid "tag name"
msgstr "タグ名"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "投稿タグのユーザーフレンドリーな名前"
#: blog/models.py:88
msgid "tag display name"
msgstr "タグ表示名"
#: blog/models.py:96
msgid "post tag"
msgstr "投稿タグ"
#: blog/models.py:97
msgid "post tags"
msgstr "投稿タグ"
#~ msgid "eVibes Engine"
#~ msgstr "eVibesエンジン"

View file

@ -1,70 +0,0 @@
# EVIBES GETTEXT TRANSLATIONS
# Copyright (C) 2025 EGOR <FUREUNOIR> GORBUNOV
# This file is distributed under the same license as the EVIBES package.
# EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: blog/apps.py:8
msgid "blog"
msgstr ""
#: blog/models.py:17
msgid "post title"
msgstr ""
#: blog/models.py:17
msgid "title"
msgstr ""
#: blog/models.py:64
msgid "post"
msgstr ""
#: blog/models.py:65
msgid "posts"
msgstr ""
#: blog/models.py:69
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
#: blog/models.py:71
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
#: blog/models.py:82
msgid "internal tag identifier for the post tag"
msgstr ""
#: blog/models.py:83
msgid "tag name"
msgstr ""
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr ""
#: blog/models.py:88
msgid "tag display name"
msgstr ""
#: blog/models.py:96
msgid "post tag"
msgstr ""
#: blog/models.py:97
msgid "post tags"
msgstr ""

View file

@ -1,74 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: nl-nl\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Titel van de post"
#: blog/models.py:17
msgid "title"
msgstr "Titel"
#: blog/models.py:64
msgid "post"
msgstr "Plaats"
#: blog/models.py:65
msgid "posts"
msgstr "Berichten"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "interne tagidentifier voor de posttag"
#: blog/models.py:83
msgid "tag name"
msgstr "Tag naam"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Gebruiksvriendelijke naam voor de posttag"
#: blog/models.py:88
msgid "tag display name"
msgstr "Tag weergavenaam"
#: blog/models.py:96
msgid "post tag"
msgstr "Post tag"
#: blog/models.py:97
msgid "post tags"
msgstr "Post tags"
#~ msgid "eVibes Engine"
#~ msgstr "eVibes motor"

View file

@ -1,73 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: pl-pl\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Tytuł postu"
#: blog/models.py:17
msgid "title"
msgstr "Tytuł"
#: blog/models.py:64
msgid "post"
msgstr "Post"
#: blog/models.py:65
msgid "posts"
msgstr "Posty"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "wewnętrzny identyfikator tagu posta"
#: blog/models.py:83
msgid "tag name"
msgstr "Nazwa tagu"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Przyjazna dla użytkownika nazwa tagu posta"
#: blog/models.py:88
msgid "tag display name"
msgstr "Wyświetlana nazwa znacznika"
#: blog/models.py:96
msgid "post tag"
msgstr "Tag posta"
#: blog/models.py:97
msgid "post tags"
msgstr "Tagi postów"
#~ msgid "eVibes Engine"
#~ msgstr "Silnik eVibes"

View file

@ -1,72 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Título da postagem"
#: blog/models.py:17
msgid "title"
msgstr "Título"
#: blog/models.py:64
msgid "post"
msgstr "Postar"
#: blog/models.py:65
msgid "posts"
msgstr "Publicações"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "identificador de tag interno para a tag de postagem"
#: blog/models.py:83
msgid "tag name"
msgstr "Nome da etiqueta"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Nome de fácil utilização para a tag de postagem"
#: blog/models.py:88
msgid "tag display name"
msgstr "Nome de exibição da tag"
#: blog/models.py:96
msgid "post tag"
msgstr "Etiqueta de postagem"
#: blog/models.py:97
msgid "post tags"
msgstr "Tags de postagem"
#~ msgid "eVibes Engine"
#~ msgstr "Motor eVibes"

View file

@ -1,73 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: ro-ro\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Blog"
#: blog/models.py:17
msgid "post title"
msgstr "Titlul postului"
#: blog/models.py:17
msgid "title"
msgstr "Titlul"
#: blog/models.py:64
msgid "post"
msgstr "Post"
#: blog/models.py:65
msgid "posts"
msgstr "Mesaje"
#: blog/models.py:69
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
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
msgid "internal tag identifier for the post tag"
msgstr "identificator intern de etichetă pentru eticheta postului"
#: blog/models.py:83
msgid "tag name"
msgstr "Nume etichetă"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Nume ușor de utilizat pentru eticheta postului"
#: blog/models.py:88
msgid "tag display name"
msgstr "Nume afișare etichetă"
#: blog/models.py:96
msgid "post tag"
msgstr "Etichetă post"
#: blog/models.py:97
msgid "post tags"
msgstr "Etichete poștale"
#~ msgid "eVibes Engine"
#~ msgstr "Motorul eVibes"

View file

@ -1,74 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\n"
"Language: ru-ru\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"
#: blog/apps.py:8
msgid "blog"
msgstr "Блог"
#: blog/models.py:17
msgid "post title"
msgstr "Заголовок сообщения"
#: blog/models.py:17
msgid "title"
msgstr "Название"
#: blog/models.py:64
msgid "post"
msgstr "Пост"
#: blog/models.py:65
msgid "posts"
msgstr "Посты"
#: blog/models.py:69
msgid "markdown files are not supported yet - use markdown content instead"
msgstr ""
"Файлы в формате Markdown не поддерживаются - используйте вместо них "
"содержимое в формате Markdown!"
#: blog/models.py:71
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr ""
"необходимо предоставить файл разметки или содержимое разметки - "
"взаимоисключающие варианты"
#: blog/models.py:82
msgid "internal tag identifier for the post tag"
msgstr "внутренний идентификатор тега для тега post"
#: blog/models.py:83
msgid "tag name"
msgstr "Название тега"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "Удобное для пользователя название тега поста"
#: blog/models.py:88
msgid "tag display name"
msgstr "Отображаемое имя тега"
#: blog/models.py:96
msgid "post tag"
msgstr "Тэг поста"
#: blog/models.py:97
msgid "post tags"
msgstr "Тэги постов"
#~ msgid "eVibes Engine"
#~ msgstr "Движок eVibes"

View file

@ -1,70 +0,0 @@
#
msgid ""
msgstr ""
"Project-Id-Version: EVIBES 2.8.10\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-29 17:23+0100\n"
"PO-Revision-Date: 2025-06-16 08:59+0100\n"
"Last-Translator: EGOR GORBUNOV <CONTACT@FUREUNOIR.COM>\n"
"Language-Team: LANGUAGE <CONTACT@FUREUNOIR.COM>\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=2; plural=(n != 1);\n"
#: blog/apps.py:8
msgid "blog"
msgstr "博客"
#: blog/models.py:17
msgid "post title"
msgstr "帖子标题"
#: blog/models.py:17
msgid "title"
msgstr "标题"
#: blog/models.py:64
msgid "post"
msgstr "职位"
#: blog/models.py:65
msgid "posts"
msgstr "职位"
#: blog/models.py:69
msgid "markdown files are not supported yet - use markdown content instead"
msgstr "不支持 Markdown 文件,请使用 Markdown 内容!"
#: blog/models.py:71
msgid ""
"a markdown file or markdown content must be provided - mutually exclusive"
msgstr "必须提供标记符文件或标记符内容 - 相互排斥"
#: blog/models.py:82
msgid "internal tag identifier for the post tag"
msgstr "职位标签的内部标签标识符"
#: blog/models.py:83
msgid "tag name"
msgstr "标签名称"
#: blog/models.py:87
msgid "user-friendly name for the post tag"
msgstr "方便用户使用的帖子标签名称"
#: blog/models.py:88
msgid "tag display name"
msgstr "标签显示名称"
#: blog/models.py:96
msgid "post tag"
msgstr "职位标签"
#: blog/models.py:97
msgid "post tags"
msgstr "帖子标签"
#~ msgid "eVibes Engine"
#~ msgstr "eVibes 引擎"

View file

@ -1,73 +0,0 @@
# Generated by Django 5.1.8 on 2025-04-28 11:56
import uuid
import django.db.models.deletion
import django_extensions.db.fields
import markdown_field.fields
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'post tag',
'verbose_name_plural': 'post tags',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'post',
'verbose_name_plural': 'posts',
},
),
]

View file

@ -1,24 +0,0 @@
# Generated by Django 5.1.8 on 2025-04-28 12:07
import django_extensions.db.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('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),
),
migrations.AlterField(
model_name='post',
name='title',
field=models.CharField(help_text='post title', max_length=128, unique=True, verbose_name='title'),
),
]

View file

@ -1,13 +0,0 @@
from django.urls import include, path
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")
urlpatterns = [
path(r"", include(payment_router.urls)),
]

View file

@ -1,3 +0,0 @@
import logging
logger = logging.getLogger("evibes")

View file

@ -1,32 +0,0 @@
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.viewsets import ReadOnlyModelViewSet
from blog.filters import PostFilter
from blog.models import Post
from blog.serializers import PostSerializer
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)
filter_backends = [DjangoFilterBackend]
filterset_class = PostFilter
additional = {"retrieve": "ALLOW"}

View file

@ -1,36 +0,0 @@
import uuid
from datetime import datetime
from django.db.models import BooleanField, Model, UUIDField
from django.utils.translation import gettext_lazy as _
from django_extensions.db.fields import CreationDateTimeField, ModificationDateTimeField
class NiceModel(Model):
id = None
uuid: uuid = UUIDField( # type: ignore
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
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")
)
def save(self, **kwargs):
self.update_modified = kwargs.pop("update_modified", getattr(self, "update_modified", True))
super().save(**kwargs)
class Meta:
abstract = True
get_latest_by = "modified"

View file

@ -1,527 +0,0 @@
from contextlib import suppress
from constance.admin import Config
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
from dalf.admin import DALFRelatedFieldAjax, DALFRelatedOnlyField
from django import forms
from django.apps import apps
from django.contrib import admin
from django.contrib.admin import ModelAdmin, TabularInline
from django.contrib.admin.widgets import get_select2_language
from django.contrib.gis.admin import GISModelAdmin
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 (
Address,
Attribute,
AttributeGroup,
AttributeValue,
Brand,
Category,
CategoryTag,
Feedback,
Order,
OrderProduct,
Product,
ProductImage,
ProductTag,
PromoCode,
Promotion,
Stock,
Vendor,
Wishlist,
)
class FieldsetsMixin:
general_fields: list = []
relation_fields: list = []
model: Model
def get_fieldsets(self, request, obj=None):
fieldsets = []
def add_translations_fieldset(fss):
with suppress(NotRegistered):
transoptions = translator.get_options_for_model(self.model)
translation_fields = []
for orig in transoptions.local_fields:
translation_fields += get_translation_fields(orig)
if translation_fields:
fss = list(fss) + [(_("translations"), {"fields": translation_fields})]
return fss
if self.general_fields:
fieldsets.append((_("general"), {"fields": self.general_fields}))
if self.relation_fields:
fieldsets.append((_("relations"), {"fields": self.relation_fields}))
opts = self.model._meta
if any(f.name == "uuid" for f in opts.fields):
if any(f.name == "slug" for f in opts.fields):
fieldsets.append((_("metadata"), {"fields": ["uuid", "slug"]}))
else:
fieldsets.append((_("metadata"), {"fields": ["uuid"]}))
ts = []
for name in ("created", "modified"):
if any(f.name == name for f in opts.fields):
ts.append(name)
if ts:
fieldsets.append((_("timestamps"), {"fields": ts, "classes": ["collapse"]}))
fieldsets = add_translations_fieldset(fieldsets)
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!"))
@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."))
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
class AttributeValueInline(TabularInline):
model = AttributeValue
extra = 0
autocomplete_fields = ["attribute"]
is_navtab = True
verbose_name = _("attribute value")
verbose_name_plural = _("attribute values")
icon = "fa-solid fa-list-ul"
class ProductImageInline(TabularInline):
model = ProductImage
extra = 0
is_navtab = True
verbose_name = _("image")
verbose_name_plural = _("images")
icon = "fa-regular fa-images"
class StockInline(TabularInline):
model = Stock
extra = 0
is_navtab = True
verbose_name = _("stock")
verbose_name_plural = _("stocks")
icon = "fa-solid fa-boxes-stacked"
class OrderProductInline(TabularInline):
model = OrderProduct
extra = 0
readonly_fields = ("product", "quantity", "buy_price")
form = OrderProductForm
is_navtab = True
verbose_name = _("order product")
verbose_name_plural = _("order products")
icon = "fa-solid fa-boxes-packing"
def get_queryset(self, request):
return super().get_queryset(request).select_related("product").only("product__name")
class CategoryChildrenInline(TabularInline):
model = Category
fk_name = "parent"
extra = 0
fields = ("name", "description", "is_active", "image", "markup_percent")
is_navtab = True
verbose_name = _("children")
verbose_name_plural = _("children")
icon = "fa-solid fa-leaf"
@admin.register(AttributeGroup)
class AttributeGroupAdmin(FieldsetsMixin, BasicModelAdmin):
model = AttributeGroup # type: ignore
list_display = ("name", "modified")
search_fields = ("uuid", "name")
readonly_fields = ("uuid", "modified", "created")
general_fields = ["is_active", "name", "parent"]
relation_fields = []
@admin.register(Attribute)
class AttributeAdmin(FieldsetsMixin, BasicModelAdmin):
model = Attribute # type: ignore
list_display = ("name", "group", "value_type", "modified")
list_filter = ("value_type", "group", "is_active")
search_fields = ("uuid", "name", "group__name")
readonly_fields = ("uuid", "modified", "created")
autocomplete_fields = ["categories", "group"]
general_fields = ["is_active", "name", "value_type"]
relation_fields = ["group", "categories"]
@admin.register(AttributeValue)
class AttributeValueAdmin(FieldsetsMixin, BasicModelAdmin):
model = AttributeValue # type: ignore
list_display = ("attribute", "value", "modified")
list_filter = ("attribute__group", "is_active")
search_fields = ("uuid", "value", "attribute__name")
readonly_fields = ("uuid", "modified", "created")
autocomplete_fields = ["attribute"]
general_fields = ["is_active", "value"]
relation_fields = ["attribute", "product"]
@admin.register(Category)
class CategoryAdmin(FieldsetsMixin, DraggableMPTTAdmin, BasicModelAdmin):
model = Category # type: ignore
list_display = ("indented_title", "parent", "is_active", "modified")
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", "priority"]
relation_fields = ["parent", "tags"]
@admin.register(Brand)
class BrandAdmin(FieldsetsMixin, BasicModelAdmin):
model = Brand # type: ignore
list_display = ("name",)
list_filter = ("categories", "is_active")
search_fields = ("uuid", "name", "categories__name")
readonly_fields = ("uuid", "slug", "modified", "created")
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
list_display = (
"name",
"partnumber",
"is_active",
"category",
"brand",
"price",
"rating",
"modified",
)
list_filter = (
"is_active",
"is_digital",
("brand", DALFRelatedFieldAjax),
("category", DALFRelatedFieldAjax),
("tags", DALFRelatedFieldAjax),
("stocks__vendor", DALFRelatedOnlyField),
"created",
"modified",
)
search_fields = (
"name",
"partnumber",
"brand__name",
"category__name",
"uuid",
"slug",
)
readonly_fields = ("slug", "uuid", "modified", "created")
autocomplete_fields = ("category", "brand", "tags")
inlines = [AttributeValueInline, ProductImageInline, StockInline]
general_fields = ["is_active", "name", "partnumber", "is_digital"]
relation_fields = ["category", "brand", "tags"]
@property
def media(self):
i18n_name = get_select2_language()
i18n_file = (f"admin/js/vendor/select2/i18n/{i18n_name}.js",) if i18n_name else ()
return super().media + forms.Media(
js=(
"admin/js/vendor/jquery/jquery.min.js",
"admin/js/vendor/select2/select2.full.min.js",
*i18n_file,
"admin/js/jquery.init.js",
"admin/js/django_admin_list_filter.js",
),
css={
"screen": (
"admin/css/vendor/select2/select2.min.css",
"admin/css/autocomplete.css",
"admin/css/django_admin_list_filter.css",
),
},
)
@admin.register(ProductTag)
class ProductTagAdmin(FieldsetsMixin, BasicModelAdmin):
model = ProductTag # type: ignore
list_display = ("tag_name",)
search_fields = ("tag_name",)
readonly_fields = ("uuid", "modified", "created")
general_fields = ["is_active", "tag_name", "name"]
relation_fields = []
@admin.register(CategoryTag)
class CategoryTagAdmin(FieldsetsMixin, BasicModelAdmin):
model = CategoryTag # type: ignore
list_display = ("tag_name",)
search_fields = ("tag_name",)
readonly_fields = ("uuid", "modified", "created")
general_fields = ["is_active", "tag_name", "name"]
relation_fields = []
@admin.register(Vendor)
class VendorAdmin(FieldsetsMixin, BasicModelAdmin):
model = Vendor # type: ignore
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 = []
@admin.register(Feedback)
class FeedbackAdmin(FieldsetsMixin, BasicModelAdmin):
model = Feedback # type: ignore
list_display = ("order_product", "rating", "comment", "modified")
list_filter = ("rating", "is_active")
search_fields = ("order_product__product__name", "comment")
readonly_fields = ("uuid", "modified", "created")
general_fields = ["is_active", "rating", "comment"]
relation_fields = ["order_product"]
@admin.register(Order)
class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
model = Order # type: ignore
list_display = (
"human_readable_id",
"user",
"status",
"total_price",
"buy_time",
"modified",
)
list_filter = ("status", "buy_time", "modified", "created")
search_fields = ("user__email", "status", "uuid", "human_readable_id")
readonly_fields = (
"total_price",
"total_quantity",
"human_readable_id",
"uuid",
"modified",
"created",
)
inlines = [OrderProductInline]
form = OrderForm
general_fields = ["is_active", "user", "status"]
relation_fields = ["promo_code", "billing_address", "shipping_address"]
@admin.register(OrderProduct)
class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
model = OrderProduct # type: ignore
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
list_filter = ("status",)
search_fields = ("order__user__email", "product__name")
readonly_fields = ("uuid", "modified", "created")
form = OrderProductForm
general_fields = ["is_active", "quantity", "buy_price", "status"]
relation_fields = ["order", "product"]
@admin.register(PromoCode)
class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
model = PromoCode # type: ignore
list_display = (
"code",
"discount_percent",
"discount_amount",
"start_time",
"end_time",
"used_on",
)
list_filter = ("discount_percent", "discount_amount", "start_time", "end_time")
search_fields = ("code",)
readonly_fields = ("used_on", "uuid", "modified", "created")
autocomplete_fields = ("user",)
general_fields = [
"is_active",
"code",
"discount_amount",
"discount_percent",
"start_time",
"end_time",
"used_on",
]
relation_fields = ["user"]
@admin.register(Promotion)
class PromotionAdmin(FieldsetsMixin, BasicModelAdmin):
model = Promotion # type: ignore
list_display = ("name", "discount_percent", "modified")
search_fields = ("name",)
readonly_fields = ("uuid", "modified", "created")
autocomplete_fields = ("products",)
general_fields = ["is_active", "name", "discount_percent", "description"]
relation_fields = ["products"]
@admin.register(Stock)
class StockAdmin(FieldsetsMixin, BasicModelAdmin):
model = Stock # type: ignore
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
list_filter = ("vendor", "quantity")
search_fields = ("product__name", "vendor__name", "sku")
readonly_fields = ("uuid", "modified", "created")
autocomplete_fields = ("product", "vendor")
general_fields = [
"is_active",
"sku",
"quantity",
"price",
"purchase_price",
"digital_asset",
]
relation_fields = ["product", "vendor"]
@admin.register(Wishlist)
class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
model = Wishlist # type: ignore
list_display = ("user", "modified")
search_fields = ("user__email",)
readonly_fields = ("uuid", "modified", "created")
general_fields = ["is_active", "user"]
relation_fields = ["products"]
@admin.register(ProductImage)
class ProductImageAdmin(FieldsetsMixin, BasicModelAdmin):
model = ProductImage # type: ignore
list_display = ("alt", "product", "priority", "modified")
list_filter = ("priority",)
search_fields = ("alt", "product__name")
readonly_fields = ("uuid", "modified", "created")
autocomplete_fields = ("product",)
general_fields = ["is_active", "alt", "priority", "image"]
relation_fields = ["product"]
@admin.register(Address)
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
model = Address # type: ignore
list_display = ("street", "city", "region", "country", "user")
list_filter = ("country", "region")
search_fields = ("street", "city", "postal_code", "user__email")
readonly_fields = ("uuid", "modified", "created")
gis_widget_kwargs = {
"attrs": {
"default_lon": 37.61556,
"default_lat": 55.75222,
"default_zoom": 6,
}
}
general_fields = [
"is_active",
"address_line",
"street",
"district",
"city",
"region",
"postal_code",
"country",
"raw_data",
]
relation_fields = ["user", "api_response"]
# Constance configuration
class ConstanceConfig:
class Meta:
app_label = "core"
object_name = "Config"
concrete_model = None
model_name = module_name = "config"
verbose_name_plural = _("Config")
abstract = False
swapped = False
is_composite_pk = False
def get_change_permission(self):
return f"change_{self.model_name}"
@property
def app_config(self):
return apps.get_app_config(self.app_label)
@property
def label(self):
return f"{self.app_label}.{self.object_name}"
@property
def label_lower(self):
return f"{self.app_label}.{self.model_name}"
def get_ordered_objects(self):
return False
_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

View file

@ -1,87 +0,0 @@
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from core.sitemaps import BrandSitemap, CategorySitemap, ProductSitemap
from core.views import (
CacheOperatorView,
ContactUsView,
GlobalSearchView,
RequestCursedURLView,
SupportedLanguagesView,
WebsiteParametersView,
download_digital_asset_view,
sitemap_detail,
sitemap_index,
)
from core.viewsets import (
AddressViewSet,
AttributeGroupViewSet,
BrandViewSet,
CategoryViewSet,
FeedbackViewSet,
OrderProductViewSet,
OrderViewSet,
ProductTagViewSet,
ProductViewSet,
PromoCodeViewSet,
PromotionViewSet,
StockViewSet,
VendorViewSet,
WishlistViewSet,
)
app_name = "core"
core_router = DefaultRouter()
core_router.register(r"products", ProductViewSet, basename="products")
core_router.register(r"orders", OrderViewSet, basename="orders")
core_router.register(r"wishlists", WishlistViewSet, basename="wishlists")
core_router.register(r"attribute_groups", AttributeGroupViewSet, basename="attribute_groups")
core_router.register(r"brands", BrandViewSet, basename="brands")
core_router.register(r"categories", CategoryViewSet, basename="categories")
core_router.register(r"vendors", VendorViewSet, basename="vendors")
core_router.register(r"feedbacks", FeedbackViewSet, basename="feedbacks")
core_router.register(r"stocks", StockViewSet, basename="stocks")
core_router.register(r"promo_codes", PromoCodeViewSet, basename="promo_codes")
core_router.register(r"promotions", PromotionViewSet, basename="promotions")
core_router.register(r"addresses", AddressViewSet, basename="addresses")
core_router.register(r"product_tags", ProductTagViewSet, basename="product_tags")
core_router.register(r"order_products", OrderProductViewSet, basename="order_products")
sitemaps = {
"products": ProductSitemap,
"categories": CategorySitemap,
"brands": BrandSitemap,
}
urlpatterns = [
path("core/", include(core_router.urls)),
path(
"sitemap.xml",
sitemap_index,
{
"sitemaps": sitemaps,
"sitemap_url_name": "core:sitemap-detail",
},
name="sitemap-index",
),
path(
"sitemap-<section>.xml",
sitemap_detail,
{"sitemaps": sitemaps},
name="sitemap-detail",
),
path(
"sitemap-<section>-<int:page>.xml",
sitemap_detail,
{"sitemaps": sitemaps},
name="sitemap-detail",
),
path("download/<str:order_product_uuid>/", 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"),
path("app/languages/", SupportedLanguagesView.as_view(), name="supported_languages"),
path("app/parameters/", WebsiteParametersView.as_view(), name="parameters"),
path("app/contact_us/", ContactUsView.as_view(), name="contact_us"),
path("app/request_cursed_url/", RequestCursedURLView.as_view(), name="request_cursed_url"),
]

View file

@ -1,312 +0,0 @@
from django.conf import settings
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from django_elasticsearch_dsl import fields
from django_elasticsearch_dsl.registries import registry
from elasticsearch import NotFoundError
from elasticsearch.dsl import Q, Search
from rest_framework.request import Request
from core.models import Brand, Category, Product
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",
]
functions = [
# product-level boosts when searching for products
{
"filter": Q("term", **{"_index": "products"}),
"field_value_factor": {
"field": "brand_priority",
"modifier": "log1p",
"factor": 1.5,
"missing": 0,
},
},
{
"filter": Q("term", **{"_index": "products"}),
"field_value_factor": {
"field": "rating",
"modifier": "log1p",
"factor": 2.0,
"missing": 0,
},
},
{
"filter": Q("term", **{"_index": "products"}),
"field_value_factor": {
"field": "total_orders",
"modifier": "log1p",
"factor": 3.0,
"missing": 0,
},
},
{
"filter": Q("term", **{"_index": "products"}),
"field_value_factor": {
"field": "category_priority",
"modifier": "log1p",
"factor": 1.2,
"missing": 0,
},
},
# category-level boost when searching for categories
{
"filter": Q("term", **{"_index": "categories"}),
"field_value_factor": {
"field": "priority",
"modifier": "log1p",
"factor": 2.0,
"missing": 0,
},
},
# brand-level boost when searching for brands
{
"filter": Q("term", **{"_index": "brands"}),
"field_value_factor": {
"field": "priority",
"modifier": "log1p",
"factor": 2.0,
"missing": 0,
},
},
]
def process_query(query: str = "", request: Request | None = None) -> dict[str, list[dict]] | None:
"""
Perform a lenient, typotolerant, multiindex search.
* Fulltext with fuzziness for spelling mistakes
* `bool_prefix` for edgengram autocomplete / icontains
"""
if not query:
raise ValueError(_("no search term provided."))
query = query.strip()
try:
query_base = Q(
"bool",
should=[
Q(
"multi_match",
query=query,
fields=SMART_FIELDS,
fuzziness="AUTO",
operator="and",
),
Q(
"multi_match",
query=query,
fields=[f for f in SMART_FIELDS if f.endswith(".auto")],
type="bool_prefix",
),
],
minimum_should_match=1,
)
function_score_query = Q(
"function_score",
query=query_base,
functions=functions,
boost_mode="multiply",
score_mode="first",
)
search = Search(index=["products", "categories", "brands", "posts"]).query(function_score_query).extra(size=100)
response = search.execute()
results: dict = {"products": [], "categories": [], "brands": [], "posts": []}
for hit in response.hits:
obj_uuid = getattr(hit, "uuid", None) or hit.meta.id
obj_name = getattr(hit, "name", None) or getattr(hit, "title", None) or "N/A"
obj_slug = ""
raw_slug = getattr(hit, "slug", None)
if raw_slug:
obj_slug = raw_slug
elif hit.meta.index == "brands":
obj_slug = slugify(obj_name)
elif hit.meta.index == "categories":
obj_slug = slugify(f"{obj_name}")
image_url = None
idx = hit.meta.index
if idx == "products" and request:
prod = get_object_or_404(Product, uuid=obj_uuid)
first = prod.images.order_by("priority").first()
if first and first.image:
image_url = request.build_absolute_uri(first.image.url)
elif idx == "brands" and request:
brand = get_object_or_404(Brand, uuid=obj_uuid)
if brand.small_logo:
image_url = request.build_absolute_uri(brand.small_logo.url)
elif idx == "categories" and request:
cat = get_object_or_404(Category, uuid=obj_uuid)
if cat.image:
image_url = request.build_absolute_uri(cat.image.url)
hit_result = {
"uuid": str(obj_uuid),
"name": obj_name,
"slug": obj_slug,
"image": image_url,
}
if settings.DEBUG:
if idx == "products":
hit_result["rating_debug"] = getattr(hit, "rating", 0)
hit_result["total_orders_debug"] = getattr(hit, "total_orders", 0)
hit_result["brand_priority_debug"] = getattr(hit, "brand_priority", 0)
hit_result["category_priority_debug"] = getattr(hit, "category_priority", 0)
if idx == "brands":
hit_result["priority_debug"] = getattr(hit, "priority", 0)
if idx == "categories":
hit_result["priority_debug"] = getattr(hit, "priority", 0)
if idx == "posts":
pass
results[idx].append(hit_result)
return results
except NotFoundError:
raise Http404
LANGUAGE_ANALYZER_MAP = {
"ar": "arabic",
"cs": "czech",
"da": "danish",
"de": "german",
"en": "english",
"es": "spanish",
"fr": "french",
"hi": "hindi",
"it": "italian",
"ja": "standard",
"kk": "standard",
"nl": "dutch",
"pl": "standard",
"pt": "portuguese",
"ro": "romanian",
"ru": "russian",
"zh": "standard",
}
def _lang_analyzer(lang_code: str) -> str:
"""Return the bestguess ES analyzer for an ISO language code."""
base = lang_code.split("-")[0].lower()
return LANGUAGE_ANALYZER_MAP.get(base, "standard")
class ActiveOnlyMixin:
"""QuerySet & indexing helpers, so only *active* objects are indexed."""
def get_queryset(self):
return super().get_queryset().filter(is_active=True)
def should_index_object(self, obj):
return getattr(obj, "is_active", False)
COMMON_ANALYSIS = {
"filter": {
"edge_ngram_filter": {"type": "edge_ngram", "min_gram": 1, "max_gram": 20},
"ngram_filter": {"type": "ngram", "min_gram": 2, "max_gram": 20},
"double_metaphone": {
"type": "phonetic",
"encoder": "double_metaphone",
"replace": False,
},
},
"analyzer": {
"autocomplete": {
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding", "edge_ngram_filter"],
},
"autocomplete_search": {
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding"],
},
"name_ngram": {
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding", "ngram_filter"],
},
"name_phonetic": {
"tokenizer": "standard",
"filter": ["lowercase", "asciifolding", "double_metaphone"],
},
"query_lc": {"tokenizer": "standard", "filter": ["lowercase", "asciifolding"]},
},
}
def _add_multilang_fields(cls):
"""
Dynamically add multilingual name/description fields and prepare methods to guard against None.
"""
for code, _lang in settings.LANGUAGES:
lc = code.replace("-", "_").lower()
# name_{lc}
name_field = f"name_{lc}"
setattr(
cls,
name_field,
fields.TextField(
attr=name_field,
analyzer=_lang_analyzer(code),
copy_to="name",
fields={
"raw": fields.KeywordField(ignore_above=256),
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
"phonetic": fields.TextField(analyzer="name_phonetic"),
},
),
)
# prepare_name_{lc} to ensure no None values
def make_prepare(attr):
return lambda self, instance: getattr(instance, attr, "") or ""
setattr(cls, f"prepare_{name_field}", make_prepare(name_field))
# description_{lc}
desc_field = f"description_{lc}"
setattr(
cls,
desc_field,
fields.TextField(
attr=desc_field,
analyzer=_lang_analyzer(code),
copy_to="description",
fields={
"raw": fields.KeywordField(ignore_above=256),
"ngram": fields.TextField(analyzer="name_ngram", search_analyzer="query_lc"),
"phonetic": fields.TextField(analyzer="name_phonetic"),
},
),
)
setattr(cls, f"prepare_{desc_field}", make_prepare(desc_field))
def populate_index():
for doc in registry.get_documents(set(registry.get_models())):
qs = doc().get_indexing_queryset()
doc().update(qs, parallel=True, refresh=True)

View file

@ -1,125 +0,0 @@
from django_elasticsearch_dsl import Document, fields
from django_elasticsearch_dsl.registries import registry
from health_check.db.models import TestModel
from core.elasticsearch import COMMON_ANALYSIS, ActiveOnlyMixin, _add_multilang_fields
from core.models import Brand, Category, Product
class _BaseDoc(ActiveOnlyMixin, Document):
name = fields.TextField(
attr="name",
analyzer="standard",
fields={
"raw": fields.KeywordField(ignore_above=256),
"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"),
},
)
description = fields.TextField(
attr="description",
analyzer="standard",
fields={
"raw": fields.KeywordField(ignore_above=256),
"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"),
},
)
slug = fields.KeywordField(attr="slug", index=False)
class Index:
settings = {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": COMMON_ANALYSIS,
"index": {"max_ngram_diff": 20},
}
def prepare_name(self, instance):
return getattr(instance, "name", "") or ""
def prepare_description(self, instance):
return getattr(instance, "description", "") or ""
class ProductDocument(_BaseDoc):
rating = fields.FloatField(attr="rating")
total_order = fields.IntegerField(attr="total_orders")
brand_priority = fields.IntegerField(
attr="brand.priority",
index=True,
fields={"raw": fields.KeywordField()},
)
category_priority = fields.IntegerField(
attr="category.priority",
index=True,
fields={"raw": fields.KeywordField()},
)
class Index(_BaseDoc.Index):
name = "products"
class Django:
model = Product
fields = ["uuid"]
_add_multilang_fields(ProductDocument)
registry.register_document(ProductDocument)
class CategoryDocument(_BaseDoc):
priority = fields.IntegerField(attr="priority")
class Index(_BaseDoc.Index):
name = "categories"
class Django:
model = Category
fields = ["uuid"]
_add_multilang_fields(CategoryDocument)
registry.register_document(CategoryDocument)
class BrandDocument(ActiveOnlyMixin, Document):
priority = fields.IntegerField(attr="priority")
class Index:
name = "brands"
settings = {
"number_of_shards": 1,
"number_of_replicas": 0,
"analysis": COMMON_ANALYSIS,
"index": {"max_ngram_diff": 18},
}
class Django:
model = Brand
fields = ["uuid"]
def prepare_name(self, instance):
return getattr(instance, "name", "") or ""
registry.register_document(BrandDocument)
class TestModelDocument(Document):
class Index:
name = "testmodels"
class Django:
model = TestModel
fields = [
"title",
]
ignore_signals = True
related_models: list = []
auto_refresh = False
registry.register_document(TestModelDocument)

View file

@ -1,10 +0,0 @@
from graphene import Mutation
class BaseMutation(Mutation):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@staticmethod
def mutate(**kwargs):
pass

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,7 +0,0 @@
from django.conf import settings
class RootDirectory:
def __init__(self):
self.label = "root"
self.path = settings.BASE_DIR / "evibes"

View file

@ -1,23 +0,0 @@
from django.core.management.base import BaseCommand
from django.db import transaction
from core.models import Product
CHUNK_SIZE = 5000
class Command(BaseCommand):
help = "Delete Product rows with no OrderProduct, in batches"
def handle(self, *args, **options):
while True:
batch_ids = list(
Product.objects.filter(orderproduct__isnull=True).values_list("pk", flat=True)[:CHUNK_SIZE]
)
if not batch_ids:
break
with transaction.atomic():
Product.objects.filter(pk__in=batch_ids).delete()
self.stdout.write(f"Deleted {len(batch_ids)} products…")
self.stdout.write("✅ All unordered products removed.")

View file

@ -1,996 +0,0 @@
# Generated by Django 5.1.5 on 2025-03-10 11:38
import uuid
import django.core.validators
import django.db.models.deletion
import django_extensions.db.fields
import mptt.fields
from django.db import migrations, models
import core.utils
import core.validators
class Migration(migrations.Migration):
initial = True
operations = [
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'feedback',
'verbose_name_plural': 'feedbacks',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'order product',
'verbose_name_plural': 'order products',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'product',
'verbose_name_plural': 'products',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'product image',
'verbose_name_plural': 'product images',
'ordering': ('priority',),
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'product tag',
'verbose_name_plural': 'product tags',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'promo code',
'verbose_name_plural': 'promo codes',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'promotion',
'verbose_name_plural': 'promotions',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'stock',
'verbose_name_plural': 'stock entries',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'vendor',
'verbose_name_plural': 'vendors',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'wishlist',
'verbose_name_plural': 'wishlists',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'attribute group',
'verbose_name_plural': 'attribute groups',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'attribute',
'verbose_name_plural': 'attributes',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'attribute value',
'verbose_name_plural': 'attribute values',
},
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'category',
'verbose_name_plural': 'categories',
'ordering': ['tree_id', 'lft'],
},
),
migrations.CreateModel(
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')),
],
options={
'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'),
),
migrations.CreateModel(
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')),
],
options={
'verbose_name': 'order',
'verbose_name_plural': 'orders',
},
),
]

View file

@ -1,107 +0,0 @@
# Generated by Django 5.1.5 on 2025-03-10 11:38
import django.contrib.postgres.indexes
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
migrations.AddIndex(
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'),
),
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'),
),
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'),
),
migrations.AddIndex(
model_name='orderproduct',
index=django.contrib.postgres.indexes.GinIndex(fields=['notifications', 'attributes'], name='core_orderp_notific_cd27e9_gin'),
),
]

View file

@ -1,498 +0,0 @@
# Generated by Django 5.1.5 on 2025-03-10 12:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('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'),
),
]

View file

@ -1,108 +0,0 @@
# Generated by Django 5.1.5 on 2025-03-10 20:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
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'),
),
]

View file

@ -1,22 +0,0 @@
# Generated by Django 5.1.5 on 2025-03-16 12:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0004_alter_product_name_alter_product_name_ar_ar_and_more'),
]
operations = [
migrations.RemoveField(
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'),
),
]

View file

@ -1,18 +0,0 @@
# Generated by Django 5.1.5 on 2025-03-20 15:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('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'),
),
]

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