Files
watersurf-erp/HISTORY.md

399 lines
46 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# История изменений 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 Количество: только целое число 099
**Проблема**: Поле «Количество» допускало дробные значения и числа больше двухзначного; требовалось ограничить целыми числами от 0 до 99 везде.
**Решение**: В моделях **CustomerOrderItem** и **SupplierOrderItem** поле `quantity` переведено на `decimal_places=0` и добавлены валидаторы `MinValueValidator(0)` и `MaxValueValidator(99)`. В формах заказа клиента и заказа поставщику поле «Количество» переопределено на `IntegerField(min_value=0, max_value=99)` с виджетом `step=1`. В шаблонах заказов в JS добавлена функция `parseQty()` (целое 099), расчёт суммы строки использует её для количества; при потере фокуса поле количества приводится к целому 099; при добавлении новой строки количество устанавливается в 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 0104), дополнительные красный/зелёный для состояний.
- Подключён шрифт 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)
```