Commit Graph

11 Commits

Author SHA1 Message Date
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
d2b49cca56 Исправлено: агрегация резервов теперь использует quantity_base
КРИТИЧНО: Все агрегации 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 хранит ссылку на единицу продажи для аудита
2026-01-02 14:46:02 +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
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
0d72c36739 Исправлена продажа нескольких экземпляров витринного букета
Проблема:
При попытке продажи 2+ экземпляров одного витринного букета возникала ошибка
IntegrityError, так как поле sold_order_item было OneToOneField.
Это означало что к одному OrderItem мог быть привязан только один ShowcaseItem,
что делало невозможной продажу нескольких экземпляров в одной позиции заказа.

Решение:
1. Изменен тип поля sold_order_item с OneToOneField на ForeignKey
   - Теперь несколько ShowcaseItem могут относиться к одному OrderItem
   - related_name изменен с 'sold_showcase_item' на 'sold_showcase_items'

2. Обновлен метод mark_sold в модели ShowcaseItem
   - Добавлена явная проверка статуса 'sold' перед продажей
   - Генерируется ValidationError если экземпляр уже продан
   - Удален комментарий про OneToOneField защиту

3. Обновлена обработка ошибок в ShowcaseManager.sell_showcase_items
   - Убрана обработка IntegrityError
   - Добавлена обработка ValidationError от mark_sold

4. Создана миграция 0012_change_sold_order_item_to_fk

Теперь можно успешно продавать 2 и более экземпляров одного витринного букета
в рамках одной позиции заказа.
2025-12-11 22:23:41 +03:00
d5e40bb1c8 Исправлена продажа множественных экземпляров витринных букетов
Проблема: При продаже 2+ экземпляров одного витринного комплекта возникала
ошибка 'Один из экземпляров уже был продан'. Это происходило потому что
объекты ShowcaseItem проверялись по старому состоянию из памяти.

Причина:
- При вызове sell_showcase_items() передавался список объектов из запроса
- Первый ShowcaseItem менял статус на 'sold' через mark_sold()
- Второй объект в списке все еще имел старый статус из памяти
- Проверка в цикле срабатывала некорректно

Решение:
- Перезагружаем ВСЕ ShowcaseItem из БД с блокировкой перед обработкой
- Используем select_for_update() для получения актуального статуса
- Теперь каждый экземпляр проверяется по свежим данным из БД
- Защита от race conditions через database-level locking

Результат:
Теперь можно продавать 2+ экземпляра одного букета без ошибок.
2025-12-11 22:14:57 +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
08a5527ba7 Fix cart lock validation and error handling improvements
## 1. Add cart lock validation to sell_from_showcase()
- Prevent selling showcase kits locked in another cashier's cart
- Check cart_lock_expires_at before allowing direct sales
- Return clear error message with lock holder's name and time remaining
- File: inventory/services/showcase_manager.py

## 2. Improve error handling in POS create_temp_kit_to_showcase()
- Add detailed logging for all error types (JSON, validation, generic)
- Provide user-friendly error messages instead of generic 500
- Log full context (kit name, showcase ID, items, user) for debugging
- Categorize errors: stock issues, integrity, locks, not found
- File: pos/views.py

## 3. Fix critical bug in create_temporary_kit()
- Replace non-existent is_active field with status='active'
- Affects 3 locations: kit creation, product lookup, kit duplication
- This was causing 500 errors when creating temporary kits from order edit
- File: products/services/kit_service.py

## 4. Improve error handling in create_temporary_kit_api()
- Add comprehensive logging for order creation endpoint
- Provide specific error messages for common failure scenarios
- Help diagnose issues when creating kits from order editing UI
- File: products/views/api_views.py

These changes complete the Soft Lock system and fix the 500 error issue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 00:24:59 +03:00
ff0756498c Fix Product filtering and add kit disassembly functionality
Fixed:
- Replace is_active with status='active' for Product filtering in IncomingModelForm
- Product model uses status field instead of is_active

Added:
- Showcase field to ProductKit for tracking showcase placement
- product_kit field to Reservation for tracking kit-specific reservations
- Disassemble button in POS terminal for showcase kits
- API endpoint for kit disassembly (release reservations, mark discontinued)
- Improved reservation filtering when dismantling specific kits

Changes:
- ShowcaseManager now links reservations to specific kit instances
- POS terminal modal shows disassemble button in edit mode
- Kit disassembly properly updates stock aggregates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 23:03:47 +03:00
8f6acfb364 Добавлена функциональность витрин для POS: модели, сервисы, UI
- Создана модель Showcase (витрина) привязанная к складу
- Расширена Reservation для поддержки витринных резервов
- Добавлены поля в OrderItem для маркировки витринных продаж
- Реализован ShowcaseManager с методами резервирования, продажи и разбора
- Обновлён админ-интерфейс для управления витринами
- Добавлена кнопка Витрина в POS (категории) и API для просмотра
- Добавлена кнопка На витрину в панели действий POS
- Миграции готовы к применению
2025-11-16 21:12:22 +03:00