- Добавлен параметр warehouse в API search_products_and_variants
- API фильтрует товары по наличию на указанном складе через Stock
- Обновлен _apply_product_filters для поддержки warehouse_id
- ProductSearchPicker теперь поддерживает data-warehouse-id
- Warehouse автоматически передается в AJAX запросы
- В WriteOffDocumentDetailView добавлены categories и tags в контекст
- Компонент поиска встроен в detail.html с жестким фильтром по складу документа
- Single-select режим для выбора одного товара
- JS автоматически заполняет select формы при выборе товара
- Отображение выбранного товара с фото и артикулом
- Автофокус на поле количества после выбора товара
- Пользователь видит только товары доступные на складе документа
- Добавлен пункт 'Документы списания' в выпадающее меню 'Операции' в base_inventory_minimal.html
- Добавлена карточка 'Документы списания' на главную страницу склада (home.html)
- Новая функциональность теперь доступна из двух мест для удобства пользователей
- Старый функционал одиночных списаний остается доступным
- Зарегистрированы модели WriteOffDocument и WriteOffDocumentItem в админке
- Настроен inline для позиций документа в админке
- Добавлены цветовые индикаторы статусов документа
- Настроены фильтры, поиск и сортировка для удобной работы
- Добавлен сигнал release_reservation_on_writeoff_item_delete
- Автоматическое освобождение резервов при удалении позиций через админку
- Защита от утечки резервов при прямом удалении через ORM
- В WriteOffCreateView добавлена передача категорий и тегов в контекст
- Шаблон writeoff_form.html обновлен с использованием product_search_picker
- Автоматическая фильтрация партий по выбранному товару
- Отображение информации о выбранном товаре с фото
- Улучшенный UX при выборе товара для списания
- Подключены CSS и JS компонента поиска товаров
- Добавлены параметры фильтрации: category, tag, in_stock
- Функция _apply_product_filters() для применения фильтров к queryset
- Функция _get_product_photo_url() для получения главного фото товара
- В ответ API добавлено поле photo_url с URL фото товара
- Отключено кэширование при использовании фильтров
- Улучшена производительность запросов с использованием order_by и values
- product_search_picker.html - универсальный шаблон компонента поиска и выбора товаров
- product-search-picker.js - JavaScript модуль с поддержкой фильтрации по категориям, тегам, наличию
- product-search-picker.css - стили для компонента
- Поддержка одиночного и множественного выбора товаров
- Фильтрация по категориям, тегам и наличию на складе
- Отображение фото товара в результатах поиска
- Адаптивный интерфейс с прокруткой для больших списков
- API для программного управления (init, search, clearSelection и др.)
- Возможность кастомизации через параметры (заголовок, высота, текст кнопок)
- list.html - список документов с фильтрацией по статусу и складу
- form.html - форма создания документа
- detail.html - детальный просмотр документа с возможностью добавления/редактирования позиций
- Интерактивное управление позициями через AJAX (добавление, редактирование, удаление)
- Отображение статистики документа (количество позиций, общее количество, себестоимость)
- Кнопки проведения и отмены документа с подтверждением
- Адаптивный дизайн с использованием Bootstrap 5
- WriteOffDocumentListView - список документов с пагинацией
- WriteOffDocumentCreateView - создание нового документа
- WriteOffDocumentDetailView - детальный просмотр документа
- WriteOffDocumentAddItemView - добавление позиции (AJAX)
- WriteOffDocumentUpdateItemView - обновление позиции (AJAX)
- WriteOffDocumentRemoveItemView - удаление позиции (AJAX)
- WriteOffDocumentConfirmView - проведение документа
- WriteOffDocumentCancelView - отмена документа
- Добавлены URL-маршруты для всех операций с документами списания
- Поддержка AJAX запросов для динамической работы с позициями
- WriteOffDocumentForm - создание/редактирование документа списания
- WriteOffDocumentItemForm - добавление/редактирование позиций документа
- Автоматическая установка текущей даты и склада по умолчанию
- Фильтрация товаров по наличию на выбранном складе
- Валидация количества с проверкой доступных остатков
- Учет текущего резерва при редактировании позиций
- Создан WriteOffDocumentService с методами работы с документами списания
- create_document() - создание документа с автогенерацией номера (WO-XXXXXX)
- add_item() - добавление позиции с автоматическим созданием резерва
- update_item() - обновление позиции с пересчетом резерва
- remove_item() - удаление позиции с освобождением резерва
- confirm_document() - проведение документа (создание WriteOff записей по FIFO)
- cancel_document() - отмена с освобождением всех резервов
- Добавлена валидация доступного количества товара при создании/обновлении позиций
- Добавлена функция generate_writeoff_document_number() для генерации номеров документов
- Создана модель WriteOffDocument для коллективного списания с поддержкой статусов (черновик/проведен/отменен)
- Добавлена модель WriteOffDocumentItem для позиций документа
- Расширена модель Reservation связью с WriteOffDocumentItem для резервирования товара в черновике
- Добавлен тип счетчика 'writeoff' в DocumentCounter для автонумерации
- Реализована логика резервирования товара в черновике документа (уменьшает quantity_free)
- При проведении документа создаются WriteOff записи по методу FIFO
- Удалены дублирующиеся функции getCookie() и getCsrfToken() в terminal.js
- Оставлена единая версия getCookie() с алиасом getCsrfToken для совместимости
- Удалены неиспользуемые пустые кнопки из панели действий
- Добавлена логика скрытия поля 'Количество букетов' в режиме редактирования комплекта
- Оптимизирована компоновка кнопок действий (используется offset-4)
- Улучшены комментарии в коде
Результат: -44 строки, код стал чище и поддерживаемее
- Упрощено добавление в корзину: 1 клик = 1 шт (без prompt)
- API показывает все букеты (available + in_cart), не только доступные
- Карточка показывает available/total и сколько в корзине
- Корзина показывает реальное количество витринных букетов
- Кнопка "Очистить" сбрасывает блокировки и обновляет отображение
- API release-all-my-locks для сброса зависших блокировок
- Автоочистка истёкших блокировок при загрузке витрины
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Новая архитектура:
- ShowcaseItem модель - физический экземпляр букета на витрине
- OneToOneField(sold_order_item) - БД-уровневая защита от двойной продажи
- Поддержка создания нескольких экземпляров одного букета
- Возможность продавать N из M доступных (например 2 из 5)
Изменения:
- inventory/models.py: добавлена модель ShowcaseItem с методами lock/unlock/mark_sold
- inventory/services/showcase_manager.py: переработан для работы с ShowcaseItem
- pos/views.py: API поддерживает quantity и showcase_item_ids
- pos/templates/pos/terminal.html: поле "Сколько букетов создать"
- pos/static/pos/js/terminal.js: выбор количества, передача showcase_item_ids
Миграции:
- 0007: создание модели ShowcaseItem
- 0008: data migration существующих букетов
- 0009: очистка ShowcaseItem для уже проданных букетов
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Проблема: При переводе заказа в статус 'completed' возникала ошибка
"Не удалось создать Sale для заказа", т.к. резервы этого же заказа
блокировали списание товара.
Причина: write_off_by_fifo() считал все резервы со статусом 'reserved'
как занятые, включая резервы текущего заказа, которые ещё не были
переведены в 'converted_to_sale'.
Решение:
- Добавлен параметр exclude_order в write_off_by_fifo() для исключения
резервов конкретного заказа из расчёта занятого товара
- SaleProcessor.create_sale() теперь передаёт order в write_off_by_fifo()
- Добавлены транзакции в views для атомарности операций с заказами:
при ошибке в сигналах статус заказа откатывается вместе со всеми
связанными изменениями
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Проблема: при отмене заказа с витринным временным комплектом резервы освобождались
(status='released'), и букет исчезал с витрины. Это неправильное поведение для временных
комплектов на витрине - они должны оставаться доступными для продажи.
Решение:
- В сигнале rollback_sale_on_status_change добавлено разделение резервов на:
* Обычные резервы - работают как раньше (released при отмене, reserved при возврате)
* Витринные временные комплекты (is_temporary=True, showcase!=null) - ВСЕГДА возвращаются
в статус reserved, независимо от типа отката заказа
- Для витринных комплектов сохраняются привязки к showcase и product_kit
- Букеты остаются видимыми на витрине и доступны для повторной продажи
Бизнес-логика:
- При ВОЗВРАТЕ (completed → draft/in_delivery): букет возвращается на витрину
- При ОТМЕНЕ (completed → cancelled): букет ТАКЖЕ возвращается на витрину
- Букет можно убрать только вручную через функцию разбора комплекта
- Добавлена специальная обработка витринных комплектов в сигнале update_reservation_on_item_change:
* При создании OrderItem с витринным комплектом привязываются существующие витринные резервы компонентов
* Не создаются новые резервы на уровне комплекта
- Исправлена логика создания Sale для комплектов в сигнале create_sale_on_order_completion:
* Для комплектов (витринных и обычных) создаются Sale для каждого компонента через резервы
* Используется FIFO-списание для компонентов
* Предотвращена ошибка передачи ProductKit в поле Reservation.product
Fixes: Cannot assign ProductKit to Reservation.product field
Fixes: Не удалось создать Sale для заказа с витринным комплектом
- Добавлена поддержка docker-compose для развертывания
- STATIC_ROOT автоматически переключается в prod (/Volume1/DockerAppsData/npm/data/static/)
- Добавлены ALLOWED_HOSTS и CSRF_TRUSTED_ORIGINS из env переменных
- Улучшена обработка .env файла (проверка существования)
- Добавлен gunicorn в requirements.txt
- Добавлены .dockerignore, Dockerfile, docker-compose.yml
- Добавлены example файлы для .env.docker и entrypoint.sh
- Обновлен .gitignore для исключения файлов с секретами
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Добавлены методы в модель Customer для расчета суммы успешных заказов:
- get_successful_orders_total() - гибкий метод с фильтрацией по датам
- get_last_year_orders_total() - сумма за последний год
Удалено устаревшее поле total_spent:
- Методы предоставляют более точные и актуальные данные
- Используют агрегацию на уровне БД для производительности
Обновлен UI карточки клиента:
- Отображается сумма всех успешных заказов
- Отображается сумма заказов за последний год
- Убрана колонка total_spent из списка клиентов
Изменения:
- customers/models.py: добавлены методы, удалено поле total_spent
- customers/views.py: добавлен расчет сумм в контекст
- customers/templates: обновлены шаблоны
- customers/admin.py: удалены упоминания total_spent
- Создана миграция 0005_remove_total_spent
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Исправлен метод write_off_by_fifo() для учета зарезервированных партий
- Добавлено автоматическое проставление даты и времени при создании заказов в POS
- Исправлена ошибка фильтрации Product (is_active -> status='active') в transfers
- Предотвращает списание из зарезервированных партий, устраняя отрицательные остатки
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Проблема:
- При сбросе клиента на системного в модальном окне продажи баланс кошелька
в виджете оплаты (возле кнопки "С баланса счёта") не обновлялся
- Виджет PaymentWidget сохранял данные предыдущего клиента
Исправления:
- Добавлена функция updatePaymentWidgetCustomer() для переинициализации виджета
- Функция updateCheckoutWalletBalance() теперь вызывает updatePaymentWidgetCustomer()
- При смене клиента виджет оплаты автоматически переинициализируется с новыми данными
Результат:
При смене клиента баланс кошелька обновляется везде, включая виджет оплаты
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Проблема:
- При сбросе клиента на системного в модальном окне продажи баланс кошелька
оставался от предыдущего клиента и не обновлялся
Исправления:
- Добавлена функция updateCheckoutWalletBalance() для обновления баланса
- Функция updateCustomerDisplay() теперь вызывает updateCheckoutWalletBalance()
- Исправлены все кнопки сброса/выбора системного клиента - теперь передают wallet_balance
Результат:
При смене клиента баланс кошелька в модальном окне обновляется корректно
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>