Devize
Devizul (estimate) este oferta de reparație atașată unei comenzi de service. Devizele sunt versionate: un amendament creează o versiune nouă și o marchează pe cea anterioară superseded. Clientul aprobă sau respinge per linie, iar starea liniilor se rulează în starea devizului.
Endpoint-uri
| Metodă | Cale | Descriere |
|---|---|---|
| GET | /api/v1/service/work-orders/{id}/estimates | Listează toate versiunile de deviz ale unei comenzi (desc. după version). |
| POST | /api/v1/service/work-orders/{id}/estimates | Creează un deviz (versiune nouă) pentru comandă. |
| GET | /api/v1/service/estimates/{id} | Citește un deviz cu liniile lui. |
| POST | /api/v1/service/estimates/{id}/send | Marchează devizul ca trimis; generează tokenul de aprobare. |
| POST | /api/v1/service/estimates/{id}/amend | Creează un amendament (versiune nouă) și marchează originalul superseded. |
| POST | /api/v1/service/estimates/{id}/respond | Aplică deciziile clientului pe linii (intern). |
Aprobare de către client
Pentru aprobarea direct de către client (fără login), folosește endpoint-urile publice din urmărire publică. respond-ul de aici este pentru personalul atelierului care înregistrează un răspuns primit telefonic / în persoană.
Statusuri deviz
draft · sent · viewed · partially_approved · approved · declined · expired · superseded.
După ce clientul răspunde, status-ul se calculează din deciziile pe linii: toate approved → approved; toate declined → declined; mix → partially_approved.
Creare deviz
| Câmp | Tip | Obligatoriu | Note |
|---|---|---|---|
currency | string (3) | nu | Implicit moneda comenzii sau RON. |
valid_until | date | nu | Valabilitatea ofertei. |
customer_message | text | nu | Mesaj afișat clientului. |
deposit_required_cents | integer ≥ 0 | nu | Avans cerut, în bani. Implicit 0. |
lines | array | nu | Liniile devizului (vezi mai jos). |
Fiecare element din lines:
| Câmp | Tip | Obligatoriu | Note |
|---|---|---|---|
line_type | enum | da | labor | part | sublet | fee | discount. |
description | string ≤ 255 | da | |
quantity | numeric ≥ 0 | nu | Implicit 1. |
unit_price_cents | integer | da | Preț unitar net, în bani. |
tax_rate_bps | integer ≥ 0 | da | Cotă TVA în puncte de bază (1900 = 19%). |
TVA-ul și totalul per linie se calculează server-side: net = round(quantity * unit_price_cents), tax = round(net * tax_rate_bps / 10000). Subtotalul, TVA-ul și totalul devizului se recalculează automat.
Exemplu
curl -X POST https://tenant.notsowms.ro/api/v1/service/work-orders/901/estimates \
-H "Authorization: Bearer tenant.7c4a8d09ca3762af61e59520943dc26494f8941b" \
-H "Content-Type: application/json" \
-d '{
"valid_until": "2026-06-25",
"customer_message": "Devizul pentru revizia de 10.000 km.",
"deposit_required_cents": 20000,
"lines": [
{ "line_type": "labor", "description": "Manoperă revizie", "quantity": 1, "unit_price_cents": 30000, "tax_rate_bps": 1900 },
{ "line_type": "part", "description": "Set plăcuțe frână față", "quantity": 1, "unit_price_cents": 22000, "tax_rate_bps": 1900 }
]
}'Răspuns 201:
{
"data": {
"id": 555,
"work_order_id": 901,
"version": 1,
"status": "draft",
"currency": "RON",
"subtotal_cents": 52000,
"tax_cents": 9880,
"total_cents": 61880,
"deposit_required_cents": 20000,
"valid_until": "2026-06-25",
"customer_message": "Devizul pentru revizia de 10.000 km.",
"lines": [
{ "id": 1, "line_type": "labor", "description": "Manoperă revizie", "quantity": 1, "unit_price_cents": 30000, "tax_rate_bps": 1900, "tax_cents": 5700, "total_cents": 30000, "customer_decision": "pending" },
{ "id": 2, "line_type": "part", "description": "Set plăcuțe frână față", "quantity": 1, "unit_price_cents": 22000, "tax_rate_bps": 1900, "tax_cents": 4180, "total_cents": 22000, "customer_decision": "pending" }
]
}
}Trimitere către client
curl -X POST https://tenant.notsowms.ro/api/v1/service/estimates/555/send \
-H "Authorization: Bearer tenant.7c4a8d09ca3762af61e59520943dc26494f8941b" \
-H "Content-Type: application/json" \
-d '{ "sent_via": "whatsapp" }'| Câmp | Tip | Note |
|---|---|---|
sent_via | enum | whatsapp | sms | email | in_person. Implicit in_person. |
Setează status = sent, sent_at = acum și generează approval_token (dacă nu există deja) — token-ul folosit de pagina publică de aprobare.
Amendament
curl -X POST https://tenant.notsowms.ro/api/v1/service/estimates/555/amend \
-H "Authorization: Bearer tenant.7c4a8d09ca3762af61e59520943dc26494f8941b"Creează o versiune nouă (parent_estimate_id = devizul curent), copiază liniile cu customer_decision = pending și marchează devizul original superseded. Răspuns 201 cu noul deviz.
Înregistrare decizii (intern)
curl -X POST https://tenant.notsowms.ro/api/v1/service/estimates/555/respond \
-H "Authorization: Bearer tenant.7c4a8d09ca3762af61e59520943dc26494f8941b" \
-H "Content-Type: application/json" \
-d '{
"responded_via": "phone_call_logged_by",
"decisions": [
{ "line_id": 1, "decision": "approved" },
{ "line_id": 2, "decision": "declined" }
]
}'| Câmp | Tip | Obligatoriu | Note |
|---|---|---|---|
decisions | array | da | Minim 1 element. |
decisions[].line_id | integer | da | Id-ul liniei de deviz. |
decisions[].decision | enum | da | approved | declined | deferred. |
responded_via | enum | nu | whatsapp | sms_reply | tap_link | phone_call_logged_by | in_person. Implicit tap_link. |