""" Banking/payment services. transaction_initiate is called by checkout (and others) to start a payment flow. Replace the stub with real gateway integration (e.g. Razorpay). """ from decimal import Decimal from django.contrib.auth import get_user_model from banking_operations.models import PaymentTransaction, PaymentGateway User = get_user_model() def transaction_initiate( request, user, amount, currency="INR", reference_type="checkout", reference_id=None, bookings=None, extra_data=None, ): """ Initiate a payment transaction (e.g. create Razorpay order and return payment URL). Args: request: Django request (for building URLs, gateway config, etc.). user: User instance (customer). amount: Total amount in payment currency (Decimal or float). currency: Currency code, e.g. "INR". reference_type: Application reference type, e.g. "checkout". reference_id: Application reference id (e.g. booking_ids or order id). bookings: Optional list of Booking instances or IDs linked to this transaction. extra_data: Optional dict for gateway-specific data. Returns: dict: On success: {"success": True, "transaction_id": "...", "payment_url": "...", "message": "..."} On failure: {"success": False, "message": "..."} """ # Stub: replace with real gateway call when banking_operations payment flow is implemented. return { "success": True, "message": "Transaction initiation stub", "transaction_id": None, "payment_url": None, } def create_payment_transaction( payment_type, payment_sub_type, payment_gateway, transaction_amount, currency="INR", notes=None, raw_data=None, user=None, ): """ Create a PaymentTransaction with pending status. Args: payment_type: Payment type - 'credit', 'debit', 'transfer', or 'other' payment_sub_type: Payment sub type - 'online', 'offline', or 'other' payment_gateway: PaymentGateway instance or payment_gateway_id (str) transaction_amount: Transaction amount (Decimal, float, or string) currency: Currency code, e.g. "INR" (default: "INR") notes: Optional transaction notes (str) raw_data: Optional raw data dict to store in payment_transaction_raw_data (dict) user: Optional User instance for last_updated_by Returns: tuple: (success: bool, transaction: PaymentTransaction or None, error_message: str or None) """ try: # Validate payment_type valid_payment_types = ['credit', 'debit', 'transfer', 'other'] if payment_type not in valid_payment_types: return False, None, f"Invalid payment_type. Must be one of: {', '.join(valid_payment_types)}" # Validate payment_sub_type valid_payment_sub_types = ['online', 'offline', 'other'] if payment_sub_type not in valid_payment_sub_types: return False, None, f"Invalid payment_sub_type. Must be one of: {', '.join(valid_payment_sub_types)}" # Get PaymentGateway instance if isinstance(payment_gateway, PaymentGateway): gateway = payment_gateway elif isinstance(payment_gateway, str): try: gateway = PaymentGateway.objects.get(payment_gateway_id=payment_gateway) except PaymentGateway.DoesNotExist: return False, None, f"PaymentGateway with id '{payment_gateway}' not found." else: return False, None, "payment_gateway must be a PaymentGateway instance or payment_gateway_id string." # Validate transaction_amount try: amount = Decimal(str(transaction_amount)) if amount <= 0: return False, None, "transaction_amount must be greater than zero." except (ValueError, TypeError): return False, None, "transaction_amount must be a valid number." # Validate currency if not currency or len(currency) > 10: return False, None, "currency must be a valid currency code (max 10 characters)." # Create PaymentTransaction transaction = PaymentTransaction.objects.create( payment_type=payment_type, payment_sub_type=payment_sub_type, payment_gateway=gateway, payment_transaction_amount=amount, payment_transaction_currency=currency, payment_transaction_status='pending', # Initial state as requested payment_transaction_notes=notes, payment_transaction_raw_data=raw_data, last_updated_by=user if isinstance(user, User) else None, ) return True, transaction.payment_transaction_id, None except Exception as e: return False, None, str(e) def update_payment_transaction( payment_transaction_id, payment_transaction_status, payment_transaction_notes=None, payment_transaction_raw_data=None, payment_transaction_response=None, payment_transaction_error=None, user=None, ): """ Update a PaymentTransaction with the given status and notes. Args: payment_transaction_id: PaymentTransaction id (str) payment_transaction_status: PaymentTransaction status - 'pending', 'completed', 'failed', 'refunded', 'cancelled' payment_transaction_notes: Optional transaction notes (str) payment_transaction_raw_data: Optional raw data dict to store in payment_transaction_raw_data (dict) payment_transaction_response: Optional response dict to store in payment_transaction_response (dict) payment_transaction_error: Optional error dict to store in payment_transaction_error (dict) user: Optional User instance for last_updated_by """ try: # Get PaymentTransaction instance if isinstance(payment_transaction_id, PaymentTransaction): transaction = payment_transaction_id elif isinstance(payment_transaction_id, str): try: transaction = PaymentTransaction.objects.get(payment_transaction_id=payment_transaction_id) except PaymentTransaction.DoesNotExist: return False, None, f"PaymentTransaction with id '{payment_transaction_id}' not found." else: return False, None, "payment_transaction_id must be a PaymentTransaction instance or payment_transaction_id string." # Update PaymentTransaction transaction.payment_transaction_status = payment_transaction_status transaction.payment_transaction_notes = payment_transaction_notes transaction.payment_transaction_raw_data = payment_transaction_raw_data transaction.payment_transaction_response = payment_transaction_response transaction.payment_transaction_error = payment_transaction_error transaction.last_updated_by = user if isinstance(user, User) else None transaction.save() return True, transaction.payment_transaction_id, None except Exception as e: return False, None, str(e)