refactor: migrate vendor billing, invoices, payments to module auto-discovery
Billing module: - Create vendor_checkout.py (checkout, portal, cancel, reactivate, change-tier) - Create vendor_addons.py (addon management routes) - Update vendor.py to aggregate new routers Orders module: - Create vendor_invoices.py (invoice settings, CRUD, PDF generation) - Update vendor.py to aggregate invoices router Payments module: - Restructure routes from routes/ to routes/api/ - Add require_module_access dependency - Set is_self_contained=True for auto-discovery Remove legacy files: - app/api/v1/vendor/billing.py - app/api/v1/vendor/invoices.py - app/api/v1/vendor/payments.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,14 +21,14 @@ from models.database.admin_menu_config import FrontendType
|
||||
|
||||
def _get_admin_router():
|
||||
"""Lazy import of admin router to avoid circular imports."""
|
||||
from app.modules.payments.routes.admin import admin_router
|
||||
from app.modules.payments.routes.api.admin import admin_router
|
||||
|
||||
return admin_router
|
||||
|
||||
|
||||
def _get_vendor_router():
|
||||
"""Lazy import of vendor router to avoid circular imports."""
|
||||
from app.modules.payments.routes.vendor import vendor_router
|
||||
from app.modules.payments.routes.api.vendor import vendor_router
|
||||
|
||||
return vendor_router
|
||||
|
||||
@@ -61,6 +61,7 @@ payments_module = ModuleDefinition(
|
||||
},
|
||||
is_core=False,
|
||||
is_internal=False,
|
||||
is_self_contained=True, # Enable auto-discovery from routes/api/
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
# app/modules/payments/routes/__init__.py
|
||||
"""Payments module routes."""
|
||||
"""
|
||||
Payments module routes.
|
||||
|
||||
from app.modules.payments.routes.admin import admin_router
|
||||
from app.modules.payments.routes.vendor import vendor_router
|
||||
Re-exports routers from the api subdirectory for backwards compatibility.
|
||||
"""
|
||||
|
||||
from app.modules.payments.routes.api.admin import admin_router
|
||||
from app.modules.payments.routes.api.vendor import vendor_router
|
||||
|
||||
__all__ = ["admin_router", "vendor_router"]
|
||||
|
||||
13
app/modules/payments/routes/api/__init__.py
Normal file
13
app/modules/payments/routes/api/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# app/modules/payments/routes/api/__init__.py
|
||||
"""
|
||||
Payments module API routes.
|
||||
|
||||
Provides REST API endpoints for payment management:
|
||||
- Admin API: Payment gateway configuration, transaction monitoring, refunds
|
||||
- Vendor API: Payment configuration, Stripe connect, transactions, balance
|
||||
"""
|
||||
|
||||
from app.modules.payments.routes.api.admin import admin_router
|
||||
from app.modules.payments.routes.api.vendor import vendor_router
|
||||
|
||||
__all__ = ["admin_router", "vendor_router"]
|
||||
@@ -1,4 +1,4 @@
|
||||
# app/modules/payments/routes/admin.py
|
||||
# app/modules/payments/routes/api/admin.py
|
||||
"""
|
||||
Admin routes for payments module.
|
||||
|
||||
@@ -8,9 +8,17 @@ Provides routes for:
|
||||
- Refund management
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter
|
||||
import logging
|
||||
|
||||
admin_router = APIRouter(prefix="/payments", tags=["Payments (Admin)"])
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from app.api.deps import require_module_access
|
||||
|
||||
admin_router = APIRouter(
|
||||
prefix="/payments",
|
||||
dependencies=[Depends(require_module_access("payments"))],
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@admin_router.get("/gateways")
|
||||
210
app/modules/payments/routes/api/vendor.py
Normal file
210
app/modules/payments/routes/api/vendor.py
Normal file
@@ -0,0 +1,210 @@
|
||||
# app/modules/payments/routes/api/vendor.py
|
||||
"""
|
||||
Vendor payment configuration and processing endpoints.
|
||||
|
||||
Vendor Context: Uses token_vendor_id from JWT token (authenticated vendor API pattern).
|
||||
The get_current_vendor_api dependency guarantees token_vendor_id is present.
|
||||
|
||||
Provides:
|
||||
- Payment gateway configuration
|
||||
- Stripe connect/disconnect
|
||||
- Payment methods listing
|
||||
- Transaction history
|
||||
- Payment balance
|
||||
- Refund processing
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_vendor_api, require_module_access
|
||||
from app.core.database import get_db
|
||||
from app.services.vendor_service import vendor_service
|
||||
from models.schema.auth import UserContext
|
||||
from app.modules.payments.schemas import (
|
||||
PaymentBalanceResponse,
|
||||
PaymentConfigResponse,
|
||||
PaymentConfigUpdate,
|
||||
PaymentConfigUpdateResponse,
|
||||
PaymentMethodsResponse,
|
||||
PaymentRefundRequest as RefundRequest,
|
||||
PaymentRefundResponse as RefundResponse,
|
||||
StripeConnectRequest,
|
||||
StripeConnectResponse,
|
||||
StripeDisconnectResponse,
|
||||
TransactionsResponse,
|
||||
)
|
||||
|
||||
vendor_router = APIRouter(
|
||||
prefix="/payments",
|
||||
dependencies=[Depends(require_module_access("payments"))],
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@vendor_router.get("/config", response_model=PaymentConfigResponse)
|
||||
def get_payment_configuration(
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Get vendor payment configuration.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Get payment gateway settings (Stripe, PayPal, etc.)
|
||||
- Get accepted payment methods
|
||||
- Get currency settings
|
||||
- Return masked/secure information only
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return PaymentConfigResponse(
|
||||
payment_gateway=None,
|
||||
accepted_methods=[],
|
||||
currency="EUR",
|
||||
stripe_connected=False,
|
||||
message="Payment configuration coming in Slice 5",
|
||||
)
|
||||
|
||||
|
||||
@vendor_router.put("/config", response_model=PaymentConfigUpdateResponse)
|
||||
def update_payment_configuration(
|
||||
payment_config: PaymentConfigUpdate,
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Update vendor payment configuration.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Update payment gateway settings
|
||||
- Connect/disconnect Stripe account
|
||||
- Update accepted payment methods
|
||||
- Validate configuration before saving
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return PaymentConfigUpdateResponse(
|
||||
message="Payment configuration update coming in Slice 5"
|
||||
)
|
||||
|
||||
|
||||
@vendor_router.post("/stripe/connect", response_model=StripeConnectResponse)
|
||||
def connect_stripe_account(
|
||||
stripe_data: StripeConnectRequest,
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Connect Stripe account for payment processing.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Handle Stripe OAuth flow
|
||||
- Store Stripe account ID securely
|
||||
- Verify Stripe account is active
|
||||
- Enable payment processing
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return StripeConnectResponse(message="Stripe connection coming in Slice 5")
|
||||
|
||||
|
||||
@vendor_router.delete("/stripe/disconnect", response_model=StripeDisconnectResponse)
|
||||
def disconnect_stripe_account(
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Disconnect Stripe account.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Remove Stripe account connection
|
||||
- Disable payment processing
|
||||
- Warn about pending payments
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return StripeDisconnectResponse(message="Stripe disconnection coming in Slice 5")
|
||||
|
||||
|
||||
@vendor_router.get("/methods", response_model=PaymentMethodsResponse)
|
||||
def get_payment_methods(
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Get accepted payment methods for vendor.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Return list of enabled payment methods
|
||||
- Include: credit card, PayPal, bank transfer, etc.
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return PaymentMethodsResponse(
|
||||
methods=[],
|
||||
message="Payment methods coming in Slice 5",
|
||||
)
|
||||
|
||||
|
||||
@vendor_router.get("/transactions", response_model=TransactionsResponse)
|
||||
def get_payment_transactions(
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Get payment transaction history.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Get all payment transactions for vendor
|
||||
- Filter by date range, status, etc.
|
||||
- Include payment details
|
||||
- Support pagination
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return TransactionsResponse(
|
||||
transactions=[],
|
||||
total=0,
|
||||
message="Payment transactions coming in Slice 5",
|
||||
)
|
||||
|
||||
|
||||
@vendor_router.get("/balance", response_model=PaymentBalanceResponse)
|
||||
def get_payment_balance(
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Get vendor payment balance and payout information.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Get available balance
|
||||
- Get pending balance
|
||||
- Get next payout date
|
||||
- Get payout history
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return PaymentBalanceResponse(
|
||||
available_balance=0.0,
|
||||
pending_balance=0.0,
|
||||
currency="EUR",
|
||||
next_payout_date=None,
|
||||
message="Payment balance coming in Slice 5",
|
||||
)
|
||||
|
||||
|
||||
@vendor_router.post("/refund/{payment_id}", response_model=RefundResponse)
|
||||
def refund_payment(
|
||||
payment_id: int,
|
||||
refund_data: RefundRequest,
|
||||
current_user: UserContext = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
Process payment refund.
|
||||
|
||||
TODO: Implement in Slice 5
|
||||
- Verify payment belongs to vendor
|
||||
- Process refund through payment gateway
|
||||
- Update order status
|
||||
- Send refund notification to customer
|
||||
"""
|
||||
vendor = vendor_service.get_vendor_by_id(db, current_user.token_vendor_id) # noqa: F841
|
||||
return RefundResponse(message="Payment refund coming in Slice 5")
|
||||
@@ -1,40 +0,0 @@
|
||||
# app/modules/payments/routes/vendor.py
|
||||
"""
|
||||
Vendor routes for payments module.
|
||||
|
||||
Provides routes for:
|
||||
- Payment method management
|
||||
- Transaction history
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
vendor_router = APIRouter(prefix="/payments", tags=["Payments (Vendor)"])
|
||||
|
||||
|
||||
@vendor_router.get("/methods")
|
||||
async def list_payment_methods():
|
||||
"""List saved payment methods for the vendor."""
|
||||
# TODO: Implement payment method listing
|
||||
return {"payment_methods": []}
|
||||
|
||||
|
||||
@vendor_router.post("/methods")
|
||||
async def add_payment_method():
|
||||
"""Add a new payment method."""
|
||||
# TODO: Implement payment method creation
|
||||
return {"status": "created", "id": "pm_xxx"}
|
||||
|
||||
|
||||
@vendor_router.delete("/methods/{method_id}")
|
||||
async def remove_payment_method(method_id: str):
|
||||
"""Remove a saved payment method."""
|
||||
# TODO: Implement payment method deletion
|
||||
return {"status": "deleted", "id": method_id}
|
||||
|
||||
|
||||
@vendor_router.get("/transactions")
|
||||
async def list_vendor_transactions():
|
||||
"""List transactions for the vendor."""
|
||||
# TODO: Implement transaction listing
|
||||
return {"transactions": [], "total": 0}
|
||||
Reference in New Issue
Block a user