Commit Graph

108 Commits

Author SHA1 Message Date
f75e861bb8 feat: Add new inventory and POS components, including a script to reproduce a POS checkout sale price bug. 2026-01-25 15:26:57 +03:00
2bc70968c3 fix(pos): restrict quantity editing for showcase kits in cart edit modal
For showcase kits (showcase_kit type), the quantity field is now disabled
in the cart item edit modal since these are pre-assembled physical items
with reservations. Price editing remains available.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 14:49:02 +03:00
38fbf36731 feat(pos): add write-off functionality for showcase kits
Add support for writing off showcase kits by creating a write-off document with components, converting reservations, and updating statuses.

- Add `write_off_from_showcase` static method to ShowcaseManager
- Add API endpoint `/pos/api/product-kits/<int:kit_id>/write-off/`
- Add write-off button to POS terminal UI
- Implement confirmation dialog with detailed information
- Add redirect to write-off document detail page after success

The write-off process includes:
1. Creating a write-off document in draft state
2. Converting existing reservations to write-off document items
3. Marking the showcase item as dismantled
4. Setting the product kit status to discontinued (if not already)

Breaking Changes: No
2026-01-24 03:21:56 +03:00
9c91a99189 refactor(pos): simplify showcase kit default name
Replace datetime-based naming with simple "Витринный букет XXX" format,
where XXX is a random 3-digit number (100-999). Date is now handled by
the separate showcase_created_at field.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 01:54:58 +03:00
1eec8b1cd5 chore(pos): remove debug logs from showcase date feature
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 01:44:56 +03:00
977ee91fee feat(pos): add editable showcase creation date for kits
- Add showcase_created_at field to ProductKit model
- Display days ago as badge in product card (0 дней, 1 день, etc.)
- Add date input field in edit modal
- Auto-set current date/time for new showcase kits

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 01:37:27 +03:00
22e300394b Исправление ошибки POS: разрешено добавление в корзину для PlatformAdmin (использование session_id вместо пользователя). Включены изменения по AI названиям букетов. 2026-01-22 20:29:05 +03:00
2dc36b3d01 fix(inventory): создавать Sale после применения скидок в POS checkout
Добавлен механизм skip_sale_creation на базе thread-local storage
для управления моментом создания Sale через сигнал.

Проблема: сигнал create_sale_on_order_completion срабатывал при
Order.objects.create(status=completed) до применения скидок.

Решение: пропускать сигнал во время создания заказа, затем явно
создавать Sale после применения всех скидок через order.save().

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 01:05:22 +03:00
d87c602f5a fix(pos): отключать чекбокс своей цены при актуализации цен в витринном комплекте
При нажатии "Пересчитать по актуальным ценам" чекбокс "Установить свою цену (приоритет)"
оставался включенным, из-за чего финальная цена не обновлялась.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 21:24:41 +03:00
2778796118 feat(pos): фиксировать цены товаров в витринных комплектах
- Добавлено поле KitItem.unit_price для хранения зафиксированной цены
- Витринные комплекты больше не обновляются при изменении цен товаров
- Добавлен красный индикатор на карточке если цена неактуальна
- Добавлен warning в модалке редактирования с кнопкой "Актуализировать"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 15:59:44 +03:00
392471ff06 fix(pos): использовать изменённые цены товаров при создании витринного комплекта
При создании витринного комплекта из корзины теперь учитываются
изменённые цены товаров вместо оригинальных.
2026-01-19 12:13:05 +03:00
1b749ebe63 fix(pos): исправить загрузку витринных комплектов
- Добавить display_name в CustomUser (name или email)
- Исправить get_showcase_kits_api: заменить username на display_name
- Использовать Case/When с output_field для выбора имени на уровне БД

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 00:15:11 +03:00
017fa4b744 feat(pos): добавить редактирование цены товара в корзине
- Добавить модалку редактирования товара в корзине (edit_cart_item_modal.html)
- Создать JS модуль cart-item-editor.js для логики редактирования
- При клике на строку товара открывается модалка с возможностью изменения цены и количества
- Добавить визуальную индикацию изменённой цены (оранжевый цвет и звёздочка)
- Экспортировать корзину в window.cart для доступа из других модулей
- Добавить авто-выделение текста при фокусе в полях ввода

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 22:08:58 +03:00
ab1e8ebd18 feat(mobile): скрыть виртуальную клавиатуру по enter
Добавляет обработчик события keydown для поля поиска. При нажатии
клавиши Enter вызывается метод blur(), чтобы скрыть виртуальную
клавиатуру на мобильных устройствах.
2026-01-18 15:35:44 +03:00
c4e7efc3b1 feat(mobile): добавить дропдаун "Ещё" в действия корзины
Добавлена кнопка выпадающего меню в мобильный интерфейс для доступа
к дополнительным функциям: "Отложенный заказ" и "На витрину".

