Реализована полноценная система оплаты для POS-терминала
Добавлена интеграция оплаты в POS с поддержкой одиночной и смешанной оплаты, работой с кошельком клиента и автоматическим созданием заказов. Backend изменения: - TransactionService: добавлены методы get_available_payment_methods() и create_multiple_payments() для фильтрации способов оплаты и атомарного создания нескольких платежей - POS API: новый endpoint pos_checkout() для создания заказов со статусом "Выполнен" с обработкой платежей, освобождением блокировок и очисткой корзины - Template tags: payment_tags.py для получения способов оплаты в шаблонах Frontend изменения: - PaymentWidget: переиспользуемый ES6 класс с поддержкой single/mixed режимов, автоматической валидацией и интеграцией с кошельком клиента - terminal.html: компактное модальное окно (70vw) с оптимизированной компоновкой, удален функционал скидок, добавлен показ баланса кошелька - terminal.js: динамическая загрузка PaymentWidget, интеграция с backend API, обработка успешной оплаты и ошибок Поддерживаемые способы оплаты: наличные, карта, онлайн, баланс счёта. Смешанная оплата позволяет комбинировать несколько способов в одной транзакции. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -235,3 +235,74 @@ class TransactionService:
|
||||
Decimal: Сумма, которую можно вернуть
|
||||
"""
|
||||
return max(order.amount_paid, Decimal('0'))
|
||||
|
||||
@staticmethod
|
||||
def get_available_payment_methods(exclude_codes=None, only_active=True):
|
||||
"""
|
||||
Получить список доступных способов оплаты.
|
||||
|
||||
Args:
|
||||
exclude_codes: list[str] - коды для исключения (например ['legal_entity'])
|
||||
only_active: bool - только активные методы
|
||||
|
||||
Returns:
|
||||
QuerySet[PaymentMethod]
|
||||
"""
|
||||
from orders.models import PaymentMethod
|
||||
|
||||
qs = PaymentMethod.objects.all()
|
||||
|
||||
if only_active:
|
||||
qs = qs.filter(is_active=True)
|
||||
|
||||
if exclude_codes:
|
||||
qs = qs.exclude(code__in=exclude_codes)
|
||||
|
||||
return qs.order_by('order', 'name')
|
||||
|
||||
@staticmethod
|
||||
@transaction.atomic
|
||||
def create_multiple_payments(order, payments_list, user):
|
||||
"""
|
||||
Создать несколько платежей за одну транзакцию (смешанная оплата).
|
||||
|
||||
Args:
|
||||
order: Order
|
||||
payments_list: list[dict] - [{'payment_method': code_or_object, 'amount': Decimal, 'notes': str}, ...]
|
||||
user: CustomUser
|
||||
|
||||
Returns:
|
||||
list[Transaction]
|
||||
|
||||
Raises:
|
||||
ValidationError: если сумма превышает amount_due или недостаточно средств
|
||||
"""
|
||||
from orders.models import Transaction
|
||||
|
||||
transactions = []
|
||||
total_amount = Decimal('0')
|
||||
|
||||
# Валидация общей суммы
|
||||
for payment_data in payments_list:
|
||||
amount = _quantize(payment_data['amount'])
|
||||
if amount <= 0:
|
||||
raise ValueError(f'Сумма платежа должна быть положительной: {amount}')
|
||||
total_amount += amount
|
||||
|
||||
if total_amount > order.amount_due:
|
||||
raise ValidationError(
|
||||
f'Общая сумма платежей ({total_amount}) превышает сумму к оплате ({order.amount_due})'
|
||||
)
|
||||
|
||||
# Создаём транзакции
|
||||
for payment_data in payments_list:
|
||||
txn = TransactionService.create_payment(
|
||||
order=order,
|
||||
amount=payment_data['amount'],
|
||||
payment_method=payment_data['payment_method'],
|
||||
user=user,
|
||||
notes=payment_data.get('notes')
|
||||
)
|
||||
transactions.append(txn)
|
||||
|
||||
return transactions
|
||||
|
||||
Reference in New Issue
Block a user