# 炸锅

> 那些炸锅和在它们上面做的油品质量检查：两个集合，以及为什么测得的值可以缺失、而那个决定绝不会。

Source: https://developers.backresto.com/zh/docs/fryers

煎炸用油会在使用中劣化，过了某个点就必须过滤掉或者倒掉。餐厅对它做检测、决定怎么
办，并且把两者都记下来。两个集合：那些炸锅，以及在它们上面做的那些检查。

| 集合 | 权限范围 | 一条记录是什么 |
| --- | --- | --- |
| `fryer-equipment` | `fryer-equipment:read` | 一台炸锅。 |
| `fryer-checks` | `fryer-checks:read` | 对其中一台做的一次油品质量检查，以及当时的决定。 |

这两个共用同一个[快照信封](https://developers.backresto.com/zh/docs/collections)：`id`、`deleted`、`capturedAt`、
`receivedAt`、`sequence` 以及其余字段，都摆在下文描述的 `data` 旁边。

## `fryer-equipment`

炸锅本身，按餐厅把它们列出来的样子。一条很短的记录：一个名字、在列表里的一个位
置，以及它站在哪里。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| `index` | integer, **必填** | 这台炸锅在列表里的位置，按应用给它们排的顺序。 |
| `name` | string, **必填** | 餐厅管它叫什么。 |
| `areaId` | string \| null | 它所在的那个[区域](https://developers.backresto.com/zh/docs/facilities)。在一家不把自己划分成区域的餐厅里为 `null`。 |
| `isDeleted` | boolean, **必填** | 应用自己的软删除。请读下面那条说明。 |

```json
{
  "id": "6b1d0f54-8e27-4c93-a7b0-52fd3e1c9a86",
  "collection": "fryer-equipment",
  "deleted": false,
  "capturedAt": "1789598411206",
  "receivedAt": "1789598603471",
  "sequence": "1",
  "data": {
    "index": 1,
    "name": "Friteuse gauche",
    "areaId": "7d2c0b61-4e8a-49f3-9c27-5a1b8e60d3f4",
    "isDeleted": false
  }
}
```

**这里没有阈值。** 和[设备](https://developers.backresto.com/zh/docs/facilities)不一样，一台炸锅既不带 `min` 也不带
`max`：记录上没有任何东西说一个好的油品读数是什么。一次检查是否可接受，是餐厅的
判断，而它留下的唯一痕迹，就是他们采取的那个行动。

**`isDeleted` 不是信封上的 `deleted`。** 一台被餐厅移走的炸锅，回来时是
`isDeleted: true` 且 `deleted: false`：仍然是一条活着的记录，描述的是一台已经不再
服役的炸锅。两个都要筛，并且把移走的那些留着。老的检查仍然指向它们。

## `fryer-checks`

对一台炸锅做的一次检查：这次检测显示了什么，以及为此做了什么。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| `timestamp` | string, **必填** | 这次检查是什么时候做的，以字符串表示的 Unix 毫秒时间戳。 |
| `testValue` | string \| null | 检测显示了什么，以文本记录。什么都没测时为 `null`。 |
| `action` | string, **必填** | 对这油做了什么决定：把它过滤掉、把它换掉、就这么留着。 |
| `fryerEquipmentId` | string, **必填** | 被检查的那台炸锅。 |
| `userId` | string \| null | 做这次检查的那名[员工](https://developers.backresto.com/zh/docs/facilities)，在应用记下了一个的时候。 |

```json
{
  "id": "e07a5c92-4f61-48b8-9d3a-b18c60e5427f",
  "collection": "fryer-checks",
  "deleted": false,
  "capturedAt": "1789777348215",
  "receivedAt": "1789777510964",
  "sequence": "2",
  "data": {
    "timestamp": "1789777200000",
    "testValue": "18",
    "action": "Filtration de l'huile",
    "fryerEquipmentId": "6b1d0f54-8e27-4c93-a7b0-52fd3e1c9a86",
    "userId": "2774953d-8d9b-4a68-8ec4-1209edd90777"
  }
}
```

**`testValue` 是一个字符串，不是一个数字。** 它是试纸或者探针显示出来的东西，以
文本记下，而记录既不带单位也不带刻度：用试纸的餐厅和用极性化合物检测仪的餐厅，
都落在这里。把它当文本留着。跨餐厅把它解析成浮点数，只会给你一列彼此之间无法比较
的值。

**`action` 是自由文本**，用的是这家餐厅的语言。schema 不对它做约束，所以请读这个
值，而不要拿它去比对一份你自己的清单，也不要拿你在一家餐厅的数据里看到的东西
建枚举。

## 一次没有值的检查意味着什么

`testValue` 可以为 null，而 `action` 是必填的，这个不对称正是你要围着它来设计的那
件事。一次检查可以被记成一个采取过的行动，背后却没有任何测得的值：有人把油换了，
因为它看起来不对劲，因为到周末了，因为反正那台炸锅要清洗了。

所以一次检查不是一次测量。它是一个决定，有时附带着一次测量。如果你在做一张油品
读数随时间变化的表，就要预料到有相当一部分行在值那一列里什么都没有，并且把它们
计入，而不是把它们丢掉：一个没有值的行动，仍然是一次确实发生过的检查。

## 拿它们做事

**按 `fryerEquipmentId` 做连接。** 一次检查只点出它的那台炸锅，别的什么都没有；
炸锅的名字在 `fryer-equipment` 上，那个你要单独遍历。两次遍历，在你这边做连接。

**报表用 `capturedAt`，同步用 `receivedAt`。** 一台平板会在找到信号时才上传，所以
一次 09:00 做的检查可能 14:00 才到。[信封那一页](https://developers.backresto.com/zh/docs/collections)讲了完整的来龙
去脉。

**缺席证明不了什么。** 一台这一周没有检查的炸锅，可能确实没被检查过，也可能正躺在
一台还没上传的设备里。不要把这类记录的计数变成一个合规数字。见
[那条提醒](https://developers.backresto.com/zh/docs/support)。
