""" Base Payment Processor Module This module provides the abstract base class for all payment processors. It defines the common interface and shared functionality. """ import logging import json from abc import ABC, abstractmethod from typing import Dict, Any, Optional from sqlalchemy.orm import scoped_session logger = logging.getLogger(__name__) class BasePaymentProcessor(ABC): """ Abstract base class for payment processors. This class defines the common interface and shared functionality for all payment processing modes. """ def __init__(self, db_session_factory, stripe_processor, splynx_repository, payment_repository, config, process_live: bool = False): """ Initialize the base payment processor. Args: db_session_factory: Factory for creating database sessions (for thread safety) stripe_processor: StripePaymentProcessor instance splynx_repository: SplynxRepository instance payment_repository: PaymentRepository instance config: Configuration object process_live: Whether to process in live mode """ self.db_session_factory = db_session_factory self.stripe_processor = stripe_processor self.splynx_repo = splynx_repository self.payment_repo = payment_repository self.config = config self.process_live = process_live self.logger = logging.getLogger(self.__class__.__name__) def get_db_session(self): """ Get a database session for the current thread. Returns: Database session """ if isinstance(self.db_session_factory, scoped_session): return self.db_session_factory() else: return self.db_session_factory @abstractmethod def process(self) -> Dict[str, Any]: """ Process payments for this processor's mode. This method must be implemented by all subclasses. Returns: Dictionary with processing results (success_count, failed_count, etc.) """ pass def handle_database_operation(self, operation_func, operation_name: str) -> Any: """ Execute a database operation with consistent error handling. Args: operation_func: Function that performs the database operation operation_name: Description of the operation for logging Returns: Result of operation_func or None if failed """ try: result = operation_func() self.payment_repo.commit() self.logger.debug(f"{operation_name} completed successfully") return result except Exception as e: self.payment_repo.rollback() self.logger.error(f"{operation_name} failed: {e}") return None def log_processing_start(self, mode: str, details: str = ""): """ Log the start of payment processing. Args: mode: Processing mode name details: Additional details to log """ env = "LIVE" if self.process_live else "SANDBOX" self.logger.info(f"Starting {mode} processing ({env})") if details: self.logger.info(details) def log_processing_complete(self, mode: str, success_count: int, failed_count: int, duration: float, additional_info: Dict[str, Any] = None): """ Log the completion of payment processing. Args: mode: Processing mode name success_count: Number of successful operations failed_count: Number of failed operations duration: Processing duration in seconds additional_info: Additional information to log """ self.logger.info(f"{mode} processing completed in {duration:.1f}s") self.logger.info(f"Results: {success_count} successful, {failed_count} failed") if additional_info: for key, value in additional_info.items(): self.logger.info(f"{key}: {value}") def create_payment_data(self, payment_record, payment_id: int, description: str = None) -> Dict[str, Any]: """ Create standardized payment data dictionary for Stripe processing. Args: payment_record: Database payment record payment_id: Payment ID description: Payment description override Returns: Dictionary with payment data for Stripe API """ if not description: description = f"Payment ID: {payment_id} - Splynx ID: {payment_record.Splynx_ID}" return { 'payment_id': payment_id, 'customer_id': payment_record.Stripe_Customer_ID, 'amount': payment_record.Payment_Amount, 'currency': "aud", 'description': description, 'stripe_pm': payment_record.Stripe_Payment_Method } def handle_payment_result(self, payment_id: int, result: Dict[str, Any], payment_type: str = "pay") -> bool: """ Handle payment processing result and update database. Args: payment_id: Payment record ID result: Payment processing result from Stripe payment_type: "pay" or "singlepay" Returns: True if successful, False otherwise """ from payment_services.payment_service import processPaymentResult #print(f"\n\nhandle_payment_result - result: {json.dumps(result,indent=2)}\n\n") cust_stripe_details = self.stripe_processor.get_customer_info(customer_id=result.get('customer_id')) #print(f"\ncust_stripe_details ({result.get('customer_id')}) - result: {json.dumps(cust_stripe_details,indent=2)}\n\n") try: # Get notification handler notification_handler = self._get_notification_handler() # Process the result processPaymentResult( db=self.payment_repo.db, splynx=self.splynx_repo.splynx, notification_handler=notification_handler, pay_id=payment_id, result=result, key=payment_type, process_live=self.process_live, cust_stripe_details=cust_stripe_details, mode=self.config.MODE ) return True except Exception as e: self.logger.error(f"Error handling payment result for payment {payment_id}: {e}") return False def _get_notification_handler(self): """ Get the notification handler function for failed payments. Returns: Notification handler function or None """ from .notification_handler import handle_failed_payment_notification #return handle_failed_payment_notification if self.process_live else None return handle_failed_payment_notification