API HTTP
Driverul FisCool încorporează un server HTTP RESTful pentru operațiuni de dispozitiv și interogări de sistem. API-ul este stateless și ușor de integrat din orice limbaj care poate face cereri HTTP.
Configurare de Bază
- URL implicit:
http://127.0.0.1:10123 - Host: implicit
127.0.0.1(doar localhost); configurabil din setările FisCool (ex:0.0.0.0pentru a expune API-ul în LAN). - Port: implicit
10123, configurabil. - Activare: serverul API poate fi dezactivat complet din setări (implicit este activat).
- Content-Type:
application/jsonpentru toate cererile POST. - Autentificare: niciuna. CORS este deschis, dar vezi Accesul din browser mai jos.
Accesul din browser (verificarea Origin)
Cererile care au un header Origin (adică vin dintr-o pagină web) sunt filtrate: prima dată când un origin nou apelează API-ul, FisCool afișează operatorului un dialog de confirmare („Permiteți <origin> să interacționeze cu dispozitivele fiscale?"). Dacă este acceptat, originul este salvat în lista de permisiuni și nu se mai întreabă; dacă este respins, cererea eșuează cu HTTP 403. Cererile fără header Origin (curl, servicii backend) nu sunt filtrate.
Endpoint-uri de Sistem
GET /
Descriere: Verificare de funcționare (health check).
Răspuns: text simplu
FisCool API Server running.
GET /status
Descriere: Returnează snapshot-ul complet al stării aplicației: dispozitive fiscale, terminale POS, configurația API, configurația aplicației, imprimantele active, sumarul licențelor. Array-urile fiscal_devices și pos_terminals sunt identice cu endpoint-urile dedicate de mai jos.
GET /devices/fiscal
Descriere: Listează toate dispozitivele fiscale configurate.
Răspuns:
{
"fiscal_devices": [
{
"config": {
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", // UUID de configurare - se folosește ca device_id
"name": "Casa 1 - DATECS DP25",
"manufacturer": "DATECS",
"model": "DP25",
"connection_details": {
"type": "Serial",
"details": { "port": "COM3", "baud_rate": 115200 }
},
"notes": "Casa principală",
"enabled": true,
"scan_folder": "C:\\FisCool\\INP", // opțional: folderul monitorizat pentru INP
"auto_send_card_to_pos": true, // funcții opționale
"linked_pos_device_id": "b2c3d4e5-f6a7-5b8c-9d0e-1f2a3b4c5d6e",
"is_system_device": false
},
"status": "Connected", // Disconnected | Connecting | Connected | Disabled | {"Error": "..."}
"status_text": "Conectat",
"busy_external": false, // true cât timp o aplicație externă ține dispozitivul ocupat
"vat_rates": { // grupele de TVA citite de pe dispozitiv (sutimi de procent)
"A": 1900, "B": 900, "E": 0
},
"connected_device_id": "DT123456", // SERIA HARDWARE - null cât timp e deconectat
"connected_device_data": {
"id": "DT123456", // seria hardware (identică cu connected_device_id)
"cif": "RO12345678", // codul fiscal al firmei programat în dispozitiv
"print_width": 32 // caractere pe linie ale imprimantei (poate lipsi)
},
"scheduled_vat_rate_changes": [] // programări schedule_vat_rate_change în așteptare
}
]
}
Notă: connected_device_id/connected_device_data sunt populate doar cât timp dispozitivul este conectat; altfel sunt null. config.id este UUID-ul folosit pentru operațiuni - nu seria hardware.
GET /devices/pos
Descriere: Listează toate terminalele POS configurate. Dispozitivele fiscale hibride cu POS integrat apar și aici (marcate "is_virtual": true) după ce seria POS devine cunoscută.
Răspuns:
{
"pos_terminals": [
{
"config": {
"id": "b2c3d4e5-f6a7-5b8c-9d0e-1f2a3b4c5d6e",
"name": "Terminal POS 1",
"manufacturer": "PAX",
"model": "A920 Pro",
"bank": "BCR",
"connection_details": {
"type": "Network",
"details": { "ip_address": "192.168.1.100", "port": 8080 }
},
"enabled": true
},
"status": "Connected",
"status_text": "Conectat",
"connected_device_id": "PAX001",
"connected_device_data": { "id": "PAX001", "cif": null },
"is_virtual": false
}
]
}
Operațiuni Dispozitive
POST /devices/operation
Descriere: Execută o operațiune pe un dispozitiv fiscal sau pe un terminal POS. Este endpoint-ul principal pentru toate interacțiunile cu dispozitivele. Toate operațiunile și payload-urile lor sunt documentate pe pagina Operațiuni Dispozitive.
Headere de Cerere
| Header | Obligatoriu | Descriere |
|---|---|---|
Content-Type | Da | application/json |
Idempotency-Key | Nu | Cheie unică ce previne execuția duplicată (vezi Idempotență). |
Structura Corpului Cererii
{
"device_id": "UUID", // UUID-ul dispozitivului țintă (config.id)
"operation": {
"type": "nume_operatiune",
// ... parametri specifici operațiunii
}
}
Exemple Complete
Exemplul 1: Tipărirea unui bon simplu
POST /devices/operation
Content-Type: application/json
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "print_receipt",
"lines": [
{
"type": "item",
"description": "Cafea Espresso",
"quantity_thousandths": 1000,
"unit_price_cents": 850,
"vat": "19%",
"um": "buc"
},
{
"type": "text",
"text": "Multumim pentru cumparaturi!"
}
],
"payments": [
{ "method": "cash", "amount_cents": 850 }
],
"close_action": "close"
}
}
Exemplul 2: Bon cu codul fiscal al cumpărătorului și plată cu cardul
POST /devices/operation
Content-Type: application/json
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "print_receipt",
"lines": [
{
"type": "item",
"description": "Servicii Consultanta IT",
"quantity_thousandths": 1000,
"unit_price_cents": 120000,
"vat": "19%"
}
],
"payments": [
{ "method": "card", "amount_cents": 120000 }
],
"buyer": { "vat_number": "RO12345678" },
"flags": { "is_invoice": true },
"close_action": "close"
}
}
Exemplul 3: Tipărirea unui raport Z
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": { "type": "print_z" }
}
Exemplul 4: Introducere numerar
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": { "type": "deposit_cash", "amount": 5000 }
}
Exemplul 5: Vânzare POS
{
"device_id": "b2c3d4e5-f6a7-5b8c-9d0e-1f2a3b4c5d6e",
"operation": { "type": "sale", "amount": 2500, "suppress_print": false }
}
Exemplul 6: Raport din jurnalul electronic
{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "je_report",
"range": { "type": "date", "start": "2024-01-01", "end": "2024-01-31" },
"doc_type": "fiscal_receipts",
"output_mode": "read_line_by_line"
}
}
Formatul Răspunsului
Succes (HTTP 200)
{
"status": 0,
"msg": "Receipt printed",
"slip_number": 1234,
"z_report_number": 45,
"fiscal_receipt_count": 1050
}
Câmpurile exacte depind de operațiune - vezi Operațiuni Dispozitive.
Eroare (HTTP 4xx/5xx)
Orice eșec - validare, conexiune sau o eroare raportată de dispozitiv - este returnat cu un status HTTP non-2xx și acest corp JSON:
// HTTP 400 Bad Request - dispozitivul a raportat „lipsă hârtie" (cod 500)
{
"status": 500,
"error": "Lipsă hârtie în imprimantă."
}
// HTTP 404 Not Found - UUID de dispozitiv necunoscut
{
"status": 404,
"error": "Dispozitivul nu a fost găsit: a1b2c3d4-..."
}
// HTTP 400 Bad Request - vânzare POS refuzată, cu chitanța de refuz atașată
{
"status": 600,
"error": "Tranzacție POS refuzată.",
"receipt": "...textul chitanței de refuz..."
}
Important: câmpul status din corp este codul de eroare al aplicației (întotdeauna un întreg pozitiv - vezi Coduri Eroare); nu este statusul HTTP. Folosiți status/error din corp pentru tratarea programatică și considerați orice răspuns HTTP non-200 un eșec.
Maparea Statusurilor HTTP
| Status HTTP | Când |
|---|---|
| 200 | Operațiune executată cu succes (corpul are status: 0). |
| 400 | Cerere/configurare invalidă (cod 400) sau o eroare operațională raportată de dispozitiv (majoritatea codurilor fiscale 5xx și POS 6xx). |
| 403 | Origin respins de operator. |
| 404 | Dispozitiv negăsit (cod 404). |
| 408 | Timeout (cod 408). |
| 501 | Operațiune nesuportată de acest dispozitiv (cod 1015). |
| 503 | Dispozitiv inaccesibil/hardware indisponibil (cod 1004 și codurile fiscale de tip hardware, ex: 500, 502, 520…). |
| 500 | Erori interne (coduri 1000-1003, …). |
Idempotență
Pentru operațiuni critice (tipărire bonuri, vânzări POS) folosiți header-ul Idempotency-Key pentru a preveni execuția duplicată la reîncercări:
POST /devices/operation
Content-Type: application/json
Idempotency-Key: bon-2024-01-15-001
{ "device_id": "...", "operation": { ... } }
Toate cererile cu aceeași cheie partajează o singură execuție - duplicatele concurente și ulterioare primesc același rezultat fără a re-executa operațiunea.
Endpoint-uri de Tipărire
GET /printers
Descriere: Listează imprimantele de sistem activate în FisCool, cu detalii de driver.
Răspuns:
{
"status": 0,
"printers": [
{ "name": "POS-80", "paper_width_mm": 80, "dpi": 203, "render_width_px": 576 }
]
}
POST /printers/print_html
Descriere: Randează HTML și îl tipărește ca bitmap pe o imprimantă de sistem activată (pipeline pentru imprimante termice). Tipărirea către o imprimantă neactivată în FisCool returnează eroarea 400.
Corpul Cererii:
{
"printer_name": "POS-80",
"html": "<h1>Salut</h1><p>Comanda #42</p>"
}
Răspuns:
{
"status": 0,
"msg": "Print job completed"
}
Endpoint-uri de Administrare
Driverul poate fi administrat și programatic (salvare/ștergere dispozitive, interogarea jurnalului, actualizări) prin endpoint-urile /manage/* - vezi pagina API Headless.
Exemple de Integrare
cURL
# Tipărește un bon simplu
curl -X POST http://127.0.0.1:10123/devices/operation \
-H "Content-Type: application/json" \
-d '{
"device_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"operation": {
"type": "print_receipt",
"lines": [{"type": "item", "description": "Test", "quantity_thousandths": 1000, "unit_price_cents": 100, "vat": "19%"}],
"payments": [{"method": "cash", "amount_cents": 100}],
"close_action": "close"
}
}'
# Listează dispozitivele fiscale
curl http://127.0.0.1:10123/devices/fiscal
JavaScript / Node.js
const axios = require('axios');
async function printReceipt(deviceId, items, payments) {
try {
const response = await axios.post('http://127.0.0.1:10123/devices/operation', {
device_id: deviceId,
operation: {
type: 'print_receipt',
lines: items,
payments: payments,
close_action: 'close'
}
});
// HTTP 200 => succes
console.log('Bon tipărit, număr:', response.data.slip_number);
} catch (error) {
// non-2xx => eșec; corpul conține {status, error}
const body = error.response?.data;
console.error('Eșec:', body?.status, body?.error);
}
}
Python
import requests
def print_receipt(device_id, items, payments):
url = "http://127.0.0.1:10123/devices/operation"
payload = {
"device_id": device_id,
"operation": {
"type": "print_receipt",
"lines": items,
"payments": payments,
"close_action": "close",
},
}
response = requests.post(url, json=payload)
if response.ok:
result = response.json()
print(f"Bon tipărit: {result.get('slip_number')}")
else:
err = response.json()
print(f"Eșec ({err.get('status')}): {err.get('error')}")
items = [{
"type": "item",
"description": "Cafea",
"quantity_thousandths": 1000,
"unit_price_cents": 250,
"vat": "19%",
}]
payments = [{"method": "cash", "amount_cents": 250}]
print_receipt("a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", items, payments)