157 lines
3.8 KiB
Python
157 lines
3.8 KiB
Python
"""Pydantic 스키마 (요청/응답 직렬화)"""
|
|
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
# ━━━━━━━━ 충전기 ━━━━━━━━
|
|
|
|
class ChargerCreate(BaseModel):
|
|
charge_box_id: str = Field(..., example="CHARGER_001")
|
|
name: str = Field("", example="A동 주차장 1번")
|
|
location: str = Field("", example="수원시 영통구 아파트 지하1층")
|
|
connector_count: int = 1
|
|
power_kw: float = 7.0
|
|
|
|
|
|
class ChargerOut(BaseModel):
|
|
id: int
|
|
charge_box_id: str
|
|
name: str
|
|
location: str
|
|
connector_count: int
|
|
power_kw: float
|
|
status: str
|
|
last_heartbeat: Optional[datetime] = None
|
|
is_active: bool
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ChargerStatusUpdate(BaseModel):
|
|
status: str
|
|
timestamp: Optional[datetime] = None
|
|
|
|
|
|
# ━━━━━━━━ 충전 세션 ━━━━━━━━
|
|
|
|
class SessionCreate(BaseModel):
|
|
"""QR 스캔 → 세션 생성 요청"""
|
|
charge_box_id: str = Field(..., example="CHARGER_001")
|
|
connector_id: int = 1
|
|
|
|
|
|
class SessionOut(BaseModel):
|
|
id: int
|
|
session_uid: str
|
|
charger_id: int
|
|
id_tag: Optional[str] = None
|
|
status: str
|
|
meter_start: Optional[int] = None
|
|
meter_stop: Optional[int] = None
|
|
charged_wh: int = 0
|
|
total_bill: int = 0
|
|
started_at: Optional[datetime] = None
|
|
stopped_at: Optional[datetime] = None
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class SessionBilling(BaseModel):
|
|
"""정산 결과"""
|
|
session_uid: str
|
|
charged_kwh: float
|
|
electricity_cost: int
|
|
service_fee: int
|
|
total_bill: int
|
|
saved_vs_cpo: int
|
|
|
|
|
|
# ━━━━━━━━ 결제 ━━━━━━━━
|
|
|
|
class PaymentRequest(BaseModel):
|
|
"""결제 시작 요청 (모바일 웹에서 호출)"""
|
|
session_uid: str
|
|
amount: int = Field(..., ge=100, example=10000, description="선결제 금액 (원)")
|
|
|
|
|
|
class PaymentConfirm(BaseModel):
|
|
"""토스페이먼츠 결제 승인 요청"""
|
|
payment_key: str
|
|
order_id: str
|
|
amount: int
|
|
|
|
|
|
class PaymentOut(BaseModel):
|
|
order_id: str
|
|
payment_key: Optional[str] = None
|
|
amount: int
|
|
actual_amount: Optional[int] = None
|
|
status: str
|
|
method: Optional[str] = None
|
|
confirmed_at: Optional[datetime] = None
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# ━━━━━━━━ Steve OCPP 콜백 ━━━━━━━━
|
|
|
|
class OcppBootNotification(BaseModel):
|
|
charge_box_id: str
|
|
charge_point_vendor: Optional[str] = None
|
|
charge_point_model: Optional[str] = None
|
|
firmware_version: Optional[str] = None
|
|
|
|
|
|
class OcppStatusNotification(BaseModel):
|
|
charge_box_id: str
|
|
connector_id: int = 1
|
|
status: str # Available, Charging, Faulted ...
|
|
error_code: str = "NoError"
|
|
timestamp: Optional[datetime] = None
|
|
|
|
|
|
class OcppStartTransaction(BaseModel):
|
|
charge_box_id: str
|
|
connector_id: int = 1
|
|
id_tag: str
|
|
meter_start: int # Wh
|
|
transaction_id: Optional[int] = None
|
|
timestamp: Optional[datetime] = None
|
|
|
|
|
|
class OcppStopTransaction(BaseModel):
|
|
charge_box_id: str
|
|
transaction_id: int
|
|
id_tag: Optional[str] = None
|
|
meter_stop: int # Wh
|
|
reason: str = "Local"
|
|
timestamp: Optional[datetime] = None
|
|
|
|
|
|
class OcppMeterValues(BaseModel):
|
|
charge_box_id: str
|
|
connector_id: int = 1
|
|
transaction_id: Optional[int] = None
|
|
value: float # Wh
|
|
measurand: str = "Energy.Active.Import.Register"
|
|
timestamp: Optional[datetime] = None
|
|
|
|
|
|
# ━━━━━━━━ 대시보드 ━━━━━━━━
|
|
|
|
class DashboardSummary(BaseModel):
|
|
total_chargers: int
|
|
active_chargers: int
|
|
charging_now: int
|
|
today_sessions: int
|
|
today_revenue: int
|
|
today_kwh: float
|
|
month_revenue: int
|
|
month_kwh: float
|