feat: T03+T04 backend - FastAPI, DB models, Rentman integration, admin auth, APScheduler
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Schema exports."""
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
"""Pydantic schemas for admin auth."""
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
access_token: str
|
||||
token_type: str = "bearer"
|
||||
|
||||
|
||||
class AdminInfo(BaseModel):
|
||||
username: str
|
||||
@@ -0,0 +1,21 @@
|
||||
"""Pydantic schema for contact form."""
|
||||
from pydantic import BaseModel, EmailStr, field_validator
|
||||
|
||||
|
||||
class ContactCreate(BaseModel):
|
||||
name: str
|
||||
email: EmailStr
|
||||
phone: str | None = None
|
||||
message: str
|
||||
privacy_consent: bool
|
||||
|
||||
@field_validator("privacy_consent")
|
||||
@classmethod
|
||||
def consent_must_be_true(cls, v: bool) -> bool:
|
||||
if not v:
|
||||
raise ValueError("privacy_consent must be True")
|
||||
return v
|
||||
|
||||
|
||||
class ContactResponse(BaseModel):
|
||||
success: bool
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Pydantic schemas for equipment endpoints."""
|
||||
from pydantic import BaseModel
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
|
||||
class EquipmentItem(BaseModel):
|
||||
id: int
|
||||
rentman_id: str
|
||||
name: str
|
||||
number: str | None = None
|
||||
category: str | None = None
|
||||
description: str | None = None
|
||||
image_url: str | None = None
|
||||
rental_price: Decimal | None = None
|
||||
available: bool = True
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class EquipmentDetail(BaseModel):
|
||||
id: int
|
||||
rentman_id: str
|
||||
name: str
|
||||
number: str | None = None
|
||||
category: str | None = None
|
||||
description: str | None = None
|
||||
specifications: dict[str, Any] | None = None
|
||||
images: list[str] | None = None
|
||||
rental_price: Decimal | None = None
|
||||
brand: str | None = None
|
||||
available: bool = True
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class PaginatedResponse(BaseModel):
|
||||
items: list[EquipmentItem]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
total_pages: int
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Pydantic schemas for rental requests."""
|
||||
from pydantic import BaseModel, EmailStr, field_validator
|
||||
from datetime import date
|
||||
|
||||
|
||||
class RentalRequestItemCreate(BaseModel):
|
||||
equipment_id: int
|
||||
quantity: int = 1
|
||||
|
||||
@field_validator("quantity")
|
||||
@classmethod
|
||||
def quantity_positive(cls, v: int) -> int:
|
||||
if v < 1:
|
||||
raise ValueError("quantity must be >= 1")
|
||||
return v
|
||||
|
||||
|
||||
class RentalRequestCreate(BaseModel):
|
||||
event_name: str
|
||||
date_start: date
|
||||
date_end: date
|
||||
location: str | None = None
|
||||
person_count: int | None = None
|
||||
contact_name: str
|
||||
contact_company: str | None = None
|
||||
contact_email: EmailStr
|
||||
contact_phone: str | None = None
|
||||
contact_street: str | None = None
|
||||
contact_postalcode: str | None = None
|
||||
contact_city: str | None = None
|
||||
message: str | None = None
|
||||
items: list[RentalRequestItemCreate]
|
||||
|
||||
@field_validator("date_end")
|
||||
@classmethod
|
||||
def date_end_after_start(cls, v: date, values) -> date:
|
||||
start = values.data.get("date_start")
|
||||
if start and v < start:
|
||||
raise ValueError("date_end must be >= date_start")
|
||||
return v
|
||||
|
||||
@field_validator("items")
|
||||
@classmethod
|
||||
def items_not_empty(cls, v: list) -> list:
|
||||
if len(v) == 0:
|
||||
raise ValueError("items must not be empty")
|
||||
return v
|
||||
|
||||
|
||||
class RentalRequestResponse(BaseModel):
|
||||
reference_number: str
|
||||
status: str
|
||||
@@ -0,0 +1,28 @@
|
||||
"""Pydantic schemas for sync status and log."""
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
|
||||
class SyncStatus(BaseModel):
|
||||
last_sync: datetime | None = None
|
||||
items_processed: int = 0
|
||||
status: str = "never"
|
||||
|
||||
|
||||
class SyncLogEntry(BaseModel):
|
||||
id: int
|
||||
sync_type: str
|
||||
status: str
|
||||
items_processed: int
|
||||
items_failed: int
|
||||
error_message: str | None = None
|
||||
started_at: datetime
|
||||
completed_at: datetime | None = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class SyncTriggerResponse(BaseModel):
|
||||
sync_id: int
|
||||
status: str
|
||||
Reference in New Issue
Block a user