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.
 
 
 

307 lines
13 KiB

"""
Notification service for Plutus payment processing application.
Handles email notifications for payment failures and success reports.
Integrates with existing emailclass.py for SMTP functionality.
"""
from datetime import datetime
from typing import List, Dict, Any, Optional
from emailclass import SendEmail
import json
import logging
logger = logging.getLogger(__name__)
class NotificationService:
def __init__(self):
self.email_client = SendEmail()
def send_payment_failure_notification(
self,
payment_data: Dict[str, Any],
recipient_email: str = "alan.woodman@interphone.com.au"
) -> bool:
"""
Send email notification for a failed payment.
Args:
payment_data: Dictionary containing payment information
recipient_email: Email address to send notification to
Returns:
bool: True if email sent successfully
"""
try:
# Extract payment information
splynx_id = payment_data.get('splynx_id', 'Unknown')
payment_id = payment_data.get('payment_id', 'Unknown')
amount = payment_data.get('amount', 0.0)
error = payment_data.get('error', 'Unknown error')
payment_method = payment_data.get('payment_method', 'Unknown')
customer_name = payment_data.get('customer_name', 'Unknown Customer')
# Configure email
self.email_client.receiver = recipient_email
self.email_client.subject = f"Payment Failure - Customer {splynx_id} - ${amount:.2f}"
self.email_client.message_type = "html"
# Create HTML email content
html_content = self._create_failure_email_html(
payment_data, splynx_id, payment_id, amount, error,
payment_method, customer_name
)
self.email_client.message_body_html = html_content
# Send email
result = self.email_client.send()
if result:
logger.info(f"Payment failure email sent successfully for payment {payment_id}")
else:
logger.error(f"Failed to send payment failure email for payment {payment_id}")
return result
except Exception as e:
logger.error(f"Error sending payment failure notification: {e}")
return False
def send_batch_summary_email(
self,
batch_summary: Dict[str, Any],
recipient_email: str = "alan.woodman@interphone.com.au"
) -> bool:
"""
Send email summary for batch payment processing.
Args:
batch_summary: Dictionary containing batch processing summary
recipient_email: Email address to send summary to
Returns:
bool: True if email sent successfully
"""
try:
batch_id = batch_summary.get('batch_id', 'Unknown')
total_processed = batch_summary.get('total_processed', 0)
successful_count = batch_summary.get('successful_count', 0)
failed_count = batch_summary.get('failed_count', 0)
total_amount = batch_summary.get('total_amount', 0.0)
# Configure email
self.email_client.receiver = recipient_email
self.email_client.subject = f"Batch Payment Summary - Batch #{batch_id} - {successful_count}/{total_processed} Successful"
self.email_client.message_type = "html"
# Create HTML email content
html_content = self._create_batch_summary_html(batch_summary)
self.email_client.message_body_html = html_content
# Send email
result = self.email_client.send()
if result:
logger.info(f"Batch summary email sent successfully for batch {batch_id}")
else:
logger.error(f"Failed to send batch summary email for batch {batch_id}")
return result
except Exception as e:
logger.error(f"Error sending batch summary email: {e}")
return False
def _create_failure_email_html(
self,
payment_data: Dict[str, Any],
splynx_id: str,
payment_id: str,
amount: float,
error: str,
payment_method: str,
customer_name: str
) -> str:
"""Create HTML content for payment failure email."""
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
return f"""
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
.header {{ background-color: #dc3545; color: white; padding: 20px; text-align: center; }}
.content {{ padding: 20px; }}
.info-table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
.info-table th, .info-table td {{ border: 1px solid #ddd; padding: 12px; text-align: left; }}
.info-table th {{ background-color: #f8f9fa; font-weight: bold; }}
.error-box {{ background-color: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px; padding: 15px; margin: 20px 0; }}
.footer {{ background-color: #f8f9fa; padding: 15px; text-align: center; color: #666; }}
.alert {{ padding: 10px; margin: 10px 0; border-radius: 4px; }}
.alert-danger {{ background-color: #f8d7da; border-left: 4px solid #dc3545; }}
</style>
</head>
<body>
<div class="header">
<h1>🚨 Payment Processing Failure</h1>
<p>Plutus Payment System Alert</p>
</div>
<div class="content">
<div class="alert alert-danger">
<strong>Payment Failed:</strong> A payment processing attempt has failed and requires attention.
</div>
<h2>Payment Details</h2>
<table class="info-table">
<tr><th>Payment ID</th><td>{payment_id}</td></tr>
<tr><th>Splynx Customer ID</th><td><a href="https://billing.interphone.com.au/admin/customers/view?id={splynx_id}">{splynx_id}</a></td></tr>
<tr><th>Customer Name</th><td>{customer_name}</td></tr>
<tr><th>Payment Amount</th><td>${amount:.2f} AUD</td></tr>
<tr><th>Payment Method</th><td>{payment_method}</td></tr>
<tr><th>Timestamp</th><td>{timestamp}</td></tr>
</table>
<h2>Error Information</h2>
<div class="error-box">
<h3>Error Details:</h3>
<p>{error}</p>
</div>
<h2>Recommended Actions</h2>
<ul>
<li>Review customer payment method in Splynx</li>
<li>Contact customer about payment failure</li>
<li>Check if customer needs to update payment details</li>
<li>Consider creating a support ticket</li>
</ul>
<p><strong>System Links:</strong></p>
<ul>
<li><a href="https://billing.interphone.com.au/admin/customers/view?id={splynx_id}">View Customer in Splynx</a></li>
<li><a href="http://your-plutus-url/single-payment/detail/{payment_id}">View Payment in Plutus</a></li>
</ul>
</div>
<div class="footer">
<p>This email was automatically generated by the Plutus Payment System</p>
<p>Timestamp: {timestamp}</p>
</div>
</body>
</html>
"""
def _create_batch_summary_html(self, batch_summary: Dict[str, Any]) -> str:
"""Create HTML content for batch summary email."""
batch_id = batch_summary.get('batch_id', 'Unknown')
total_processed = batch_summary.get('total_processed', 0)
successful_count = batch_summary.get('successful_count', 0)
failed_count = batch_summary.get('failed_count', 0)
total_amount = batch_summary.get('total_amount', 0.0)
success_amount = batch_summary.get('success_amount', 0.0)
failed_payments = batch_summary.get('failed_payments', [])
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# Determine status color
if failed_count == 0:
status_color = "#28a745" # Green
status_text = "✅ All Successful"
elif successful_count == 0:
status_color = "#dc3545" # Red
status_text = "❌ All Failed"
else:
status_color = "#ffc107" # Yellow
status_text = "⚠️ Partial Success"
# Build failed payments table
failed_payments_html = ""
if failed_payments:
failed_payments_html = """
<h2>Failed Payments</h2>
<table class="info-table">
<tr><th>Payment ID</th><th>Customer ID</th><th>Amount</th><th>Error</th></tr>
"""
for payment in failed_payments[:10]: # Limit to first 10 failures
failed_payments_html += f"""
<tr>
<td>{payment.get('id', 'N/A')}</td>
<td><a href="https://billing.interphone.com.au/admin/customers/view?id={payment.get('splynx_id', 'N/A')}">{payment.get('splynx_id', 'N/A')}</a></td>
<td>${payment.get('amount', 0.0):.2f}</td>
<td>{payment.get('error', 'Unknown error')[:100]}...</td>
</tr>
"""
failed_payments_html += "</table>"
if len(failed_payments) > 10:
failed_payments_html += f"<p><em>... and {len(failed_payments) - 10} more failed payments</em></p>"
return f"""
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; color: #333; }}
.header {{ background-color: {status_color}; color: white; padding: 20px; text-align: center; }}
.content {{ padding: 20px; }}
.info-table {{ width: 100%; border-collapse: collapse; margin: 20px 0; }}
.info-table th, .info-table td {{ border: 1px solid #ddd; padding: 12px; text-align: left; }}
.info-table th {{ background-color: #f8f9fa; font-weight: bold; }}
.footer {{ background-color: #f8f9fa; padding: 15px; text-align: center; color: #666; }}
.stats {{ display: flex; justify-content: space-around; margin: 20px 0; }}
.stat-box {{ text-align: center; padding: 15px; border-radius: 8px; }}
.stat-success {{ background-color: #d4edda; }}
.stat-danger {{ background-color: #f8d7da; }}
.stat-info {{ background-color: #d1ecf1; }}
</style>
</head>
<body>
<div class="header">
<h1>📊 Batch Payment Summary</h1>
<h2>Batch #{batch_id}</h2>
<h3>{status_text}</h3>
</div>
<div class="content">
<h2>Processing Summary</h2>
<div class="stats">
<div class="stat-box stat-info">
<h3>{total_processed}</h3>
<p>Total Processed</p>
</div>
<div class="stat-box stat-success">
<h3>{successful_count}</h3>
<p>Successful</p>
</div>
<div class="stat-box stat-danger">
<h3>{failed_count}</h3>
<p>Failed</p>
</div>
</div>
<table class="info-table">
<tr><th>Metric</th><th>Value</th></tr>
<tr><td>Batch ID</td><td>#{batch_id}</td></tr>
<tr><td>Total Amount Processed</td><td>${total_amount:.2f} AUD</td></tr>
<tr><td>Successful Amount</td><td>${success_amount:.2f} AUD</td></tr>
<tr><td>Success Rate</td><td>{(successful_count/total_processed*100):.1f}%</td></tr>
<tr><td>Processing Time</td><td>{timestamp}</td></tr>
</table>
{failed_payments_html}
<h2>Actions Required</h2>
<ul>
{"<li>✅ No action required - all payments successful</li>" if failed_count == 0 else f"<li>⚠️ Review {failed_count} failed payment(s)</li>"}
{"<li>📧 Consider contacting customers with failed payments</li>" if failed_count > 0 else ""}
<li>📊 <a href='http://your-plutus-url/batch/{batch_id}'>View detailed batch report</a></li>
</ul>
</div>
<div class="footer">
<p>This email was automatically generated by the Plutus Payment System</p>
<p>Batch processed at: {timestamp}</p>
</div>
</body>
</html>
"""