# Consegne

> I controlli in accettazione e le fotografie scattate al ricevimento: due collezioni, ogni campo, e cosa significano in cucina.

Source: https://developers.backresto.com/it/docs/deliveries

Una consegna è un controllo in accettazione: un membro del personale che riceve
un ordine, registra le temperature e decide se accettarlo. È il registro che
chiede un ispettore della sicurezza alimentare. Le immagini scattate al
ricevimento sono una seconda collezione accanto a essa.

| Collezione | Scope | Che cos'è un record |
| --- | --- | --- |
| `deliveries` | `deliveries:read` | Un controllo in accettazione, con una lettura di temperatura per prodotto. |
| `delivery-pictures` | `delivery-pictures:read` | Una fotografia scattata durante una consegna, che rimanda a essa. |

Entrambe sono normali [collezioni](https://developers.backresto.com/it/docs/collections): lo stesso involucro di
snapshot attorno a `data`, gli stessi endpoint, lo stesso cursore, la stessa
regola dei 90 giorni. Riportano lo storico delle consegne che l'app conservava
ancora quando sono state aperte, non solo ciò che è stato registrato da allora.

## `deliveries`

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | Quando è avvenuto il controllo, millisecondi dall'epoch come stringa. |
| `isCompliant` | boolean, **obbligatorio** | Il verdetto del membro del personale sulla consegna nel suo insieme. |
| `supplierDeliveriesId` | string \| null | Il [fornitore](https://developers.backresto.com/it/docs/catalogue) da cui proviene la merce: l'`id` di un record `suppliers`. |
| `temperatureRecords` | array \| null | Una voce per ogni prodotto misurato. Veda più sotto. |
| `nonComplianceReasons` | string[] \| null | Perché la consegna è stata rifiutata o accettata con riserva. Testo libero scelto dal membro del personale; vuoto quando è conforme. |
| `correctiveActions` | string[] \| null | Cosa è stato fatto al riguardo. Vuoto quando non serviva nulla. |
| `commentary` | string \| null | Nota in testo libero. Spesso `null`. |
| `userId` | string \| null | Il [membro del personale](https://developers.backresto.com/it/docs/facilities) che l'ha ricevuta, quando l'app ne ha registrato uno. |

### `temperatureRecords[]`

| Campo | Tipo | Significato |
| --- | --- | --- |
| `product` | string | Cosa è stato misurato, come lo ha chiamato il membro del personale. Mai vuoto. |
| `lotNumber` | string \| null | Il lotto o la partita, quando è stato acquisito. |
| `value` | number \| null | La lettura. `null` quando il prodotto è stato registrato senza una misurazione. |
| `unit` | `"C"` | Sempre Celsius. Veda più sotto. |

**Le temperature sono sempre in Celsius.** Un ristorante la cui app registra in
Fahrenheit invia comunque letture in Fahrenheit, e queste vengono convertite al
loro arrivo, prima di essere memorizzate. `unit` è `"C"` in ogni voce, così chi
consuma i dati non deve mai convertire né tirare a indovinare.

```json
{
  "id": "8f2c1b04-0d5a-4b7e-9f31-6ad2c0e77a51",
  "collection": "deliveries",
  "deleted": false,
  "capturedAt": "1787932805120",
  "receivedAt": "1787932911004",
  "sequence": "88",
  "data": {
    "timestamp": "1787932800000",
    "isCompliant": false,
    "supplierDeliveriesId": "supplier-7",
    "temperatureRecords": [
      { "product": "Poulet fermier", "lotNumber": "L2291", "value": 6.4, "unit": "C" },
      { "product": "Farine T55", "lotNumber": null, "value": null, "unit": "C" }
    ],
    "nonComplianceReasons": ["Température trop élevée"],
    "correctiveActions": ["Produit refusé", "Fournisseur prévenu"],
    "commentary": "Camion en retard, rupture de chaîne du froid probable",
    "userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
  }
}
```

## `delivery-pictures`

Un'etichetta, un pallet danneggiato, una sonda accostata a un display: quelle
immagini sono la prova dietro `isCompliant`. Ognuna è un record che rimanda alla
sua consegna e porta con sé un file, quindi i byte arrivano dall'endpoint degli
asset.

| Campo | Tipo | Significato |
| --- | --- | --- |
| `timestamp` | string, **obbligatorio** | Quando è stata scattata l'immagine, millisecondi dall'epoch come stringa. |
| `deliveryId` | string \| null | Il record `deliveries` a cui appartiene. |
| `part` | number \| null | Posizione di questo record all'interno di un'immagine che l'app ha memorizzato in più parti. Lo porti avanti così com'è anziché interpretarlo. |
| `groupId` | string \| null | Lega insieme quelle parti. I record che condividono un `groupId` sono la stessa immagine. |
| `asset` | object, **obbligatorio** | Indica il file: sempre `objectKey` e `status`, più `contentType`, `byteLength` e `sha256` una volta caricato. |

```json
{
  "id": "c61e0a7d-35b2-4f89-a1d4-7e90b2c45f18",
  "collection": "delivery-pictures",
  "deleted": false,
  "capturedAt": "1787932861240",
  "receivedAt": "1787932990517",
  "sequence": "143",
  "data": {
    "timestamp": "1787932860000",
    "deliveryId": "8f2c1b04-0d5a-4b7e-9f31-6ad2c0e77a51",
    "part": 4,
    "groupId": "b4d81f0a-c2e7-4a55-9d10-6f3e8a2b7c91",
    "asset": {
      "objectKey": "delivery-pictures/b4d81f0a/4.jpg",
      "status": "uploaded",
      "contentType": "image/jpeg",
      "byteLength": 902450,
      "sha256": "9f2a…"
    }
  }
}
```

I byte sono una seconda chiamata, sull'id del record stesso:

```http
GET /v1/restaurants/{restaurantId}/collections/delivery-pictures/records/{recordId}/assets
```

Risponde con URL firmati validi per quindici minuti, esattamente come descritto
nella [pagina sulle collezioni](https://developers.backresto.com/it/docs/collections). Lo chieda su una qualunque
parte di un'immagine e ottiene lo stesso file: l'API risolve il gruppo per lei,
quindi non serve capire quale parte lo contenga.

Per mostrare le fotografie di una consegna, percorra `delivery-pictures` e tenga
i record il cui `deliveryId` è l'`id` di quella consegna, uno per `groupId`.

## Leggerlo correttamente

**`isCompliant` è il registro, non un calcolo.** È ciò che ha deciso la persona
che ha ricevuto la consegna, e può non coincidere con quello che concluderebbe
lei dalle sole temperature: una lettura presa con una sonda di superficie, un
prodotto con una soglia propria, una valutazione discrezionale. Lo presenti come
il loro verdetto. Se ne vuole uno suo, lo calcoli accanto al loro e lo etichetti
come suo.

**I campi in testo libero sono testo libero.** `nonComplianceReasons`,
`correctiveActions` e `product` vengono digitati dal personale durante il
servizio, nella lingua del ristorante, con l'ortografia di un martedì di corsa.
Non ne costruisca un enum, non ci basi sopra la chiave di una join, e non dia
per scontato il francese.

**`value` può essere `null`.** Un prodotto registrato senza una lettura è
normale. Spesso è un prodotto secco. Tratti `null` come "non misurato", mai
come `0`.

**I timestamp sono stringhe.** `timestamp` è una stringa decimale di
millisecondi dall'epoch, perché l'intera piattaforma BackResto memorizza così i
timestamp. `Number(timestamp)` è sicuro oggi e per le prossime centinaia di
migliaia di anni, ma non lasci che un parser JSON lo converta in silenzio e poi
lo riscriva avendo perso precisione.

**Un'immagine può arrivare dopo la sua consegna.** Un telefono carica le
fotografie quando può, a volte minuti dopo il controllo stesso. Una consegna
ancora senza immagini può semplicemente averne una in arrivo; percorra di nuovo
più tardi prima di concludere che non ne ha.
