Feature: общая сумма заказа и автор только для отображения в формах заказов
Made-with: Cursor
This commit is contained in:
10
HISTORY.md
10
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 везде.
|
||||
|
||||
@@ -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}),
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,8 @@
|
||||
{% if form.client.errors %}<small class="ws-text-danger">{{ form.client.errors.0 }}</small>{% endif %}
|
||||
</div>
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.author.id_for_label }}">{{ form.author.label }}</label>
|
||||
{{ form.author }}
|
||||
{% if form.author.errors %}<small class="ws-text-danger">{{ form.author.errors.0 }}</small>{% endif %}
|
||||
<label>Автор</label>
|
||||
<span class="ws-readonly">{{ author_display|default:"—" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-form-section">
|
||||
@@ -78,6 +77,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="ws-order-total-row"><strong>Общая сумма заказа:</strong> <span id="order-total-sum" class="ws-num">—</span></p>
|
||||
<div class="ws-btn-group" style="margin-top: 0.75rem;">
|
||||
<button type="button" class="btn btn-ws-secondary" id="add-order-row">+ Добавить строку</button>
|
||||
</div>
|
||||
@@ -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);
|
||||
|
||||
@@ -50,9 +50,8 @@
|
||||
</div>
|
||||
<div class="ws-form-row ws-form-row-2">
|
||||
<div class="ws-form-group">
|
||||
<label for="{{ form.author.id_for_label }}">{{ form.author.label }}</label>
|
||||
{{ form.author }}
|
||||
{% if form.author.errors %}<small class="ws-text-danger">{{ form.author.errors.0 }}</small>{% endif %}
|
||||
<label>Автор</label>
|
||||
<span class="ws-readonly">{{ author_display|default:"—" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ws-form-section">
|
||||
@@ -92,6 +91,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="ws-order-total-row"><strong>Общая сумма заказа:</strong> <span id="supplier-order-total-sum" class="ws-num">—</span></p>
|
||||
<div class="ws-btn-group" style="margin-top: 0.75rem;">
|
||||
<button type="button" class="btn btn-ws-secondary" id="add-supplier-order-row">+ Добавить строку</button>
|
||||
</div>
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user