You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

261 lines
8.5 KiB

"""
Payment Orchestrator Module
This module coordinates the execution of different payment processing modes.
"""
import logging
from datetime import datetime
from typing import Dict, Any, Optional
from flask import Flask
logger = logging.getLogger(__name__)
class PaymentOrchestrator:
"""
Orchestrator for payment processing operations.
This class coordinates the execution of different payment processing modes
(batch, payment plan, payment intent follow-up, refund follow-up).
"""
VALID_MODES = ["batch", "payplan", "payintent", "refund"]
def __init__(self, app: Flask, config, process_live: bool = False):
"""
Initialize the payment orchestrator.
Args:
app: Flask application instance
config: Configuration object
process_live: Whether to process in live mode
"""
self.app = app
self.config = config
self.process_live = process_live
self.logger = logging.getLogger(self.__class__.__name__)
# Initialize components (deferred to run())
self.stripe_processor = None
self.splynx_repo = None
self.payment_repo = None
def run(self, mode: str) -> Dict[str, Any]:
"""
Run payment processing for the specified mode.
Args:
mode: Processing mode ("batch", "payplan", "payintent", "refund")
Returns:
Dictionary with processing results
"""
if mode not in self.VALID_MODES:
error_msg = f"Invalid mode '{mode}'. Valid modes: {', '.join(self.VALID_MODES)}"
self.logger.error(error_msg)
return {
'success': False,
'error': error_msg,
'mode': mode
}
start_time = datetime.now()
# Log script start
try:
from services import log_script_start
environment = "live" if self.process_live else "sandbox"
log_script_start("query_mysql_new.py", mode, environment)
except Exception as e:
self.logger.warning(f"Failed to log script start: {e}")
# Initialize components within Flask app context
with self.app.app_context():
self._initialize_components()
try:
# Execute the appropriate processing mode
if mode == "batch":
result = self._process_batch()
elif mode == "payplan":
result = self._process_payment_plans()
elif mode == "payintent":
result = self._process_payment_intents()
elif mode == "refund":
result = self._process_refunds()
# Calculate duration
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
result['duration'] = duration
# Log script completion
self._log_completion(mode, result, duration)
return result
except Exception as e:
self.logger.error(f"Error during {mode} processing: {e}", exc_info=True)
duration = (datetime.now() - start_time).total_seconds()
return {
'success': False,
'error': str(e),
'mode': mode,
'duration': duration
}
def _initialize_components(self):
"""Initialize all required components within Flask app context."""
from app import db
from stripe_payment_processor import StripePaymentProcessor
from splynx import Splynx, SPLYNX_URL, SPLYNX_KEY, SPLYNX_SECRET
from repositories import PaymentRepository, SplynxRepository
# Initialize Stripe processor
api_key = self.config.STRIPE_LIVE_API_KEY if self.process_live else self.config.STRIPE_TEST_API_KEY
self.stripe_processor = StripePaymentProcessor(api_key=api_key, enable_logging=True)
# Initialize Splynx
splynx_client = Splynx(url=SPLYNX_URL, key=SPLYNX_KEY, secret=SPLYNX_SECRET)
self.splynx_repo = SplynxRepository(splynx_client)
# Initialize payment repository
self.payment_repo = PaymentRepository(db.session)
self.logger.info("Components initialized successfully")
def _process_batch(self) -> Dict[str, Any]:
"""
Process batch payments (Direct Debit and Card).
Returns:
Dictionary with processing results
"""
from app import db
from payment_processors import BatchPaymentProcessor
self.config.MODE = 'batch'
processor = BatchPaymentProcessor(
db_session_factory=db.session,
stripe_processor=self.stripe_processor,
splynx_repository=self.splynx_repo,
payment_repository=self.payment_repo,
config=self.config,
process_live=self.process_live
)
result = processor.process()
result['mode'] = self.config.MODE
return result
def _process_payment_plans(self) -> Dict[str, Any]:
"""
Process payment plans.
Returns:
Dictionary with processing results
"""
from app import db
from payment_processors import PaymentPlanProcessor
self.config.MODE = 'payplan'
processor = PaymentPlanProcessor(
db_session_factory=db.session,
stripe_processor=self.stripe_processor,
splynx_repository=self.splynx_repo,
payment_repository=self.payment_repo,
config=self.config,
process_live=self.process_live
)
result = processor.process()
result['mode'] = self.config.MODE
return result
def _process_payment_intents(self) -> Dict[str, Any]:
"""
Process payment intent follow-ups.
Returns:
Dictionary with processing results
"""
from app import db
from payment_processors import FollowUpProcessor
self.config.MODE = 'payintent'
processor = FollowUpProcessor(
db_session_factory=db.session,
stripe_processor=self.stripe_processor,
splynx_repository=self.splynx_repo,
payment_repository=self.payment_repo,
config=self.config,
process_live=self.process_live
)
result = processor.process_payment_intents()
result['mode'] = self.config.MODE
return result
def _process_refunds(self) -> Dict[str, Any]:
"""
Process refund follow-ups.
Returns:
Dictionary with processing results
"""
from app import db
from payment_processors import FollowUpProcessor
self.config.MODE = 'refund'
processor = FollowUpProcessor(
db_session_factory=db.session,
stripe_processor=self.stripe_processor,
splynx_repository=self.splynx_repo,
payment_repository=self.payment_repo,
config=self.config,
process_live=self.process_live
)
result = processor.process_refunds()
result['mode'] = self.config.MODE
return result
def _log_completion(self, mode: str, result: Dict[str, Any], duration: float):
"""
Log script completion using services module.
Args:
mode: Processing mode
result: Processing result dictionary
duration: Execution duration in seconds
"""
try:
from services import log_script_completion
success_count = result.get('success_count', result.get('succeeded', result.get('completed', 0)))
failed_count = result.get('failed_count', result.get('failed', 0))
total_amount = result.get('total_amount', 0.0)
batch_ids = result.get('batch_ids') or ([result.get('batch_id')] if result.get('batch_id') else None)
errors = [result.get('error')] if result.get('error') else None
log_script_completion(
script_name="query_mysql.py",
mode=mode,
success_count=success_count,
failed_count=failed_count,
total_amount=total_amount,
batch_ids=batch_ids,
duration_seconds=duration,
errors=errors
)
self.logger.info(f"Script completed in {duration:.1f}s: {success_count} successful, {failed_count} failed")
except Exception as e:
self.logger.warning(f"Failed to log script completion: {e}")