Files
ai-contract-platform/backend/app/api/tenant_settings.py
T

332 lines
13 KiB
Python

from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends, Form, Header
from sqlalchemy.orm import Session
from app.core.response import success_response
from app.db import get_db_session
from app.services.audit_log_service import AuditLogService
from app.services.auth_service import AuthService
from app.services.tenant_service import TenantService
router = APIRouter(prefix="/tenant-settings", tags=["tenant-settings"])
ROUTE_PERMISSION_SCOPE = "tenant_settings"
ROUTE_PERMISSION_ACTIONS = {
"get": "tenant_settings:get",
"update": "tenant_settings:update",
"billing": "tenant_settings:billing",
"billing_orders": "tenant_settings:billing_orders",
"create_billing_order": "tenant_settings:create_billing_order",
"activate_billing_order": "tenant_settings:activate_billing_order",
"update_billing_plan": "tenant_settings:update_billing_plan",
"billing_invoices": "tenant_settings:billing_invoices",
"request_billing_invoice": "tenant_settings:request_billing_invoice",
"issue_billing_invoice": "tenant_settings:issue_billing_invoice",
}
def get_tenant_service(db: Session = Depends(get_db_session)) -> TenantService:
return TenantService(db)
def get_audit_log_service(db: Session = Depends(get_db_session)) -> AuditLogService:
return AuditLogService(db)
def require_current_user(
authorization: Optional[str] = Header(default=None),
db: Session = Depends(get_db_session),
):
return AuthService(db).require_current_user(authorization)
@router.get("/me")
def get_current_tenant_settings(
tenant_service: TenantService = Depends(get_tenant_service),
current_user: dict = Depends(require_current_user),
):
return success_response(tenant_service.get_current_settings(current_user))
@router.get("/billing")
def get_current_tenant_billing(
tenant_service: TenantService = Depends(get_tenant_service),
current_user: dict = Depends(require_current_user),
):
return success_response(tenant_service.get_current_billing(current_user))
@router.get("/billing/orders")
def list_current_tenant_commercial_orders(
limit: int = 50,
tenant_service: TenantService = Depends(get_tenant_service),
current_user: dict = Depends(require_current_user),
):
return success_response(tenant_service.list_commercial_orders(current_user, limit=limit))
@router.get("/billing/invoices")
def list_current_tenant_commercial_invoices(
limit: int = 50,
tenant_service: TenantService = Depends(get_tenant_service),
current_user: dict = Depends(require_current_user),
):
return success_response(tenant_service.list_commercial_invoices(current_user, limit=limit))
@router.post("/billing/orders")
def create_current_tenant_commercial_order(
order_type: str = Form(default="subscription"),
plan_code: str = Form(...),
plan_name: Optional[str] = Form(default=None),
billing_cycle: str = Form(default="monthly"),
amount_cents: int = Form(default=0),
currency: str = Form(default="CNY"),
payment_provider: str = Form(default="offline"),
invoice_required: bool = Form(default=False),
contact_name: Optional[str] = Form(default=None),
contact_phone: Optional[str] = Form(default=None),
contact_email: Optional[str] = Form(default=None),
note: Optional[str] = Form(default=None),
review_quota_monthly: Optional[int] = Form(default=None),
generation_quota_monthly: Optional[int] = Form(default=None),
knowledge_base_quota: Optional[int] = Form(default=None),
storage_quota_mb: Optional[int] = Form(default=None),
max_users: Optional[int] = Form(default=None),
max_storage_mb: Optional[int] = Form(default=None),
tenant_service: TenantService = Depends(get_tenant_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = tenant_service.create_commercial_order(
current_user=current_user,
order_type=order_type,
plan_code=plan_code,
plan_name=plan_name,
billing_cycle=billing_cycle,
amount_cents=amount_cents,
currency=currency,
payment_provider=payment_provider,
invoice_required=invoice_required,
contact_name=contact_name,
contact_phone=contact_phone,
contact_email=contact_email,
note=note,
review_quota_monthly=review_quota_monthly,
generation_quota_monthly=generation_quota_monthly,
knowledge_base_quota=knowledge_base_quota,
storage_quota_mb=storage_quota_mb,
max_users=max_users,
max_storage_mb=max_storage_mb,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="create_commercial_order",
resource_type="commercial_order",
resource_id=result["id"],
detail_json={
"order_no": result["order_no"],
"order_type": result["order_type"],
"plan_code": result["plan_code"],
"amount_cents": result["amount_cents"],
"invoice_status": result["invoice_status"],
},
)
return success_response(result)
@router.post("/billing/orders/{order_id}/invoice")
def request_current_tenant_commercial_invoice(
order_id: str,
invoice_type: str = Form(default="vat_general"),
invoice_title: str = Form(...),
tax_number: str = Form(...),
registered_address: Optional[str] = Form(default=None),
registered_phone: Optional[str] = Form(default=None),
bank_name: Optional[str] = Form(default=None),
bank_account: Optional[str] = Form(default=None),
receiver_email: Optional[str] = Form(default=None),
receiver_phone: Optional[str] = Form(default=None),
note: Optional[str] = Form(default=None),
tenant_service: TenantService = Depends(get_tenant_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = tenant_service.request_commercial_invoice(
current_user=current_user,
order_id=order_id,
invoice_type=invoice_type,
invoice_title=invoice_title,
tax_number=tax_number,
registered_address=registered_address,
registered_phone=registered_phone,
bank_name=bank_name,
bank_account=bank_account,
receiver_email=receiver_email,
receiver_phone=receiver_phone,
note=note,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="request_commercial_invoice",
resource_type="commercial_invoice",
resource_id=result["id"],
detail_json={
"order_id": result["order_id"],
"invoice_type": result["invoice_type"],
"invoice_title": result["invoice_title"],
"amount_cents": result["amount_cents"],
"status": result["status"],
},
)
return success_response(result)
@router.post("/billing/invoices/{invoice_id}/issue")
def issue_current_tenant_commercial_invoice(
invoice_id: str,
invoice_no: str = Form(...),
invoice_file_id: Optional[str] = Form(default=None),
note: Optional[str] = Form(default=None),
tenant_service: TenantService = Depends(get_tenant_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = tenant_service.issue_commercial_invoice(
current_user=current_user,
invoice_id=invoice_id,
invoice_no=invoice_no,
invoice_file_id=invoice_file_id,
note=note,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="issue_commercial_invoice",
resource_type="commercial_invoice",
resource_id=result["id"],
detail_json={
"order_id": result["order_id"],
"invoice_no": result["invoice_no"],
"invoice_file_id": result["invoice_file_id"],
"status": result["status"],
},
)
return success_response(result)
@router.post("/billing/orders/{order_id}/activate")
def activate_current_tenant_commercial_order(
order_id: str,
payment_provider: str = Form(default="offline"),
payment_proof_file_id: Optional[str] = Form(default=None),
payment_reference: Optional[str] = Form(default=None),
tenant_service: TenantService = Depends(get_tenant_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = tenant_service.activate_commercial_order(
current_user,
order_id,
payment_provider=payment_provider,
payment_proof_file_id=payment_proof_file_id,
payment_reference=payment_reference,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="activate_commercial_order",
resource_type="commercial_order",
resource_id=order_id,
detail_json={
"order_no": result["order"]["order_no"],
"plan_code": result["tenant"]["plan_code"],
"billing_status": result["tenant"]["billing_status"],
"payment_provider": result["order"]["payment_provider"],
"payment_reference": result["order"]["payment_reference"],
"payment_proof_file_id": result["order"]["payment_proof_file_id"],
},
)
return success_response(result)
@router.put("/billing/plan")
def update_current_tenant_billing_plan(
plan_code: str = Form(...),
plan_name: str = Form(...),
billing_status: str = Form(default="active"),
trial_ends_at: Optional[datetime] = Form(default=None),
review_quota_monthly: Optional[int] = Form(default=None),
generation_quota_monthly: Optional[int] = Form(default=None),
knowledge_base_quota: Optional[int] = Form(default=None),
storage_quota_mb: Optional[int] = Form(default=None),
max_users: Optional[int] = Form(default=None),
max_storage_mb: Optional[int] = Form(default=None),
tenant_service: TenantService = Depends(get_tenant_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = tenant_service.update_current_billing_plan(
current_user=current_user,
plan_code=plan_code,
plan_name=plan_name,
billing_status=billing_status,
trial_ends_at=trial_ends_at,
review_quota_monthly=review_quota_monthly,
generation_quota_monthly=generation_quota_monthly,
knowledge_base_quota=knowledge_base_quota,
storage_quota_mb=storage_quota_mb,
max_users=max_users,
max_storage_mb=max_storage_mb,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="update_commercial_billing_plan",
resource_type="tenant",
resource_id=result["id"],
detail_json={
"plan_code": result["plan_code"],
"plan_name": result["plan_name"],
"billing_status": result["billing_status"],
"review_quota_monthly": result["review_quota_monthly"],
"generation_quota_monthly": result["generation_quota_monthly"],
"knowledge_base_quota": result["knowledge_base_quota"],
"storage_quota_mb": result["storage_quota_mb"],
"max_users": result["max_users"],
"max_storage_mb": result["max_storage_mb"],
},
)
return success_response(result)
@router.put("/me")
def update_current_tenant_settings(
name: str = Form(...),
code: str = Form(...),
status_value: str = Form(alias="status", default="active"),
tenant_service: TenantService = Depends(get_tenant_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = tenant_service.update_current_settings(current_user, name, code, status_value)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="update_tenant_settings",
resource_type="tenant",
resource_id=result["id"],
detail_json={
"name": result["name"],
"code": result["code"],
"status": result["status"],
"plan_name": result["plan_name"],
"max_users": result["max_users"],
"max_storage_mb": result["max_storage_mb"],
},
)
return success_response(result)