# Nettoyage

> Le plan de nettoyage, les tâches réellement effectuées et les photographies qui le prouvent : trois collections, et ce qu'un enregistrement manquant ne prouve pas.

Source: https://developers.backresto.com/fr/docs/cleaning

Le nettoyage, dans l'application, c'est un plan et sa preuve. Le restaurant
écrit ce qui doit être nettoyé, où et à quelle fréquence ; le personnel coche
les tâches au fur et à mesure ; certaines de ces tâches exigent une
photographie. Trois collections, une par couche, et c'est la jointure entre
elles qui représente le plus gros du travail.

| Collection | Scope | Ce qu'est un enregistrement |
| --- | --- | --- |
| `cleaning-tasks` | `cleaning-tasks:read` | Une ligne du plan : ce qui doit être nettoyé, où, à quelle fréquence, et si cela exige une photographie. |
| `cleaning-task-records` | `cleaning-task-records:read` | Une tâche réellement effectuée : quand, et par qui. |
| `cleaning-task-pictures` | `cleaning-task-pictures:read` | La photographie qui le prouve. Porte un fichier. |

Toutes les trois partagent l'[enveloppe de snapshot](https://developers.backresto.com/fr/docs/collections) :
`id`, `deleted`, `capturedAt`, `receivedAt`, `sequence` et le reste entourent
le `data` décrit ci-dessous.

## `cleaning-tasks`

Le plan lui-même. Ces enregistrements changent rarement (un restaurant écrit
son plan une fois et le modifie quand la cuisine change). C'est donc la
collection que vous parcourez le moins souvent et que vous gardez en cache le
plus longtemps.

