Files
Airwallex/airwallex-sdk/airwallex/models/invoice.py
zqq61 4f53889a8e feat: Airwallex 发卡管理后台完整实现
- 后端: FastAPI + SQLAlchemy + SQLite, JWT认证, 代理支持的AirwallexClient
- 前端: React 18 + Vite + Ant Design 5, 中文界面
- 功能: 卡片管理, 持卡人管理, 交易记录, API令牌, 系统设置, 审计日志
- 第三方API: X-API-Key认证, 权限控制
- Docker部署: docker-compose编排前后端
2026-03-15 23:05:08 +08:00

103 lines
5.7 KiB
Python

"""
Models for the Airwallex Invoice API.
"""
from typing import Optional, List, Dict, Any, Union
from datetime import datetime
from pydantic import Field, validator
from .base import AirwallexModel
class RecurringBilling(AirwallexModel):
"""Model for recurring billing information."""
period: int = Field(..., description="The length of the billing cycle")
period_unit: str = Field(..., description="The unit of the billing cycle, e.g., 'MONTH', 'YEAR'")
class PriceTier(AirwallexModel):
"""Model for price tier information."""
amount: float = Field(..., description="The price for this tier")
upper_bound: Optional[float] = Field(None, description="The upper bound of this tier")
class Price(AirwallexModel):
"""Model for price information."""
id: str = Field(..., description="Unique price ID")
name: str = Field(..., description="Price name")
description: Optional[str] = Field(None, description="Price description")
active: bool = Field(..., description="Whether this price is active")
currency: str = Field(..., description="Currency code (ISO 4217)")
product_id: str = Field(..., description="ID of the associated product")
pricing_model: str = Field(..., description="Pricing model type (e.g., 'tiered')")
recurring: Optional[RecurringBilling] = Field(None, description="Recurring billing details")
tiers: Optional[List[PriceTier]] = Field(None, description="Pricing tiers for tiered pricing")
metadata: Optional[Dict[str, str]] = Field(None, description="Additional metadata")
request_id: Optional[str] = Field(None, description="Request ID when creating this price")
class InvoiceItem(AirwallexModel):
"""Model for an Airwallex invoice item."""
id: str = Field(..., description="Unique invoice item ID")
invoice_id: str = Field(..., description="ID of the invoice this item belongs to")
amount: float = Field(..., description="Amount for this invoice item")
currency: str = Field(..., description="Currency code (ISO 4217)")
period_start_at: datetime = Field(..., description="Billing period start (inclusive)")
period_end_at: datetime = Field(..., description="Billing period end (exclusive)")
price: Price = Field(..., description="Price details")
quantity: Optional[float] = Field(None, description="Product quantity")
class Invoice(AirwallexModel):
"""Model for an Airwallex invoice."""
resource_name: str = "invoices"
id: str = Field(..., description="Unique invoice ID")
customer_id: str = Field(..., description="ID of the customer who will be charged")
subscription_id: Optional[str] = Field(None, description="ID of the subscription which generated this invoice")
currency: str = Field(..., description="Currency code (ISO 4217)")
total_amount: float = Field(..., description="Total amount of the invoice")
status: str = Field(..., description="Invoice status (SENT, PAID, PAYMENT_FAILED)")
payment_intent_id: Optional[str] = Field(None, description="ID of the associated payment intent")
period_start_at: datetime = Field(..., description="Billing period start (inclusive)")
period_end_at: datetime = Field(..., description="Billing period end (exclusive)")
created_at: datetime = Field(..., description="Invoice creation timestamp")
updated_at: Optional[datetime] = Field(None, description="Invoice last update timestamp")
paid_at: Optional[datetime] = Field(None, description="Timestamp when invoice was paid")
last_payment_attempt_at: Optional[datetime] = Field(None, description="Timestamp of last payment attempt")
next_payment_attempt_at: Optional[datetime] = Field(None, description="Timestamp of next scheduled payment attempt")
past_payment_attempt_count: Optional[int] = Field(None, description="Number of payment attempts made so far")
remaining_payment_attempt_count: Optional[int] = Field(None, description="Number of remaining payment attempts")
items: Optional[List[InvoiceItem]] = Field(None, description="Invoice items")
@validator('status')
def validate_status(cls, v):
"""Validate invoice status."""
valid_statuses = ['SENT', 'PAID', 'PAYMENT_FAILED']
if v not in valid_statuses:
raise ValueError(f"Status must be one of {valid_statuses}")
return v
class InvoicePreviewRequest(AirwallexModel):
"""Model for invoice preview request."""
customer_id: str = Field(..., description="ID of the customer for this invoice")
subscription_id: Optional[str] = Field(None, description="ID of the subscription to preview the invoice for")
trial_end_at: Optional[datetime] = Field(None, description="End of the trial period if applicable")
recurring: Optional[RecurringBilling] = Field(None, description="Recurring billing details")
class SubscriptionItem(AirwallexModel):
"""Model for subscription item in invoice preview."""
price_id: str = Field(..., description="ID of the price")
quantity: float = Field(1, description="Quantity of the product")
items: Optional[List[SubscriptionItem]] = Field(None, description="List of subscription items")
class InvoicePreviewResponse(AirwallexModel):
"""Model for invoice preview response."""
customer_id: str = Field(..., description="ID of the customer for this invoice")
subscription_id: Optional[str] = Field(None, description="ID of the subscription for this invoice")
currency: str = Field(..., description="Currency code (ISO 4217)")
total_amount: float = Field(..., description="Total amount of the invoice")
created_at: datetime = Field(..., description="Expected invoice creation timestamp")
items: List[InvoiceItem] = Field(..., description="Invoice items in the preview")