summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorspl3g <spleefer6@gmail.com>2026-06-01 21:23:12 +0300
committerspl3g <spleefer6@gmail.com>2026-06-01 21:23:12 +0300
commitc0fe3e1db70bdba85cf382624817d8d8ea9d6f85 (patch)
tree74065ec21768d63f6cc537bdce72b63ddf513b32 /core
parent386e9defbea931ebc5139a5db5c74e6f44bbbe02 (diff)
add orders list, update, create
Diffstat (limited to 'core')
-rw-r--r--core/forms.py103
-rw-r--r--core/management/commands/import_data.py14
-rw-r--r--core/models.py27
-rw-r--r--core/templates/core/base.html2
-rw-r--r--core/templates/core/order_form.html20
-rw-r--r--core/templates/core/order_list.html32
-rw-r--r--core/templates/core/product_list.html5
-rw-r--r--core/views.py104
8 files changed, 293 insertions, 14 deletions
diff --git a/core/forms.py b/core/forms.py
new file mode 100644
index 0000000..1ade0fe
--- /dev/null
+++ b/core/forms.py
@@ -0,0 +1,103 @@
+from django import forms
+from django.forms import inlineformset_factory
+
+from .models import Product, Supplier, Order, OrderItem
+from extra_views import InlineFormSetFactory
+
+class ProductForm(forms.ModelForm):
+ supplier_name = forms.CharField(label="Поставщик", required=True)
+
+ class Meta:
+ model = Product
+ fields = [
+ "article",
+ "name",
+ "unit",
+ "price",
+ "manufacturer",
+ "category",
+ "discount",
+ "quantity",
+ "description",
+ "photo",
+ ]
+ labels = {
+ "article": "Артикуль",
+ "name": "Название",
+ "unit": "Единица измерения",
+ "price": "Цена",
+ "manufacturer": "Производитель",
+ "category": "Категория",
+ "discount": "Скидка",
+ "quantity": "Колличество",
+ "description": "Описание",
+ "photo": "Фото",
+ }
+ widgets = {
+ "description": forms.Textarea(attrs={"rows": 3})
+ }
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ if self.instance.pk:
+ if self.instance.supplier:
+ self.fields["supplier_name"].initial = self.instance.supplier.name
+
+ def save(self, commit=True):
+ supplier, _ = Supplier.objects.get_or_create(
+ name=self.cleaned_data["supplier_name"].strip()
+ )
+
+ instance = super().save(commit=False)
+ instance.supplier = supplier
+
+ if commit:
+ instance.save()
+
+ return instance
+
+
+ def clean_price(self):
+ price = self.cleaned_data.get("price")
+ if price < 0:
+ raise forms.ValidationError("Цена не может быть отрицательной")
+ return price
+
+ def clean_quantity(self):
+ quantity = self.cleaned_data.get("quantity")
+ if quantity < 0:
+ raise forms.ValidationError("Колличество не может быть отрицательной")
+ return quantity
+
+
+class OrderForm(forms.ModelForm):
+ class Meta:
+ model = Order
+ fields = [
+ "delivery_date",
+ "pickup_point",
+ "pickup_code",
+ "status",
+ ]
+
+ labels = {
+ "order_date": "Дата заказа",
+ "delivery_date": "Дата доставки",
+ "pickup_point": "Пункт выдачи",
+ "client_name": "Имя клиента",
+ "pickup_code": "Код выдачи",
+ "status": "Статус",
+ "items": "Продукты",
+ }
+ widgets = {
+ "delivery_date": forms.SelectDateWidget
+ }
+
+class OrderItemFormSet(InlineFormSetFactory):
+ model = OrderItem
+ fields = ["product", "count"]
+ factory_kwargs = {
+ "extra": 1,
+ "can_delete": True,
+ "labels": {"product": "Продукт", "count": "Количество"}
+ }
diff --git a/core/management/commands/import_data.py b/core/management/commands/import_data.py
index f78f27e..cf1d4b6 100644
--- a/core/management/commands/import_data.py
+++ b/core/management/commands/import_data.py
@@ -79,6 +79,8 @@ class Command(BaseCommand):
else PickupPoint.objects.first()
)
+ status = "completed" if row.pop("status", None) == "Завершен" else "new"
+
user_obj = User.objects.get(full_name=row["client_name"])
order, created = Order.objects.get_or_create(
id=row["id"],
@@ -86,16 +88,14 @@ class Command(BaseCommand):
user=user_obj,
delivery_date=delivery_date,
order_date=order_date,
+ status=status,
defaults=row,
)
if created and items_string:
items = items_string.split(", ")
for i in range(0, len(items), 2):
art = items[i].strip()
- try:
- prod = Products.get(article=art)
- OrderItem.objects.create(
- order=order, product=prod, count=int(items[i+1])
- )
- except Exception:
- pass
+ prod = Product.objects.get(article=art)
+ OrderItem.objects.create(
+ order=order, product=prod, count=int(items[i+1])
+ )
diff --git a/core/models.py b/core/models.py
index db8b4c1..ee673ff 100644
--- a/core/models.py
+++ b/core/models.py
@@ -1,5 +1,10 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
+from PIL import Image
+from io import BytesIO
+from django.core.files.base import ContentFile
+import os
+
class Role(models.Model):
name = models.CharField(max_length=50, unique=True, verbose_name="Name of the role")
@@ -43,8 +48,23 @@ class Product(models.Model):
this = Product.objects.get(id=self.id)
if this.photo and self.photo and this.photo != self.photo:
this.photo.delete(save=False)
+
except Exception:
pass
+
+ if self.photo:
+ img = Image.open(self.photo)
+ img.thumbnail((300, 200))
+
+ output = BytesIO()
+ img.save(output, img.format)
+ output.seek(0)
+ self.photo.save(
+ os.path.basename(self.photo.name),
+ output,
+ save=False
+ )
+
super().save(*args, **kwargs)
@property
@@ -56,12 +76,17 @@ class Product(models.Model):
return self.name
class Order(models.Model):
+ STATUS_CHOICES = (
+ ("new", "Новый"),
+ ("completed", "Завершен"),
+ )
+
order_date = models.DateTimeField(auto_now_add=True)
delivery_date = models.DateTimeField()
pickup_point = models.ForeignKey(PickupPoint, on_delete=models.CASCADE)
client_name = models.CharField(max_length=255, null=True, blank=True)
pickup_code = models.IntegerField()
- status = models.CharField(max_length=50, default="Новый")
+ status = models.CharField(max_length=50, choices=STATUS_CHOICES, default="Новый")
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
class OrderItem(models.Model):
diff --git a/core/templates/core/base.html b/core/templates/core/base.html
index 56d9e17..74aba44 100644
--- a/core/templates/core/base.html
+++ b/core/templates/core/base.html
@@ -14,7 +14,7 @@
</div>
<div class="header-right">
{% if user.is_authenticated %}
- <span>{{ user.role.name }}</span>
+ <span>{{ user.role.name }}</span> |
<strong>{{ user.full_name }}</strong>
<form action="{% url 'logout' %}" method="post" style="display: inline;">
{% csrf_token %}
diff --git a/core/templates/core/order_form.html b/core/templates/core/order_form.html
new file mode 100644
index 0000000..b46b593
--- /dev/null
+++ b/core/templates/core/order_form.html
@@ -0,0 +1,20 @@
+{% extends 'core/base.html' %}
+
+{% block title %}{% if is_edit %}Редактирование{% else %}Добавление{% endif %} заказа - ОООБувь{% endblock %}
+
+{% block h1 %}{% if is_edit %}Редактирование{% else %}Добавление{% endif %} заказа{% endblock %}
+
+{% block content %}
+<div>
+ <form method="post" enctype="multipart/form-data">
+ {% csrf_token %}
+ {{ form }}
+
+ <h3>Товары в заказе</h3>
+ {% for formset in inlines %}
+ {{ formset }}
+ {% endfor %}
+ <button type="submit" class="btn">Сохранить</button>
+ </form>
+</div>
+{% endblock %}
diff --git a/core/templates/core/order_list.html b/core/templates/core/order_list.html
new file mode 100644
index 0000000..8fe80bd
--- /dev/null
+++ b/core/templates/core/order_list.html
@@ -0,0 +1,32 @@
+{% extends 'core/base.html' %}
+
+{% block title %}Заказы - ООООБУВЬ {% endblock %}
+
+{% block h1 %}Заказы{% endblock %}
+
+{% block content %}
+{% if user.role.name == "Администратор" or user.role.name == "Менеджер" %}
+<div>
+ <a href="{% url 'order_create' %}" class="btn">Добавить заказ</a>
+</div>
+{% endif %}
+<div>
+ {% for order in orders %}
+ <div class="product-card">
+ <div class="details">
+ <strong>
+ {% for orderitem in order.items.all %}
+ {{orderitem.product.article}}
+ {% endfor %}
+ </strong><br/>
+ Пункт выдачи: {{ order.pickup_point.address }}<br/>
+ Статус: {{ order.status }}<br/>
+ {% if user.role.name == "Администратор" or user.role.name == "Менеджер" %}
+ <a href="{% url 'order_update' order.id %}">Редактировать заказ</a>
+ {% endif %}
+ </div>
+ <div class="delivery">{{ order.delivery_date }}</div>
+ </div>
+ {% endfor %}
+</div>
+{% endblock %}
diff --git a/core/templates/core/product_list.html b/core/templates/core/product_list.html
index ad7a5bf..b2aa6e0 100644
--- a/core/templates/core/product_list.html
+++ b/core/templates/core/product_list.html
@@ -33,11 +33,9 @@
</select>
</div>
- {% comment %}
<div style="margin-left: 10px;">
<a href="{% url 'order_list' %}" class="btn" style="background-color: #5bc0de;">Заказы</a>
</div>
- {% endcomment %}
{% if user.role.name == 'Администратор' %}
<div style="margin-left: auto;">
@@ -75,6 +73,9 @@
Единица измерения: {{ product.unit }}
<br/>
Колличество на складе: {{ product.discount }}
+ {% if user.role.name == 'Администратор' %}
+ <br/><a href="{% url 'product_edit' product.id %}">Редактировать товар</a>
+ {% endif%}
</div>
<div class="sale">{{ product.discount }}</div>
</div>
diff --git a/core/views.py b/core/views.py
index f090d81..0e62eaf 100644
--- a/core/views.py
+++ b/core/views.py
@@ -7,9 +7,12 @@ from django.contrib.auth.views import LoginView
from django.contrib import messages
from django.db.models import Q
from django.contrib.auth.mixins import UserPassesTestMixin
+from django.http import HttpResponseRedirect
+from extra_views import CreateWithInlinesView, UpdateWithInlinesView
+from django import forms
-from .models import Product, Supplier
-from .forms import ProductForm
+from .models import Product, Supplier, Order, OrderItem
+from .forms import ProductForm, OrderForm, OrderItemFormSet
class UserLoginView(LoginView):
template_name = "core/login.html"
@@ -54,7 +57,7 @@ class AdminRequiredMixin(UserPassesTestMixin):
return (
self.request.user.is_authenticated
and self.request.user.role
- and self.request.user.role == "Администратор"
+ and self.request.user.role.name == "Администратор"
)
class ProductCreateUpdateMixin:
@@ -72,3 +75,98 @@ class ProductCreateView(AdminRequiredMixin, ProductCreateUpdateMixin, CreateView
def form_valid(self, form):
messages.success(self.request, "Товар успешно добавлен")
return super().form_valid(form)
+
+class ProductUpdateView(AdminRequiredMixin, ProductCreateUpdateMixin, UpdateView):
+ model = Product
+ form_class = ProductForm
+ template_name = "core/product_form.html"
+ success_url = reverse_lazy("product_list")
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context["is_edit"] = True
+ return context
+
+
+class AdminManagerRequiredMixin(UserPassesTestMixin):
+ def test_func(self):
+ return (
+ self.request.user.is_authenticated
+ and self.request.user.role
+ and (self.request.user.role.name == "Администратор" or self.request.user.role.name == "Менеджер")
+ )
+
+class OrderListView(AdminManagerRequiredMixin, ListView):
+ model = Order
+ template_name = "core/order_list.html"
+ context_object_name = "orders"
+
+
+class OrderCreateView(CreateWithInlinesView):
+ model = Order
+ form_class = OrderForm
+ inlines = [OrderItemFormSet]
+ success_url = reverse_lazy("order_list")
+
+class OrderUpdateView(UpdateWithInlinesView):
+ model = Order
+ form_class = OrderForm
+ inlines = [OrderItemFormSet]
+ success_url = reverse_lazy("order_list")
+
+# formset variant
+# class OrderCreateView(CreateView):
+# model = Order
+# form_class = OrderForm
+# template_name = "core/order_form.html"
+# success_url = reverse_lazy("order_list")
+
+# def get_context_data(self, **kwargs):
+# context = super().get_context_data(**kwargs)
+# if self.request.POST:
+# # re-use the bound formset if post() already stashed an invalid one
+# context["formset"] = getattr(self, "formset", OrderItemFormSet(self.request.POST))
+# else:
+# context["formset"] = OrderItemFormSet()
+# return context
+
+# def post(self, request, *args, **kwargs):
+# self.object = None
+# form = self.get_form()
+# formset = OrderItemFormSet(request.POST)
+# if form.is_valid() and formset.is_valid():
+# self.object = form.save()
+# formset.instance = self.object
+# formset.save()
+# return HttpResponseRedirect(self.get_success_url())
+# # stash the invalid formset so get_context_data renders it with errors
+# self.formset = formset
+# return self.form_invalid(form)
+
+
+# class OrderUpdateView(UpdateView):
+# model = Order
+# form_class = OrderForm
+# template_name = "core/order_form.html"
+# success_url = reverse_lazy("order_list")
+
+# def get_context_data(self, **kwargs):
+# context = super().get_context_data(**kwargs)
+# if self.request.POST:
+# context["formset"] = getattr(
+# self, "formset", OrderItemFormSet(self.request.POST, instance=self.object)
+# )
+# else:
+# context["formset"] = OrderItemFormSet(instance=self.object)
+# return context
+
+# def post(self, request, *args, **kwargs):
+# self.object = self.get_object()
+# form = self.get_form()
+# formset = OrderItemFormSet(request.POST, instance=self.object)
+# if form.is_valid() and formset.is_valid():
+# form.save()
+# formset.save()
+# return HttpResponseRedirect(self.get_success_url())
+# self.formset = formset
+# return self.form_invalid(form)