feat: Airwallex 发卡管理后台完整实现
- 后端: FastAPI + SQLAlchemy + SQLite, JWT认证, 代理支持的AirwallexClient - 前端: React 18 + Vite + Ant Design 5, 中文界面 - 功能: 卡片管理, 持卡人管理, 交易记录, API令牌, 系统设置, 审计日志 - 第三方API: X-API-Key认证, 权限控制 - Docker部署: docker-compose编排前后端
This commit is contained in:
102
airwallex-sdk/airwallex/models/invoice.py
Normal file
102
airwallex-sdk/airwallex/models/invoice.py
Normal file
@@ -0,0 +1,102 @@
|
||||
"""
|
||||
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")
|
||||
Reference in New Issue
Block a user