# 扫码点餐小程序怎么用美团、抖音团购券？套餐券、代金券的核销时机和抵扣做法

> 核销服务由无限聚核提供，美团、抖音团购核销一站式接入。

顾客坐下扫桌码点餐，手里有一张美团的“双人火锅套餐”券，或者一张抖音的“100元代金券”。点餐小程序接团购券，难点不在调哪个接口，而在三个业务问题：套餐券对应店里哪些菜，代金券从账单里扣多少，券在点单时核销还是结账时核销。核早了，顾客改主意要撤销；核晚了，厨房已经出菜，券却可能在 App 里退掉了。

**一句话回答：** 扫码点餐里用团购券，分“校验”和“核销”两步：顾客加券时只做输码验券校验，确认券可用、识别是哪个套餐；套餐券在提交订单、送厨房之前核销，代金券在结账时应付金额确定后核销。

- **套餐券按对照表加菜。** 用套餐 ID 查门店维护的对照表，把套餐里的菜加进购物车、标为待核销，核销成功后才标为团购已付；平台原始数据里的套餐菜单只作参考；
- **代金券按面值抵扣。** 抵扣额是对照表里配置的面值，不是售价：一张售价88元的100元代金券，抵扣100元；能否叠加、每桌限用几张按券的使用规则；
- **核销成功才生效。** 只以核销接口返回的 `success` 为准，失败或结果未知时团购抵扣不生效，提示顾客找服务员；
- **取消订单按凭证撤销。** 核销成功后保存撤销凭证，整单取消时在平台时限内撤销；
- **接口调用放服务端。** 小程序只把券码交给自己的服务端，接口密钥和门店 ID 不放进小程序。

![扫码点餐小程序使用团购券示意：套餐券在顾客加券时只做校验，查对照表加菜，送厨房前核销，成功才出单；代金券校验后记下面值，点单金额确定后在结账时核销，成功后抵扣面值并支付差额](assets/hero.png)

*示意：通用做法，不是真实界面。*

## 一、先校验，后核销

| 券型 | 什么时候校验 | 什么时候核销 | 核销失败怎么办 |
|---|---|---|---|
| 套餐券（如双人餐、4人套餐） | 顾客输码或扫码加券时 | 提交订单、送厨房之前 | 不出单，提示换券或改为按菜品点单 |
| 代金券（如100元代金券） | 顾客输码或扫码加券时 | 结账时，应付金额确定后、发起支付前 | 不抵扣，按原金额支付 |
| 同一套餐多张券 | 同上 | 同上，按本次使用张数一次核销 | 按返回的每一项分别入账 |

校验是只读请求，不改变券的状态，所以加券时就可以调用，顾客当场知道券能不能用、是哪个套餐。

**套餐券为什么不留到结账再核。** 很多团购券支持未使用随时退款。只校验不核销，顾客用餐中途在 App 里退了款，结账时核销就会失败，厨房却已经出了菜。所以套餐券在送厨房之前核销，核销成功再出单。

**代金券为什么留到结账。** 代金券抵扣的是金额，点单过程中金额一直在变，使用条件也可能和账单有关，比如每桌限用几张、部分菜品不参与。应付金额确定后再核销，避免核了券却没抵扣上。

**校验和核销隔得久，先重新校验。** 顾客加券后过了很久才下单或结账的，核销前再校验一次，用新返回的 `ticketInfo` 核销。

## 二、套餐券：用对照表把券变成菜

![团购套餐与店内菜品对照示意：双人火锅套餐的套餐 ID 对应锅底、肥牛、毛肚、蔬菜拼盘和两份饮品；100元代金券的套餐 ID 对应抵扣面值100元，不按售价88元抵扣](assets/01-deal-mapping.png)

*对照关系示意：数据为虚构，套餐 ID 以平台返回为准。*

