Commit Graph

27 Commits

Author SHA1 Message Date
9bd06cf5c6 Изменено поле quantity в OrderItem для поддержки дробных количеств
- Поле quantity изменено с PositiveIntegerField на DecimalField(max_digits=10, decimal_places=3)

- Это необходимо для корректной работы с единицами продажи (например, 2.5 банча)

- Создана миграция 0004_change_orderitem_quantity_to_decimal

- Теперь POS корректно обрабатывает товары с дробными количествами в единицах продажи
2026-01-02 18:01:49 +03:00
eab4f8a4ae Смягчена валидация времени доставки: разрешены равные времена начала и окончания
- Изменена проверка с >= на > в Delivery.clean()

- Равные времена разрешены для POS-продаж (самовывоз в точное время)

- Обновлены сообщения об ошибках валидации
2026-01-02 17:47:30 +03:00
5b68f14bb4 feat(products): add support for product sales units
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.
2026-01-02 02:09:44 +03:00
b1855cc9f0 Рефакторинг системы кошелька клиентов
Основные изменения:
- Переход от денормализованного поля wallet_balance к вычисляемому балансу
- Баланс теперь вычисляется как SUM(signed_amount) транзакций
- Добавлено кеширование баланса для производительности (5 минут)
- Новая модель WalletTransaction с полем signed_amount (может быть +/-)
- WalletService для всех операций с кошельком (deposit, spend, adjustment)
- Защита от отрицательного баланса и race conditions через select_for_update
- Добавлен balance_after в каждую транзакцию для аудита
- Обновлены миграции для переноса данных из старой схемы

Улучшения безопасности:
- Атомарные транзакции для всех операций с балансом
- Блокировка строк при модификации баланса
- Валидация недостаточности средств
- Обязательное описание для корректировок баланса

UI/UX изменения:
- Обновлён вывод баланса кошелька в деталях клиента
- Добавлена история транзакций с типами и описаниями
- Цветовая индикация положительных транзакций (зелёный)

Техническая документация:
- Добавлены docstrings для всех методов WalletService
- Комментарии к критичным участкам кода
- Примеры использования в docstrings
2025-12-28 00:02:09 +03:00
1654962ba2 feat(inventory): add validation for item availability in released reservations
- 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)
2025-12-27 02:31:43 +03:00
642b9551de Добавлены поля needs_product_photo и needs_delivery_photo в модель Order с toggle switches в форме 2025-12-25 12:26:09 +03:00
2f8a421e64 Улучшение модели Recipient: PhoneNumberField и поле notes
- Заменено поле phone с CharField на PhoneNumberField для автоматической нормализации телефонов
- Убран регион BY, установлен region=None для универсальности (поддержка номеров разных стран)
- Добавлено поле notes для дополнительной информации о получателе (мессенджеры, соцсети и т.д.)
- Улучшена логика поиска существующих получателей:
  * Использование нормализованного телефона из PhoneNumberField
  * Регистронезависимый поиск по имени (name__iexact)
  * Обновление notes при нахождении существующего получателя
- Обновлена форма OrderForm для работы с PhoneNumberField и новым полем notes
- Обновлен шаблон order_form.html для отображения нового поля
- Созданы миграции для изменений модели
2025-12-25 11:44:18 +03:00
298d797286 Исправление проблем с сохранением адреса, получателя и даты доставки
- Исправлено: адрес теперь сохраняется для черновиков заказов
- Исправлено: получатель корректно предзаполняется при редактировании заказа
- Исправлено: адрес при редактировании отображается в режиме 'новый' для возможности редактирования
- Исправлено: дата доставки корректно предзаполняется при редактировании заказа
- Исправлено: при редактировании получателя обновляется существующий объект вместо создания нового
- Улучшена логика обработки Delivery для черновиков (создание с опциональными полями)
- Улучшена логика обновления получателя через загрузку заказа из БД с select_related
2025-12-25 00:30:27 +03:00
61ce3f550d Улучшен интерфейс ввода даты и времени доставки
- Исправлены имена полей времени (time_from/time_to вместо delivery_time_start/end)
- Поля времени сделаны необязательными (дата остается обязательной)
- Добавлен улучшенный UI с быстрыми кнопками для даты и времени
- Поля ввода расположены в один ряд, кнопки быстрого выбора ниже
- Добавлены CSS и JS файлы для улучшенного интерфейса
- Обновлена валидация: время необязательно, но если указано одно - должно быть и другое
2025-12-24 18:25:20 +03:00
d62caa924b Упрощение системы получателей доставки
- Удалено избыточное поле customer_is_recipient из модели Order
- Добавлено свойство @property is_customer_recipient для обратной совместимости
- Заменены радиокнопки recipient_mode на чекбокс 'Другой получатель' в форме
- Добавлено поле recipient_source для выбора между историей и новым получателем
- Обновлен AddressService.process_recipient_from_form() для работы с чекбоксом
- Обновлены шаблоны: order_form.html (чекбокс вместо радиокнопок) и order_detail.html
- Удалено customer_is_recipient из admin и demo команды
- Создана миграция для удаления поля customer_is_recipient