| Champ | Type | Signification |
| --- | --- | --- |
| `index` | integer, **obligatoire** | La position de la tâche dans le plan, telle que l'application l'ordonne. |
| `name` | string, **obligatoire** | Ce qui doit être nettoyé, avec les mots du restaurant. |
| `description` | string \| null | Des instructions plus longues, quand quelqu'un en a écrit. |
| `areaId` | string \| null | La [zone](https://developers.backresto.com/fr/docs/facilities) à laquelle elle appartient. `null` dans un restaurant qui ne se découpe pas en zones. |
| `recurrence` | integer, **obligatoire** | À quelle fréquence la tâche revient, sous forme d'entier simple. |
| `requirePhotoProof` | boolean \| null | `true` quand la tâche exige une photographie. `null` signifie que l'application ne l'a jamais renseigné. |
| `isDeleted` | boolean, **obligatoire** | Le soft delete propre à l'application. Lisez la note ci-dessous. |

```json
{
  "id": "c9a4f7e2-1b83-4d05-a6f1-90e3b7c4d218",
  "collection": "cleaning-tasks",
  "deleted": false,
  "capturedAt": "1789601204773",
  "receivedAt": "1789601399042",
  "sequence": "1",
  "data": {
    "index": 3,
    "name": "Nettoyage de la trancheuse",
    "description": "Démonter la lame, dégraisser, désinfecter.",
    "areaId": "7d2c0b61-4e8a-49f3-9c27-5a1b8e60d3f4",
    "recurrence": 1,
    "requirePhotoProof": true,
    "isDeleted": false
  }
}
```

**`recurrence` ne porte aucune unité.** C'est un entier, et l'enregistrement ne
dit pas ce qu'il compte. Affichez-le comme l'application l'affiche plutôt que
d'écrire "tous les 1 jours" sur une supposition.

**`isDeleted` n'est pas le `deleted` de l'enveloppe.** Une tâche que le
restaurant a retirée de son plan revient avec `isDeleted: true` et
`deleted: false` : c'est toujours un enregistrement vivant, qui décrit une
ligne qui ne s'applique plus. Filtrez sur les deux, et gardez les supprimées
sous la main : de vieux enregistrements pointent encore vers elles.

## `cleaning-task-records`

Une tâche effectuée. Petit à dessein : quelle tâche, quand, qui.

| Champ | Type | Signification |
| --- | --- | --- |
| `timestamp` | string, **obligatoire** | Quand la tâche a été effectuée, en millisecondes depuis l'epoch sous forme de chaîne de caractères. |
| `cleaningTaskId` | string, **obligatoire** | L'enregistrement `cleaning-tasks` qu'elle satisfait. |
| `userId` | string \| null | Le [membre du personnel](https://developers.backresto.com/fr/docs/facilities) qui l'a effectuée, quand l'application en a enregistré un. |

```json
{
  "id": "5f8b3d16-2c90-4a77-b4e8-31d0a9c65f7b",
  "collection": "cleaning-task-records",
  "deleted": false,
  "capturedAt": "1789775012558",
  "receivedAt": "1789775204910",
  "sequence": "2",
  "data": {
    "timestamp": "1789774800000",
    "cleaningTaskId": "c9a4f7e2-1b83-4d05-a6f1-90e3b7c4d218",
    "userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
  }
}
```

`cleaningTaskId` est obligatoire : chaque enregistrement a donc une tâche.
L'inverse n'est pas vrai : une tâche peut rester dans le plan sans aucun
enregistrement en face pendant des semaines, et c'est l'état normal d'une tâche
hebdomadaire un mardi.

## `cleaning-task-pictures`

La photographie. Elle porte un fichier, ce qui en fait la seule collection de
cette page que vous ne pouvez pas consommer depuis le seul endpoint des
enregistrements.

| Champ | Type | Signification |
| --- | --- | --- |
| `timestamp` | string, **obligatoire** | Quand la photographie a été prise, en millisecondes depuis l'epoch sous forme de chaîne de caractères. |
| `cleaningTaskRecordId` | string \| null | L'enregistrement `cleaning-task-records` qu'elle prouve. Peut être `null`. Voyez ci-dessous. |
| `part` | number \| null | Non documenté, et décimal plutôt qu'un compteur. Transportez-le plutôt que de l'interpréter : la même réserve que sur les [étiquettes de traçabilité](https://developers.backresto.com/fr/docs/traceability-labels). |
| `groupId` | string \| null | Relie ces photographies entre elles. Des enregistrements qui partagent un `groupId` appartiennent à la même preuve. |
| `asset` | object, **obligatoire** | Nomme le fichier : `objectKey` et `status` toujours, plus `contentType`, `byteLength` et `sha256` une fois qu'il est téléversé. |

```json
{
  "id": "2d71c8a9-6e34-4b0f-8517-ac93e25d0b46",
  "collection": "cleaning-task-pictures",
  "deleted": false,
  "capturedAt": "1789775118330",
  "receivedAt": "1789775301774",
  "sequence": "3",
  "data": {
    "timestamp": "1789774860000",
    "cleaningTaskRecordId": "5f8b3d16-2c90-4a77-b4e8-31d0a9c65f7b",
    "part": 1,
    "groupId": "a03e5c88-71bd-4f92-b6d4-2e8f10c73a5b",
    "asset": {
      "objectKey": "cleaning-task-pictures/2d71c8a9/1.jpg",
      "status": "uploaded",
      "contentType": "image/jpeg",
      "byteLength": 812043,
      "sha256": "9f2a…"
    }
  }
}
```

Les octets sont un second appel, sur l'identifiant propre à l'enregistrement :

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

Il répond par une liste d'URL signées, valables **quinze minutes** chacune,
portant chacune sa propre autorisation, si bien que le téléchargement ne
demande aucun en-tête. Récupérez les octets maintenant, stockez les octets
plutôt que le lien, et rappelez l'endpoint quand vous avez besoin d'une URL
fraîche. Les règles (ce qui apparaît, à quoi sert `sha256`, pourquoi
`contentType` mérite d'être lu) sont sur
[la page des collections](https://developers.backresto.com/fr/docs/collections), et elles sont les mêmes ici.

**`asset.status` vous dit s'il y a des octets à récupérer.** Il vaut `pending`
ou `uploaded`. Un `asset` en `pending`, c'est une photographie que l'appareil a
annoncée et n'a pas fini d'envoyer : l'enregistrement est réel, le fichier ne
l'est pas, et l'endpoint des fichiers répond sans lui. Lisez le statut avant de
prendre une liste de fichiers vide pour une photographie qui n'a jamais été
prise.

**`cleaningTaskRecordId` peut être `null`.** Une photographie peut exister sans
pointer vers un enregistrement : une jointure qui le suppose toujours présent
laisse tomber des photographies. Comptez-les à part plutôt que de les écarter
en silence.

## Joindre les trois

La forme que vous voulez presque certainement, c'est une ligne par tâche
effectuée, avec son entrée dans le plan et ses photographies :

- `cleaning-task-records.cleaningTaskId` → `cleaning-tasks.id`
- `cleaning-task-pictures.cleaningTaskRecordId` → `cleaning-task-records.id`

Trois parcours, joints de votre côté. Aucun endpoint ne le fait pour vous, et
il n'y a pas de filtre par tâche ni par date : vous parcourez chaque collection
en entier et vous réconciliez, comme le décrit
[la page de l'enveloppe](https://developers.backresto.com/fr/docs/collections).

Faites vos rapports sur `capturedAt` et synchronisez sur `receivedAt` : une
tablette dans une chambre froide téléverse quand elle trouve du réseau, et une
photographie prise à 09:00 peut arriver à 14:00, après l'enregistrement auquel
elle appartient, ou avant lui.

## Ce qu'un enregistrement manquant ne veut pas dire

**Une entrée du plan sans enregistrement correspondant n'est pas la preuve que
la tâche a été sautée.** Elle a pu être effectuée sur un appareil qui n'a pas
encore téléversé, ou avant que la capture ne soit activée pour ce restaurant.
Même chose pour une tâche marquée `requirePhotoProof: true` sans photographie
en face : la photographie peut être en cours de téléversement, et un fichier
dont le téléversement n'est pas achevé est absent plutôt que cassé.

N'imprimez donc pas un taux de réalisation du nettoyage issu de cette API en
l'appelant conformité. Ce que vous pouvez dire honnêtement, c'est ce qui est
arrivé, et quand. Voyez [la note sur l'exhaustivité](https://developers.backresto.com/fr/docs/support) avant de
mettre un chiffre sous les yeux de qui que ce soit.
