-
Notifications
You must be signed in to change notification settings - Fork 0
プラン設定機能追加 #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
プラン設定機能追加 #26
Changes from all commits
fd49363
26d04af
92040eb
f2c9715
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,13 +1,14 @@ | ||||||||||
| # billing_router.py | ||||||||||
|
|
||||||||||
| from fastapi import APIRouter, Depends, HTTPException, Query | ||||||||||
| from typing import List, Dict, Any, Tuple | ||||||||||
| from typing import List, Dict, Any, Tuple, Optional | ||||||||||
| from pydantic import BaseModel, Field | ||||||||||
| from datetime import datetime, timedelta | ||||||||||
| from dateutil.relativedelta import relativedelta | ||||||||||
|
|
||||||||||
| # SaaS SDK のクライアント | ||||||||||
| from saasus_sdk_python.src.auth import TenantApi | ||||||||||
| from saasus_sdk_python.src.auth.models.plan_reservation import PlanReservation | ||||||||||
| from saasus_sdk_python.src.pricing import ( | ||||||||||
| PricingPlansApi, | ||||||||||
| MeteringApi, | ||||||||||
|
|
@@ -34,6 +35,11 @@ class UpdateCountBody(BaseModel): | |||||||||
| method: str = Field(..., pattern="^(add|sub|direct)$") | ||||||||||
| count: int = Field(..., ge=0) | ||||||||||
|
|
||||||||||
| class UpdateTenantPlanRequest(BaseModel): | ||||||||||
| next_plan_id: Optional[str] = None | ||||||||||
| tax_rate_id: Optional[str] = None | ||||||||||
| using_next_plan_from: Optional[int] = None | ||||||||||
|
|
||||||||||
|
|
||||||||||
| # --- 認可ヘルパー --- | ||||||||||
| def has_billing_access(auth_user: Any, tenant_id: str) -> bool: | ||||||||||
|
|
@@ -360,4 +366,124 @@ def update_count_of_now( | |||||||||
| metering_unit_name=unit, | ||||||||||
| update_metering_unit_timestamp_count_now_param=param, | ||||||||||
| ) | ||||||||||
| return resp | ||||||||||
| return resp | ||||||||||
|
|
||||||||||
| @router.get( | ||||||||||
| "/pricing_plans", | ||||||||||
| summary="Get pricing plans list" | ||||||||||
| ) | ||||||||||
| def get_pricing_plans(auth_user: Any = Depends(fastapi_auth)): | ||||||||||
| # プラン一覧を取得する | ||||||||||
| try: | ||||||||||
| # 料金プラン一覧を取得 | ||||||||||
| plans = PricingPlansApi(api_client=pricing_api_client).get_pricing_plans() | ||||||||||
| return plans.pricing_plans | ||||||||||
| except Exception as e: | ||||||||||
| raise HTTPException(status_code=500, detail="Failed to retrieve pricing plans") | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @router.get( | ||||||||||
| "/tax_rates", | ||||||||||
| summary="Get tax rates list" | ||||||||||
| ) | ||||||||||
| def get_tax_rates(auth_user: Any = Depends(fastapi_auth)): | ||||||||||
| # 税率一覧を取得する | ||||||||||
| try: | ||||||||||
| # 税率一覧を取得 | ||||||||||
| tax_rates = TaxRateApi(api_client=pricing_api_client).get_tax_rates() | ||||||||||
| return tax_rates.tax_rates | ||||||||||
| except Exception as e: | ||||||||||
| print(f"TaxRateApi error: {e}") | ||||||||||
| raise HTTPException(status_code=500, detail="Failed to retrieve tax rates") | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @router.get( | ||||||||||
| "/tenants/{tenant_id}/plan", | ||||||||||
| summary="Get tenant plan information" | ||||||||||
| ) | ||||||||||
| def get_tenant_plan_info( | ||||||||||
| tenant_id: str, | ||||||||||
| auth_user: Any = Depends(fastapi_auth) | ||||||||||
| ): | ||||||||||
| # テナントプラン情報を取得する | ||||||||||
| # 管理者権限チェック | ||||||||||
| if not has_billing_access(auth_user, tenant_id): | ||||||||||
| raise HTTPException(status_code=403, detail="Insufficient permissions") | ||||||||||
|
|
||||||||||
| try: | ||||||||||
| # テナント詳細情報を取得 | ||||||||||
| tenant = TenantApi(api_client=api_client).get_tenant(tenant_id=tenant_id) | ||||||||||
|
|
||||||||||
| # 現在のプランの税率情報を取得(プラン履歴の最新エントリから) | ||||||||||
| current_tax_rate_id = None | ||||||||||
| if tenant.plan_histories: | ||||||||||
| latest_plan_history = tenant.plan_histories[-1] | ||||||||||
| if latest_plan_history.tax_rate_id: | ||||||||||
| current_tax_rate_id = latest_plan_history.tax_rate_id | ||||||||||
|
|
||||||||||
| # レスポンスを構築 | ||||||||||
| response = { | ||||||||||
| "id": tenant.id, | ||||||||||
| "name": tenant.name, | ||||||||||
| "plan_id": tenant.plan_id, | ||||||||||
| "tax_rate_id": current_tax_rate_id, | ||||||||||
| "plan_reservation": None, | ||||||||||
| } | ||||||||||
|
|
||||||||||
| # 予約情報がある場合は追加(using_next_plan_fromで判定) | ||||||||||
| if hasattr(tenant, 'using_next_plan_from') and tenant.using_next_plan_from is not None: | ||||||||||
| plan_reservation = { | ||||||||||
| "next_plan_id": getattr(tenant, 'next_plan_id', None), | ||||||||||
| "using_next_plan_from": tenant.using_next_plan_from, | ||||||||||
| "next_plan_tax_rate_id": getattr(tenant, 'next_plan_tax_rate_id', None), | ||||||||||
| } | ||||||||||
| response["plan_reservation"] = plan_reservation | ||||||||||
|
|
||||||||||
| return response | ||||||||||
| except Exception as e: | ||||||||||
| print(f"TenantApi error: {e}") | ||||||||||
| raise HTTPException(status_code=500, detail="Failed to retrieve tenant detail") | ||||||||||
|
||||||||||
| raise HTTPException(status_code=500, detail="Failed to retrieve tenant detail") | |
| raise HTTPException(status_code=500, detail=f"Failed to retrieve tenant detail: {str(e)}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
エラー詳細はprintでコンソール出力、フロントには出さない形式で対応。
Copilot
AI
Oct 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition checks for truthiness (if request.tax_rate_id:) which will be False for empty strings, but the comment on line 476 indicates empty strings should be handled. Change to if request.tax_rate_id is not None: to match the behavior of next_plan_id and allow empty strings to be set.
| # 税率IDが指定されている場合のみ設定 | |
| if request.tax_rate_id: | |
| # 税率IDがNoneでない場合は設定(空文字も含む) | |
| if request.tax_rate_id is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next_plan_idは解除予約で空文字が必要、tax_rate_idは不要のため対応しない。
Copilot
AI
Oct 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message lacks context about the actual error. Consider including the exception details or a more specific error message to aid in debugging. For example: detail=f\"Failed to update tenant plan: {str(e)}\"
| raise HTTPException(status_code=500, detail="Failed to update tenant plan") | |
| raise HTTPException(status_code=500, detail=f"Failed to update tenant plan: {str(e)}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
エラー詳細はprintでコンソール出力、フロントには出さない形式で対応。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message lacks context about the actual error. Consider including the exception details or a more specific error message to aid in debugging. For example:
detail=f\"Failed to retrieve tax rates: {str(e)}\"There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
エラー詳細はprintでコンソール出力、フロントには出さない形式で対応。