Обновлен шаблон terminal.html с добавлением структуры дропдауна.
Добавлены стили в terminal.css для адаптивного отображения.
Реализована логика в terminal.js для обработки кликов по мобильным
кнопкам и вызова соответствующих десктопных действий.
2026-01-18 01:24:48 +03:00
c77fcaf669 feat: Добавить мобильную адаптацию для POS-терминала
- Добавить фиксированную панель корзины внизу экрана на мобильных
  - Отображение количества товаров и суммы
  - Кнопки "Продать" и "Очистить" всегда доступны
  - Тап на панель открывает корзину как overlay

- Фиксировать поиск и категории сверху на мобильных
  - Поиск всегда виден при скролле
  - Категории в collapsible-блоке (сворачиваются)
  - Категории в 3 колонки на мобильных

- Улучшить поиск по токенам (разбивает фразу на слова)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 23:03:40 +03:00
2f1f0621e6 feat: упростить создание заказов и рефакторинг единиц измерения
- Добавить inline-редактирование цен в списке товаров
- Оптимизировать карточки товаров в POS-терминале
- Рефакторинг моделей единиц измерения
- Миграция unit -> base_unit в SalesUnit
- Улучшить UI форм создания/редактирования товаров

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 03:34:43 +03:00
928b340486 style(pos): улучшить адаптивность сетки товаров
- Изменить брейкпоинт для 5 колонок с 992px на 1100px
- Увеличить ширину правой панели с 4/12 до 5/12 колонок

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 03:11:00 +03:00
18cca326af feat(pos): улучшить адаптивность POS-терминала для мобильных устройств
- col-md-8/4 → col-12 col-md-8/4 для корректного отображения на мобильных
- Кнопки действий: height: 60px → min-height: 44px (минимальный размер для тапа)
- Модальные окна: добавлен modal-fullscreen-sm-down/md-down
- Колонки внутри модалок: добавлен col-12 для мобильной адаптивности
- Увеличена мелкая кнопка отмены скидки: 32px → 40px
- CSS: добавлены медиа-запросы для мобильных устройств
  * min-height: 44px для полей ввода и кнопок
  * font-size: 16px предотвращает зум на iOS
  * Оптимизация отступов в модалках
  * UX улучшения для тач-устройств
  * Плавная прокрутка на iOS
- Исправлено перекрытие товаров корзиной на мобильных (position: absolute → relative)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 19:21:05 +03:00
c8284a6ac5 fix(pos): отключить автофокус на мобильных устройствах
Добавлено определение мобильных устройств через User-Agent и ширину экрана.
Фокус на поле поиска и поле ввода количества теперь устанавливается только
на десктопах, чтобы избежать появления экранной клавиатуры на мобильных.
2026-01-16 19:06:36 +03:00
c070e42cab feat(discounts, orders): рефакторинг системы скидок - единый источник правды
- Добавлен combine_mode в форму создания/редактирования скидок
- Добавлена колонка "Объединение" в список скидок с иконками
- Добавлен фильтр по режиму объединения скидок
- Добавлена валидация: только одна exclusive скидка на заказ
- Удалены дублирующие поля из Order и OrderItem:
  - applied_discount, applied_promo_code, discount_amount
- Скидки теперь хранятся только в DiscountApplication
- Добавлены свойства для обратной совместимости

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 13:46:02 +03:00
f57e639dbe feat(discounts): добавлено комбинирование скидок по режимам
Добавлено поле combine_mode с тремя режимами:
- stack - складывать с другими скидками
- max_only - применять только максимальную
- exclusive - отменяет все остальные скидки

