feat(backend): sync endpoints + all models + seed + order workflow

- 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>
This commit is contained in:
2026-03-13 17:31:02 +02:00
parent ad41956ea1
commit 3a922a50e6
25 changed files with 1410 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
import pytest
import pytest_asyncio
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
from app.db.base import Base
@@ -22,3 +23,40 @@ async def setup_test_db():
yield
app.dependency_overrides.clear()
await engine.dispose()
@pytest_asyncio.fixture
async def client():
async with AsyncClient(
transport=ASGITransport(app=app), base_url="http://test"
) as c:
yield c
@pytest_asyncio.fixture
async def auth_headers(client):
r = await client.post(
"/api/auth/register",
json={
"email": "test@service.ro",
"password": "testpass123",
"tenant_name": "Test Service",
"telefon": "0722000000",
},
)
token = r.json()["access_token"]
return {"Authorization": f"Bearer {token}"}
@pytest_asyncio.fixture
async def tenant_id(client):
r = await client.post(
"/api/auth/register",
json={
"email": "tenant@service.ro",
"password": "testpass123",
"tenant_name": "Tenant Service",
"telefon": "0722000001",
},
)
return r.json()["tenant_id"]