feat: T03+T04 backend - FastAPI, DB models, Rentman integration, admin auth, APScheduler

This commit is contained in:
Implementation Engineer
2026-07-09 01:36:46 +02:00
parent 3bfa54b4b3
commit 15fd1b0f8d
78 changed files with 2174 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
"""Schema exports."""
Binary file not shown.
Binary file not shown.
+16
View File
@@ -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
+21
View File
@@ -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
+42
View File
@@ -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
+52
View File
@@ -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
+28
View File
@@ -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