Files
orion/app/modules/payments/services/payment_service.py
Samir Boulahtit f20266167d
Some checks failed
CI / ruff (push) Failing after 7s
CI / pytest (push) Failing after 1s
CI / architecture (push) Failing after 9s
CI / dependency-scanning (push) Successful in 27s
CI / audit (push) Successful in 8s
CI / docs (push) Has been skipped
fix(lint): auto-fix ruff violations and tune lint rules
- Auto-fixed 4,496 lint issues (import sorting, modern syntax, etc.)
- Added ignore rules for patterns intentional in this codebase:
  E402 (late imports), E712 (SQLAlchemy filters), B904 (raise from),
  SIM108/SIM105/SIM117 (readability preferences)
- Added per-file ignores for tests and scripts
- Excluded broken scripts/rename_terminology.py (has curly quotes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:10:42 +01:00

232 lines
6.2 KiB
Python

# app/modules/payments/services/payment_service.py
"""
Payment service for processing payments through configured gateways.
This service provides a unified interface for payment operations
regardless of the underlying gateway (Stripe, PayPal, etc.).
Usage:
from app.modules.payments.services import PaymentService
payment_service = PaymentService()
# Process a payment
result = await payment_service.process_payment(
amount=1000, # Amount in cents
currency="EUR",
payment_method_id="pm_xxx",
description="Order #123",
)
# Issue a refund
refund = await payment_service.refund(
transaction_id="txn_xxx",
amount=500, # Partial refund
)
"""
import logging
from dataclasses import dataclass
from datetime import UTC, datetime
from enum import Enum
from typing import Any
logger = logging.getLogger(__name__)
class PaymentStatus(str, Enum):
"""Payment transaction status."""
PENDING = "pending"
PROCESSING = "processing"
SUCCEEDED = "succeeded"
FAILED = "failed"
CANCELLED = "cancelled"
REFUNDED = "refunded"
PARTIALLY_REFUNDED = "partially_refunded"
class PaymentGateway(str, Enum):
"""Supported payment gateways."""
STRIPE = "stripe"
PAYPAL = "paypal"
BANK_TRANSFER = "bank_transfer"
@dataclass
class PaymentResult:
"""Result of a payment operation."""
success: bool
transaction_id: str | None = None
gateway: PaymentGateway | None = None
status: PaymentStatus = PaymentStatus.PENDING
amount: int = 0 # Amount in cents
currency: str = "EUR"
error_message: str | None = None
gateway_response: dict[str, Any] | None = None
created_at: datetime | None = None
def to_dict(self) -> dict[str, Any]:
return {
"success": self.success,
"transaction_id": self.transaction_id,
"gateway": self.gateway.value if self.gateway else None,
"status": self.status.value,
"amount": self.amount,
"currency": self.currency,
"error_message": self.error_message,
"created_at": self.created_at.isoformat() if self.created_at else None,
}
@dataclass
class RefundResult:
"""Result of a refund operation."""
success: bool
refund_id: str | None = None
transaction_id: str | None = None
amount: int = 0
status: PaymentStatus = PaymentStatus.PENDING
error_message: str | None = None
class PaymentService:
"""
Service for processing payments through configured gateways.
This service provides a unified interface for:
- Processing payments
- Issuing refunds
- Managing payment methods
- Retrieving transaction history
"""
def __init__(self) -> None:
self._default_gateway = PaymentGateway.STRIPE
async def process_payment(
self,
amount: int,
currency: str = "EUR",
payment_method_id: str | None = None,
gateway: PaymentGateway | None = None,
description: str | None = None,
metadata: dict[str, Any] | None = None,
) -> PaymentResult:
"""
Process a payment through the specified gateway.
Args:
amount: Amount in cents
currency: Currency code (EUR, USD, etc.)
payment_method_id: Stored payment method ID
gateway: Payment gateway to use (default: stripe)
description: Payment description
metadata: Additional metadata for the transaction
Returns:
PaymentResult with transaction details
"""
gateway = gateway or self._default_gateway
logger.info(
f"Processing payment: {amount} {currency} via {gateway.value}",
extra={"amount": amount, "currency": currency, "gateway": gateway.value},
)
# TODO: Implement actual gateway processing
# For now, return a mock successful result
return PaymentResult(
success=True,
transaction_id=f"txn_{gateway.value}_mock",
gateway=gateway,
status=PaymentStatus.SUCCEEDED,
amount=amount,
currency=currency,
created_at=datetime.now(UTC),
)
async def refund(
self,
transaction_id: str,
amount: int | None = None,
reason: str | None = None,
) -> RefundResult:
"""
Issue a refund for a transaction.
Args:
transaction_id: Original transaction ID
amount: Refund amount in cents (None for full refund)
reason: Reason for refund
Returns:
RefundResult with refund details
"""
logger.info(
f"Issuing refund for transaction {transaction_id}",
extra={"transaction_id": transaction_id, "amount": amount, "reason": reason},
)
# TODO: Implement actual refund processing
return RefundResult(
success=True,
refund_id=f"rf_{transaction_id}",
transaction_id=transaction_id,
amount=amount or 0,
status=PaymentStatus.REFUNDED,
)
async def get_transaction(self, transaction_id: str) -> dict[str, Any] | None:
"""
Get transaction details by ID.
Args:
transaction_id: Transaction ID
Returns:
Transaction details or None if not found
"""
# TODO: Implement transaction lookup
return None
async def list_transactions(
self,
store_id: int | None = None,
platform_id: int | None = None,
status: PaymentStatus | None = None,
limit: int = 50,
offset: int = 0,
) -> list[dict[str, Any]]:
"""
List transactions with optional filters.
Args:
store_id: Filter by store
platform_id: Filter by platform
status: Filter by status
limit: Maximum results
offset: Pagination offset
Returns:
List of transaction records
"""
# TODO: Implement transaction listing
return []
# Singleton instance
payment_service = PaymentService()
__all__ = [
"PaymentService",
"PaymentStatus",
"PaymentGateway",
"PaymentResult",
"RefundResult",
"payment_service",
]