- inventory/signals.py: обработчик изменения статуса Order
* При смене статуса на 'завершён' (is_positive_end=True): reserved → sold
* При смене на 'отменён' (is_negative_end=True): reserved → available
- inventory/services/showcase_manager.py: метод reserve_for_order()
* Переводит ShowcaseItem: in_cart → reserved
* Создаёт жёсткую связь с OrderItem
* Автоматическое управление статусами через сигналы
- Транзакционная безопасность через @transaction.atomic
- inventory/models.py: добавлен статус 'reserved' в STATUS_CHOICES
- Миграция: 0004_add_reserved_status_to_showcaseitem.py
- Статус reserved используется для витринных букетов в отложенных заказах
- Жизненный цикл: available → in_cart → reserved → sold
Проблемы:
1. При продаже витринного комплекта через POS создавались дубликаты резервов
- reserve_stock_on_item_create создавал новые резервы для витринного комплекта
- Хотя резервы уже существовали от ShowcaseManager.reserve_kit_to_showcase
2. При переходе заказа в Completed создавались дубликаты Sale
- ShowcaseManager.sell_showcase_items создавал Sale
- Затем сигнал create_sale_on_order_completion создавал Sale повторно
3. При отмене заказа (Completed → Cancelled) терялась связь ShowcaseItem с резервами
- ShowcaseItem возвращался на витрину, но резервы теряли поле showcase_item
- При повторном переходе в Completed резервы дублировались
Исправления:
1. inventory/signals.py - reserve_stock_on_item_create (строки 165-180):
- Добавлена проверка витринного комплекта (is_temporary && showcase)
- Для витринных комплектов сигнал пропускает создание новых резервов
- Привязка существующих резервов происходит в update_reservation_on_item_change
2. inventory/signals.py - create_sale_on_order_completion (строки 346-365):
- Добавлена проверка уже обработанных резервов (status='converted_to_sale')
- Сигнал пропускает витринные резервы, уже обработанные ShowcaseManager
- Логирует информацию о пропущенных резервах
3. inventory/signals.py - rollback_sale_on_status_change (строки 746-774):
- При возврате ShowcaseItem на витрину восстанавливается связь с резервами
- Обновляется поле showcase_item в резервах через Reservation.objects.update()
- Логируется количество восстановленных связей
4. inventory/services/showcase_manager.py - sell_showcase_items (строки 201-206):
- Добавлена проверка статуса резерва перед созданием Sale
- Если резерв уже в 'converted_to_sale', он пропускается
- Защита от двойного списания одного резерва
Результат:
✅ Резервы создаются только один раз при размещении на витрине
✅ Sale создаются только один раз при продаже
✅ ShowcaseItem корректно возвращается на витрину со связью с резервами
✅ Остатки на складе корректные (60 → 55 после продажи, 60 после отмены)
✅ Нет дублирования при многократных переходах Completed ↔ Cancelled
feat(inventory): introduce stock deficit notifications and base quantity tracking
- Added `quantity_base` field to reservation model for precise inventory calculations
- Implemented non-blocking stock deficit warnings during kit creation process
- Enhanced API responses with warning details for frontend display
- Updated terminal interface to show formatted stock shortage alerts
BREAKING CHANGE: API response structure now includes `warnings` array instead of previous stock warning format
Implement functionality to allow sales even when stock is insufficient, tracking pending quantities and resolving them when new stock arrives via incoming documents. This includes new fields in Sale model (is_pending_cost, pending_quantity), updates to batch manager for negative write-offs, and signal handlers for automatic processing.
- Add is_pending_cost and pending_quantity fields to Sale model
- Modify write_off_by_fifo to support allow_negative flag and return pending quantity
- Update incoming document service to allocate pending sales to new batches
- Enhance sale processor and signals to handle pending sales
- Remove outdated tests.py file
- Add migration for new Sale fields
- Updated generated timestamps in initial migrations of accounts, customers,
inventory, orders, products, tenants, and user_roles apps
- Reflect new generation time from 08:35 to 23:23 on 2026-01-03
- No changes to migration logic or schema detected
- Ensures migration files align with most recent generation time for consistency
Проблема: при создании тенанта автоматически создаются дефолтные
Склад и Витрина. Если пользователь удалит их, система может сломаться:
POS, создание заказов и резервирование перестанут работать.
Решение: реализована строгая валидация + мягкое удаление для витрин.
Изменения в inventory/views/warehouse.py:
- Добавлена валидация перед деактивацией склада:
* Блокировка деактивации последнего активного склада
* Проверка ненулевых остатков товаров
* Проверка активных резервов
* Предупреждение при деактивации дефолтного склада
Изменения в inventory/views/showcase.py:
- ShowcaseListView: по умолчанию показывает только активные витрины
- ShowcaseDeleteView: изменена логика с жесткого на мягкое удаление
- Добавлена валидация перед деактивацией витрины:
* Блокировка деактивации последней активной витрины склада
* Проверка активных резервов
* Проверка физических экземпляров комплектов (ShowcaseItem)
* Предупреждение при деактивации дефолтной витрины
Изменения в inventory/forms_showcase.py:
- Проверка уникальности названия витрины учитывает только активные
Изменения в inventory/admin.py:
- ShowcaseAdmin: добавлены методы delete_model() и delete_queryset()
для блокировки удаления последней витрины через админку
- WarehouseAdmin: добавлены методы delete_model() и delete_queryset()
для блокировки удаления последнего склада через админку
Преимущества:
✅ Система не сломается - всегда есть хотя бы один активный склад/витрина
✅ Данные в безопасности - мягкое удаление для обеих сущностей
✅ Понятные сообщения об ошибках для пользователя
✅ Защита работает как в UI, так и в Django Admin
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Обновлены начальные миграции для всех приложений
- Удалены устаревшие миграции для единиц измерения и SKU
- Добавлен новый сервис unit_service.py для управления единицами
- Обновлены команды инициализации данных тенанта
Проблема: при приёмке товаров отображались только товары с ненулевым
остатком на складе, товары с нулевым остатком не находились.
Решение: добавлен параметр skip_stock_filter в компонент поиска товаров,
который отключает фильтрацию по остаткам. Для приёмки этот параметр
включён по умолчанию.
Изменения:
- api_views.py: добавлен параметр skip_stock_filter в _apply_product_filters
- product_search_picker.html: добавлен data-атрибут skip_stock_filter
- product-search-picker.js: передача параметра в API
- incoming_document_detail.html: включён skip_stock_filter=True
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Обновлён pos/views.py: метод pos_checkout теперь создаёт Order и связанную модель Delivery
- Обновлён showcase_manager.py: метод sell_showcase_item_to_customer использует новую архитектуру
- Удалён устаревший скрипт create_demo_orders.py
- Исправлена ошибка 'property is_delivery of Order object has no setter'
КРИТИЧНО: При создании Sale использовалось неправильное поле!
Проблема:
- При проведении заказа Sale создавался с reservation.quantity
- Это количество в ЕДИНИЦАХ ПРОДАЖИ, а не в базовых!
- Пример: 1 ветка списывала 1 банч вместо 0.05 банча
Решение:
- Строка 410: sale_quantity = reservation.quantity_base (для товаров)
- Строка 368: quantity=reservation.quantity_base (для комплектов)
- Fallback на .quantity для обратной совместимости
Теперь:
- Sale.quantity всегда в базовых единицах
- FIFO списание корректно
- StockBatch уменьшается на правильное количество
- Добавлено 'quantity_base' в список полей, влияющих на Stock
- Теперь Stock пересчитывается при изменении quantity_base
- Обновлена документация сигнала update_stock_on_reservation_change
КРИТИЧНО: Все агрегации Reservation.quantity заменены на quantity_base
Проблемы и решения:
🔴 КРИТИЧНО - BatchManager.write_off_by_fifo():
- Проблема: суммировал quantity вместо quantity_base
- Влияние: FIFO расчет свободного товара был некорректен
- Решение: aggregate(Sum('quantity_base')) в строках 118, 125
🟡 СРЕДНЯЯ ВАЖНОСТЬ - ShowcaseManager:
- reserve_showcase_item(): обновление quantity и quantity_base (строка 403)
- release_showcase_reservation(): обновление обоих полей (строка 481)
- Теперь витринные резервы полностью консистентны
🟡 СРЕДНЯЯ ВАЖНОСТЬ - TransformationService:
- confirm(): проверка доступности через quantity_base (строка 254)
- Корректная валидация при трансформации товаров
🟢 НИЗКАЯ ВАЖНОСТЬ - WriteOffDocumentService:
- update_item(): синхронизация quantity и quantity_base (строка 175)
- Полнота данных в резервах документов списания
🟢 НИЗКАЯ ВАЖНОСТЬ - Сигналы (signals.py):
- update_order_item_reservation(): обновление обоих полей для товаров
- Для обычных товаров: quantity_base = quantity_in_base_units (строка 1081)
- Для комплектов: quantity_base = quantity (компоненты в базовых) (строка 1107)
- Добавлено обновление sales_unit при изменении OrderItem
Архитектура:
- Принцип: quantity_base ВСЕГДА содержит количество в базовых единицах
- Все агрегации резервов используют quantity_base для корректных расчетов
- quantity сохраняется для совместимости и отображения
- sales_unit хранит ссылку на единицу продажи для аудита
- Проблема: debug_page показывал quantity вместо quantity_base для резервов
- Проблема: Stock.refresh_from_batches() суммировал quantity вместо quantity_base
- Решение:
- debug_page.html: добавлены колонки для единиц продажи и базовых единиц
- debug_page.html: теперь показывается quantity (ед.прод.) и quantity_base (базовые)
- models.py: Stock.refresh_from_batches() теперь суммирует quantity_base
- Теперь quantity_reserved и quantity_free отображаются корректно в базовых единицах
- Проблема: сигнал на Order срабатывал ДО вычисления quantity_in_base_units в OrderItem.save()
- Решение: переместили резервирование на сигнал post_save для OrderItem
- Теперь quantity_in_base_units гарантированно вычислено перед резервированием
- Изменения:
- signals.py: reserve_stock_on_order_create → reserve_stock_on_item_create
- Сигнал теперь на OrderItem вместо Order
- Резервы создаются для каждой позиции отдельно после её сохранения
- Проблема: при выборе товара через ProductSearchPicker, select оставался пустым
- Решение: динамическое создание <option> элемента с выбранным товаром
- Затронутые файлы:
- incoming_document_detail.html: функции selectProduct() и clearSelectedProduct()
- writeoff_document/detail.html: аналогичные исправления
- Теперь компонент корректно работает во всех документах системы
Добавлена полноценная интеграция единиц измерения (UoM) для продажи
товаров в разных единицах с автоматическим пересчётом цен и остатков.
## Основные изменения:
### Backend
- Расширен API поиска товаров (api_views.py): добавлена сериализация sales_units
- Создан новый endpoint get_product_sales_units_api для загрузки единиц с остатками
- Добавлено поле sales_unit в OrderItemForm и SaleForm с валидацией
- Созданы CRUD views для управления единицами продажи (uom_views.py)
- Обновлена ProductForm: использует base_unit вместо устаревшего unit
### Frontend
- Создан модуль sales-units.js с функциями для работы с единицами
- Интегрирован в select2-product-search.js: автозагрузка единиц при выборе товара
- Добавлены контейнеры для единиц в order_form.html и sale_form.html
- Реализовано автоматическое обновление цены при смене единицы продажи
- При выборе базовой единицы цена возвращается к базовой цене товара
### UI
- Добавлены страницы управления единицами продажи в навбар
- Созданы шаблоны: sales_unit_list.html, sales_unit_form.html, sales_unit_delete.html
- Добавлены фильтры по товару, единице, активности и дефолтности
## Исправленные ошибки:
- Порядок инициализации: обработчики устанавливаются ДО триггера события change
- Цена корректно обновляется при выборе единицы продажи
- При выборе "Базовая единица" возвращается базовая цена товара
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add new models UnitOfMeasure and ProductSalesUnit to enable selling products in different units (e.g., bunches, kg). Update Product model with base_unit field and methods for unit conversions and availability. Extend Sale, Reservation, and OrderItem models with sales_unit fields and snapshots. Modify SaleProcessor to handle quantity conversions. Include admin interfaces for managing units. Add corresponding database migrations.
- Replace large operation cards with smaller, uniform inventory-card components
- Update icon sizes and text styles for better visual hierarchy
- Group operations into a cleaner 4x3 grid layout using Bootstrap columns
- Simplify card hover effects with subtler shadows and background gradients
- Remove unused purple utility classes and old card-body styles
- Add focus outline support for accessibility on inventory cards
fix(customers): show total debt only when applicable and add external links
- Display total debt row only if debt is greater than zero in customer detail
- Remove redundant conditional inside debt display cell
- Add target="_blank" and rel attributes to order detail links to open in new tab
Проблема: при входе в localhost/admin/ (public схема) возникала ошибка
"relation user_roles_userrole does not exist", так как tenant-only
таблицы не существуют в public схеме.
Решение:
- Создан TenantAdminOnlyMixin для скрытия tenant-only моделей от public admin
- Применён миксин ко всем ModelAdmin классам в tenant-only приложениях:
user_roles, customers, orders, inventory, products
- Добавлена проверка _is_public_schema() в RoleBasedPermissionBackend
для предотвращения запросов к tenant-only таблицам в public схеме
Теперь:
- localhost/admin/ показывает только public модели (Client, Domain, User)
- shop.localhost/admin/ показывает все модели магазина
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Создан TenantOnboardingService как единый источник истины для:
- Активации заявки на регистрацию тенанта
- Создания Client, Domain, Subscription
- Инициализации системных данных (Customer, статусы, способы оплаты, склад, витрина)
Новые сервисы:
- TenantOnboardingService (tenants/services/onboarding.py)
- WarehouseService (inventory/services/warehouse_service.py)
- ShowcaseService (inventory/services/showcase_service.py)
- PaymentMethodService (orders/services/payment_method_service.py)
Рефакторинг:
- admin.py: 220 строк → 5 строк (делегирование сервису)
- init_tenant_data.py: 259 строк → 68 строк
- activate_registration.py: использует сервис
- Тесты обновлены для вызова сервиса напрямую
При создании тенанта автоматически создаются склад и витрина по умолчанию.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Основные изменения:
- Переименование ConfigurableKitProduct → ConfigurableProduct
- Добавлена поддержка Product как варианта (не только ProductKit)
- Создан справочник атрибутов (ProductAttribute, ProductAttributeValue)
- CRUD для управления атрибутами с inline редактированием значений
- Пересозданы миграции с нуля для всех приложений
- Добавлена ссылка на атрибуты в навигацию
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Implement `check_released_reservations_available` function to verify if items from released reservations are still available for re-sale when attempting to change a returned order's status
- Update `create_sale_on_order_completion` signal to use this check, allowing transitions to positive statuses only if items are available, otherwise blocking with ValidationError
- Wrap Order.save() in transaction.atomic() to ensure ValidationError in signals rolls back the save operation
- Add comprehensive tests for scenarios where items are available or used in other orders
- Update date carousel in order to always center on today's date and remove unnecessary saving logic
- Add test flag to Django Debug Toolbar settings
Closes#123 (assuming related issue)
- Remove WriteOffForm from forms.py and add comment directing to WriteOffDocumentForm
- Update navigation templates to remove writeoff links and sections
- Add 'Сумма' column to sale list with multiplication filter
- Delete writeoff-related templates (list, form, confirm delete)
- Add 'multiply' filter to inventory_filters.py for calculations
- Comment out writeoff URLs in urls.py, keeping WriteOff model for automatic creation
- Remove WriteOff views from __init__.py and delete writeoff.py view file
This change simplifies writeoff management by removing direct individual writeoff operations and enforcing use of WriteOffDocument for all writeoffs, with WriteOff records created automatically upon document processing.
Удалены все упоминания URL-паттерна 'movement-list' после удаления
модели StockMovement:
- Карточка "Журнал" на главной странице inventory
- Пункт меню "Журнал" в навигации base_inventory_minimal
- Экспорт StockMovementListView из views/__init__.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Текущее состояние перед рефакторингом Transfer → TransferDocument.
Все изменения с последнего коммита по улучшению системы поступлений.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Удалена старая одноэтапная система incoming и оставлена только новая
двухэтапная система IncomingDocument (черновик → проведение).
Изменения:
- URL структура изменена с /incoming-documents/ на /incoming/
- URL names: incoming-document-* → incoming-*
- Удалены старые views, forms, templates для Incoming/IncomingBatch
- Обновлена навигация и все ссылки в шаблонах
- Модели IncomingBatch/Incoming сохранены как внутренняя архитектура
Удалено ~1590 строк кода:
- inventory/views/incoming.py (389 строк)
- inventory/forms.py (206 строк старых форм)
- inventory/admin.py (56 строк)
- 4 шаблона incoming/*.html (895 строк)
Обновлено:
- inventory/urls.py - новая URL структура
- inventory/views/incoming_document.py - обновлены redirects
- Все шаблоны с ссылками на incoming
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Добавлено свойство can_edit в модель Incoming
- Добавлена проверка в IncomingUpdateView для запрета редактирования обработанных приходов
- Скрыта кнопка редактирования в списке приходов для обработанных записей
- Добавлено предупреждение в форму редактирования
Это предотвращает проблемы с целостностью данных при FIFO-списаниях, когда партия уже может быть использована в продажах.
Исправлена проблема, когда при отмене проведенной трансформации оба сигнала выполнялись последовательно:
- rollback_transformation_on_cancel возвращал резервы в 'reserved'
- release_reservations_on_draft_cancel ошибочно освобождал их в 'released'
Изменена проверка в release_reservations_on_draft_cancel: вместо проверки наличия партий Output (которые уже удалены) теперь проверяется статус резервов ('converted_to_transformation') или наличие поля converted_at, что работает независимо от порядка выполнения сигналов.
Реализована полная система трансформации товаров (превращение одного товара в другой).
Пример: белая гипсофила → крашеная гипсофила.
Особенности реализации:
- Резервирование входных товаров в статусе draft
- FIFO списание входных товаров при проведении
- Автоматический расчёт себестоимости выходных товаров
- Возможность отмены как черновиков, так и проведённых трансформаций
Модели (inventory/models.py):
- Transformation: документ трансформации (draft/completed/cancelled)
- TransformationInput: входные товары (списание)
- TransformationOutput: выходные товары (оприходование)
- Добавлен статус 'converted_to_transformation' в Reservation
- Добавлен тип 'transformation' в DocumentCounter
Бизнес-логика (inventory/services/transformation_service.py):
- TransformationService с методами CRUD
- Валидация наличия товаров
- Автоматическая генерация номеров документов
Сигналы (inventory/signals.py):
- Автоматическое резервирование входных товаров
- FIFO списание при проведении
- Создание партий выходных товаров
- Откат операций при отмене
Интерфейс без Django Admin:
- Список трансформаций (list.html)
- Форма создания (form.html)
- Детальный просмотр с добавлением товаров (detail.html)
- Интеграция с компонентом поиска товаров
- 8 views для полного CRUD + проведение/отмена
Миграция:
- 0003_alter_documentcounter_counter_type_and_more.py
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Отделена модель Delivery от Order (OneToOne связь)
- Добавлены обязательные поля delivery_date, time_from, time_to в Delivery
- Delivery обязательна при создании заказа (кроме черновиков)
- Добавлены методы calculate_total() и reset_delivery_cost() в Order
- Добавлена валидация полей доставки в OrderForm
- Исправлено создание доменов - убран порт из домена в БД
- Исправлен редирект после установки пароля (правильный формат URL)
- Исправлена ошибка NoReverseMatch в navbar для public схемы
- Удалены все старые миграции (база создается с нуля)
- Обновлены views для работы с новой моделью Delivery
- Add script to set correct permissions on static files after collectstatic
- Introduce collectstatic command in entrypoint with permission fixing
- Add WhiteNoise middleware for efficient static file serving without DB access
- Configure WhiteNoise static files storage backend in settings
- Set STATIC_ROOT path properly for Docker container environment
- Add fallback static files serving in Django urls for production without nginx
- Enhance inventory_detail.html scripts to log errors if JS files or components fail to load
- Add whitenoise package to requirements for static file serving support
- Добавлены поля snapshot_* в модель InventoryLine для фиксации значений на момент завершения
- Обновлен InventoryProcessor для сохранения snapshot перед обработкой
- Обновлен InventoryDetailView для отображения snapshot-значений в проведенных инвентаризациях
- Добавлена миграция 0018 для новых полей
- Теперь в проведенных инвентаризациях отображаются оригинальные значения и правильная разница, а не текущие скорректированные остатки
- Убран ID документа из отображения (было: WO-0000025, стало: WO-000002)
- Теперь отображается только document_number родительского документа
- Устранена путаница с номерами: WriteOffDocumentItem не имеет собственного номера
- Автоматическое проведение документов списания и оприходования после завершения инвентаризации
- Оптимизация SQL-запросов: устранение N+1, bulk-операции для Stock, агрегация для StockBatch и Reservation
- Изменение формулы расчета разницы: (quantity_fact + quantity_reserved) - quantity_available
- Переименование поля 'По факту' в 'Подсчитано (факт, свободные)'
- Добавлены столбцы 'В резервах' и 'Всего на складе' в таблицу инвентаризации
- Перемещение столбца 'В системе (свободно)' после 'В резервах' с визуальным выделением
- Центральное выравнивание значений в столбцах таблицы
- Автоматическое выделение текста при фокусе на поле ввода количества
- Исправление форматирования разницы (убраны лишние нули)
- Изменение статуса 'Не обработана' на 'Не проведено'
- Добавление номера документа для инвентаризаций (INV-XXXXXX)
- Отображение всех типов списаний в debug-странице (WriteOff, WriteOffDocument, WriteOffDocumentItem)
- Улучшение отображения документов в детальном просмотре инвентаризации с возможностью перехода к ним
- Fix MEDIA_ROOT path to match Docker volume mount (/app/myproject/media)
- Update docker-compose.yml volume mounts to match MEDIA_ROOT
- Add setup_directories() function in entrypoint.sh to create media directories with proper permissions
- Add logging to TenantAwareFileSystemStorage for debugging
- Fix is_returned flag logic improvements (from previous work)
- Унифицирован формат номеров документов: IN-XXXXXX (6 цифр), как WO-XXXXXX и MOVE-XXXXXX
- Убрано дублирование функции _extract_number_from_document_number
- Оптимизирована инициализация счетчика incoming: быстрая проверка перед полной инициализацией
- Удален неиспользуемый файл utils.py (функциональность перенесена в document_generator.py)
- Все функции генерации номеров используют единый подход через DocumentCounter.get_next_value()
- Добавлено поле receipt_type в модель IncomingBatch с типами: supplier, inventory, adjustment
- Исправлен баг в InventoryProcessor: теперь корректно создается IncomingBatch при инвентаризации
- Создан IncomingAdjustmentCreateView для оприходования без инвентаризации
- Обновлены формы, шаблоны и админка для поддержки разных типов поступлений
- Добавлена навигация и URL для оприходования
- Тип поступления отображается в списках приходов и партий
- Изменён TIME_ZONE с Europe/Moscow на Europe/Minsk в settings.py
- Исправлено создание заказов в POS: теперь используется timezone.localtime() для корректной конвертации UTC → Minsk
- delivery_date и delivery_time_start/end теперь сохраняются в минском времени, а не UTC
- Исправлена разница в 3 часа между временем создания заказа и фактическим временем
- Удалено устаревшее поле payment_method из showcase_manager.py (поле было удалено из модели Order)
Теперь все временные метки заказов соответствуют реальному минскому времени
- Добавлены методы reserve_product_to_showcase и release_showcase_reservation в ShowcaseManager
- Методы работают с резервами для всех активных экземпляров витринного комплекта
- НЕ блокируют создание резерва при нехватке товара, возвращают информацию о дефиците (overdraft)
- Обновлён API endpoint update_product_kit для корректировки резервов при изменении состава
- Добавлено визуальное предупреждение на фронте о нехватке товара на складе
- В модалке редактирования комплекта добавлены контролы для изменения количества товаров (+/-, поле ввода, удаление)
- Автоматический пересчёт цен при изменении состава
- Очистка корзины POS после успешного создания витринного комплекта