> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maple.inc/llms.txt
> Use this file to discover all available pages before exploring further.

# 菜单配方

> 针对真实餐厅常见场景的菜单片段示例——多选加料选项、嵌套选项、按时段的特价，以及欢乐时光折扣。

这些是可复制并改编的常见菜单场景片段。每个片段只展示菜单文档中相关的部分——请将其放入[发布菜单](/zh/developer-api/guides/publish-menu)中的完整结构里。关于其背后的模型，请参阅[菜单模型](/zh/developer-api/concepts/the-menu-model)。

所有价格都是整数的最小货币单位（`450` = \$4.50），并且每个对象都带有由您自己拥有的 `externalId`。

## 多选：最多选 3 份，最多 2 种不同

“选择您的加料选项——总共最多 3 份，但不超过 2 种不同的加料选项。”总数量和不同种类数是两条独立的规则：

```json theme={null}
{
  "externalId": "grp-toppings",
  "name": "Toppings",
  "minSelections": 0,
  "maxSelections": 3,
  "maxUniqueSelections": 2,
  "options": [
    { "externalId": "top-mushroom", "name": "Mushroom", "maxQuantity": 3, "price": { "amount": { "amountMinor": 150, "currency": "USD" } } },
    { "externalId": "top-pepperoni", "name": "Pepperoni", "maxQuantity": 3, "price": { "amount": { "amountMinor": 200, "currency": "USD" } } },
    { "externalId": "top-olives", "name": "Olives", "maxQuantity": 3, "price": { "amount": { "amountMinor": 100, "currency": "USD" } } }
  ]
}
```

* `maxSelections: 3` 限制所选的**总**数量。
* `maxUniqueSelections: 2` 限制**不同**选项的数量。顾客可以选 2 份 Mushroom + 1 份 Olives（共 3 份，2 种），但不能选三种不同的加料选项。
* 每个选项上的 `maxQuantity: 3` 允许对同一种加料选项加倍或加三倍。

<Tip>
  使用 `freeSelectionCount` 让前几份免费。例如 `"freeSelectionCount": 1` 只从第二份加料选项开始收费。
</Tip>

## 嵌套加料选项

一个选择会引出更多选择——选一个配菜，如果选的是沙拉，再选一种酱汁。选项可以带有自己的加料组：

