feat: add clients nomenclator, order edit/delete/devalidate, invoice types, dashboard redesign

- New clients table with PF/PJ support, fiscal data (CUI, IBAN, eFactura fields)
- Full CRUD API for clients with search, sync integration
- Order lifecycle: edit header (DRAFT), devalidate (VALIDAT→DRAFT), delete order/invoice
- Invoice types: FACTURA (B2B) vs BON_FISCAL (B2C) with different nr formats
- OrderCreateView redesigned as multi-step flow (client→vehicle→details)
- Autocomplete from catalog_norme/catalog_preturi in OrderLineForm
- Dashboard now combines stats + full orders table with filter tabs and search
- ClientPicker and VehiclePicker with inline creation capability
- Frontend schema aligned with backend (missing columns causing sync errors)
- Mobile responsive fixes for OrderDetailView buttons

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 00:36:40 +02:00
parent 3e449d0b0b
commit 9db4e746e3
34 changed files with 2221 additions and 211 deletions

View File

@@ -1,5 +1,6 @@
from app.db.models.tenant import Tenant
from app.db.models.user import User
from app.db.models.client import Client
from app.db.models.vehicle import Vehicle
from app.db.models.order import Order
from app.db.models.order_line import OrderLine
@@ -20,6 +21,7 @@ from app.db.models.invite import InviteToken
__all__ = [
"Tenant",
"User",
"Client",
"Vehicle",
"Order",
"OrderLine",

View File

@@ -0,0 +1,25 @@
from sqlalchemy import Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from app.db.base import Base, UUIDMixin, TenantMixin, TimestampMixin
class Client(Base, UUIDMixin, TenantMixin, TimestampMixin):
__tablename__ = "clients"
tip_persoana: Mapped[str | None] = mapped_column(String(2), default="PF")
denumire: Mapped[str | None] = mapped_column(String(200))
nume: Mapped[str | None] = mapped_column(String(100))
prenume: Mapped[str | None] = mapped_column(String(100))
cod_fiscal: Mapped[str | None] = mapped_column(String(20))
reg_com: Mapped[str | None] = mapped_column(String(30))
telefon: Mapped[str | None] = mapped_column(String(20))
email: Mapped[str | None] = mapped_column(String(200))
adresa: Mapped[str | None] = mapped_column(Text)
judet: Mapped[str | None] = mapped_column(String(50))
oras: Mapped[str | None] = mapped_column(String(100))
cod_postal: Mapped[str | None] = mapped_column(String(10))
tara: Mapped[str | None] = mapped_column(String(2), default="RO")
cont_iban: Mapped[str | None] = mapped_column(String(34))
banca: Mapped[str | None] = mapped_column(String(100))
activ: Mapped[int] = mapped_column(Integer, default=1, server_default="1")
oracle_id: Mapped[int | None] = mapped_column(Integer)

View File

@@ -7,6 +7,8 @@ from app.db.base import Base, UUIDMixin, TenantMixin, TimestampMixin
class Invoice(Base, UUIDMixin, TenantMixin, TimestampMixin):
__tablename__ = "invoices"
order_id: Mapped[str | None] = mapped_column(String(36), index=True)
client_id: Mapped[str | None] = mapped_column(String(36))
tip_document: Mapped[str | None] = mapped_column(String(20), default="FACTURA", server_default="FACTURA")
nr_factura: Mapped[str | None] = mapped_column(String(50))
serie_factura: Mapped[str | None] = mapped_column(String(20))
data_factura: Mapped[str | None] = mapped_column(Text)

View File

@@ -8,6 +8,7 @@ class Order(Base, UUIDMixin, TenantMixin, TimestampMixin):
__tablename__ = "orders"
nr_comanda: Mapped[str | None] = mapped_column(String(50))
vehicle_id: Mapped[str | None] = mapped_column(String(36))
client_id: Mapped[str | None] = mapped_column(String(36))
tip_deviz_id: Mapped[str | None] = mapped_column(String(36))
status: Mapped[str] = mapped_column(String(20), default="DRAFT", server_default="DRAFT")
data_comanda: Mapped[str | None] = mapped_column(Text)

View File

@@ -7,6 +7,7 @@ from app.db.base import Base, UUIDMixin, TenantMixin, TimestampMixin
class Vehicle(Base, UUIDMixin, TenantMixin, TimestampMixin):
__tablename__ = "vehicles"
nr_inmatriculare: Mapped[str] = mapped_column(String(20))
client_id: Mapped[str | None] = mapped_column(String(36))
marca_id: Mapped[str | None] = mapped_column(String(36))
model_id: Mapped[str | None] = mapped_column(String(36))
an_fabricatie: Mapped[int | None] = mapped_column(Integer)

View File

@@ -52,14 +52,7 @@ ANSAMBLE = [
"Revizie",
]
TIPURI_DEVIZ = [
"Deviz reparatie",
"Deviz revizie",
"Deviz diagnosticare",
"Deviz estimativ",
"Deviz vulcanizare",
"Deviz ITP",
]
TIPURI_DEVIZ = ["Service", "ITP", "Regie", "Constatare"]
TIPURI_MOTOARE = ["Benzina", "Diesel", "Hibrid", "Electric", "GPL"]