sophhub 0.4.71 → 0.4.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hotel-booking",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"types": [
|
|
5
|
+
"builtin"
|
|
6
|
+
],
|
|
7
|
+
"displayName": "酒店预订",
|
|
8
|
+
"description": "国内酒店查询、下单、支付、状态查询、取消与部分退订全流程 skill",
|
|
9
|
+
"changelog": [
|
|
10
|
+
{
|
|
11
|
+
"changes": [
|
|
12
|
+
"初次提交:关键词检索 → 起价列表 → 房型详情 → 预订校验 → 创单 → 支付 → 状态查询 → 取消 → 部分退订"
|
|
13
|
+
],
|
|
14
|
+
"date": "2026-09-30",
|
|
15
|
+
"version": "1.0.0"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"createdAt": "2026-09-30",
|
|
19
|
+
"updatedAt": "2026-09-30",
|
|
20
|
+
"emoji": "🏨",
|
|
21
|
+
"tags": [
|
|
22
|
+
"工具"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hotel-booking
|
|
3
|
+
description: "中国国内酒店查询与预订。当用户需要查酒店、订酒店、看房价、查酒店订单、取消或退订酒店时使用。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hotel Booking(酒店查询与预订)
|
|
7
|
+
|
|
8
|
+
国内酒店查询、创建订单、企业账户支付、订单状态查询、取消与部分退订的全流程 skill。
|
|
9
|
+
分步执行,信息未确认时主动向用户确认。
|
|
10
|
+
|
|
11
|
+
> **平台说明**:订房通过 **Sophnet 平台**完成,支付使用平台账户余额。余额不足会导致支付失败,
|
|
12
|
+
> 需提示用户前往 Sophnet 平台充值后重试。
|
|
13
|
+
|
|
14
|
+
## 重要原则
|
|
15
|
+
|
|
16
|
+
- **信息完全确定才执行**:创建订单、支付涉及真实资金与行程,仅在用户已明确确认**酒店、房型、入住/离店日期、房间数、入住人、联系人**后执行。
|
|
17
|
+
- **支付前务必二次确认**:**不得在创建订单后自动连续支付**。创单成功后先向用户展示订单号、酒店房型、入离日期与金额,**等用户明确说「确认支付」「付款吧」等**再执行 `pay-order`。
|
|
18
|
+
- **取消 / 退订前务必二次确认**:**不得在用户未确认时执行退订**。退订必须先用 `refund-part --dry-run` 展示订单现状与拟退日期,等用户明确确认后才去掉 `--dry-run` 真正提交。
|
|
19
|
+
- **`cityId` 全程透传**:城市 ID 是预订会话字段,从 `search-city` 拿到后必须一路带到创单;不要把城市名或别的 ID 体系的值当 `cityId` 用。
|
|
20
|
+
- **用户必填变量**:入住人姓名 / 手机号 / 证件号通过**环境变量**配置,与机票 skill 同名(见文末)。
|
|
21
|
+
- **房型报价必须完整展示**:展示详情时要把脚本返回的**全部房型与价格计划逐行列出**,不得只显示前几条;
|
|
22
|
+
每条至少含房型、床型、每晚价、N 晚合计、库存、早餐、取消规则。
|
|
23
|
+
|
|
24
|
+
## 流程概览
|
|
25
|
+
|
|
26
|
+
| 步骤 | 说明 | 脚本子命令 |
|
|
27
|
+
|------|------|------------|
|
|
28
|
+
| 第一步 | 关键词 / 地标 / 酒店名检索,拿到候选城市 `cityId` 与酒店 ID | `search-city` |
|
|
29
|
+
| 第二步 | 用酒店 ID 查起价列表(筛选酒店用) | `search-hotel` |
|
|
30
|
+
| 第三步 | 查房型与价格计划:逐晚价、库存、取消规则、早餐 | `hotel-detail` |
|
|
31
|
+
| 第四步 | 预订校验(报价码是否仍有效) | `validate` |
|
|
32
|
+
| 第五步 | 创建订单(房型与日期取缓存,价格由脚本按逐晚价合计) | `create-order` |
|
|
33
|
+
| 第六步 | 支付(企业账户,异步受理) | `pay-order` |
|
|
34
|
+
| 第七步 | 订单状态查询(支付后必须轮询确认终态) | `order-status` |
|
|
35
|
+
| 第八步 | 取消订单(未支付取消 / 已支付退订由网关按状态自动选择) | `cancel-order` |
|
|
36
|
+
| 第九步 | 部分退订(已确认订单,按房间 + 日期段退) | `refund-part` |
|
|
37
|
+
| 附加 | 列出本地缓存的历史订单 / 保存入住人身份 | `list-orders`、`save-passenger`、`list-passengers` |
|
|
38
|
+
|
|
39
|
+
## 第一步:关键词 / 地标检索
|
|
40
|
+
|
|
41
|
+
用户说「外滩附近的酒店」「上海浦东川沙诺富特酒店」这类需求时使用;也可以直接给城市名。
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
python3 {baseDir}/scripts/hotel_booking.py search-city --keyword 外滩
|
|
45
|
+
python3 {baseDir}/scripts/hotel_booking.py search-city --keyword 上海 --city-id 10801 --city-name 上海
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- 输出:候选城市(含在途 `cityId`)与命中酒店(含在途酒店 ID)。
|
|
49
|
+
- **`cityId` 必须记下来**:后续 `hotel-detail`、`create-order` 都要透传同一个值。
|
|
50
|
+
脚本会把最近一次 `search-city` 的 `cityId` 写进缓存,`hotel-detail` 未显式传时会自动带上;
|
|
51
|
+
**但用户换城市时必须重新执行 `search-city`**,否则可能沿用旧城市的 `cityId`(那会查不到酒店)。
|
|
52
|
+
- 命中多个城市时脚本不会替你选,**必须让用户确认城市**再把 `--city-id` 传进来。
|
|
53
|
+
- 结果会写入 `~/.openclaw/hotel-booking/.last_search.json`,供第二步免参使用。
|
|
54
|
+
|
|
55
|
+
## 第二步:起价列表
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
python3 {baseDir}/scripts/hotel_booking.py search-hotel --check-in 2026-10-22 --check-out 2026-10-23
|
|
59
|
+
python3 {baseDir}/scripts/hotel_booking.py search-hotel --check-in 2026-10-22 --check-out 2026-10-23 --hotel-ids 11357228,11357229
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **起价不是最终价**,只用于筛酒店;真实可订价一律以第三步的房型报价为准,向用户说明这一点。
|
|
63
|
+
- 不传 `--hotel-ids` 时默认用第一步缓存的候选酒店 ID(这就是「关键词 → 起价」的推荐路径)。
|
|
64
|
+
- **已知限制**:按 `cityId` 的"条件搜索"在测试环境实测返回空数组。脚本在拿不到酒店 ID 时会退回条件搜索,
|
|
65
|
+
此时起价为空属正常现象,**不要反复重试**,改用关键词检索拿酒店 ID 再查。
|
|
66
|
+
|
|
67
|
+
## 第三步:房型与价格计划详情
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python3 {baseDir}/scripts/hotel_booking.py hotel-detail --origin-hotel-id 11357228 --check-in 2026-10-22 --check-out 2026-10-23
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- 输出一行一个**价格计划**,含 `originRoomId`、`ratePlanId`、每晚价、N 晚合计、库存、早餐、取消规则、价格类型。
|
|
74
|
+
- **向用户完整展示**这些行(含取消规则),由用户选择房型与价格计划;选完把这两个 ID 记下来。
|
|
75
|
+
- 同一天同一房型可能有多个价格计划(含早/无早、可取消/不可取消),**让用户挑,不要替他决定**。
|
|
76
|
+
- 报价会写入 `~/.openclaw/hotel-booking/.last_detail.json`;`create-order` 默认从这份缓存读房型与日期。
|
|
77
|
+
- **报价会变**:`shoppingCode` 随报价快照轮换(实测同一房型同一晚 70 分钟内换过 3 个)。
|
|
78
|
+
准备下单前如已有间隔,**重新执行一次 `hotel-detail` 并把最新总价给用户确认**。
|
|
79
|
+
|
|
80
|
+
## 第四步:预订校验
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python3 {baseDir}/scripts/hotel_booking.py validate
|
|
84
|
+
python3 {baseDir}/scripts/hotel_booking.py validate --room-id 259735835 --rate-plan-id 1655121775 --customer-num 2
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- 只回答「报价码是否仍有效」;**该接口不返回库存与逐晚价**,价格一律以 `hotel-detail` 为准。
|
|
88
|
+
- 校验失败(报价已失效)时重新执行 `hotel-detail` 取最新报价。
|
|
89
|
+
- 这一步是可选加速检查:**真正的价格防线在网关**(见第五步),跳过它不会导致按错价下单。
|
|
90
|
+
|
|
91
|
+
## 第五步:创建订单
|
|
92
|
+
|
|
93
|
+
在用户已选定房型与价格计划后执行。酒店、日期、`cityId` 从缓存读取,入住人从环境变量读取。
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
python3 {baseDir}/scripts/hotel_booking.py create-order --room-id 259735835 --rate-plan-id 1655121775
|
|
97
|
+
python3 {baseDir}/scripts/hotel_booking.py create-order --room-id 259735835 --rate-plan-id 1655121775 --rooms 2
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- 金额由脚本按**逐晚价合计 × 房间数**计算,与网关的比价口径一致;逐晚价不完整时脚本会直接拒绝下单。
|
|
101
|
+
- 输出:订单号、应付金额、**超时自动取消时间**(到点未支付会自动取消并释放冻结额度)。
|
|
102
|
+
- 创单成功后**不要立即支付**:先展示订单号、酒店房型、入离日期、金额,等用户明确确认。
|
|
103
|
+
|
|
104
|
+
### 房价变动与库存不足(重要)
|
|
105
|
+
|
|
106
|
+
网关在下单前会重新取一次房型报价复核价格,因此可能直接拒单:
|
|
107
|
+
|
|
108
|
+
| 返回 | 含义 | 你要做的 |
|
|
109
|
+
|------|------|----------|
|
|
110
|
+
| `40109` 价格已变化 | 用户看到的价格已过期 | 重新执行 `hotel-detail`,把**最新总价**展示给用户,等用户再次确认后重新创单 |
|
|
111
|
+
| `40110` 无可售库存 | 该价格计划库存为 0 | 提示用户换房型或换日期,重新 `hotel-detail` |
|
|
112
|
+
| `40101` 上游异常 | 未拿到上游响应 | 写操作**绝不允许自动重试**;先 `order-status` 查订单是否已生成,再决定下一步 |
|
|
113
|
+
|
|
114
|
+
## 第六步:支付
|
|
115
|
+
|
|
116
|
+
**仅在用户明确确认支付后执行。**
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
python3 {baseDir}/scripts/hotel_booking.py pay-order --order-no 1124469436763392
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- 支付方式固定为企业账户(`BP_ACCOUNT`),金额默认取订单详情的订单总额。
|
|
123
|
+
- 输出 `code=0` **只代表受理**,订单进入「确认中」;**必须**用第七步确认最终状态。
|
|
124
|
+
- 收到 `40108`:酒店支付能力当前未开放,如实告诉用户,不要反复重试。
|
|
125
|
+
|
|
126
|
+
## 第七步:订单状态查询
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
python3 {baseDir}/scripts/hotel_booking.py order-status --order-no 1124469436763392
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- 状态含义:待支付 → 确认中 → 已确认 / 已取消 / 退订中 / 部分退订 / 已退订。
|
|
133
|
+
- 支付后请间隔一段时间复查;「确认中」是上游尚未出票的正常中间态,**不等于失败**。
|
|
134
|
+
- 结果为「已确认」时再看确认号;若长时间停在「确认中」,把订单号给用户,由用户与供应商/平台确认。
|
|
135
|
+
|
|
136
|
+
## 第八步:取消订单
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
python3 {baseDir}/scripts/hotel_booking.py cancel-order --order-no 1124469436763392
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- 未支付的订单取消后立即释放冻结额度;已支付但尚未确认的订单,取消等价于退订。
|
|
143
|
+
- 已确认的订单**只能部分退订**(第九步),走不到这一步。
|
|
144
|
+
- **取消前先向用户确认**:取消后能否免费取决于该价格计划的取消规则,把 `hotel-detail` 里的取消规则一并说明。
|
|
145
|
+
|
|
146
|
+
## 第九步:部分退订(已确认订单)
|
|
147
|
+
|
|
148
|
+
必须先 dry-run 展示,再经用户确认:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# 1) 先看清楚(不提交)
|
|
152
|
+
python3 {baseDir}/scripts/hotel_booking.py refund-part --order-no <orderNo> --room-no 1 --check-in 2026-10-17 --check-out 2026-10-18 --dry-run
|
|
153
|
+
|
|
154
|
+
# 2) 用户明确确认后,去掉 --dry-run 提交
|
|
155
|
+
python3 {baseDir}/scripts/hotel_booking.py refund-part --order-no <orderNo> --room-no 1 --check-in 2026-10-17 --check-out 2026-10-18
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- 退订日期必须**连续**,不能从中间挑;只允许同一房间号、同一日期段。
|
|
159
|
+
- 退款金额由供应商生成的退单决定,脚本与接口都不会预估算:**不要向用户承诺具体金额**,只说明以退单为准。
|
|
160
|
+
- 受理(退单进入审核)与**入账**是两个时刻,入账取决于供应商放款;请间隔复查 `order-status`。
|
|
161
|
+
- 同一订单要发起**下一笔**退订,必须等上一笔入账完成(订单回到「部分退订」状态)再提交,否则会被状态校验拦下。
|
|
162
|
+
|
|
163
|
+
## 环境变量
|
|
164
|
+
|
|
165
|
+
| 变量 | 用途 | 是否必填 |
|
|
166
|
+
|------|------|----------|
|
|
167
|
+
| `SOPH_API_KEY` | 网关 API Key(也支持从 `~/.openclaw/openclaw.json` 读取) | 必填 |
|
|
168
|
+
| `PASSENGER_NAME` | 入住人姓名 | 下单必填 |
|
|
169
|
+
| `PASSENGER_MOBILE` | 入住人手机号(联系人默认同此) | 下单必填 |
|
|
170
|
+
| `PASSENGER_CREDENTIAL_NO` | 入住人证件号 | 下单必填 |
|
|
171
|
+
| `SOPH_GATEWAY_BASE_URL` | 覆盖网关地址(默认 `https://www.sophnet.com/api`),仅联调时用 | 可选 |
|
|
172
|
+
|
|
173
|
+
> 与 flight-booking 复用同一组入住人变量,用户配置一次即可两个 skill 通用。
|
|
174
|
+
> 需要多间房时,脚本按「同一入住人依次占用房间 1..N」生成入住人列表;如需不同入住人,请先与用户确认后按房间逐一处理。
|
|
175
|
+
|
|
176
|
+
## 常见问题
|
|
177
|
+
|
|
178
|
+
| 现象 | 处理 |
|
|
179
|
+
|------|------|
|
|
180
|
+
| 列表接口起价为空 | 按 `cityId` 的条件搜索在测试环境实测返空,属已知限制;改用关键词检索拿酒店 ID 再查起价 |
|
|
181
|
+
| 下单报「价格已变化」 | 重新 `hotel-detail` → 把最新价给用户确认 → 重新创单,不要盲目重试 |
|
|
182
|
+
| 下单报「无可售库存」 | 换房型或换日期 |
|
|
183
|
+
| 退订接口报「重复操作订单」 | 上一笔退订还在处理中;等它入账、订单回到「部分退订」后再退下一段 |
|
|
184
|
+
| 支付或退订报能力未开放 | 平台侧开关未打开,如实告知用户,不要重试 |
|