@dalehkx/quote-cli 0.3.3 → 0.3.5

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.
@@ -0,0 +1,596 @@
1
+ # API 接口映射文档
2
+
3
+ 本文档记录 CLI 各功能与 `terminal-api-v2` 真实接口的对应关系。
4
+
5
+ Base URL: `https://ec-hwbeta.casstime.com/terminal-api-v2`
6
+
7
+ ---
8
+
9
+ ## 认证
10
+
11
+ 所有业务接口需带 Header: `Authorization: bearer {accessToken}`
12
+
13
+ ### 登录(用户名密码)
14
+
15
+ ```
16
+ POST /public/auth/ecapp/login/password
17
+ ```
18
+
19
+ **Request:**
20
+ ```json
21
+ {
22
+ "userLoginName": "账号",
23
+ "password": "密码",
24
+ "deviceId": "quote-cli"
25
+ }
26
+ ```
27
+
28
+ **Response (errorCode=0):**
29
+ ```json
30
+ {
31
+ "errorCode": 0,
32
+ "data": {
33
+ "accessToken": "平台 access token",
34
+ "tokenType": "bearer",
35
+ "refreshToken": "刷新用 token",
36
+ "expiresIn": 7200,
37
+ "userLoginId": "用户ID"
38
+ }
39
+ }
40
+ ```
41
+
42
+ **错误码:**
43
+ | errorCode | 含义 |
44
+ |-----------|------|
45
+ | 702 | 账号或密码错误 |
46
+ | 703 | 帐号已失效 |
47
+ | 705 | 密码错误,剩余重试次数 |
48
+ | 706 | 账号已被锁定 |
49
+
50
+ ---
51
+
52
+ ### 登录(手机验证码)
53
+
54
+ ```
55
+ POST /public/auth/ecapp/login/cellphone
56
+ ```
57
+
58
+ **Request:**
59
+ ```json
60
+ {
61
+ "cellphone": "手机号",
62
+ "verifyCode": "验证码",
63
+ "deviceId": "quote-cli"
64
+ }
65
+ ```
66
+
67
+ **Response:** 同上
68
+
69
+ ---
70
+
71
+ ### 刷新 Token
72
+
73
+ ```
74
+ POST /public/auth/ecapp/refresh_token
75
+ ```
76
+
77
+ **Request:**
78
+ ```json
79
+ {
80
+ "refreshToken": "当前 refreshToken",
81
+ "clientId": "CASSAPP",
82
+ "deviceId": "quote-cli"
83
+ }
84
+ ```
85
+
86
+ **Response:** 同登录响应
87
+
88
+ **注意:** CLI 内部已实现自动续签逻辑:
89
+ - access token 过期时,自动调用此接口换取新 token 再重试请求
90
+ - 服务端返回 errorCode `401 / 652 / 653 / 654` 时同样触发续签+重试
91
+ - refresh token 本身失效(服务端返回以上错误码)时清空本地凭证,提示 `quote login`
92
+
93
+ ---
94
+
95
+ ## 询价单
96
+
97
+ ### 创建询价(简易)
98
+
99
+ CLI 命令: `quote inquiry create`
100
+
101
+ ```
102
+ POST /inquiries/simple_inquiry
103
+ ```
104
+
105
+ **Request:**
106
+ ```json
107
+ {
108
+ "vin": "VIN码(可选)",
109
+ "carBrandName": "品牌名称",
110
+ "carModelName": "车型",
111
+ "userName": "用户名",
112
+ "source": "ANDROID",
113
+ "qualities": ["BRAND"],
114
+ "userNeeds": [
115
+ {
116
+ "originalNeed": "配件原始名称",
117
+ "needsName": "配件名称",
118
+ "quantity": 4,
119
+ "oeCode": "OE编号",
120
+ "remark": "备注",
121
+ "inquirySource": "MANUALLY"
122
+ }
123
+ ]
124
+ }
125
+ ```
126
+
127
+ **Response:**
128
+ ```json
129
+ {
130
+ "errorCode": 0,
131
+ "data": {
132
+ "inquiryId": "询价单ID",
133
+ "isSimpleDemand": true
134
+ }
135
+ }
136
+ ```
137
+
138
+ **品质枚举 (qualities):**
139
+ | 值 | 含义 |
140
+ |----|------|
141
+ | ORIGINAL_BRAND | 原厂件 |
142
+ | BRAND | 品牌件 |
143
+ | EXTERNAL_BRAND | 外贸件 |
144
+ | INTERNAL_BRAND | 内贸件 |
145
+ | SECOND_HAND | 二手件 |
146
+ | EQUIVALENT_BRAND | 同质件 |
147
+
148
+ ---
149
+
150
+ ### 询价单列表
151
+
152
+ CLI 命令: `quote inquiry list`
153
+
154
+ ```
155
+ POST /inquiries/list?page=1&size=20
156
+ ```
157
+
158
+ **Request:**
159
+ ```json
160
+ {
161
+ "searchContext": "关键字(可选)",
162
+ "statusIds": ["WAIT_QUOTATION"],
163
+ "startDate": "2026-01-01",
164
+ "endDate": "2026-06-15"
165
+ }
166
+ ```
167
+
168
+ **状态映射:**
169
+ | CLI status | 平台 statusIds |
170
+ |------------|---------------|
171
+ | pending | WAIT_QUOTATION, QUOTING |
172
+ | quoted | QUOTED, PART_QUOTED |
173
+ | ordered | ORDERED |
174
+ | closed | CLOSED, EXPIRED |
175
+
176
+ **Response:**
177
+ ```json
178
+ {
179
+ "errorCode": 0,
180
+ "data": {
181
+ "content": [...],
182
+ "totalElements": 100,
183
+ "totalPages": 5,
184
+ "number": 0,
185
+ "size": 20,
186
+ "isFirst": true,
187
+ "isLast": false
188
+ }
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ### 询价单详情
195
+
196
+ CLI 命令: `quote inquiry detail <id>`
197
+
198
+ ```
199
+ GET /inquiries/{inquiryId}/detailV2?platform=ANDROID
200
+ ```
201
+
202
+ **Response:** 包含车型信息、需求配件列表、报价状态等完整详情。
203
+
204
+ ---
205
+
206
+ ## 报价结果
207
+
208
+ ### 获取商家报价
209
+
210
+ CLI 命令: `quote reply list -i <inquiryId>`
211
+
212
+ ```
213
+ GET /inquiries/store/quotation?inquiryId={id}&storeId={storeId}
214
+ ```
215
+
216
+ **Response:**
217
+ ```json
218
+ {
219
+ "errorCode": 0,
220
+ "data": {
221
+ "demandId": "询价单号",
222
+ "consultingQuotationProducts": [
223
+ {
224
+ "quotationProductId": "报价结果ID",
225
+ "originalItemName": "配件名称",
226
+ "brandName": "品牌",
227
+ "displayPrice": "280.00",
228
+ "quality": "BRAND",
229
+ "qualityDescription": "品牌件",
230
+ "arrivalTime": 2,
231
+ "productType": "FINISHED_GOODS",
232
+ "remark": "备注"
233
+ }
234
+ ]
235
+ }
236
+ }
237
+ ```
238
+
239
+ ---
240
+
241
+ ### 获取导购方案
242
+
243
+ CLI 命令: `quote compare -i <inquiryId>`
244
+
245
+ ```
246
+ GET /inquiries/quotation_scheme?quotationId={id}
247
+ ```
248
+
249
+ ---
250
+
251
+ ## 下单
252
+
253
+ ### 完整下单流程
254
+
255
+ CLI 命令:
256
+ ```bash
257
+ # 交互式(推荐):引导选择地址和物流
258
+ quote order confirm -i <inquiryId> -r <replyId>
259
+
260
+ # 非交互:全部用 flag 指定
261
+ quote order confirm -i <inquiryId> -r <replyId> -a <addressId> -l <logisticsCode>
262
+
263
+ # 先查可用物流和 code(用于 -l 参数)
264
+ quote order logistics -i <inquiryId> -r <replyId>
265
+
266
+ # 查看收货地址(用于 -a 参数)
267
+ quote order addresses
268
+ ```
269
+
270
+ 已通过 beta 环境实测验证(成功创建订单 S2606180009597),完整 5 步流程如下:
271
+
272
+ ---
273
+
274
+ **Step 1:** 采购确认
275
+ ```
276
+ POST /inquiries/purchase_confirm
277
+ ```
278
+
279
+ **Request:**
280
+ ```json
281
+ {
282
+ "inquiryId": "询价单号",
283
+ "quotationProductIds": ["报价结果ID"]
284
+ }
285
+ ```
286
+
287
+ **Response:** 返回询价单信息,忽略,继续下一步。
288
+
289
+ ---
290
+
291
+ **Step 2:** 找报价所在 store
292
+
293
+ 遍历 `detailV2.inquiryQuoteStores[]`,逐一调:
294
+ ```
295
+ GET /inquiries/store/quotation?inquiryId={id}&storeId={storeId}
296
+ ```
297
+ 在 `consultingQuotationProducts` 中找到 `quotationProductId === replyId` 的条目,取:
298
+ - `quotationProductId` → `productId`(用于下单)
299
+ - `location` → `facilityId`(仓库 ID,如 `CN_GZ`)
300
+ - `storeId` → `sellerStoreId`
301
+
302
+ ---
303
+
304
+ **Step 3:** 生成结算单
305
+ ```
306
+ POST /buy/proxy_order_bff/tosettle
307
+ ```
308
+
309
+ **Request:**
310
+ ```json
311
+ {
312
+ "application": "ANDROID",
313
+ "businessGroup": "INQUIRY",
314
+ "businessUnit": "COMMON_INQUIRY",
315
+ "originSource": "INQUIRY_CONFIRM",
316
+ "buyerUserLoginId": "来自登录缓存 userLoginId",
317
+ "buyerCompanyId": "来自登录缓存 garageCompanyId(必须为字符串)",
318
+ "terminal": "APP",
319
+ "postalAddressId": "收货地址ID(必填,来自 GET /address/proxy_order_bff/post_addresses/{userLoginId})",
320
+ "toSettleItems": [
321
+ {
322
+ "productId": "quotationProductId(报价结果ID)",
323
+ "facilityId": "仓库ID(item.location,如 CN_GZ)",
324
+ "sellerStoreId": "店铺ID",
325
+ "inquiryId": "询价单号(必填,缺少会报 500"询价单号不能为空")",
326
+ "quantity": 1,
327
+ "needInvoice": "B",
328
+ "itemInvoice": "N"
329
+ }
330
+ ]
331
+ }
332
+ ```
333
+
334
+ **Response:**
335
+ ```json
336
+ { "settleId": "6a33670c..." }
337
+ ```
338
+
339
+ > ⚠️ `POST /inquiry-cart/settle/v2` 在 beta 环境返回 999,不可用,改走 proxy_order_bff 路径。
340
+
341
+ ---
342
+
343
+ **Step 4:** 获取结算单详情(含总价、商品条目、物流选项)
344
+ ```
345
+ POST /buy/settle
346
+ ```
347
+
348
+ **Request:**
349
+ ```json
350
+ {
351
+ "type": "INIT",
352
+ "settlePayload": {
353
+ "settleId": "结算单ID",
354
+ "application": "ANDROID",
355
+ "terminal": "APP"
356
+ }
357
+ }
358
+ ```
359
+
360
+ **Response 关键字段:**
361
+ ```json
362
+ {
363
+ "totalAmount": {
364
+ "productTotalAmount": 29.0,
365
+ "totalAmount": 23.2
366
+ },
367
+ "validGroups": [
368
+ {
369
+ "storeId": "GZYC0001",
370
+ "inquiryItems": [
371
+ {
372
+ "productItems": [
373
+ {
374
+ "settleItemId": "6a338f05ef868400014e86f4",
375
+ "productId": "6a32e1cef41487000145696b",
376
+ "quantity": 1,
377
+ "facilityId": "CN_GZ"
378
+ }
379
+ ]
380
+ }
381
+ ],
382
+ "xiaomaLogisticsService": [
383
+ {
384
+ "storeId": "GZYC0001",
385
+ "facilityId": "CN_GZ",
386
+ "defaultLogisticsDTO": {
387
+ "logisticsCompanyCode": "YJAA",
388
+ "logisticsCompanyName": "粤俊物流",
389
+ "transportationCode": "CAR_FREIGHT",
390
+ "logisticsLocationCode": "YJAA066AA",
391
+ "logisticsLocationName": "粤俊茂名站",
392
+ "deliverType": "self_mention",
393
+ "departureTime": "01:30发车",
394
+ "lineShiftCode": "YJAA020AAYJAA066AA1301",
395
+ "lineShiftName": "晚班"
396
+ },
397
+ "commonlyUsedLogistics": [
398
+ {
399
+ "displayLogisticsCompaniesCode": "HTAA",
400
+ "displayLogisticsCompaniesName": "恒泰物流",
401
+ "transportWayDTOS": [{ "transportationCode": "CAR_FREIGHT", "logisticsLocationDTOS": [...] }]
402
+ }
403
+ ]
404
+ }
405
+ ]
406
+ }
407
+ ]
408
+ }
409
+ ```
410
+
411
+ **提取逻辑:**
412
+ - `totalAmount.totalAmount` = 含折扣实付金额(用于 settle_submit)
413
+ - `validGroups[].inquiryItems[].productItems[].settleItemId` = 提交下单的商品条目 ID
414
+ - 物流优先取 `defaultLogisticsDTO`,无则从 `commonlyUsedLogistics[0]` 构造
415
+ - `departureTime / lineShiftCode / lineShiftName` 无值时传空字符串(接口要求 string 不接受 null)
416
+
417
+ ---
418
+
419
+ **Step 5:** 提交结算下单
420
+ ```
421
+ POST /buy/proxy_order_bff/settle_submit
422
+ ```
423
+
424
+ **Request:**
425
+ ```json
426
+ {
427
+ "settleId": "结算单ID",
428
+ "clientRequestId": "前端生成的 UUID(幂等防重复提交)",
429
+ "application": "ANDROID",
430
+ "businessGroup": "INQUIRY",
431
+ "businessUnit": "COMMON_INQUIRY",
432
+ "buyerCompanyId": "garageCompanyId(字符串)",
433
+ "postalAddressId": "收货地址ID",
434
+ "terminal": "APP",
435
+ "goldCoinUsed": false,
436
+ "totalAmount": 23.2,
437
+ "invoices": [
438
+ { "storeId": "店铺ID", "inquiryId": "询价单号", "needInvoice": "B" }
439
+ ],
440
+ "logistics": {
441
+ "xiaomaLogistics": [
442
+ {
443
+ "storeId": "GZYC0001",
444
+ "facilityId": "CN_GZ",
445
+ "logisticsCompanyCode": "YJAA",
446
+ "logisticsCompanyName": "粤俊物流",
447
+ "transportationCode": "CAR_FREIGHT",
448
+ "transportationName": "汽运",
449
+ "logisticsLocationCode": "YJAA066AA",
450
+ "logisticsLocationName": "粤俊茂名站",
451
+ "landingLogisticsLocationCode": "YJAA",
452
+ "landingLogisticsLocationName": "粤俊物流",
453
+ "deliverType": "self_mention",
454
+ "departureTime": "01:30发车",
455
+ "lineShiftCode": "YJAA020AAYJAA066AA1301",
456
+ "lineShiftName": "晚班"
457
+ }
458
+ ]
459
+ },
460
+ "products": [
461
+ {
462
+ "settleItemId": "6a338f05ef868400014e86f4",
463
+ "productId": "6a32e1cef41487000145696b",
464
+ "quantity": 1,
465
+ "storeId": "GZYC0001",
466
+ "facilityId": "CN_GZ"
467
+ }
468
+ ]
469
+ }
470
+ ```
471
+
472
+ **Response:**
473
+ ```json
474
+ {
475
+ "isSuccess": true,
476
+ "orderIds": ["S2606180009597"]
477
+ }
478
+ ```
479
+
480
+ **注意:**
481
+ - `logistics` 为必填字段(传空对象 `{}` 会报"物流信息不能为空")
482
+ - `products[].settleItemId` 来自 Step 4 的 `validGroups[].inquiryItems[].productItems[].settleItemId`
483
+ - 返回 `errorCode: 999, teamCode: 3000` 表示订单服务内部错误(beta 环境对已下过单的报价重复下单会触发)
484
+
485
+ ---
486
+
487
+ ### 收货地址
488
+
489
+ ```
490
+ GET /address/proxy_order_bff/post_addresses/{userLoginId}
491
+ ```
492
+
493
+ 返回用户地址列表。每条地址字段:`id`, `receiverName`, `contactNumber`, `provinceGeoName`, `cityGeoName`, `countyGeoName`, `address`。
494
+
495
+ fallback:`GET /address` 返回单条默认地址(字段名为 `addressId` 而非 `id`)。
496
+
497
+ ---
498
+
499
+ ### 订单列表
500
+
501
+ CLI 命令: `quote order list`
502
+
503
+ ```
504
+ POST /orders
505
+ ```
506
+
507
+ > ⚠️ 注意:`POST /inquiries/order/list` 是"工单询价"场景的询价单列表,不是真实订单列表,不可混用。
508
+
509
+ **Request:**
510
+ ```json
511
+ {
512
+ "pageNumber": 1,
513
+ "pageSize": 20
514
+ }
515
+ ```
516
+
517
+ **可选过滤字段:**
518
+ | 字段 | 类型 | 说明 |
519
+ |------|------|------|
520
+ | `statusId` | string | `ORDER_WAIT_PAYED` / `ORDER_APPROVED` / `ORDER_SENT` / `ORDER_COMPLETED` / `ORDER_CANCELLED` |
521
+ | `partInfo` | string | 配件名称或零件号 |
522
+ | `orderTimeBegin` / `orderTimeEnd` | string | 下单时间范围 |
523
+ | `createdName` | string | 下单人名称 |
524
+
525
+ **Response:**
526
+ ```json
527
+ {
528
+ "errorCode": 0,
529
+ "data": {
530
+ "orders": [
531
+ {
532
+ "orderId": "订单ID",
533
+ "productStoreName": "店铺名称",
534
+ "actualCurrencyAmount": 280.00,
535
+ "orderName": "配件名称拼接",
536
+ "statusId": "ORDER_WAIT_PAYED",
537
+ "statusIdDesc": "等待付款",
538
+ "carBrandName": "大众",
539
+ "carModelInfo": "朗逸",
540
+ "orderDate": 1718000000000
541
+ }
542
+ ],
543
+ "totalElements": 50,
544
+ "pageNumber": 1
545
+ }
546
+ }
547
+ ```
548
+
549
+ **订单状态枚举 (statusId):**
550
+ | 值 | 含义 |
551
+ |----|------|
552
+ | ORDER_WAIT_PAYED | 待付款 |
553
+ | ORDER_APPROVED | 待发货 |
554
+ | ORDER_SENT | 待收货 |
555
+ | ORDER_COMPLETED | 已完成 |
556
+ | ORDER_CANCELLED | 已取消 |
557
+
558
+ ---
559
+
560
+ ## 通用响应格式
561
+
562
+ 所有接口响应均遵循:
563
+
564
+ ```json
565
+ {
566
+ "errorCode": 0,
567
+ "data": { ... }
568
+ }
569
+ ```
570
+
571
+ | errorCode | 含义 |
572
+ |-----------|------|
573
+ | 0 | 成功 |
574
+ | 401 | 认证失败(token 无效或已过期) |
575
+ | 605 | 参数格式校验失败 |
576
+ | 652 | 账号在其它设备登录,当前 token 已失效 |
577
+ | 653 | token 已过期 |
578
+ | 654 | token 校验失败 |
579
+ | 999 | 系统繁忙 |
580
+
581
+ ---
582
+
583
+ ## Token 校验
584
+
585
+ ```
586
+ GET /users/check_token
587
+ Authorization: bearer {accessToken}
588
+ ```
589
+
590
+ **Response:**
591
+ ```json
592
+ {
593
+ "errorCode": 0,
594
+ "data": { "isSuccess": true }
595
+ }
596
+ ```
@@ -0,0 +1,111 @@
1
+ # 数据结构定义
2
+
3
+ 所有数据以 JSON 文件形式存储在 `.quote-data/` 目录下。
4
+
5
+ ## 目录结构
6
+
7
+ ```
8
+ .quote-data/
9
+ ├── config.json # 用户配置
10
+ ├── inquiries/ # 询价单(每条一个文件)
11
+ │ └── INQ-YYYYMMDD-NNN.json
12
+ ├── replies/ # 报价(每条一个文件)
13
+ │ └── QUO-YYYYMMDD-NNN.json
14
+ └── orders/ # 订单(每条一个文件)
15
+ └── ORD-YYYYMMDD-NNN.json
16
+ ```
17
+
18
+ ## ID 格式
19
+
20
+ `{PREFIX}-{YYYYMMDD}-{SEQ}`
21
+
22
+ - PREFIX: INQ(询价)、QUO(报价)、ORD(订单)
23
+ - YYYYMMDD: 创建日期
24
+ - SEQ: 当日序号,三位补零
25
+
26
+ ## Config
27
+
28
+ ```json
29
+ {
30
+ "role": "buyer",
31
+ "name": "张三",
32
+ "company": "XX修理厂",
33
+ "phone": "138xxxx1234"
34
+ }
35
+ ```
36
+
37
+ ## Inquiry (询价单)
38
+
39
+ ```json
40
+ {
41
+ "id": "INQ-20260615-001",
42
+ "product": "前刹车片",
43
+ "oeNumber": "04465-33471",
44
+ "vehicle": "丰田凯美瑞 2020",
45
+ "quantity": 4,
46
+ "note": "",
47
+ "status": "pending",
48
+ "createdAt": "2026-06-15T10:00:00.000Z",
49
+ "createdBy": "张三"
50
+ }
51
+ ```
52
+
53
+ | 字段 | 类型 | 必填 | 说明 |
54
+ |------|------|------|------|
55
+ | id | string | 自动 | 唯一标识 |
56
+ | product | string | 是 | 产品/零件名称 |
57
+ | oeNumber | string | 否 | OE 编号 / 型号 |
58
+ | vehicle | string | 否 | 适用车型 / 设备型号 |
59
+ | quantity | number | 否 | 数量,默认 1 |
60
+ | note | string | 否 | 备注 |
61
+ | status | string | 自动 | pending / quoted / ordered / closed |
62
+ | createdAt | string | 自动 | ISO 时间戳 |
63
+ | createdBy | string | 自动 | 创建人(取自 config) |
64
+
65
+ ## Reply (报价)
66
+
67
+ ```json
68
+ {
69
+ "id": "QUO-20260615-001",
70
+ "inquiryId": "INQ-20260615-001",
71
+ "supplier": "深圳XX汽配",
72
+ "price": 280,
73
+ "currency": "CNY",
74
+ "brand": "天合TRW",
75
+ "delivery": 2,
76
+ "note": "原厂件",
77
+ "createdAt": "2026-06-15T11:00:00.000Z"
78
+ }
79
+ ```
80
+
81
+ | 字段 | 类型 | 必填 | 说明 |
82
+ |------|------|------|------|
83
+ | id | string | 自动 | 唯一标识 |
84
+ | inquiryId | string | 是 | 关联询价单 ID |
85
+ | supplier | string | 否 | 供应商名称 |
86
+ | price | number | 是 | 报价金额 |
87
+ | currency | string | 否 | 货币,默认 CNY |
88
+ | brand | string | 否 | 品牌 |
89
+ | delivery | number | 否 | 货期(天) |
90
+ | note | string | 否 | 备注 |
91
+ | createdAt | string | 自动 | ISO 时间戳 |
92
+
93
+ ## Order (订单)
94
+
95
+ ```json
96
+ {
97
+ "id": "ORD-20260615-001",
98
+ "inquiryId": "INQ-20260615-001",
99
+ "replyId": "QUO-20260615-001",
100
+ "status": "confirmed",
101
+ "confirmedAt": "2026-06-15T12:00:00.000Z"
102
+ }
103
+ ```
104
+
105
+ | 字段 | 类型 | 必填 | 说明 |
106
+ |------|------|------|------|
107
+ | id | string | 自动 | 唯一标识 |
108
+ | inquiryId | string | 是 | 关联询价单 |
109
+ | replyId | string | 是 | 选中的报价 |
110
+ | status | string | 自动 | confirmed |
111
+ | confirmedAt | string | 自动 | ISO 时间戳 |