Refactor payment service, fix DB session, and consolidate endpoints

- Fix critical NameError in database.py by restoring Session factory
- Refactor payment_service.py and crud.py to use shared constants.py and utils.py
- Deduplicate state mapping and input sanitization logic
- Move transaction amount calculation logic from CRUD to Router layer
- Enforce type safety in schemas using IntEnum for TransactionType/Status
- Move capture endpoint from transaction.py to payment.py (now /payments/capture)
- Update create_customer_profile signature for clarity
This commit is contained in:
2026-02-01 12:31:42 -05:00
parent 449eb74279
commit 97261f6c51
13 changed files with 335 additions and 428 deletions

View File

@@ -1,26 +1,19 @@
## File: transaction.py (New transaction router)
"""
Transaction Router - Endpoints for transaction lookup and capture operations.
"""
import logging
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
import enum
# Import locally to avoid circular imports
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
from app import crud, database, schemas, models
from app.services import payment_service
from app.services.payment_service import parse_authnet_response, TransactionStatus
logger = logging.getLogger(__name__)
# Create a router for transaction endpoints
transaction_router = APIRouter()
class TransactionStatus(enum.IntEnum):
APPROVED = 0
DECLINED = 1
# Test endpoint to verify router is working
@transaction_router.get("/test/", summary="Test transaction router")
def test_transaction_router():
@@ -29,9 +22,6 @@ def test_transaction_router():
return {"test": "transaction router is working"}
@transaction_router.get("/transaction/delivery/{delivery_id}", summary="Get pre-authorization transaction for a delivery")
def get_delivery_transaction(delivery_id: int, db: Session = Depends(database.get_db)):
"""
@@ -84,36 +74,4 @@ def update_transaction_auto_id(transaction_id: int, new_auto_id: int, db: Sessio
return {"message": "Transaction auto_id updated"}
@transaction_router.post("/capture/", response_model=schemas.Transaction, summary="Capture a previously authorized amount")
def capture_authorized_amount(transaction: schemas.TransactionCapture, db: Session = Depends(database.get_db)):
# This endpoint captures a previously authorized transaction
# It finds the original transaction by its ID and captures the funds
logger.info(f"POST /capture - Capturing authorized transaction {transaction.auth_net_transaction_id}")
auth_transaction = crud.get_transaction_by_auth_id(db, auth_net_transaction_id=transaction.auth_net_transaction_id)
if not auth_transaction:
raise HTTPException(status_code=404, detail="Authorization transaction not found")
# Call the capture service function
auth_net_response = payment_service.capture_authorized_transaction(transaction)
status, _, rejection_reason = _parse_authnet_response(auth_net_response)
# Use the existing CRUD function to update the transaction
return crud.update_transaction_for_capture(
db=db,
auth_net_transaction_id=transaction.auth_net_transaction_id,
charge_amount=transaction.charge_amount,
status=status,
rejection_reason=rejection_reason
)
def _parse_authnet_response(response):
"""
Parse Authorize.Net response for transaction status
"""
if response.messages.resultCode == "Ok":
status = TransactionStatus.APPROVED
rejection_reason = None
else:
status = TransactionStatus.DECLINED
rejection_reason = "Payment declined by gateway."
return status, None, rejection_reason