From a183121721a2195d59198f4bc42cf66fffd63939 Mon Sep 17 00:00:00 2001 From: cursor-agent Date: Thu, 26 Feb 2026 16:17:24 +0000 Subject: [PATCH] =?UTF-8?q?Feature:=20=D0=BE=D0=B1=D1=89=D0=B0=D1=8F=20?= =?UTF-8?q?=D1=81=D1=83=D0=BC=D0=BC=D0=B0=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7?= =?UTF-8?q?=D0=B0=20=D0=B8=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2?= =?UTF-8?q?=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=85=20=D0=B7=D0=B0=D0=BA?= =?UTF-8?q?=D0=B0=D0=B7=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- HISTORY.md | 10 ++++++++++ app/documents/forms.py | 4 ++-- app/documents/views.py | 10 ++++++++-- app/static/css/theme-compact.css | 14 +++++++++++++- app/templates/documents/order_form.html | 17 ++++++++++++++--- .../documents/supplier_order_form.html | 17 ++++++++++++++--- 6 files changed, 61 insertions(+), 11 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 02a4f16..917e1e2 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,15 @@ # История изменений ERP WaterSurf +## 2025-02-26 16:15 UTC – Форма заказа: общая сумма и автор только для отображения + +**Задача**: В форме заказа показывать общую сумму заказа (сумма стоимостей строк табличной части) как надпись; поле «Автор» сделать надписью (не вводом), при создании документа подставлять текущего пользователя и сохранять, при открытии — только отображать. + +**Решение**: В формах заказа клиента и заказа поставщику поле `author` убрано из полей формы; в представлениях при создании вызывается `set_author(form, request)` (подстановка сотрудника из профиля пользователя), при редактировании автор не меняется. В контекст передаётся `author_display` (для создания — сотрудник из профиля, для редактирования — автор документа). В шаблонах «Автор» выводится как надпись `{{ author_display|default:"—" }}`. Добавлена надпись «Общая сумма заказа» под таблицей товаров; значение обновляется в JS при изменении строк (сумма всех полей «Стоимость»). + +**Изменения**: documents/forms.py (убрано author из CustomerOrderForm и SupplierOrderForm), documents/views.py (set_author только при создании, author_display в контексте), order_form.html и supplier_order_form.html (автор — надпись, блок общей суммы и JS), theme-compact.css (стили .ws-readonly, .ws-order-total-row). + +--- + ## 2025-02-26 15:50 UTC – Количество: только целое число 0–99 **Проблема**: Поле «Количество» допускало дробные значения и числа больше двухзначного; требовалось ограничить целыми числами от 0 до 99 везде. diff --git a/app/documents/forms.py b/app/documents/forms.py index 18857a8..847e115 100644 --- a/app/documents/forms.py +++ b/app/documents/forms.py @@ -82,7 +82,7 @@ SupplierOrderItemFormSetUpdate = inlineformset_factory( class CustomerOrderForm(forms.ModelForm): class Meta: model = CustomerOrder - fields = ("date", "number", "order_kind", "organization", "client", "author") + fields = ("date", "number", "order_kind", "organization", "client") widgets = { "date": forms.DateInput(attrs={"type": "date"}, format="%Y-%m-%d"), "number": forms.TextInput(attrs={"size": 15, "maxlength": 15}), @@ -92,7 +92,7 @@ class CustomerOrderForm(forms.ModelForm): class SupplierOrderForm(forms.ModelForm): class Meta: model = SupplierOrder - fields = ("date", "number", "organization", "supplier", "customer_order", "currency", "rate", "author") + fields = ("date", "number", "organization", "supplier", "customer_order", "currency", "rate") widgets = { "date": forms.DateInput(attrs={"type": "date"}, format="%Y-%m-%d"), "number": forms.TextInput(attrs={"size": 15, "maxlength": 15}), diff --git a/app/documents/views.py b/app/documents/views.py index b2d1317..1994068 100644 --- a/app/documents/views.py +++ b/app/documents/views.py @@ -32,9 +32,11 @@ logger = logging.getLogger(__name__) def set_author(form, request): - """Подставить автора из профиля пользователя.""" + """Подставить автора из профиля пользователя при создании документа.""" + if form.instance.pk: + return # при редактировании автора не меняем author = get_author_employee(request.user) - if author and "author" in form.fields: + if author: form.instance.author = author @@ -54,6 +56,7 @@ class CustomerOrderCreate(LoginRequiredMixin, CreateView): ctx = super().get_context_data(**kwargs) ctx["formset"] = CustomerOrderItemFormSet(instance=self.object) if self.object and self.object.pk else CustomerOrderItemFormSet() ctx["title"] = "Заказ клиента" + ctx["author_display"] = get_author_employee(self.request.user) if not self.object or not self.object.pk else self.object.author return ctx def form_valid(self, form): @@ -85,6 +88,7 @@ class CustomerOrderUpdate(LoginRequiredMixin, UpdateView): ctx = super().get_context_data(**kwargs) ctx["formset"] = CustomerOrderItemFormSetUpdate(instance=self.object) ctx["title"] = "Заказ клиента" + ctx["author_display"] = self.object.author return ctx def form_valid(self, form): @@ -134,6 +138,7 @@ class SupplierOrderCreate(LoginRequiredMixin, CreateView): ctx = super().get_context_data(**kwargs) ctx["formset"] = SupplierOrderItemFormSet(instance=self.object) if self.object and self.object.pk else SupplierOrderItemFormSet() ctx["title"] = "Заказ поставщику" + ctx["author_display"] = get_author_employee(self.request.user) if not self.object or not self.object.pk else self.object.author return ctx def form_valid(self, form): @@ -165,6 +170,7 @@ class SupplierOrderUpdate(LoginRequiredMixin, UpdateView): ctx = super().get_context_data(**kwargs) ctx["formset"] = SupplierOrderItemFormSetUpdate(instance=self.object) ctx["title"] = "Заказ поставщику" + ctx["author_display"] = self.object.author return ctx def form_valid(self, form): diff --git a/app/static/css/theme-compact.css b/app/static/css/theme-compact.css index 721ca2c..59139c8 100644 --- a/app/static/css/theme-compact.css +++ b/app/static/css/theme-compact.css @@ -1,5 +1,17 @@ /* Компактные формы и таблицы документов — в стиле Material Design 3 */ +/* Поле только для отображения (Автор и т.п.) */ +.ws-form-compact .ws-readonly { + color: var(--ws-text-primary); + font-size: 14px; +} + +.ws-form-compact .ws-order-total-row { + margin-top: 0.75rem; + margin-bottom: 0; + font-size: 14px; +} + /* Подпись слева от поля, в одну строку */ .ws-form-compact .ws-form-group { display: flex; @@ -38,7 +50,7 @@ .ws-form-compact .ws-form-row { display: grid; gap: 10px; - margin-bottom: 10px; + margin-bottom: 6px; align-items: center; } diff --git a/app/templates/documents/order_form.html b/app/templates/documents/order_form.html index a297f9e..3d42f8d 100644 --- a/app/templates/documents/order_form.html +++ b/app/templates/documents/order_form.html @@ -36,9 +36,8 @@ {% if form.client.errors %}{{ form.client.errors.0 }}{% endif %}
- - {{ form.author }} - {% if form.author.errors %}{{ form.author.errors.0 }}{% endif %} + + {{ author_display|default:"—" }}
@@ -78,6 +77,7 @@
+

