- All business models: Vehicle, Order, OrderLine, Invoice, Appointment, CatalogMarca/Model/Ansamblu/Norma/Pret/TipDeviz/TipMotor, Mecanic - Sync endpoints: GET /sync/full, GET /sync/changes?since=, POST /sync/push with tenant isolation and last-write-wins conflict resolution - Order CRUD with state machine: DRAFT -> VALIDAT -> FACTURAT Auto-recalculates totals (manopera + materiale) - Vehicle CRUD: list, create, get, update - Seed data: 24 marci, 11 ansamble, 6 tipuri deviz, 5 tipuri motoare, 3 preturi - Alembic migration for all business models - 13 passing tests (auth + sync + orders) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
111 lines
3.1 KiB
Python
111 lines
3.1 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.db.base import uuid7
|
|
from app.db.models.vehicle import Vehicle
|
|
from app.db.session import get_db
|
|
from app.deps import get_tenant_id
|
|
from app.vehicles import schemas
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("")
|
|
async def list_vehicles(
|
|
tenant_id: str = Depends(get_tenant_id),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
r = await db.execute(
|
|
select(Vehicle).where(Vehicle.tenant_id == tenant_id)
|
|
)
|
|
vehicles = r.scalars().all()
|
|
return [
|
|
{
|
|
"id": v.id,
|
|
"nr_auto": v.nr_inmatriculare,
|
|
"marca_id": v.marca_id,
|
|
"model_id": v.model_id,
|
|
"an": v.an_fabricatie,
|
|
"client_nume": v.client_nume,
|
|
}
|
|
for v in vehicles
|
|
]
|
|
|
|
|
|
@router.post("")
|
|
async def create_vehicle(
|
|
data: schemas.CreateVehicleRequest,
|
|
tenant_id: str = Depends(get_tenant_id),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
vehicle = Vehicle(
|
|
id=uuid7(),
|
|
tenant_id=tenant_id,
|
|
nr_inmatriculare=data.nr_auto,
|
|
marca_id=data.marca_id,
|
|
model_id=data.model_id,
|
|
an_fabricatie=data.an_fabricatie,
|
|
vin=data.vin,
|
|
client_nume=data.proprietar_nume,
|
|
client_telefon=data.proprietar_telefon,
|
|
)
|
|
db.add(vehicle)
|
|
await db.commit()
|
|
return {"id": vehicle.id}
|
|
|
|
|
|
@router.get("/{vehicle_id}")
|
|
async def get_vehicle(
|
|
vehicle_id: str,
|
|
tenant_id: str = Depends(get_tenant_id),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
r = await db.execute(
|
|
select(Vehicle).where(
|
|
Vehicle.id == vehicle_id, Vehicle.tenant_id == tenant_id
|
|
)
|
|
)
|
|
v = r.scalar_one_or_none()
|
|
if not v:
|
|
raise HTTPException(status_code=404, detail="Vehicle not found")
|
|
return {
|
|
"id": v.id,
|
|
"nr_auto": v.nr_inmatriculare,
|
|
"marca_id": v.marca_id,
|
|
"model_id": v.model_id,
|
|
"an": v.an_fabricatie,
|
|
"vin": v.vin,
|
|
"client_nume": v.client_nume,
|
|
"client_telefon": v.client_telefon,
|
|
"client_email": v.client_email,
|
|
}
|
|
|
|
|
|
@router.put("/{vehicle_id}")
|
|
async def update_vehicle(
|
|
vehicle_id: str,
|
|
data: schemas.UpdateVehicleRequest,
|
|
tenant_id: str = Depends(get_tenant_id),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
r = await db.execute(
|
|
select(Vehicle).where(
|
|
Vehicle.id == vehicle_id, Vehicle.tenant_id == tenant_id
|
|
)
|
|
)
|
|
v = r.scalar_one_or_none()
|
|
if not v:
|
|
raise HTTPException(status_code=404, detail="Vehicle not found")
|
|
update_data = data.model_dump(exclude_unset=True)
|
|
if "nr_auto" in update_data:
|
|
update_data["nr_inmatriculare"] = update_data.pop("nr_auto")
|
|
if "proprietar_nume" in update_data:
|
|
update_data["client_nume"] = update_data.pop("proprietar_nume")
|
|
if "proprietar_telefon" in update_data:
|
|
update_data["client_telefon"] = update_data.pop("proprietar_telefon")
|
|
for key, value in update_data.items():
|
|
setattr(v, key, value)
|
|
await db.commit()
|
|
return {"ok": True}
|