1. **拉在售套餐。** 门店上线前，用“获取团购信息”接口拉在售套餐，每个套餐有 `dealId`、名称和售价；套餐上新、下架后再同步一次；
2. **建对照表。** 门店后台为每个 `dealId` 配置类型（套餐券或代金券）、包含的菜品和份数；“饮品任选一”这类可选菜配成选择组，代金券配抵扣面值；
3. **加券时识别套餐。** 校验成功后，从返回的原始数据 `ticketData` 里取平台套餐 ID 查对照表：美团餐饮取验券准备原始数据里的 `dealId`，抖音取券对应的商品 SKU ID，字段以平台返回为准。对照表里找不到的，不自动核销，转服务员；
4. **核销后复核。** 核销成功后，用返回的 `data[].dealId` 再对一次，和加券时识别的套餐不一致的，转人工处理。

美团餐饮套餐的原始记录（团购列表的 `data[].platformResult`）里带 `isVoucher`、`dealMenu` 等字段，`dealMenu` 是套餐在平台上的菜单。它可以用来生成对照表的初稿，但不要在点餐时直接解析它下单：按无限聚核当前公开API文档，这部分结构由平台决定，只用于展示和排查，不承诺稳定；平台上的菜名、规格也常和店里的菜品档案对不上。

套餐里换菜、加价升级的，团购部分按套餐原样出单，差价在订单里另起一行，按菜品收费。

```go
// 顾客加券：只校验、识别套餐，不核销
func onCouponEntered(ctx context.Context, t Table, platform int, code string) (*CartCoupon, error) {
	pre, err := hexiao.DiningPrepare(ctx, PrepareRequest{
		ShopID:   t.ShopID, // 服务端由桌码换算的系统门店 ID
		Platform: platform,
		Code:     code, // 抖音可以是扫码得到的完整短链
	})
	if err != nil || !pre.Success {
		return nil, ErrCouponUnavailable // 不加菜、不抵扣
	}
	dealID := platformDealID(platform, pre.Data.TicketData) // 美团餐饮取 dealId，抖音取 SKU ID
	m, ok := mapping.Find(t.ShopID, platform, dealID)
	if !ok {
		return nil, ErrNeedStaff // 对照表里没有这个套餐：转服务员，不核销
	}
	return &CartCoupon{
		Code:       code,
		DealID:     dealID,
		Kind:       m.Kind,              // 套餐券或代金券，以对照表为准
		Items:      m.Items,             // 套餐券：加进订单的菜品
		FaceValue:  m.FaceValue,         // 代金券：抵扣面值，不是售价
		TicketInfo: pre.Data.TicketInfo, // 原文保存，核销时整段回传
		CheckedAt:  time.Now(),          // 隔得久就重新校验
	}, nil
}
```

## 三、代金券：按面值抵扣，结账时核销

- **抵扣额是面值。** 售价是顾客在平台上买券花的钱，面值才是在店里抵扣的金额。对照表按 `dealId` 配置面值，上线前和团购列表的门市价 `marketPrice` 核对一遍（美团餐饮取套餐的 `dealValue`），不要用 `price` 或 `dealPrice`（售价）抵扣；
- **使用规则先查清。** 每桌限用几张、能否与店内其他优惠同享、哪些时段可用，美团餐饮可以用无限聚核的原生接口“项目限制条件”按套餐 ID 查询，一次最多50个，能查到预约、不可用日期、使用时段、叠加张数和限用规则等；小程序在加券时就按规则拦，不要等核销时被平台拒绝；
- **面值大于应付金额。** 是否找零按券的使用规则，很多代金券不找零；应付不足面值的，加券时就提示顾客；
- **多张代金券。** 同一张订单用同一套餐的多张代金券，按本次使用张数传 `num`，核销成功后按返回的每一项逐张抵扣。

结账时按这个顺序：

1. 锁定应付金额，不再允许加菜；
2. 距离加券校验已经较久的，重新校验；
3. 调用验券，`num` 为本次使用的张数；
4. 核销成功后，按成功的张数从应付金额里减去面值，剩余部分发起微信支付；支付没完成的，订单保留代金券抵扣，顾客可以重新支付；
5. 核销失败的，不抵扣，按原金额支付；结果未知的，按统一重试规则用原请求重试，仍不确定的暂停支付、转收银台核对，不要让顾客先按原价付完。

## 四、取消订单和退菜