Логика упрощена: recipient is None = получатель = покупатель, иначе - отдельный получатель
2025-12-24 17:54:57 +03:00
9f4f03e340 Исправление доступа к полям доставки после рефакторинга
- Добавлены свойства обратной совместимости в модель Order для доступа к полям доставки через связь delivery
- Исправлены фильтры по delivery_date в модели Customer (get_successful_orders_total)
- Исправлены фильтры в orders/filters.py для работы с delivery__delivery_date
- Добавлен select_related('delivery') в customer_detail view для оптимизации запросов

Исправляет ошибку FieldError: Cannot resolve keyword 'delivery_date' into field
2025-12-24 13:35:23 +03:00
94fe363cb1 Рефакторинг: отделение Delivery от Order, обязательные поля доставки, исправление доменов
- Отделена модель Delivery от Order (OneToOne связь)
- Добавлены обязательные поля delivery_date, time_from, time_to в Delivery
- Delivery обязательна при создании заказа (кроме черновиков)
- Добавлены методы calculate_total() и reset_delivery_cost() в Order
- Добавлена валидация полей доставки в OrderForm
- Исправлено создание доменов - убран порт из домена в БД
- Исправлен редирект после установки пароля (правильный формат URL)
- Исправлена ошибка NoReverseMatch в navbar для public схемы
- Удалены все старые миграции (база создается с нуля)
- Обновлены views для работы с новой моделью Delivery
2025-12-23 23:52:59 +03:00
6669d47cdf feat(orders): add recipient management and enhance order forms
- Introduced Recipient model to manage order recipients separately from customers.
- Updated Order model to link to Recipient, replacing recipient_name and recipient_phone fields.
- Enhanced OrderForm to include recipient selection modes: customer, history, and new.
- Added AJAX endpoint to fetch recipient history for customers.
- Updated admin interface to manage recipients and display recipient information in order details.
- Refactored address handling to accommodate new recipient logic.
- Improved demo order creation to include random recipients.
2025-12-23 00:08:41 +03:00
7b32cdcebf Обновления и новые функции: изменение шаблона клиента, обновление сигналов инвентаря, добавление снимков наборов и элементов заказа, обновление моделей заказов и продуктов 2025-12-18 00:14:24 +03:00
7d45106411 Убрана автоматическая обработка переплаты - только ручное управление 2025-11-29 20:42:58 +03:00
7c1780697a Добавлено свойство overpayment для корректного отображения переплаты 2025-11-29 20:38:15 +03:00
42eddc0fd1 Упрощена логика обработки переплаты - убрана автоматика из calculate_total
Проблема:
- calculate_total() пытался автоматически обрабатывать переплату
- Это приводило к дублированию логики и сложной отладке
- Нарушался принцип единственной ответственности

Решение:
- Удалена автоматическая обработка переплаты из Order.calculate_total()
- Теперь calculate_total() ТОЛЬКО считает сумму - всё
- Переплата обрабатывается ТОЛЬКО в TransactionService при создании платежей/возвратов
- Добавлено предупреждение в UI о переплате с инструкцией

Как работает теперь:
1. При оплате - TransactionService автоматически вызывает add_overpayment()
2. При изменении товаров - calculate_total() только пересчитывает сумму
3. Если появилась переплата - оператор видит предупреждение
4. Оператор вручную создаёт возврат в кошелёк через форму

Преимущества:
- Одно место ответственности за переплаты
- Прозрачность для оператора
- Нет скрытых автоматизмов
- Легко обслуживать и отлаживать
- Стандартный подход для e-commerce
2025-11-29 20:34:20 +03:00
575c5d0c2f Исправлена двойная обработка переплаты при изменении суммы заказа
Проблема:
- add_overpayment вызывался дважды:
  1. При оплате 300 руб (заказ 150) → +150 в кошелёк
  2. При изменении суммы до 100 → +200 в кошелёк
- Итого: 350 руб вместо правильных 200 руб

Причина:
- calculate_total() вызывал add_overpayment при любой переплате
- Не учитывалось, что переплата уже была обработана при оплате

Решение:
- Сохраняем old_total перед пересчётом
- Вызываем add_overpayment ТОЛЬКО если:
  - old_total > 0 (заказ уже существовал)
  - total_amount < old_total (сумма УМЕНЬШИЛАСЬ)
  - amount_paid > total_amount (есть переплата)
- Это предотвращает двойную обработку при первичной оплате

Теперь переплата обрабатывается корректно только при изменении суммы заказа
2025-11-29 20:28:00 +03:00
a7ccbbec48 Исправлен баг с переплатой при изменении суммы заказа
Проблема:
- Создан заказ на 150 руб, оплачено 300 руб → 150 руб в кошелёк
- Изменены товары, сумма стала 100 руб
- amount_paid остался 300, total_amount стал 100
- Новая переплата 200 руб НЕ переносилась в кошелёк автоматически

Решение:
- В Order.calculate_total() добавлена проверка переплаты после пересчёта суммы
- Если amount_paid > total_amount, вызывается WalletService.add_overpayment()
- Излишек автоматически переносится в кошелёк, amount_paid нормализуется до total_amount
- Создаётся WalletTransaction для аудита