Изменения:
- Модель Discount: добавлено поле combine_mode
- Calculator: новый класс DiscountCombiner, методы возвращают списки скидок
- Applier: создание нескольких DiscountApplication записей
- Admin: отображение combine_mode с иконками
- POS API: возвращает списки применённых скидок
- POS UI: отображение нескольких скидок с иконками режимов

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 12:56:38 +03:00
42d8c34e8c feat(pos): добавлен полноценный интерфейс скидок в модальное окно продажи
- Добавлен API endpoint /pos/api/discounts/available/ для получения списка доступных скидок
- Добавлен метод DiscountApplier.apply_manual_discount() для применения ручных скидок
- Обновлен POS checkout для обработки manual_discount_id
- Расширена секция скидок в модальном окне:
  * Отображение автоматических скидок (read-only)
  * Dropdown для выбора скидки вручную
  * Подробная детализация: подитог, общая скидка, скидки на позиции
  * Поле промокода с иконкой
- Увеличен размер модального окна и изменено соотношение колонок (5/7)
- Убрана вертикальная прокрутка из модального окна

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 01:59:43 +03:00
6313b8f6e7 fix(pos): исправлена проблема с CSRF токеном при API запросах
- Заменен getCookie('csrftoken') на getCsrfToken() во всех fetch запросах
  (checkAutoDiscounts, applyPromoCode, handleCheckoutSubmit и др.)
- Это исправляет ошибку 403 Forbidden, возникающую из-за CSRF_USE_SESSIONS=True

fix(discounts): исправлен фильтр товаров в CRUD скидок

- Изменен фильтр с is_active=True на status='active' для корректной
  работы с моделью Product

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 01:41:17 +03:00
6978f4e59f feat(pos): интеграция системы скидок в POS терминал
API endpoints:
- POST /api/discounts/validate-promo/: валидация промокода
- POST /api/discounts/calculate/: расчёт скидок для корзины

Обновлён pos_checkout:
- добавлен параметр promo_code в payload
- автоматическое применение скидок к заказу

UI (terminal.html):
- секция скидок в модальном окне оплаты
- поле ввода промокода
- отображение автоматических скидок
- кнопки применения/удаления промокода

JavaScript (terminal.js):
- переменные состояния скидок
- функции applyPromoCode, removePromoCode
- checkAutoDiscounts: проверка автоматических скидок
- updateCheckoutTotalWithDiscounts: пересчёт итога
- обработчики кнопок промокода

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 00:30:55 +03:00
4ea01b8269 fix(inventory, orders, pos): удалена зависимость от django-simple-history для tenant-моделей
- Добавлен pre_save сигнал для Order вместо django-simple-history
- Переписаны все функции signals.py без использования instance.history
- Заменены .username на .name|default:.email для CustomUser в шаблонах
- Исправлен CSRF-токен в POS для работы с CSRF_USE_SESSIONS=True

Теперь создание заказов работает корректно в мультитенантной архитектуре.
2026-01-10 17:21:00 +03:00
d44ae0b598 Добавлен расчёт и отображение доступного количества комплектов
- Добавлен метод calculate_available_quantity() в модель ProductKit для точного расчёта максимального количества комплектов на основе свободных остатков компонентов
- Обновлён метод check_availability() для использования нового расчёта (обратная совместимость)
- Удалён устаревший сервис kit_availability.py

Исправлено отображение остатков комплектов:
- products_list.html: вместо прочерка показывается количество комплектов
- catalog.html: добавлено отображение доступного количества комплектов с цветовой индикацией
- POS terminal.js: в карточке товара показывается конкретное количество вместо общего 'В наличии'

Обновлены представления:
- ProductsListView: аннотирует комплекты атрибутом total_free
- CatalogView: рассчитывает доступное количество для каждого комплекта
- POS get_products(): убран хардкод, используется реальный расчёт по складу
2026-01-06 01:02:28 +03:00
a1f5557036 Исключены зарезервированные букеты из отображения в POS
- inventory/views/showcase.py: фильтр .exclude(status='reserved')
  * Витринные букеты со статусом 'reserved' не отображаются в POS
  * Защита от конфликтов: один букет - один заказ
- pos/views.py: фильтр .exclude(showcase_items__status='reserved')
  * Showcase комплекты без доступных букетов скрыты в POS
  * Фильтрация на уровне queryset для производительности
