332 lines
13 KiB
Python
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)
|