Общая сумма заказа:

@@ -126,6 +126,17 @@ var el = row.querySelector('.row-amount'); if (el) el.textContent = formatNum(price * qty); }); + var totalEl = document.getElementById('order-total-sum'); + if (totalEl) { + var sum = 0; + document.querySelectorAll('#order-items .item-row').forEach(function(row) { + var priceInput = row.querySelector('input[name$="-price"]'); + var qty = parseQty(row.querySelector('input[name$="-quantity"]')?.value); + var price = parseNum(priceInput?.value); + sum += price * qty; + }); + totalEl.textContent = formatNum(sum); + } } form.addEventListener('input', updateRowAmounts); diff --git a/app/templates/documents/supplier_order_form.html b/app/templates/documents/supplier_order_form.html index 4975220..bcbd0b2 100644 --- a/app/templates/documents/supplier_order_form.html +++ b/app/templates/documents/supplier_order_form.html @@ -50,9 +50,8 @@
- - {{ form.author }} - {% if form.author.errors %}{{ form.author.errors.0 }}{% endif %} + + {{ author_display|default:"—" }}
@@ -92,6 +91,7 @@
+

Общая сумма заказа:

@@ -138,6 +138,17 @@ var el = row.querySelector('.row-amount'); if (el) el.textContent = formatNum(price * qty); }); + var totalEl = document.getElementById('supplier-order-total-sum'); + if (totalEl) { + var sum = 0; + document.querySelectorAll('#supplier-order-items .item-row').forEach(function(row) { + var priceInput = row.querySelector('input[name$="-price"]'); + var qty = parseQty(row.querySelector('input[name$="-quantity"]')?.value); + var price = parseNum(priceInput?.value); + sum += price * qty; + }); + totalEl.textContent = formatNum(sum); + } } form.addEventListener('input', updateRowAmounts);