- Консистентная видимость витрины для всех кассиров
2026-01-05 01:39:14 +03:00
b1e728f91b Обновлён frontend для отложенных заказов с резервированием витринных букетов
- pos/static/pos/js/terminal.js: переработана функция createDeferredOrder()
- Новый flow:
  1. Вызывает POST /orders/api/create-from-pos/ для создания Order (draft)
  2. Получает order_number в ответе
  3. ShowcaseItem резервируются на backend (in_cart → reserved)
  4. Очищает корзину POS (cart.clear + saveCartToRedis)
  5. Перезагружает витрину (refreshShowcaseKits) для синхронизации UI
  6. Открывает /orders/<order_number>/edit/ в новой вкладке
- Устранена race condition: резервирование ДО очистки корзины
- Витринные букеты корректно исчезают из POS после резервирования
2026-01-05 01:36:40 +03:00
b7db4cd162 conventional-commit
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
2026-01-04 16:18:57 +03:00
2995710a3e Исправлена передача единиц продажи при создании отложенного заказа из POS
- В terminal.js добавлена передача sales_unit_id в данные черновика заказа

- В order_form.html добавлено заполнение поля sales_unit при предзаполнении из черновика

- Теперь при создании отложенного заказа с товаром в единицах продажи сохраняется корректная единица измерения
2026-01-02 18:33:51 +03:00
f0327b264c Добавлена поддержка единиц продажи в POS checkout
- При создании OrderItem теперь передаётся sales_unit из данных корзины

- Это позволяет корректно рассчитывать total_amount для товаров с единицами продажи

- Исправлена ошибка когда сумма заказа была 0 при использовании единиц продажи
2026-01-02 17:51:01 +03:00
275bc1b78d Исправлена ошибка создания заказов в POS после рефакторинга модели доставки
- Обновлён 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'
2026-01-02 17:46:32 +03:00
1ead77b2d8 Добавлено округление количества для корректного отображения в POS
Проблема:

- JavaScript float arithmetic даёт погрешность при вычислениях

- На карточке товара показывалось -0.050000000000044

- Происходило при: available - reserved - inCart

Решение:

- Добавлена функция roundQuantity(value, decimals=3)

- Округляет результат вычислений до 3 знаков после запятой

- Применяется ТОЛЬКО для отображения, не для расчётов

- Используется для: free, reserved, inCart в карточках товаров

Результат:

- Отображение: -0.05 вместо -0.050000000000044

- Данные с бэка остаются точными (строка)

- Погрешность устранена только визуально

Примечание:

- Округление в JS НЕИЗБЕЖНО для отображения

- Это НЕ маскировка - это правильное форматирование

- Бэкенд уже отдаёт точные данные как строки
2026-01-02 15:38:41 +03:00
4d121e95af Исправлено: передача free_qty как строки для сохранения точности
Проблема:

- free_qty передавался как float(decimal) в JSON API

- При конвертации Decimal→float терялась точность

- JavaScript показывал -0.050000000000044 вместо -0.05

Решение:

- free_qty теперь передаётся как строка: str(free_qty)

- Добавлено отдельное поле free_qty_sort (float) для сортировки

- После сортировки free_qty_sort удаляется из результата

- JavaScript parseFloat() корректно парсит строку без потери точности

Результат:

- Отображение остатков точное: -0.05 вместо -0.050000000000044

- Нет округления на фронте - видны реальные данные

- Сортировка по остаткам работает корректно
2026-01-02 15:30:00 +03:00
bb821f9ef4 Исправление отображения фото в POS и улучшение обработки изображений
- Исправлен POS для использования миниатюр вместо оригиналов для быстрой загрузки
- Убран fallback на оригиналы - показываем миниатюру или ничего (лучше видно ошибки)
- Исправлен ImageService - возвращает пустую строку если миниатюра обработанного файла не найдена
- Исправлена ошибка JavaScript при массовом удалении фото (insertAdjacentElement на null)
- Добавлен контейнер photos-messages-container для надежного отображения сообщений
- Улучшено логирование ImageService для отладки путей к файлам
- Добавлена проверка exists() с детальным логированием в TenantAwareFileSystemStorage
2025-12-21 19:52:55 +03:00
34e5a0143b Исправлено время заказов: переход на минский часовой пояс (Europe/Minsk)
- Изменён 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)