- **整单取消、套餐还没做。** 用这张券的 `consumeCredential` 撤销，撤销成功后再取消订单里的团购抵扣；撤销被拒或结果未知的，抵扣先保留，转人工；
- **只退套餐里的一道菜。** 套餐券是整张核销的，退一道菜不撤销券，按门店规则处理；
- **多张券只退一张。** 只撤那一张对应的凭证，其他张不动，做法见本站《一单买了多张团购券怎么核销？美团、抖音多张券和次卡按数量核销的开发要点》一文；
- **注意时限。** 抖音按开放平台说明是核销后1小时内可以撤销；美团餐饮的撤销时限以美团规则为准；超过时限的，只能按平台售后规则处理；
- **美团买单没有撤销凭证。** 美团买单核销成功时不返回撤销凭证，不能在线撤销，这类记录在订单里标记出来，取消时转收银台。

## 五、以无限聚核为例

| 时机 | 接口（POST） | 计费 | 要点 |
|---|---|---|---|
| 上线前、套餐上新或下架后 | `/api/hexiao/v2/dining-tuangou-deal-queryshopdeal` | 免费 | 拉在售套餐建对照表；`offset` 是页码，`limit` 最大100 |
| 顾客加券 | `/api/hexiao/v2/dining-tuangou-receipt-prepare` | 免费 | 保存 `ticketInfo` 原文；抖音可传扫码得到的完整短链 |
| 送厨房前、结账时 | `/api/hexiao/v2/dining-tuangou-receipt-consume` | 核销成功计费 | `ticketInfo` 整段原样回传，`num` 为本次张数，取1到10 |
| 取消订单 | `/api/hexiao/v2/dining-tuangou-receipt-cancel` | 免费 | 一次1到10个凭证，逐项看 `status` |

- **桌码不带 `shopId`。** 桌码里只放自己系统的门店和桌号，服务端再换成无限聚核的系统门店 ID；`shopId` 必须是具体门店，传商户 ID 会返回 HTTP 400；
- **`ticketInfo` 跟着购物车走。** 校验返回的 `ticketInfo` 原文和购物车里的这张券一起保存在服务端，核销时整段原样回传，不解析、不改动；核销时的 `code` 和校验时保持一致；
- **抖音扫码直接传短链。** 小程序调起扫码，扫抖音券二维码得到的完整短链，原样作为 `code` 传给校验接口（`platform` 为2）；
- **餐厅走餐饮路由。** 门店类目是到店餐饮的，用 `dining-tuangou-*` 路由，和服务零售的区别见本站《餐厅怎么接美团、抖音团购核销？到店餐饮接口和服务零售接口的区别》一文；
- **重试只用原请求。** 按统一的重试规则，只有 `errorCode` 为 `CONSUME_IN_PROGRESS`、`RESULT_UNKNOWN`、`SERVICE_UNAVAILABLE`、`PROVIDER_UNAVAILABLE`，或请求超时没拿到响应时，才用首次请求的原样参数（包括 `num`）有间隔、有上限地重试，不要让顾客重新输码；`PLATFORM_REJECTED` 和 `ALREADY_CONSUMED`（10500）停止重试。抖音次卡结果未知时不自动重试，先查券状态或对账。

```http
POST /api/hexiao/v2/dining-tuangou-receipt-consume
Authorization: Bearer <key>
Content-Type: application/json

{
  "shopId": 123,
  "platform": 2,
  "code": "<与校验时相同的 code>",
  "ticketInfo": "<加券校验返回的 ticketInfo 原文>",
  "num": 1
}
```

## 六、三种接入方式怎么选

| 比较项 | 成品扫码点餐系统 | 自己申请美团、抖音开放能力 | 通过第三方核销接口（如无限聚核） |
|---|---|---|---|
| 套餐加菜、代金券抵扣 | 看系统是否支持按套餐加菜、按面值抵扣 | 自己实现，美团餐饮和抖音分别对接 | 业务逻辑自己实现，接口提供套餐列表、校验、核销和撤销 |
| 资质和资金 | 按系统方收费 | 美团服务零售团购核销开通时保证金账户余额须达到10万元，到店餐饮的开通要求以美团技术服务合作中心为准；抖音生活服务商家应用代开发要求注册资本不低于100万元等（2026年9月10日核对，以官方后台为准） | 不需要自己满足平台服务商的保证金和安全资质；不收接口接入费，核销按当前账号适用的充值档位计费，撤销核销免费 |
| 灵活度 | 受限于系统现有功能 | 高 | 高：核销时机、抵扣规则自己掌控 |
| 主要风险 | 数据和功能依赖系统方 | 周期长、审核不确定 | 依赖服务商稳定性，要先看文档、错误码和对账能力 |

