Vai al contenuto
v26.3

Conto cliente: credito e punti fedeltà

Ogni cliente (api/v1/customers) gestisce due conti separati e permanenti:

  • Credito prepagato (accountBalance) — credito in denaro reale che il cliente versa in anticipo e utilizza poi come mezzo di pagamento negli acquisti. Rimborsabile.
  • Punti fedeltà / bonus (loyaltyPoints / bonusBalance) — punti/bonus che vengono accreditati e riscattati negli acquisti. Non rimborsabili (il bonus decade in caso di liquidazione del credito).

Questa pagina corregge un'indicazione errata più datata nella panoramica REST API: non esistono POST /customers/{id}/creditGET /customers/{id}/transactions — queste rotte non esistono nel codice. Le rotte reali sono documentate di seguito.

Endpoint

CustomersController — base api/v1/customers:

Metodo Endpoint Scopo
GET /{id}/account-transactions Movimenti di credito/conto (registro del prepagato)
GET /{id}/point-transactions Movimenti dei punti fedeltà
POST /{id}/payout Liquidare il credito residuo (solo accountBalance, non il bonus)
POST /{id}/settle Compensare con un versamento un saldo aperto (ad es. un debito Disco)
GET /card/{cardId} Risolvere il cliente tramite la carta cliente
GET /{id}/invoice-summary Panoramica fatture/abbonamento del cliente

Entrambi gli endpoint delle transazioni accettano facoltativamente dateFrom/dateTo come parametri di query per delimitare il periodo.

Movimenti di conto (account-transactions)

GET /api/v1/customers/cus_a1b2c3/account-transactions?dateFrom=2026-07-01&dateTo=2026-07-31
Authorization: Bearer eyJ...
{
  "success": true,
  "data": [
    {
      "id": "cat_001",
      "customerId": "cus_a1b2c3",
      "customerName": "Max Mustermann",
      "receiptId": "rec_9f8e7d",
      "type": 0,
      "amount": 50.00,
      "balanceAfter": 50.00,
      "bonusBalanceAfter": 2.50,
      "description": "Guthaben-Aufladung: Guthaben 50€ x 1",
      "personalId": "usr_kasse1",
      "transactionDate": "2026-07-05T18:22:00Z"
    }
  ]
}

type è un int senza uno schema enum pubblico proprio; valori osservati in pratica: 0 ricarica/ versamento, 1 utilizzo (pagamento con credito), 2 correzione (rettifica manuale di storno), 3 accredito bonus, 4 utilizzo/decadenza bonus, 5 liquidazione.

Movimenti dei punti (point-transactions)

GET /api/v1/customers/cus_a1b2c3/point-transactions
Authorization: Bearer eyJ...
{
  "success": true,
  "data": [
    {
      "id": "cpt_001",
      "customerId": "cus_a1b2c3",
      "customerName": "Max Mustermann",
      "receiptId": "rec_9f8e7d",
      "articleId": "art_cola",
      "articleName": "Cola 0,3l",
      "type": 0,
      "points": 3.5,
      "pointsAfter": 42.5,
      "description": "Punkte für Verkauf",
      "transactionDate": "2026-07-05T18:22:00Z"
    }
  ]
}

type: 0 = accreditati (Earned), 1 = riscattati (Redeemed), 2 = correzione (Correction).

Liquidare (payout)

Liquida il credito dall'accountBalance (non dal bonus — questo decade in tal caso).

POST /api/v1/customers/cus_a1b2c3/payout
Authorization: Bearer eyJ...
Content-Type: application/json

{ "amount": 20.00 }
{ "success": true, "data": { "success": true, "accountBalance": 30.00, "bonusBalance": 0 } }

Caso di errore (credito insufficiente) — 400 con errorCode: "INSUFFICIENT_BALANCE".

Compensare il saldo (settle)

Per un saldo aperto (negativo) — ad es. un debito Disco (importo residuo scoperto all'uscita, vedi API Disco) — il cliente versa un importo e il saldo si muove verso lo zero:

POST /api/v1/customers/cus_a1b2c3/settle
Authorization: Bearer eyJ...
Content-Type: application/json

{ "amount": 15.00, "method": "EC" }

method è libero (predefinito "Bar") e finisce solo nella descrizione della registrazione — nessun collegamento a un terminale di pagamento.

Ricaricare il credito — il percorso reale

Non esiste un endpoint /credit dedicato. Un credito prepagato viene invece ricaricato esattamente come qualsiasi altra vendita: tramite i normali endpoint di pagamento (POST /api/v1/payments/direct o POST /api/v1/payments/table), con due condizioni:

  1. L'articolo venduto ha extraOption: 1 (KundenAufladung) — un „articolo di ricarica" (ad es. „Credito 50 €"), creato tramite la normale API articoli (POST /api/v1/articles).
  2. Il pagamento è collegato al cliente tramite customerId.

Il prezzo dell'articolo (× quantità) viene quindi accreditato automaticamente all'accountBalance del cliente — in aggiunta all'effettiva elaborazione del pagamento (l'ospite paga l'importo di ricarica del tutto normalmente tramite payments[], ad es. in contanti o con carta). Se sull'articolo è configurato un bonus di ricarica (cardUploadPercent/cardUploadAmount), viene accreditato automaticamente anche un bonus aggiuntivo.

POST /api/v1/payments/direct
Authorization: Bearer eyJ...
Idempotency-Key: 6f1c2a9e-3b7d-4e21-9b0a-1f2e3d4c5b6a
Content-Type: application/json

{
  "items": [ { "articleId": "art_aufladung50", "quantity": 1 } ],
  "payments": [ { "method": "Cash", "amount": 50.00 } ],
  "customerId": "cus_a1b2c3"
}

La ricarica compare quindi come voce type: 0 in account-transactions (vedi sopra), collegata tramite receiptId allo scontrino di cassa generato.

Flusso

  1. Creare il clientePOST /api/v1/customers (minimo: name/customerNumber).
  2. Ricaricare il credito — vendita di un articolo KundenAufladung con customerId (POST /api/v1/payments/direct, v. sopra).
  3. Addebitare sul conto — gli acquisti successivi del cliente con payments[].method = "CustomerAccount" vengono detratti dall'accountBalance (addebitato, non ricaricato).
  4. ControlloGET /{id}/account-transactions verifica lo storico.
  5. Punti — vengono accreditati/riscattati nel normale processo di vendita, consultabili tramite GET /{id}/point-transactions.
  6. Liquidare/compensarePOST /{id}/payout (restituzione del credito residuo) oppure POST /{id}/settle (saldare un saldo aperto/debito).

Distinzione: credito del conto cliente ↔ credito della carta Disco

Due concetti diversi, facilmente confusi:

Credito del conto cliente Credito della carta Disco
Endpoint payments/* + customers/* POST /api/v1/disco/guest/{cardId}/topup
Legame al record del cliente, permanente alla carta fisica, per una permanenza
Liquidazione POST /{id}/payout Credito residuo al checkout (disco/guest/{cardId}/checkout)

→ Dettagli sulla variante a carta: API Disco (Club Cashless).