Теперь все временные метки заказов соответствуют реальному минскому времени
2025-12-14 15:27:03 +03:00
ce2cfca3f2 Добавлена возможность добавлять новые товары в витринный комплект при редактировании
- Интегрирован готовый компонент ProductSearchPicker в модалку редактирования
- Добавлен collapse-блок с поиском товаров, который отображается только в режиме редактирования
- При выборе товара он автоматически добавляется в tempCart или увеличивается количество если уже есть
- Добавлен CSS и JS для компонента product-search-picker
- В view передаётся categories QuerySet для работы фильтров компонента
- Блок добавления товаров показывается только при редактировании, скрыт при создании нового комплекта
2025-12-14 14:00:51 +03:00
aff25d0317 Реализована возможность редактирования состава витринного комплекта с поддержкой отрицательных резервов
- Добавлены методы reserve_product_to_showcase и release_showcase_reservation в ShowcaseManager
- Методы работают с резервами для всех активных экземпляров витринного комплекта
- НЕ блокируют создание резерва при нехватке товара, возвращают информацию о дефиците (overdraft)
- Обновлён API endpoint update_product_kit для корректировки резервов при изменении состава
- Добавлено визуальное предупреждение на фронте о нехватке товара на складе
- В модалке редактирования комплекта добавлены контролы для изменения количества товаров (+/-, поле ввода, удаление)
- Автоматический пересчёт цен при изменении состава
- Очистка корзины POS после успешного создания витринного комплекта
2025-12-14 13:49:13 +03:00
4ce610985b Исправлен порядок операций при конвертации резервов в продажи
Проблема:
При продаже витринного комплекта резервы оставались в статусе 'reserved'
вместо 'converted_to_sale'. Товары из состава комплекта не освобождались.

Причина:
В методе sell_showcase_items порядок операций был неправильный:
1. create_sale_from_reservation вызывался ПЕРВЫМ
2. reservation.order_item устанавливался ПОСЛЕ

В SaleProcessor.create_sale_from_reservation есть логика:
  if order and reservation.order_item:
      sale_price = reservation.order_item.price
  else:
      sale_price = reservation.product.actual_price

Так как order_item был None, цена бралась из product.actual_price,
а не из OrderItem, и резерв не конвертировался корректно.

Решение:
Правильный порядок операций:
1. Устанавливаем reservation.order_item = order_item
2. Сохраняем reservation
3. Вызываем create_sale_from_reservation (теперь order_item доступен)
4. Обновляем статус на 'converted_to_sale'
5. Сохраняем финальное состояние

Теперь резервы корректно преобразуются в продажи с правильной ценой
из позиции заказа, и товары освобождаются после продажи.
2025-12-11 22:55:06 +03:00
95cb1c4bac Рефакторинг: убрано дублирование валидации витринных комплектов
Проблема:
Валидация showcase_items выполнялась в двух местах:
1. В pos/views.py - проверка status='in_cart' БЕЗ блокировки БД
2. В showcase_manager.py - перезагрузка с select_for_update() и повторная проверка

Это создавало:
- Дублирование кода и логики
- Возможность race condition между двумя запросами
- Избыточные обращения к БД
- Мертвый код (неработающие logger.info)

Решение (best practices):
1. Views только загружают объекты по ID без фильтров по статусу
2. ВСЯ валидация и бизнес-логика в одном месте - ShowcaseManager.sell_showcase_items
3. select_for_update() гарантирует актуальность данных и блокировку на уровне БД
4. Удален мертвый код (logger.info которые не выполнялись)
5. Убрано избыточное логирование ошибок валидации

Результат:
- Единое место ответственности (Single Responsibility)
- Нет дублирования
- Атомарная транзакция с блокировкой
- Чистый, понятный код без костылей
2025-12-11 22:27:15 +03:00
8dc6594334 Добавлено подробное логирование ошибок валидации в POS checkout
Для диагностики проблемы с продажей витринных комплектов добавлено
логирование ValidationError с полным traceback. Это поможет определить
в какой именно момент и почему происходит ошибка валидации.
2025-12-11 22:21:11 +03:00
37c203a783 Добавлена валидация и логирование для продажи витринных комплектов в POS
Проблема: Продолжает возникать ошибка 'Один из экземпляров уже был продан'
при попытке продажи витринных букетов.