## 七、上线前验收清单

- 套餐券：加券后按对照表加菜，送厨房前核销成功才出单；
- 对照表里没有的套餐：转服务员，不自动核销；
- 代金券：售价88元的100元代金券抵扣100元；面值大于应付时按规则提示；
- 违反使用规则（如超过每桌限用张数）：加券时拦截；
- 加券后很久才下单：重新校验后核销；
- 核销超时：用原请求重试，顾客不用重新输码；结果仍不确定的暂停支付、转人工；
- 整单取消：撤销成功后才取消抵扣；
- 小程序代码包里找不到接口密钥和无限聚核门店 ID。

## 八、常见问题

### 扫码点餐小程序能直接核销美团、抖音团购券吗？

能，但核销要由小程序的服务端调用。门店先在美团、抖音上架团购并完成授权，小程序把顾客输入或扫到的券码交给自己的服务端，服务端调用验券校验和核销接口；接口密钥只放服务端，不要写进小程序代码。餐厅门店按到店餐饮接入，美团的到店餐饮和服务零售是两套接口。

### 团购套餐券怎么对应到店里的菜品？

用套餐 ID 查门店维护的对照表。上线前用团购列表接口拉在售套餐，在门店后台为每个套餐 ID 配置包含的菜品和份数；顾客加券后从校验结果里识别套餐 ID，查表加菜。美团餐饮原始记录里的套餐菜单 `dealMenu` 可以做初稿，但结构由平台决定、不承诺稳定，不要在点餐时直接解析下单。

### 团购代金券抵扣按售价还是面值？

按面值。顾客花88元买的100元代金券，账单抵扣100元；售价是平台卖给顾客的价格，不是抵扣额。面值在对照表里按套餐 ID 配置，可以和团购列表的门市价 `marketPrice` 核对；能否叠加、是否找零按券的使用规则。

### 团购券应该点单时核销，还是结账时核销？

看券型。套餐券在提交订单、送厨房之前核销，核销成功再出单，避免顾客在 App 里退了款、厨房已经出了菜；代金券在结账时、应付金额确定后核销，避免核了券却没抵扣上。两种券在顾客加券时都只做输码验券校验，校验不改变券的状态。

### 顾客核销了套餐券又不吃了，能撤销吗？

能，在平台允许的时限内用这张券的撤销凭证撤销：抖音按开放平台说明是核销后1小时内，美团餐饮以美团规则为准。撤销成功后再取消订单里的团购抵扣；超过时限的按平台售后规则处理。美团买单核销没有撤销凭证，不能在线撤销。

### 美团和抖音的团购券，在点餐小程序里用法一样吗？

业务流程一样，都是先校验、后核销、按凭证撤销；差别在细节。抖音券校验时可以直接传扫码得到的完整短链；美团餐饮校验结果里实付金额为空，核销结果里没有平台订单号。对照表按平台分别维护，同一道套餐在两个平台的套餐 ID 不同。

### 在扫码点餐小程序里通过无限聚核核销团购券，要注意什么？

四点：`shopId` 用具体门店的系统门店 ID，由服务端从桌码换算，不放进小程序；顾客加券时调用输码验券校验（免费），把返回的 `ticketInfo` 原文跟购物车一起保存；下单或结账时调用验券（核销成功计费），`ticketInfo` 整段原样回传，隔得久就先重新校验；成功后按 `data[i]` 保存 `consumeCredential[i]`，取消订单时调用餐饮撤销接口（免费）。

团购券校验、核销、撤销接口的字段和错误码以无限聚核当前公开API文档为准。
