Проблема:
- calculate_total() пытался автоматически обрабатывать переплату
- Это приводило к дублированию логики и сложной отладке
- Нарушался принцип единственной ответственности
Решение:
- Удалена автоматическая обработка переплаты из Order.calculate_total()
- Теперь calculate_total() ТОЛЬКО считает сумму - всё
- Переплата обрабатывается ТОЛЬКО в TransactionService при создании платежей/возвратов
- Добавлено предупреждение в UI о переплате с инструкцией
Как работает теперь:
1. При оплате - TransactionService автоматически вызывает add_overpayment()
2. При изменении товаров - calculate_total() только пересчитывает сумму
3. Если появилась переплата - оператор видит предупреждение
4. Оператор вручную создаёт возврат в кошелёк через форму
Преимущества:
- Одно место ответственности за переплаты
- Прозрачность для оператора
- Нет скрытых автоматизмов
- Легко обслуживать и отлаживать
- Стандартный подход для e-commerce
Проблема:
- 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 (есть переплата)
- Это предотвращает двойную обработку при первичной оплате
Теперь переплата обрабатывается корректно только при изменении суммы заказа
Проблема:
- Создан заказ на 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 для аудита
Теперь при уменьшении суммы заказа переплата корректно возвращается клиенту
Изменения в 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 автоматически зачислится в кошелёк как переплата
Цель:
- Исключить путаницу в истории транзакций при оплате кошельком
- Разграничить поведение: кошелёк строго ограничен, внешние методы допускают переплату
- Обеспечить прозрачность движения средств для операторов
- Разделен экран на две колонки: заказ слева, оплата справа
- Форма оплаты вынесена за пределы основной формы заказа (устранена проблема вложенных форм)
- Исправлен метод calculate_total() для сохранения итоговой суммы в БД
- Добавлена модель Transaction для учета платежей и возвратов
- Добавлена модель PaymentMethod для методов оплаты
- Удалена старая модель Payment, заменена на Transaction
- Добавлен TransactionService для управления транзакциями
- Обновлен интерфейс форм оплаты для правой колонки
- Кнопка 'Сохранить изменения' теперь работает корректно
Убрано поле скидки из системы для последующей реализации полноценной системы скидок.
Изменения:
- Удалено поле 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
- 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
- Добавлено поле wallet_balance в модель Customer
- Создана модель WalletTransaction для истории операций
- Реализован сервис WalletService с методами:
* add_overpayment - автоматическое зачисление переплаты
* pay_with_wallet - оплата заказа из кошелька
* adjust_balance - ручная корректировка баланса
- Интеграция с Payment.save() для автоматической обработки переплат
- UI для оплаты из кошелька в деталях заказа
- Отображение баланса и долга на странице клиента
- Админка с inline транзакций и запретом ручного создания
- Добавлен способ оплаты account_balance
- Миграция 0004 для customers приложения