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
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}")
|
|
|