Files
watersurf-erp/HISTORY.md

34 KiB
Raw Blame History

История изменений ERP WaterSurf

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.

Проверка:

cd /opt/watersurf-erp
docker compose up -d
docker compose logs -f app
# Открыть https://erp.gen7x.ru/ (после перезагрузки Nginx)