# История изменений ERP WaterSurf ## 2025-02-26 17:25 UTC – Сортировка по всем колонкам в списках документов **Задача**: Во всех списках документов сделать сортировку по каждой колонке таблицы. **Решение**: Добавлен миксин **SortableListMixin**: читает GET-параметры `sort` и `order` (asc/desc), применяет order_by к queryset. Заголовки колонок — ссылки, активная колонка отмечена стрелкой ↑/↓. По умолчанию сортировка по дате по убыванию. Списки: заказы клиентов, заказы поставщику, поступления, перемещения, расходы денежных средств. **Изменения**: documents/views.py (SortableListMixin, sort_fields в ListView), шаблоны списков (ссылки в th), theme.css (ws-th-sort, ws-sort-arrow). --- ## 2025-02-26 17:15 UTC – Иконки «Карандаш» и «Крестик» вместо надписей «Изменить» и «Удалить» в списках **Задача**: В таблицах списков документов заменить текстовые ссылки «Изменить» и «Удалить» на иконки: карандаш (редактирование) и красный крестик (удаление). **Решение**: В колонке действий добавлены кнопки-иконки: SVG-карандаш (акцентный цвет) и SVG-крестик (красный). Ссылки сохранены, добавлены `title` и `aria-label` для доступности. Стили `.ws-btn-icon-edit` и `.ws-btn-icon-delete` задают размер 28×28 px, скругление, подсветку при наведении. Изменения внесены во все списки: заказы клиентов, заказы поставщику, поступления, перемещения, расходы денежных средств. **Изменения**: theme.css (стили иконок), customer_order_list.html, supplier_order_list.html, cash_inflow_list.html, cash_transfer_list.html, cash_expense_list.html. --- ## 2025-02-26 17:10 UTC – Заголовки и строки таблиц списков документов в одну строку **Задача**: Заголовки таблицы и строки списка не должны переноситься на несколько строк. **Решение**: Добавлен класс **ws-table-list-nowrap** для таблиц списков: для него заданы `white-space: nowrap` у `th` и `td`. Обёртка `.ws-table-wrap` уже имеет `overflow-x: auto`, при необходимости таблица прокручивается по горизонтали. Класс применён к спискам: заказы клиентов, заказы поставщику, поступления, перемещения, расходы денежных средств. **Изменения**: theme.css (правила .ws-table-list-nowrap), customer_order_list.html, supplier_order_list.html, cash_inflow_list.html, cash_transfer_list.html, cash_expense_list.html. --- ## 2025-02-26 17:00 UTC – Справочник «Статусы заказов» и поле «Статус заказа» в заказе клиента **Задача**: Справочник статусов заказов, поле в заказе клиента, отображение в списке с цветовой подложкой («Выполнено» — зелёная, «В работе» — песочная). **Решение**: В справочниках добавлена модель **OrderStatus** (название). Начальные данные: «В работе», «Выполнено». В модель **CustomerOrder** добавлено поле **status** (FK на OrderStatus, null/blank). В форме заказа клиента добавлено поле выбора статуса (по умолчанию при создании — «В работе»). В списке заказов клиентов добавлена колонка «Статус заказа» после «Номер»; значение выводится бейджем с классом `ws-status-done` (зелёная подложка) для «Выполнено» и `ws-status-inprogress` (песочная подложка) для «В работе». **Изменения**: references/models.py (OrderStatus), references/admin.py, references/views.py, references/urls.py, base.html (меню «Статусы заказов»), references/migrations 0002, 0003 (данные); documents/models.py (status у CustomerOrder), documents/migrations 0004; documents/forms.py, views.py (форма, get_initial); order_form.html (поле статус); customer_order_list.html (колонка и бейдж); theme.css (ws-status-badge, ws-status-done, ws-status-inprogress). --- ## 2025-02-26 16:50 UTC – Общая сумма над блоком Товары; клик по строке списка открывает документ **Изменения**: Блок «Общая сумма заказа» перенесён над всей табличной частью «Товары» — сразу под полями Клиент/Автор. В списках заказов клиентов и заказов поставщику документ открывается при клике по строке (в обоих случаях — форма редактирования); клик по ссылкам «Изменить»/«Удалить» не переходит по строке. Добавлены класс строки `ws-row-clickable`, атрибут `data-href` и скрипт перехода. **Файлы**: order_form.html, supplier_order_form.html (общая сумма над секцией Товары), customer_order_list.html, supplier_order_list.html (кликабельные строки + extra_js), theme.css (cursor: pointer для .ws-row-clickable), theme-compact.css (отступ у .ws-order-total-row). --- ## 2025-02-26 16:35 UTC – Общая сумма над таблицей; автор всегда подставляется при создании **Изменения**: Блок «Общая сумма заказа» перенесён над табличную часть «Товары» в формах заказа клиента и заказа поставщику. Поле «Автор» в моделях — ForeignKey на справочник Employee; при создании документа автор теперь подставляется всегда: сначала из профиля пользователя (UserProfile.employee), при отсутствии — создаётся/берётся сотрудник с именем из ФИО или логина пользователя. В контексте для отображения используется тот же хелпер, чтобы надпись «Автор» показывала будущего автора уже при открытии формы создания. **Файлы**: order_form.html, supplier_order_form.html (общая сумма над таблицей), documents/views.py (_get_author_for_request, set_author с fallback). --- ## 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 везде. **Решение**: В моделях **CustomerOrderItem** и **SupplierOrderItem** поле `quantity` переведено на `decimal_places=0` и добавлены валидаторы `MinValueValidator(0)` и `MaxValueValidator(99)`. В формах заказа клиента и заказа поставщику поле «Количество» переопределено на `IntegerField(min_value=0, max_value=99)` с виджетом `step=1`. В шаблонах заказов в JS добавлена функция `parseQty()` (целое 0–99), расчёт суммы строки использует её для количества; при потере фокуса поле количества приводится к целому 0–99; при добавлении новой строки количество устанавливается в 1. **Изменения**: documents/models.py (quantity: decimal_places=0, validators), documents/forms.py (IntegerField для quantity), order_form.html и supplier_order_form.html (parseQty, focusout, клон с quantity=1), миграция 0003_quantity_integer_0_99. --- ## 2025-02-26 00:50 UTC – Форма заказа клиента: сетка, компактные поля, ширина **Проблема**: На форме заказа клиента поле «Номер» визуально смещено вправо; высота полей и отступы между строками слишком большие; поля «Вид заказа», «Организация», «Клиент», «Автор» узкие. **Решение**: Строка «Дата»/«Номер» переведена на чёткую двухколоночную сетку (grid 1fr 1fr): у обеих колонок одинаковый layout (label 6.5rem + input flex 1), оба поля растягиваются по своей колонке. Уменьшена высота полей ввода (padding 6px 10px, min-height 30px в компактной форме; в базовой 8px 12px, min-height 34px). Уменьшены вертикальные отступы между рядами (gap 10px, margin-bottom 10px) и перед блоком «Товары». Строки с «Вид заказа»/«Организация» и «Клиент»/«Автор» растягиваются на всю ширину формы (убрано max-width: 600px), селекты занимают 100% своей ячейки сетки. **Изменения**: theme-compact.css (сетка дата/номер, компактные отступы и высота полей, ws-form-row-2 на всю ширину), theme.css (компактные padding и min-height у полей, отступ секции формы). --- ## 2025-02-26 00:40 UTC – Планы развития: SPA, канбан, дашборды **Добавлено**: В README зафиксированы планы развития фронтенда — канбан заказов (drag-and-drop), живые уведомления, дашборды. Описан рекомендуемый путь перехода на SPA (REST API + отдельный React-фронт) и гибридный вариант миграции. --- ## 2025-02-26 00:35 UTC – Фронтенд в стиле Material Design 3 (MUI-подобный) **Задача**: Использовать визуальный язык Material Design 3 (как в MUI 7), без платных модулей. MUI 7 — React-библиотека; проект на Django с серверными шаблонами, поэтому реализовано через CSS в духе MD3. **Решение**: Переработаны theme.css и theme-compact.css под Material Design 3 (тёмная тема): токены поверхностей (elevation, границы), скругления 12px/8px/20px (карточки, кнопки, поля), кнопки Filled/Outlined в стиле MD3, таблицы с заголовками в uppercase и разделителями, поля ввода Outlined с фокусом. Сохранены шрифт Geologica, цвета брендбука WaterSurf и компактные формы/таблицы по прежним пожеланиям. Классы в шаблонах не менялись. **Изменения**: theme.css (MD3-токены, карточки, навбар, кнопки, формы, таблицы, алерты), theme-compact.css (компактные формы и таблицы товаров в стиле MD3), base.html (версия CSS v5/v2 для сброса кэша). --- ## 2025-02-26 00:25 UTC – Единое отображение чисел с разделителями разрядов **Задача**: Везде, где выводятся числовые значения, показывать их с разделителем разрядов и запятой как десятичным разделителем. **Решение**: Добавлен шаблонный фильтр **ws_num** (documents/templatetags/document_filters.py): формат «1 851 635,50», неразрывный пробел между разрядами. Фильтр подключён во всех списках документов и на странице экономики заказа (суммы, маржа, проценты). **Изменения**: document_filters.py, шаблоны списков документов и customer_order_detail.html (load document_filters, вывод через |ws_num:2 или |ws_num:1). --- ## 2025-02-26 00:15 UTC – Экономика заказа клиента: связи и отчёт **Задача**: Цепочка «Заказ клиента → Поступления денежных средств (несколько) → Заказ поставщику по заказу → Расход на оплату поставщику; плюс прочие расходы по заказу (логистика)». По заказу клиента видеть: сколько поступило, сколько потрачено, маржа, маржинальность, рентабельность. **Решение**: - В модель **SupplierOrder** добавлено поле **customer_order** (FK на CustomerOrder, null/blank) — заказ поставщику оформляется по заказу клиента. - В модель **CashExpense** добавлено поле **customer_order** (FK на CustomerOrder, null/blank) — расходы по заказу клиента без привязки к заказу поставщику (логистика и т.п.). - В формах заказа поставщику и расхода денежных средств добавлены поля выбора заказа клиента; в шаблоне заказа поставщику выведено поле «Заказ клиента». - В модель **CustomerOrder** добавлен метод **get_economics()**: сумма поступлений (cash_inflows), расходы через заказы поставщику (CashExpense по supplier_order.customer_order), прямые расходы по заказу (cash_expenses), итого расходов, маржа, маржинальность % (маржа/поступления), рентабельность % (маржа/расходы). - Добавлена страница **Просмотр заказа клиента** (CustomerOrderDetail): данные заказа, блок «Экономика заказа» (таблица показателей), списки поступлений, заказов поставщику и прочих расходов по заказу с ссылками на создание/редактирование. В списке заказов клиента номер ведёт на эту страницу. **Изменения**: documents/models.py (customer_order в SupplierOrder и CashExpense, get_economics), миграция 0002_add_customer_order_links, documents/forms.py (поля customer_order), supplier_order_form.html (поле заказ клиента), documents/views.py (CustomerOrderDetail), documents/urls.py, шаблон customer_order_detail.html, customer_order_list.html (ссылка с номера на просмотр). --- ## 2025-02-25 23:55 UTC – Дата при открытии формы, без лишней пустой строки при редактировании **Проблема**: При открытии формы редактирования заказа поле «Дата» не подставлялось из БД; в табличной части вместе с существующими строками отображалась лишняя пустая строка. **Решение**: Для виджета даты (DateInput с type="date") задан явный формат `format="%Y-%m-%d"`, чтобы значение из БД выводилось в виде, ожидаемом HTML5 (YYYY-MM-DD). Для редактирования заказов используются отдельные formset-классы с `extra=0`: при открытии формы показываются только сохранённые строки; новая строка добавляется по кнопке «+ Добавить строку». **Изменения**: documents/forms.py (format для всех DateInput; CustomerOrderItemFormSetUpdate и SupplierOrderItemFormSetUpdate с extra=0), documents/views.py (импорт и использование *FormSetUpdate в Update-представлениях заказов). --- ## 2025-02-25 23:45 UTC – Сохранение заказа: дата и табличная часть **Проблема**: При сохранении заказа клиента не сохранялись поле «Дата» и табличная часть (товары). **Причина**: В JavaScript переиндексация строк и клонирование использовали неверный формат имён полей formset: префикс в Django — `items` (related_name), имена имеют вид `items-0-product`, `items-1-price`. В коде искали `items0`, `items1` (без дефиса), из‑за чего переиндексация не срабатывала, клоны получали те же имена `items-0-*`, при отправке дубликаты перезаписывали друг друга и formset обрабатывал только одну строку. При ошибке валидации formset в контекст не передавался обновлённый formset с ошибками. **Решение**: В reindexRows и при клонировании строк используется корректный формат: `prefix + '-\\d+'` для индекса (например `items-0`), замена на `prefix + '-' + i`; при клонировании — `prefix + '-\\d+-'` для совпадения с суффиксом поля. При невалидном formset в контекст передаётся `formset=formset`, чтобы на форме отображались ошибки. **Изменения**: order_form.html, supplier_order_form.html (регулярные выражения в reindexRows и в обработчике «Добавить строку»), documents/views.py (передача formset в get_context_data при ошибке валидации для заказов клиента и поставщику). --- ## 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 – Удаление строки табличной части по кнопке-крестику **Проблема**: Удаление строки происходило при сохранении документа (чекбокс «Удалить»), что было неочевидно и неудобно. **Решение**: В формах заказа клиента и заказа поставщику чекбокс и подпись «Удалить» заменены на кнопку в виде красного крестика (×). По нажатию строка сразу удаляется из DOM, индексы полей formset пересчитываются (reindexRows), обновляется TOTAL_FORMS и пересчёт сумм по строкам. При добавлении новой строки после вставки клона также вызывается reindexRows(). **Изменения**: order_form.html (кнопка .ws-btn-remove-row, reindexRows, делегированный click на tbody), supplier_order_form.html (аналогично), theme-compact.css (стили .ws-btn-remove-row — красный крестик, hover; удалены стили .ws-delete-row-label). --- ## 2025-02-25 22:50 UTC – Добавление строки: одна строка за клик, понятное удаление **Проблема**: По кнопке «Добавить строку» добавлялось сразу две строки; было неочевидно, как удалить лишнюю. **Причина**: В order_form.html блок `{% block extra_js %}` был вложен в `{% block content %}`, из‑за чего скрипт попадал на страницу дважды и на кнопку вешались два обработчика. **Решение**: Блок контента формы закрыт до скрипта: сначала `{% endblock %}`, затем `{% block extra_js %}` со скриптом — скрипт подключается один раз, добавляется одна строка за клик. Для удаления строки: у чекбокса в колонке «Удалить» добавлена подпись «Удалить» (label), при клонировании строки у новой подписи обновляется атрибут `for` под новый id чекбокса. Стили для подписи: cursor pointer, мелкий текст. **Изменения**: order_form.html (структура блоков, label «Удалить», обновление for у клона), supplier_order_form.html (label «Удалить», обновление for у клона), theme-compact.css (стили .ws-delete-row-label). --- ## 2025-02-25 22:45 UTC – Поле «Цена»: ввод с клавиатуры сохраняется **Проблема**: В табличной части заказа в поле «Цена» сохранялось только изменение стрелками вверх/вниз, введённое с клавиатуры значение не сохранялось. **Причина**: При blur в поле подставлялось отформатированное значение с пробелами («1 851 635.00»). Для `input type="number"` такие значения недопустимы, браузер сбрасывал поле. **Решение**: Форматирование с пробелами убрано из самого поля «Цена». Разделитель разрядов остаётся только в ячейке «Стоимость» (обновляется по input). Обработчики blur/focus для поля цены и начальное форматирование при загрузке удалены в order_form.html и supplier_order_form.html. Перед отправкой формы по-прежнему выполняется удаление пробелов из значений цены. **Изменения**: documents/order_form.html, documents/supplier_order_form.html. --- ## 2025-02-25 22:40 UTC – Убрана горизонтальная полоса прокрутки в таблице товаров **Проблема**: В табличной части заказа по-прежнему отображалась горизонтальная полоса прокрутки. **Решение**: Для обёртки таблицы задано `overflow-x: hidden`, у колонок убраны `min-width`, для ячеек включены `overflow: hidden` и `box-sizing: border-box`. Ширины колонок заданы в сумме 100% (45+14+12+10+14+5), чтобы таблица не выходила за контейнер. **Изменения**: theme-compact.css. --- ## 2025-02-25 22:35 UTC – Табличная часть заказа: без скролла, цена/стоимость с разделителем **Проблема**: В таблице товаров появлялась горизонтальная полоса прокрутки; поле «Товар» слишком широкое; в полях «Цена» и «Стоимость» не было разделителя разрядов. **Решение**: Включён table-layout: fixed и заданы доли колонок в % (Товар 28%, Цена 14%, Валюта 12%, Количество 10%, Стоимость 14%, Удалить 5%), чтобы таблица помещалась без скролла. Поле «Товар» ограничено по ширине, select с overflow: hidden. Поля «Цена» и «Стоимость»: выравнивание по правому краю, узкое поле под 8-значную сумму. В JS добавлены formatNum/parseNum: разделитель тысяч (неразрывный пробел) и запятая как десятичный разделитель; при blur цена форматируется, при focus и при submit — пробелы снимаются перед отправкой. Стоимость в ячейке выводится с разделителем. Аналогичные правки в форме заказа поставщику. **Изменения**: order_form.html, supplier_order_form.html (colgroup, классы ячеек, JS форматирование), theme-compact.css (ширины колонок). --- ## 2025-02-25 22:25 UTC – Временное отключение авторизации для отладки **Проблема**: Для быстрой разработки и отладки нужно работать без входа. **Решение**: Добавлена настройка `REQUIRE_LOGIN` (по умолчанию `false`). При `REQUIRE_LOGIN=false` представления не требуют входа; мидлварь `OptionalAuthMiddleware` подставляет первого активного суперпользователя для анонимных запросов, чтобы меню и поле «Автор» работали. Миксин `config.mixins.LoginRequiredMixin` проверяет `REQUIRE_LOGIN` и при `false` не перенаправляет на логин. Чтобы вернуть авторизацию: в `.env` задать `REQUIRE_LOGIN=true` и перезапустить приложение. **Изменения**: config/settings.py (REQUIRE_LOGIN, OptionalAuthMiddleware), config/mixins.py, config/middleware.py, documents/views.py, references/views.py, users/views.py (импорт LoginRequiredMixin из config.mixins), .env.example (комментарий про REQUIRE_LOGIN). --- ## 2025-02-25 22:15 UTC – Поле «Дата»: размер и кнопка календаря **Проблема**: Дата не помещалась в поле (обрезка по ширине), кнопка выбора календаря сливалась с тёмным фоном. **Решение**: Ширина поля даты увеличена до 11.5rem. Для кнопки календаря (::-webkit-calendar-picker-indicator) задан акцентный фон (--ws-accent), белая иконка календаря через SVG data URI, при наведении — --ws-accent-hover. **Изменения**: theme-compact.css. --- ## 2025-02-25 22:10 UTC – Поле «Дата» как ввод даты (type=date) **Проблема**: Поле даты в документах было текстовым (size=10). **Решение**: Во всех формах документов (заказ клиента, заказ поставщику, поступление, перемещение, расход) виджет даты заменён на `DateInput(attrs={"type": "date"})` — отображается нативный выбор даты в браузере. **Изменения**: documents/forms.py (виджеты date во всех пяти формах). --- ## 2025-02-25 22:00 UTC – Компактные формы денежных документов (поступление, перемещение, расход) **Проблема**: Формы поступления, перемещения и расхода денежных средств выводили все поля списком с подписями сверху. **Решение**: Общий шаблон cash_doc_form.html переведён на компактную раскладку по образцу заказов: первая строка — Дата и Номер (подпись слева от поля, 10 и 15 символов), остальные поля — парами в одну строку в две колонки (подпись слева). Добавлены виджеты даты/номера в CashInflowForm, CashTransferForm, CashExpenseForm. **Изменения**: documents/forms.py (виджеты date/number в трёх формах), documents/cash_doc_form.html (компактная разметка с ws-form-compact). --- ## 2025-02-25 21:45 UTC – Подписи полей слева от полей в одну строку **Проблема**: Подписи полей в формах заказов были расположены над полями ввода. **Решение**: В компактных формах подписи выровнены слева от полей в одну строку: группа поля — flex-строка (label + поле), минимальная ширина подписи 6.5rem, сообщения об ошибках переносятся на следующую строку с отступом. **Изменения**: theme-compact.css (стили .ws-form-group как flex row, выравнивание подписей). --- ## 2025-02-25 21:30 UTC – Компактные формы документов (заказы клиента и поставщику) **Проблема**: Формы создания/редактирования заказов занимали много места: каждое поле с новой строки на всю ширину. **Решение**: - Дата и Номер в одной строке: поле «Дата» — 10 символов (size=10), «Номер» — 15 символов (size=15, maxlength=15). - Вид заказа и Организация в одной строке; Клиент и Автор в одной строке (заказ клиента). Аналогично заказ поставщику: Организация и Поставщик, Валюта и Курс, затем Автор. - Таблица товаров: колонка «Товар» шире (35%, min 14rem), колонка «Количество» уже (поле ввода 4ch, до двухзначного числа). - Добавлены виджеты для даты/номера в формах и для количества в formset (size=3, width: 4ch). Новый файл `static/css/theme-compact.css` с раскладкой строк формы (grid) и ширинами колонок таблицы. **Изменения**: documents/forms.py (CustomerOrderForm, SupplierOrderForm, CustomerOrderItemForm, SupplierOrderItemForm, виджеты), documents/order_form.html и supplier_order_form.html (компактная разметка по полям), base.html (подключение theme-compact.css), новый theme-compact.css. --- ## 2025-02-25 21:00 UTC – Принудительное применение темы (кэш, шрифт, кнопки) **Проблема**: На скриншоте стили не применялись: кнопка бирюзовая вместо синей (#34AFE3), шрифт Geologica не отображался. **Решение**: - К ссылке theme.css добавлен параметр ?v=4 для сброса кэша браузера и прокси. - Для кнопки .btn-ws-primary заданы явные цвета #34AFE3 и #00868F и усилена специфичность селекторов (body .btn.btn-ws-primary). - На html и body задан font-family Geologica; для потомков — font-family: inherit, чтобы шрифт применялся ко всей странице. **Изменения**: base.html (theme.css?v=4), theme.css (коммент v4, кнопки по HEX, наследование шрифта). --- ## 2025-02-25 20:45 UTC – Логотип убран; дизайн строго по брендбуку **Проблема**: Логотип в шапке был вставлен некорректно; визуально тема не отличалась от дефолтной — цвета и шрифты не применялись. **Решение**: - Логотип из шапки убран, в навбаре снова текст «WaterSurf ERP». - Файл логотипа удалён из `static/images/`. - Фон страницы и поверхностей задан только основными цветами бренда: Black #0A121D; границы — Gray 04 #617E92; текст — Gray 01 #F5F9FD, Gray 03 #B1C7D7, Gray 04 #617E92. - Ключевой акцент взят только из дополнительных цветов: Blue (02) #34AFE3, при наведении Blue (03) #00868F. - Добавлены переопределения Bootstrap с !important для body, main, кнопок, полей ввода, таблиц и типографики, чтобы гарантированно применялись Geologica и палитра брендбука. **Изменения**: base.html (удалён img логотипа), theme.css (палитра только из брендбука, акцент из дополнительных, переопределения Bootstrap), удалён app/static/images/watersurf-logo.png. --- ## 2025-02-25 20:15 UTC – Стили по корпоративному брендбуку и логотип **Проблема**: Нужно привести интерфейс в соответствие с корпоративным брендбуком WaterSurf и использовать логотип компании. **Решение**: - В `static/css/theme.css` применены цвета брендбука: базовый фон #0A121D, ключевой акцент #0DADBB, градации серого (Gray 01–04), дополнительные красный/зелёный для состояний. - Подключён шрифт Geologica (Google Fonts): Light для основного текста, Medium для подзаголовков, Bold для заголовков; учтён letter-spacing по брендбуку. - В шапке вместо текстовой надписи выводится логотип WaterSurf из `static/images/watersurf-logo.png`, рядом — подпись «ERP». - Сохранены тёмная тема, минималистичные карточки, таблицы и формы в едином стиле. **Изменения**: base.html (подключение Geologica, логотип в навбаре), theme.css (палитра и типографика брендбука), добавлен каталог static/images и файл watersurf-logo.png. --- ## 2025-02-25 19:00 UTC – Кнопка «Добавить строку» в табличной части заказов **Проблема**: В форме заказа клиента (и заказа поставщику) нельзя было добавить более одной строки товаров — formset показывал только одну пустую строку (extra=1). **Решение**: Под таблицей товаров добавлена кнопка «+ Добавить строку». По нажатию скрипт клонирует последнюю строку, подменяет в ней индексы полей (items-N-…) и значение TOTAL_FORMS в management form, очищает значения и добавляет строку в таблицу. Аналогично реализовано для заказа поставщику. --- ## 2025-02-25 18:45 UTC – Тёмная тема и обновлённый UI/UX **Проблема**: Требовался современный тёмный интерфейс, минималистичный и удобный. **Решение**: - Добавлена кастомная тема в `static/css/theme.css`: тёмный фон (оттенки #0d1117–#21262d), акцент бирюзовый (#2dd4bf), типографика Inter, переменные для цветов и отступов. - Обновлён базовый шаблон: навбар с выпадающими меню в стиле темы, контейнер контента с ограничением ширины, сообщения (alerts) в стиле темы. - Все страницы переведены на карточки (ws-card), таблицы (ws-table) с чередованием и hover, кнопки (btn-ws-primary, btn-ws-secondary, btn-ws-danger), формы с группами полей и явными метками. - Учтены UX: читаемый контраст, фокус на полях ввода, разделители секций в формах, выравнивание чисел в таблицах, пустые состояния. **Изменения**: base.html, registration/login.html, home.html, шаблоны references/* и documents/*, новый static/css/theme.css. В Dockerfile добавлен collectstatic при сборке образа. --- ## 2025-02-25 18:15 UTC – Ошибка 500 при создании заказа клиента **Проблема**: При открытии формы создания заказа клиента возникала ошибка 500 (AttributeError: 'NoneType' object has no attribute 'pk'). **Решение**: В `CustomerOrderCreate.get_context_data` при создании нового заказа `self.object` ещё None; обращение к `self.object.pk` вызывало исключение. Условие заменено на `if self.object and self.object.pk`, как в форме заказа поставщику. --- ## 2025-02-25 15:25 UTC – Исправление 403 CSRF при входе **Проблема**: При первой авторизации под администратором по https://erp.gen7x.ru возникала ошибка 403 (ошибка проверки CSRF, запрос отклонён). **Решение**: Добавлена настройка `CSRF_TRUSTED_ORIGINS` в `config/settings.py`: указаны `https://erp.gen7x.ru`, а также localhost/127.0.0.1 для локальной отладки. При работе за Nginx Django проверяет заголовок Origin/Referer; без доверенного источника запросы с формы логина отклонялись. **Изменения**: `app/config/settings.py` — список CSRF_TRUSTED_ORIGINS; опциональная переменная `CSRF_TRUSTED_ORIGINS` в `.env.example`. --- ## 2025-02-25 15:10 UTC – Администратор и SSH для Git **Проблема**: Требовалось создать первого администратора системы и настроить SSH для самостоятельного push в Gitea. **Решение**: - Создан Django superuser (логин `admin`, пароль и email записаны в `/root/docs/secrets/mysecrets.md`). - Сгенерирован SSH-ключ для Gitea (`/root/.ssh/gitea_cursor_agent_ed25519`), публичный ключ добавлен в учётную запись cursor-agent через API. - В `~/.ssh/config` добавлен хост `git.gen7x.ru` (HostName 127.0.0.1, Port 2222, User git, указан ключ). - Remote репозитория переведён на SSH: `git@git.gen7x.ru:cursor-agent/watersurf-erp.git`, выполнен успешный push ветки main. **Изменения**: - README.md: секция «Git и пуш» обновлена с указанием SSH и отсутствия необходимости ввода пароля с сервера. --- ## 2025-02-25 15:00 UTC – Начальная структура проекта (MVP) **Проблема**: необходимо развернуть систему класса ERP для WaterSurf с веб-доступом, авторизацией и хранением данных в БД. **Решение**: - Создан проект в `/opt/watersurf-erp`: Django 5, PostgreSQL 16, Docker Compose. - Реализованы справочники: Валюты, Виды заказов, Клиенты, Организации, Поставщики, Сотрудники, Счета денежных средств, Товары (CRUD через веб и админку). - Реализованы документы: Заказ клиента, Заказ поставщику (с табличными частями товаров), Поступление/Перемещение/Расход денежных средств (автогенерация номера). - Связь пользователь → сотрудник (профиль) для автоматической подстановки автора в документах. - Настроены Nginx (erp.gen7x.ru), добавлен volume в список бэкапов платформы. **Изменения**: - Структура приложения: config, references, documents, users; шаблоны, формы, представления; миграции. - Файлы: README.md, HISTORY.md, .env.example, docker-compose.yml, Dockerfile, manage.sh, requirements.txt. **Проверка**: ```bash cd /opt/watersurf-erp docker compose up -d docker compose logs -f app # Открыть https://erp.gen7x.ru/ (после перезагрузки Nginx) ```