Исправлена форма заказа: две колонки и корректная работа кнопки сохранения

- Разделен экран на две колонки: заказ слева, оплата справа
- Форма оплаты вынесена за пределы основной формы заказа (устранена проблема вложенных форм)
- Исправлен метод calculate_total() для сохранения итоговой суммы в БД
- Добавлена модель Transaction для учета платежей и возвратов
- Добавлена модель PaymentMethod для методов оплаты
- Удалена старая модель Payment, заменена на Transaction
- Добавлен TransactionService для управления транзакциями
- Обновлен интерфейс форм оплаты для правой колонки
- Кнопка 'Сохранить изменения' теперь работает корректно
This commit is contained in:
2025-11-29 14:33:23 +03:00
parent 438ca5d515
commit c1351e1f49
14 changed files with 1188 additions and 548 deletions

View File

@@ -74,7 +74,7 @@ class WalletService:
def pay_with_wallet(order, amount, user):
"""
Оплата заказа из кошелька клиента.
Списывает средства с кошелька и создаёт платёж в заказе.
Создаёт транзакцию. Списание из кошелька происходит автоматически в Transaction.save().
Args:
order: Заказ для оплаты
@@ -84,15 +84,15 @@ class WalletService:
Returns:
Decimal: Фактически списанная сумма или None
"""
from customers.models import Customer, WalletTransaction
from orders.models import Payment, PaymentMethod
from customers.models import Customer
from orders.services.transaction_service import TransactionService
# Округляем запрошенную сумму
amount = _quantize(amount)
if amount <= 0:
return None
# Блокируем запись клиента
# Блокируем запись клиента для проверки баланса
customer = Customer.objects.select_for_update().get(pk=order.customer_id)
# Остаток к оплате по заказу
@@ -105,46 +105,24 @@ class WalletService:
if usable_amount <= 0:
return None
# Получаем способ оплаты "С баланса счёта"
try:
payment_method = PaymentMethod.objects.get(code='account_balance')
except PaymentMethod.DoesNotExist:
raise ValueError(
'Способ оплаты "account_balance" не найден. '
'Запустите команду create_payment_methods.'
)
# Создаём платёж в заказе
Payment.objects.create(
# Создаём транзакцию
# Transaction.save() автоматически спишет из кошелька и создаст WalletTransaction
TransactionService.create_payment(
order=order,
amount=usable_amount,
payment_method=payment_method,
created_by=user,
payment_method='account_balance',
user=user,
notes='Оплата из кошелька клиента'
)
# Уменьшаем баланс кошелька
customer.wallet_balance = _quantize(customer.wallet_balance - usable_amount)
customer.save(update_fields=['wallet_balance'])
# Создаём транзакцию для аудита
WalletTransaction.objects.create(
customer=customer,
amount=usable_amount,
transaction_type='spend',
order=order,
description=f'Оплата заказа #{order.order_number} из кошелька',
created_by=user
)
return usable_amount
@staticmethod
@transaction.atomic
def refund_wallet_payment(order, amount, user):
"""
Возврат средств в кошелёк при удалении платежа.
Увеличивает баланс кошелька и создаёт транзакцию deposit.
Возврат средств в кошелёк.
Используется для создания транзакции возврата с кошельком.
Args:
order: Заказ, по которому был платёж
@@ -154,27 +132,20 @@ class WalletService:
Returns:
Decimal: Возвращённая сумма
"""
from customers.models import Customer, WalletTransaction
from orders.services.transaction_service import TransactionService
amount = _quantize(amount)
if amount <= 0:
return None
# Блокируем запись клиента
customer = Customer.objects.select_for_update().get(pk=order.customer_id)
# Увеличиваем баланс
customer.wallet_balance = _quantize(customer.wallet_balance + amount)
customer.save(update_fields=['wallet_balance'])
# Создаём транзакцию возврата
WalletTransaction.objects.create(
customer=customer,
amount=amount,
transaction_type='deposit',
# Transaction.save() автоматически вернёт в кошелёк и создаст WalletTransaction
TransactionService.create_refund(
order=order,
description=f'Возврат платежа по заказу #{order.order_number}',
created_by=user
amount=amount,
payment_method='account_balance',
user=user,
reason='Возврат в кошелёк'
)
return amount