Изменения для диагностики:
1. Добавлена валидация showcase_item_ids ПЕРЕД передачей в sell_showcase_items
2. Проверка что все экземпляры имеют status='in_cart' и locked_by_user=текущий
3. Фильтр по статусу исключает уже проданные/разобранные экземпляры
4. Добавлено детальное логирование:
   - Запрошенные showcase_item_ids
   - Количество найденных заблокированных экземпляров
   - Недостающие IDs если не все найдены

Улучшенное сообщение об ошибке:
Вместо 'уже был продан' теперь 'уже не заблокированы на вас' с просьбой
обновить страницу - более понятно для пользователя.

Логи помогут выявить:
- Передаются ли дубликаты в showcase_item_ids
- Истекают ли блокировки до момента продажи
- Меняется ли статус экземпляров между добавлением в корзину и checkout
2025-12-11 22:18:16 +03:00
741fdc97a8 Добавлены кнопки +/- для управления количеством витринных комплектов в корзине
Теперь витринные букеты можно увеличивать и уменьшать по экземплярам:

UI изменения:
- Заменен badge на полноценные кнопки +/- как у обычных товаров
- Поле количества readonly с желтым фоном для визуального отличия
- Кнопки используют тот же дизайн что и для обычных товаров

Функционал увеличения (increaseShowcaseKitQty):
- Блокирует еще один доступный экземпляр через API
- Проверяет наличие свободных букетов на витрине
- Показывает сообщение если нет доступных
- Обновляет showcase_item_ids и qty в корзине

Функционал уменьшения (decreaseShowcaseKitQty):
- Снимает блокировку с последнего экземпляра из списка
- При qty=1 полностью удаляет из корзины
- Обновляет список витрины после изменения

Все операции синхронизируются с сервером и Redis.
2025-12-11 22:10:06 +03:00
b396029554 Исправлено восстановление витринных комплектов из корзины при перезагрузке страницы
Проблема: Витринные букеты исчезали из корзины после перезагрузки страницы,
но оставались заблокированными на пользователя через ShowcaseItem.

Решение:
- Изменена валидация корзины при загрузке из Redis
- Теперь проверяется наличие showcase_item_ids в данных корзины
- Блокировки валидируются через ShowcaseItem (не Reservation)
- Проверяется: status='in_cart', locked_by_user, cart_lock_expires_at > now()
- Обновляется qty на актуальное количество действующих блокировок
- Если ни один ShowcaseItem не заблокирован - не восстанавливается в корзину

Теперь витринные букеты корректно восстанавливаются при перезагрузке
и автоматически удаляются из корзины при истечении блокировки.
2025-12-11 22:05:15 +03:00
65ffed2f9b Блокировка кнопки 'НА ВИТРИНУ' при наличии витринного комплекта в корзине
- Добавлена проверка наличия витринных комплектов (showcase_kit) в корзине
- Кнопка 'НА ВИТРИНУ' блокируется при наличии витринного букета
- Добавлено визуальное оформление: opacity 0.5, disabled state, tooltip
- Показывается предупреждение при попытке создать новый букет
- Функция updateShowcaseButtonState() вызывается при каждом изменении корзины
2025-12-11 22:01:32 +03:00
c76163640e Рефакторинг POS терминала: устранение дублирования кода и оптимизация UI
- Удалены дублирующиеся функции getCookie() и getCsrfToken() в terminal.js
- Оставлена единая версия getCookie() с алиасом getCsrfToken для совместимости
- Удалены неиспользуемые пустые кнопки из панели действий
- Добавлена логика скрытия поля 'Количество букетов' в режиме редактирования комплекта
- Оптимизирована компоновка кнопок действий (используется offset-4)
- Улучшены комментарии в коде

Результат: -44 строки, код стал чище и поддерживаемее
2025-12-10 00:35:56 +03:00
5c94a5ab95 POS: улучшения работы с витринными букетами
- Упрощено добавление в корзину: 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>
2025-12-10 00:23:00 +03:00
cfc6ce451e ShowcaseItem: защита от двойной продажи витринных букетов
Новая архитектура:
- 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>
2025-12-09 23:51:37 +03:00
40b180171a Исправлена кнопка ОТЛОЖЕННЫЙ заказ - удален старый обработчик 2025-12-08 19:00:54 +03:00