API WebSocket

Această pagină descrie protocolul WebSocket utilizat de driverul FisCool pentru integrarea în timp real, precum și maparea acestuia pe API-ul HTTP standard.

1. Conexiunea WebSocket

Acesta este un model „invers" (inițiat de client). Dvs., integratorul, găzduiți serverul WebSocket; driverul FisCool funcționează ca Client WebSocket și se conectează în afară, către serverul dvs., deschizând o conexiune persistentă. Serverul dvs. controlează apoi dispozitivele locale prin acea conexiune.

Deoarece driverul se conectează spre exterior, acest lucru funcționează fără port forwarding, IP static sau reguli de firewall de intrare pe mașina pe care rulează driverul - chiar și în spatele NAT. Este metoda ideală pentru a controla o flotă de drivere din propriul dvs. backend central.

RolCineResponsabilitate
Server WebSocketDvs. (integratorul)Îl găzduiți, autentificați conexiunile, trimiteți cereri, citiți răspunsuri.
Client WebSocketDriverul FisCoolSe conectează către serverul dvs., execută cererile pe dispozitivele locale, răspunde.

Cerințe de Configurare

Pentru a îndrepta un driver către serverul dvs., îi furnizați un certificat de configurare - un mic obiect JSON care conține URL-ul serverului dvs. și un token de autentificare la alegerea dvs. Nu aveți nimic de solicitat de la noi: URL-ul și token-ul vă aparțin, fiind definite de propriul dvs. server.

Instrucțiuni: certificatul se încarcă în driver din meniul Setări → Certificat sistem vânzare.

Format Certificat (JSON)