Теперь при уменьшении суммы заказа переплата корректно возвращается клиенту
2025-11-29 20:23:25 +03:00
3f22677573 Защита от переплаты кошельком и улучшение отображения транзакций
Изменения в UI (order_form.html):
- Добавлен data-code к опциям способов оплаты для идентификации метода кошелька
- ID для селекта способа оплаты (payment-method-select) и поля суммы (payment-amount-input)
- Динамическое ограничение max на поле суммы платежа при выборе кошелька
- Подсказка 'Макс: X руб.' отображается только для оплаты кошельком
- Для внешних методов (карта, наличные) ограничение отсутствует — переплата допустима

Логика JS:
- При выборе метода с code == 'account_balance' устанавливается max = order.amount_due
- Для остальных методов max удаляется — оператор может внести сумму больше остатка
- Переплата по внешним методам корректно зачисляется в кошелёк через WalletService.add_overpayment

Серверная защита (transaction_service.py):
- В TransactionService.create_payment добавлена проверка:
  если payment_method.code == 'account_balance' и amount > order.amount_due — ValidationError
- Сообщение: 'Сумма оплаты из кошелька (X руб.) не может превышать остаток к оплате (Y руб.)'
- Защита от обхода UI через API или прямой вызов

Улучшение отображения (order_form.html, order_detail.html):
- Для возврата в кошелёк (transaction_type == 'refund' и code == 'account_balance') показываем 'на баланс счёта' вместо названия метода
- История становится понятнее: '−750,00 руб. Возврат 29.11.2025 на баланс счёта'

Сценарий:
- Кошелёк клиента 500 руб., заказ 65 руб.
- Оператор выбирает оплату из кошелька — поле суммы ограничено 65 руб.
- Попытка ввести 500 заблокирована UI и серверной валидацией
- Для внешней оплаты (карта онлайн) можно внести 500 руб. — остаток 435 автоматически зачислится в кошелёк как переплата

Цель:
- Исключить путаницу в истории транзакций при оплате кошельком
- Разграничить поведение: кошелёк строго ограничен, внешние методы допускают переплату
- Обеспечить прозрачность движения средств для операторов
2025-11-29 16:54:24 +03:00
c1351e1f49 Исправлена форма заказа: две колонки и корректная работа кнопки сохранения
- Разделен экран на две колонки: заказ слева, оплата справа
- Форма оплаты вынесена за пределы основной формы заказа (устранена проблема вложенных форм)
- Исправлен метод calculate_total() для сохранения итоговой суммы в БД
- Добавлена модель Transaction для учета платежей и возвратов
- Добавлена модель PaymentMethod для методов оплаты
- Удалена старая модель Payment, заменена на Transaction
- Добавлен TransactionService для управления транзакциями
- Обновлен интерфейс форм оплаты для правой колонки
- Кнопка 'Сохранить изменения' теперь работает корректно
2025-11-29 14:33:23 +03:00
cf1dce2621 Удалить поле discount_amount из модели Order
Убрано поле скидки из системы для последующей реализации полноценной системы скидок.

Изменения:
- Удалено поле discount_amount из модели Order
- Убрано из формы OrderForm
- Удалено из шаблонов order_form.html и order_detail.html
- Убрано из админки OrderAdmin
- Обновлен метод calculate_total() (без вычитания скидки)

В будущем будет создана отдельная модель Discount с промокодами, процентными скидками и автоматическими акциями.

ВАЖНО: После этого коммита нужно создать и применить миграцию:
  python manage.py makemigrations orders -n remove_discount_amount
  python manage.py migrate orders
2025-11-29 02:00:23 +03:00
f911a57640 Before simplifying order creation and editing 2025-11-28 23:11:34 +03:00
82ed5a409e Добавлена функциональность редактирования заказов с обновлением резервов товаров 2025-11-27 21:13:42 +03:00
c62cdb0298 feat: Add customer prefill from URL parameter in order creation
- Modified order_create view to read customer from GET parameter
- Pass preselected_customer to template context
- Template renders select with preselected option for Select2
- Fixed draft creation timing with callback after Select2 initialization
- Auto-create draft when customer is preselected from URL
- Graceful handling if customer not found or invalid ID
2025-11-27 00:17:02 +03:00
5ead7fdd2e Реализация системы кошелька клиента для переплат
- Добавлено поле wallet_balance в модель Customer
- Создана модель WalletTransaction для истории операций
- Реализован сервис WalletService с методами:
  * add_overpayment - автоматическое зачисление переплаты
  * pay_with_wallet - оплата заказа из кошелька
  * adjust_balance - ручная корректировка баланса
- Интеграция с Payment.save() для автоматической обработки переплат
- UI для оплаты из кошелька в деталях заказа
- Отображение баланса и долга на странице клиента
- Админка с inline транзакций и запретом ручного создания
- Добавлен способ оплаты account_balance
- Миграция 0004 для customers приложения
2025-11-26 14:47:11 +03:00
0653ec0545 Рефакторинг моделей заказов и добавление методов оплаты 2025-11-26 13:38:02 +03:00