```json theme={null}
{
  "externalId": "itm-combo",
  "name": "Burger Combo",
  "variations": [{ "externalId": "var-combo", "name": "Regular", "price": { "amount": { "amountMinor": 1200, "currency": "USD" } } }],
  "modifierGroups": [
    {
      "externalId": "grp-side",
      "name": "Choose your side",
      "minSelections": 1,
      "maxSelections": 1,
      "options": [
        { "externalId": "side-fries", "name": "Fries" },
        {
          "externalId": "side-salad",
          "name": "Side salad",
          "modifierGroups": [
            {
              "externalId": "grp-dressing",
              "name": "Dressing",
              "minSelections": 1,
              "maxSelections": 1,
              "options": [
                { "externalId": "drs-ranch", "name": "Ranch" },
                { "externalId": "drs-vinaigrette", "name": "Vinaigrette" }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

选择 **Side salad** 会出现必选的 **Dressing** 选项；选择 **Fries** 则不会。可根据菜单需要嵌套任意深度。

<Note>
  订单资源目前只在每个行项目上提供直接选择的第一层加料选项——更深层的嵌套选择尚未展开到订单资源中。
</Note>

## 可用时间：每日特价

只在工作日早晨显示的早餐栏目。可以将时间窗口放在分类上（它会限制其中的所有内容），也可以放在单个菜品上：

```json theme={null}
{
  "externalId": "cat-breakfast",
  "name": "Breakfast",
  "availability": {
    "windows": [
      { "dayOfWeek": 1, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 2, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 3, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 4, "startTime": "07:00", "endTime": "11:00" },
      { "dayOfWeek": 5, "startTime": "07:00", "endTime": "11:00" }
    ]
  },
  "items": [{ "externalId": "itm-pancakes", "name": "Pancakes", "variations": [{ "externalId": "var-pancakes", "name": "Regular", "price": { "amount": { "amountMinor": 950, "currency": "USD" } } }] }]
}
```

* `dayOfWeek` 从 `0`（星期日）到 `6`（星期六）；每个生效的日子添加一个窗口。
* `startTime` / `endTime` 是当地时间 `HH:MM`（24 小时制），按菜单的时区计算——请设置顶层的 `timezone`（它[默认为 UTC](/zh/developer-api/guides/publish-menu)）。
* 没有 `availability` 的对象始终可用。

这就是按时段的菜单的工作方式——每个门店只有[一份菜单](/zh/developer-api/concepts/the-menu-model)，再用可用时间窗口把它划分开。

## 欢乐时光：周期性折扣

周期性折扣需要三个顶层对象协同工作——针对什么（商品集）、折扣的计算方式，以及何时生效（促销）：

```json theme={null}
{
  "productSets": [
    { "externalId": "set-drinks", "name": "All drinks", "itemIdsAny": ["itm-latte", "itm-cold-brew"] }
  ],
  "discounts": [
    {
      "externalId": "disc-happy-hour",
      "name": "20% off drinks",
      "benefitType": "percentage",
      "percentage": 20,
      "benefitTargetProductSetId": "set-drinks"
    }
  ],
  "promotions": [
    {
      "externalId": "promo-happy-hour",
      "name": "Happy hour",
      "discountId": "disc-happy-hour",
      "applicationMode": "automatic",
      "availability": {
        "windows": [
          { "dayOfWeek": 1, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 2, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 3, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 4, "startTime": "16:00", "endTime": "18:00" },
          { "dayOfWeek": 5, "startTime": "16:00", "endTime": "18:00" }
        ]
      }
    }
  ]
}
```

* \*\*商品集（product set）\*\*说明折扣适用于\_什么\_（这里是两个饮品；若要应用于整个菜单，请使用 `"allProducts": true`）。
* \*\*折扣（discount）\*\*说明\_优惠多少\_（八折，即减 20%）。其他 `benefitType` 包括 `amount`、`set_price`、`free_item` 和 `bxgy`。
* \*\*促销（promotion）\*\*把它们联系在一起，并说明\_何时\_生效：`applicationMode: "automatic"` 表示无需优惠码自动应用，`availability` 给出每周重复的时间窗口。如果是一次性活动，请改用 `validFrom` / `validUntil`。

<Note>
  将这些对象关联起来的 ID——`discountId`、`benefitTargetProductSetId` 以及 `itemIdsAny` 的成员——都是您分配的 `externalId`。菜单中的交叉引用始终使用您的 ID，而不是 Maple 的。促销的 `availability` 窗口使用菜单的时区（请设置顶层的 `timezone`；默认为 UTC）。
</Note>

## 标记售罄（86）

无需调整菜单结构即可将某个菜品标记为缺货——在菜品（或规格）上设置 `stockStatus`：

```json theme={null}
{ "externalId": "itm-latte", "name": "Latte", "stockStatus": "out_of_stock", "variations": [{ "externalId": "var-latte", "name": "Regular", "price": { "amount": { "amountMinor": 450, "currency": "USD" } } }] }
```

`stockStatus` 可以是 `in_stock`、`out_of_stock` 或 `low_stock`。重新发布时省略它会保留当前值，因此库存更新可以是一次小而有针对性的发布。

## 组合使用

这些可以组合。一个早餐分类（可用时间）中可以包含一个自选组合的菜品（嵌套加料选项），其中带有“第一份加料选项免费”的组（`freeSelectionCount`），同时饮品上还运行着欢乐时光促销。发布完整的菜单，Maple 会将其作为一次差异来应用——请参阅[发布菜单](/zh/developer-api/guides/publish-menu)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.