Fișierul JSON trebuie să conțină url și token, ambele indicând către infrastructura dvs. token-ul este un secret partajat opac pe care serverul dvs. îl validează când driverul se conectează (alegeți orice valoare doriți). Câmpul driver_id este configurat separat în interfața aplicației (câmpul „ID Driver"), ca să vă puteți distinge driverele; valoarea din fișier (dacă există) este ignorată la import.

{
  "url": "wss://api.domeniultau.ro/ws",   // URL-ul serverului WebSocket
  "token": "abc-123-xyz"                  // token de autentificare
}

Driverul construiește URL-ul de conexiune astfel:

{url}?token={token}&driver_id={driver_id_din_interfata}

Notă: driverul se reconectează automat în cazul pierderii conexiunii (reîncercare la fiecare 5 secunde) și monitorizează pachetele de ping primite de la server pentru a verifica starea tunelului.

2. Protocolul de Comunicare

Toate mesajele sunt cadre text JSON încapsulate într-un plic standardizat.

Cerere (Server → Driver)

{
  "id": 101,             // ID unic al cererii (pentru corelare cu răspunsul)
  "type": 0,             // 0 = cerere
  "content": {
    "action": 203,       // codul acțiunii (vezi mai jos)
    "idempotency_id": "uuid-optional",   // OPȚIONAL, respectat doar de acțiunea 203
    "parameters": {      // payload-ul specific acțiunii
      ...
    }
  }
}

Driverul reacționează doar la mesajele cu type = 0; orice altceva este ignorat.

Răspuns (Driver → Server)

{
  "id": 101,             // același ID ca în cerere
  "type": 1,             // 1 = răspuns
  "status": 0,           // 0 = succes, 1 = eroare de execuție, 2 = acțiune necunoscută
  "content": {           // rezultatul operațiunii (sau detaliile erorii)
    ...
  }
}

Răspunsuri Fragmentate (Chunked)

Răspunsurile mari (în prezent doar rezultatele căutării de imagini, acțiunea 205) sunt transmise în fragmente de ~5 KB cu type = 3:

{
  "type": 3,             // cadru de răspuns fragmentat
  "id": 101,
  "status": 0,
  "content": {
    "d": "…fragment de șir JSON…",   // fragmentul de date
    "f": false                        // true la fragmentul final
  }
}

Concatenați toate fragmentele d în ordinea sosirii până când f = true, apoi parsați șirul rezultat ca JSON.

3. Acțiuni Disponibile

Cod AcțiuneNumeDescriere
999PINGKeep-alive. Driverul răspunde cu un pong (vezi mai jos).
201GET_CASEReturnează dispozitivele fiscale configurate.
204GET_POSReturnează doar terminalele POS configurate.
203DEVICE_OPERATIONExecută o operațiune fiscală sau POS (bon, raport Z, vânzare, …). Este acțiunea principală - vezi Operațiuni Dispozitive pentru toate payload-urile.
200GET_SYSTEM_PRINTERSReturnează imprimantele de sistem activate în FisCool.
202PRINT_HTMLRandează HTML și îl tipărește ca bitmap pe o imprimantă de sistem. Parametri: {"html": "...", "printer_name": "..."}.
205SEARCH_IMAGESCaută imagini de produse. Parametri: {"query": "...", "limit": 5}. Răspunsul (data-URI-uri base64) este livrat ca răspuns fragmentat.

Acțiunea 201 - răspuns GET_CASE

{
  "id": 42, "type": 1, "status": 0,
  "content": {
    "status": 0,
    "msg": "Device list retrieved",
    "case": [ ... ]      // array de dispozitive fiscale (aceleași obiecte ca GET /devices/fiscal)
  }
}

Acțiunea 204 - răspuns GET_POS

{
  "id": 43, "type": 1, "status": 0,
  "content": {
    "status": 0,
    "msg": "POS terminals retrieved",
    "terminals": [ ... ]
  }
}

Acțiunea 200 - răspuns GET_SYSTEM_PRINTERS

{
  "id": 44, "type": 1, "status": 0,
  "content": {
    "status": 0,
    "msg": "System printers retrieved",
    "printers": ["POS-80", "Microsoft Print to PDF"]   // numele imprimantelor, doar cele activate în FisCool
  }
}

Acțiunea 202 - răspuns PRINT_HTML

{
  "id": 45, "type": 1, "status": 0,
  "content": {
    "status": 0,
    "msg": "Bitmap print job completed successfully"
  }
}

La eșec, status-ul exterior este 1, iar content conține un cod de eroare de imprimantă (20012005, vezi Coduri de Eroare).

Acțiunea 205 - răspuns SEARCH_IMAGES

Livrat ca răspuns segmentat (type = 3, vezi mai sus). După reasamblarea fragmentelor, conținutul este:

{
  "status": 0,
  "msg": "Images retrieved",
  "images": ["data:image/jpeg;base64,...", ...]   // cel mult "limit" imagini
}

4. Mecanismul Keep-Alive (Ping/Pong)

Pentru a menține conexiunea activă și a detecta întreruperile, driverul implementează un watchdog:

  • Timeout: driverul așteaptă cel puțin un cadru de intrare (de regulă un PING) la fiecare 20 de secunde.
  • Comportament: dacă nu se recepționează nimic în acest interval, driverul consideră conexiunea moartă, o închide și se reconectează.
  • Cadrele Ping de la nivelul protocolului WebSocket primesc automat răspuns cu cadre Pong.

Format Ping (Server → Driver)

{
  "id": 9999,
  "type": 0,
  "content": {
    "action": 999,
    "parameters": {}
  }
}

Format Pong (Driver → Server)

{
  "id": 9999,
  "type": 1,
  "status": 0,
  "content": {
    "pong": "pong"
  }
}

5. Operațiuni Dispozitiv (Acțiunea 203) vs API-ul HTTP

Acțiunea WebSocket 203 este echivalentul direct al endpoint-ului HTTP POST /devices/operation. Ambele execută aceeași logică internă; diferă doar transportul.

Structura Cererii

WebSocket (acțiunea 203): payload-ul se pune în câmpul parameters al plicului.

{
  "id": 500,
  "type": 0,
  "content": {
    "action": 203,
    "parameters": {
      "device_id": "uuid-dispozitiv",
      "operation": {
        "type": "print_receipt",
        "lines": [ ... ]
      }
    }
  }
}

HTTP (POST /devices/operation): același payload este corpul (body) cererii JSON.

Structura Răspunsului și Dublul Status

Există două câmpuri de status într-un răspuns WebSocket. Este important să înțelegeți diferența dintre ele:

NivelCâmpValori PosibileSemnificație
1. Plic (outer) status 0 = succes execuție
1 = eroare execuție
2 = acțiune necunoscută
Indică dacă driverul a reușit să proceseze cererea. 1 înseamnă că a apărut o excepție (eroare de comunicare, validare, eroare de dispozitiv, …).
2. Conținut (inner) content.status 0 = succes logic
> 0 = cod de eroare specific
Rezultatul de business al operațiunii - identic cu corpul răspunsului din API-ul HTTP. Vezi Coduri Eroare.

Regula de aur:

  • Dacă status-ul exterior este 0, operațiunea a reușit complet (iar statusul interior este tot 0).
  • Dacă status-ul exterior este 1, citiți content.status și content.error pentru a afla de ce (eroare hardware, parametri greșiți, …).

Exemplu de Succes (outer 0, inner 0)

{
  "id": 500,
  "type": 1,
  "status": 0,        // ← OK
  "content": {
    "status": 0,      // ← bonul a ieșit OK
    "msg": "Receipt printed",
    "slip_number": 123,
    "z_report_number": 45,
    "fiscal_receipt_count": 1050
  }
}

Exemplu de Eroare (outer 1, inner 500)

{
  "id": 500,
  "type": 1,
  "status": 1,        // ← a apărut o eroare
  "content": {
    "status": 500,    // ← cod specific
    "error": "Lipsă hârtie în imprimantă."
  }
}

Cum Începeți

Pentru a integra prin WebSocket:

  1. Rulați un server WebSocket pe propria infrastructură, care implementează protocolul descris mai sus.
  2. Alegeți un token de autentificare și faceți ca serverul dvs. să accepte conexiunile care îl prezintă (prin parametrul de interogare token). Folosiți driver_id pentru a identifica ce driver s-a conectat.
  3. Creați un certificat JSON cu url-ul și token-ul serverului dvs. și încărcați-l în fiecare driver din Setări → Certificat sistem vânzare.
  4. Când un driver se conectează, trimiteți-i cereri (acțiunea 203 pentru operațiuni de dispozitiv, 201/204 pentru a lista dispozitivele) și citiți răspunsurile.

Pentru întrebări tehnice, contactați office@ceapa.cool.