diff --git a/HISTORY.md b/HISTORY.md index 5e8bbd6..e4a7e7a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,15 @@ # История изменений ERP WaterSurf +## 2025-02-25 23:30 UTC – Поле Цена: разделители числа, без стрелок в Цена и Количество + +**Проблема**: В поле «Цена» не было разделителей разрядов; стрелки вверх/вниз в полях «Цена» и «Количество» мешали. + +**Решение**: Поле «Цена» выводится как текст (TextInput с inputmode="decimal"): при потере фокуса значение форматируется с неразрывными пробелами и запятой как десятичный разделитель; при фокусе показывается «сырое» число для редактирования; при загрузке страницы существующие цены форматируются. Перед отправкой формы пробелы и запятая по-прежнему снимаются. У полей «Количество» (type="number») скрыты спиннеры через CSS (-moz-appearance: textfield и ::-webkit-inner-spin-button). + +**Изменения**: documents/forms.py (виджет price — TextInput), order_form.html и supplier_order_form.html (focusin/focusout для форматирования цены, начальное форматирование), theme-compact.css (скрытие спиннеров у .ws-col-qty input[type="number"]). + +--- + ## 2025-02-25 23:15 UTC – Удаление строки табличной части по кнопке-крестику **Проблема**: Удаление строки происходило при сохранении документа (чекбокс «Удалить»), что было неочевидно и неудобно. diff --git a/app/documents/forms.py b/app/documents/forms.py index 5b4e73e..6ce7216 100644 --- a/app/documents/forms.py +++ b/app/documents/forms.py @@ -17,6 +17,7 @@ class CustomerOrderItemForm(forms.ModelForm): model = CustomerOrderItem fields = ("product", "price", "currency", "quantity") widgets = { + "price": forms.TextInput(attrs={"inputmode": "decimal", "class": "ws-price-input"}), "quantity": forms.NumberInput(attrs={"size": 3, "min": 0, "max": 99, "style": "width: 4ch"}), } @@ -26,6 +27,7 @@ class SupplierOrderItemForm(forms.ModelForm): model = SupplierOrderItem fields = ("product", "price", "currency", "quantity") widgets = { + "price": forms.TextInput(attrs={"inputmode": "decimal", "class": "ws-price-input"}), "quantity": forms.NumberInput(attrs={"size": 3, "min": 0, "max": 99, "style": "width: 4ch"}), } diff --git a/app/static/css/theme-compact.css b/app/static/css/theme-compact.css index 67f7f77..ec84bb9 100644 --- a/app/static/css/theme-compact.css +++ b/app/static/css/theme-compact.css @@ -167,6 +167,17 @@ box-sizing: border-box; } +/* Убрать стрелки вверх/вниз у поля Количество (Цена — text, без стрелок) */ +.ws-table-items .ws-col-qty input[type="number"] { + -moz-appearance: textfield; +} + +.ws-table-items .ws-col-qty input[type="number"]::-webkit-outer-spin-button, +.ws-table-items .ws-col-qty input[type="number"]::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + .ws-table-items .ws-col-currency select { max-width: 100%; } diff --git a/app/templates/documents/order_form.html b/app/templates/documents/order_form.html index ec1a246..c23f65a 100644 --- a/app/templates/documents/order_form.html +++ b/app/templates/documents/order_form.html @@ -131,7 +131,24 @@ }); }); + form.addEventListener('focusin', function(e) { + if (e.target.name && e.target.name.indexOf('-price') !== -1) { + var n = parseNum(e.target.value); + e.target.value = (e.target.value.trim() === '' || isNaN(n)) ? '' : n.toFixed(2); + } + }); + form.addEventListener('focusout', function(e) { + if (e.target.name && e.target.name.indexOf('-price') !== -1) { + if (e.target.value.trim() === '') return; + var n = parseNum(e.target.value); + e.target.value = isNaN(n) ? '' : formatNum(n); + } + }); + updateRowAmounts(); + form.querySelectorAll('input[name$="-price"]').forEach(function(input) { + if (input.value && input.value.trim() !== '') input.value = formatNum(parseNum(input.value)); + }); function reindexRows() { var prefix = getPrefix(); diff --git a/app/templates/documents/supplier_order_form.html b/app/templates/documents/supplier_order_form.html index 5301379..e71168e 100644 --- a/app/templates/documents/supplier_order_form.html +++ b/app/templates/documents/supplier_order_form.html @@ -136,7 +136,24 @@ }); }); + form.addEventListener('focusin', function(e) { + if (e.target.name && e.target.name.indexOf('-price') !== -1) { + var n = parseNum(e.target.value); + e.target.value = (e.target.value.trim() === '' || isNaN(n)) ? '' : n.toFixed(2); + } + }); + form.addEventListener('focusout', function(e) { + if (e.target.name && e.target.name.indexOf('-price') !== -1) { + if (e.target.value.trim() === '') return; + var n = parseNum(e.target.value); + e.target.value = isNaN(n) ? '' : formatNum(n); + } + }); + updateRowAmounts(); + form.querySelectorAll('input[name$="-price"]').forEach(function(input) { + if (input.value && input.value.trim() !== '') input.value = formatNum(parseNum(input.value)); + }); function reindexRows() { var prefix = getPrefix();