@agenzo/merchant-cli 0.9.0 → 0.9.2
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/dist/index.js +171 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1197,6 +1197,22 @@ var ridePayOrderSchema = {
|
|
|
1197
1197
|
default: false,
|
|
1198
1198
|
description: "[\u65B9\u6848 B/R16] Explicit opt-in to settle this pay_per_call ride via the EVO bound-card fallback rail. Set true ONLY when the user explicitly chose EVO; forwarded to the pay body as evo_explicit=true. Without it, a pay_per_call settlement lacking --payment-token-id is hard-gated server-side. Ignored for monthly_settlement and on the payment-token-id direct-charge path."
|
|
1199
1199
|
},
|
|
1200
|
+
authenticate: {
|
|
1201
|
+
type: "bool",
|
|
1202
|
+
required: false,
|
|
1203
|
+
default: false,
|
|
1204
|
+
description: "Opt-in to require cardholder 3DS on the network-token direct charge (payment-token-id, EVO/Mastercard). On step-up the response is AUTHENTICATION_REQUIRED with three_ds_url + charge_no; resume via authorized-charge-no. Default off = frictionless. Ignored on the EVO preauth path and for UnionPay/Visa."
|
|
1205
|
+
},
|
|
1206
|
+
"return-url": {
|
|
1207
|
+
type: "string",
|
|
1208
|
+
required: false,
|
|
1209
|
+
description: "Optional 3DS/passkey return URL for the network-token authenticate path; falls back to the platform EVO_3DS_RETURN_URL."
|
|
1210
|
+
},
|
|
1211
|
+
"authorized-charge-no": {
|
|
1212
|
+
type: "string",
|
|
1213
|
+
required: false,
|
|
1214
|
+
description: "Resume a network-token 3DS challenge: charge_no from a prior AUTHENTICATION_REQUIRED response (settled via resume_token). Relaxes the exactly-one-credential rule (continuation, not a fresh charge)."
|
|
1215
|
+
},
|
|
1200
1216
|
"idempotency-key": {
|
|
1201
1217
|
type: "string",
|
|
1202
1218
|
required: true,
|
|
@@ -1574,6 +1590,7 @@ var hotelCreateOrderSchema = {
|
|
|
1574
1590
|
children: { type: "int", required: false, default: 0, description: "Children per room (match quote)", constraints: "0-10" },
|
|
1575
1591
|
nationality: { type: "string", required: false, default: "CN", description: "Guest nationality (match quote)" },
|
|
1576
1592
|
"guest-name": { type: "string", required: true, description: "Primary guest name", constraints: "Use the name as the user gives it. If a supplier returns NAME_FORMAT_INVALID, re-collect in Latin letters and retry" },
|
|
1593
|
+
"room-guests": { type: "string", required: false, description: "Per-room primary guests, listed in room order, for booking several rooms under different names. Omit it and every room reuses guest-name (backward compatible); guest-name stays required either way", constraints: "JSON array of {guest_name (non-empty string)}; room_index is optional and filled in from the array position (1-based, validated against room-num by the platform) \u2014 pass it explicitly only to override; else PARAM_INVALID" },
|
|
1577
1594
|
"contact-name": { type: "string", required: true, description: "Booking contact name (may equal guest-name)" },
|
|
1578
1595
|
"contact-phone": { type: "string", required: true, description: "Booking contact phone number", constraints: "Digits; collect country code separately in --contact-country-code" },
|
|
1579
1596
|
"contact-country-code": { type: "string", required: false, default: "86", description: "Phone country calling code without '+'" },
|
|
@@ -1662,6 +1679,22 @@ var hotelPayOrderSchema = {
|
|
|
1662
1679
|
default: false,
|
|
1663
1680
|
description: "[\u65B9\u6848 B/R16] Explicit opt-in to settle this pay_per_call order via the EVO bound-card fallback rail. Set true ONLY when the user explicitly chose EVO; forwarded to the pay body as evo_explicit=true. Without it, a pay_per_call settlement lacking --payment-token-id is hard-gated server-side. Ignored for monthly_settlement and on the payment-token-id direct-charge path."
|
|
1664
1681
|
},
|
|
1682
|
+
authenticate: {
|
|
1683
|
+
type: "bool",
|
|
1684
|
+
required: false,
|
|
1685
|
+
default: false,
|
|
1686
|
+
description: "Opt-in to require cardholder 3DS on the network-token direct charge (payment-token-id, EVO/Mastercard). On step-up the response is AUTHENTICATION_REQUIRED with three_ds_url + charge_no; resume via authorized-charge-no. Default off = frictionless. Ignored on the EVO preauth path and for UnionPay/Visa."
|
|
1687
|
+
},
|
|
1688
|
+
"return-url": {
|
|
1689
|
+
type: "string",
|
|
1690
|
+
required: false,
|
|
1691
|
+
description: "Optional 3DS/passkey return URL for the network-token authenticate path; falls back to the platform EVO_3DS_RETURN_URL."
|
|
1692
|
+
},
|
|
1693
|
+
"authorized-charge-no": {
|
|
1694
|
+
type: "string",
|
|
1695
|
+
required: false,
|
|
1696
|
+
description: "Resume a network-token 3DS challenge: charge_no from a prior AUTHENTICATION_REQUIRED response (settled via resume_token), then triggers upstream payOrder on success (pay_per_call only)."
|
|
1697
|
+
},
|
|
1665
1698
|
"idempotency-key": {
|
|
1666
1699
|
type: "string",
|
|
1667
1700
|
required: true,
|
|
@@ -2363,30 +2396,38 @@ var flightListNationalitiesSchema = flightSchema(
|
|
|
2363
2396
|
);
|
|
2364
2397
|
var flightSearchSchema = flightSchema(
|
|
2365
2398
|
"search",
|
|
2366
|
-
"Search flights (one-way/round-trip/multi-city). journeys always carries all legs; journey-id
|
|
2399
|
+
"Search flights (one-way/round-trip/multi-city). journeys always carries all legs; for round-trip/multi-city relay the CHOSEN candidate's next_journey_ids into --journey-id until is_final_leg is true \u2014 only then do offers carry a real priceKey (product_token).",
|
|
2367
2400
|
{
|
|
2368
2401
|
"trip-type": { type: "int", required: true, description: "1=one-way, 2=round-trip, 3=multi-city." },
|
|
2369
|
-
journeys: { type: "json", required: true, description: "JSON array of {date, origin, destination, origin_type?, destination_type?}. origin/destination are IATA 3-letter codes; *_type 1=city, 2=airport." },
|
|
2402
|
+
journeys: { type: "json", required: true, description: "JSON array of {date, origin, destination, origin_type?, destination_type?}. origin/destination are IATA 3-letter codes; *_type 1=city, 2=airport. Carries ALL legs on every call, including relay calls." },
|
|
2370
2403
|
"cabin-class": { type: "string", required: false, default: "economy", description: "economy | premium_economy | business | first." },
|
|
2371
2404
|
"adult-num": { type: "int", required: false, default: 1, description: "Adults (1-9)." },
|
|
2372
2405
|
"child-num": { type: "int", required: false, default: 0, description: "Children (0-9)." },
|
|
2373
2406
|
"infant-num": { type: "int", required: false, default: 0, description: "Infants (0-9)." },
|
|
2374
2407
|
airline: { type: "string", required: false, description: "Airline 2-letter code filter." },
|
|
2375
2408
|
"transfer-number": { type: "int", required: false, default: 0, description: "0=any,1=direct,2=1 stop,3=2 stops." },
|
|
2376
|
-
"journey-id": { type: "json", required: false, description: "
|
|
2409
|
+
"journey-id": { type: "json", required: false, description: "Relay key: copy offers[].next_journey_ids VERBATIM from the candidate the user chose in the previous search. Omit on the first search. Do not build it from the top-level journey_ids, and never send more ids than there are legs (rejected)." }
|
|
2377
2410
|
},
|
|
2378
2411
|
{
|
|
2379
|
-
offers: { type: "array", description: "
|
|
2412
|
+
offers: { type: "array", description: "Candidates for the current leg. Each has next_journey_ids (relay key), journey_id, segment_ids, paired_segment_ids, total_sale_price (WHOLE-TRIP total), currency, cabin_class, baggage/refund/change_rules, and product_token when price_key_ready." },
|
|
2380
2413
|
price_key_ready: { type: "bool", description: "True only when all legs are selected (final search)." },
|
|
2381
|
-
|
|
2414
|
+
current_leg: { type: "int", description: "Which leg this result is choosing (1-based)." },
|
|
2415
|
+
total_legs: { type: "int", description: "Total legs in the trip." },
|
|
2416
|
+
is_final_leg: { type: "bool", description: "True when these offers can be bookable. False means relay another round with the chosen candidate's next_journey_ids." },
|
|
2417
|
+
journey_ids: { type: "array", description: "DEPRECATED for relay: flattened across all candidates, so it cannot tell you which id belongs to which. Relay offers[].next_journey_ids instead." }
|
|
2382
2418
|
},
|
|
2383
|
-
{ command: `agenzo-merchant-cli flight-flink search --trip-type 1 --journeys '[{"date":"2026-08-01","origin":"PEK","destination":"SHA"}]'`, output_summary: "Returns offers[]; use a product_token where price_key_ready is true, then verify." }
|
|
2419
|
+
{ command: `agenzo-merchant-cli flight-flink search --trip-type 1 --journeys '[{"date":"2026-08-01","origin":"PEK","destination":"SHA"}]'`, output_summary: "Returns offers[]; use a product_token where price_key_ready is true, then verify. Round-trip: the first search has is_final_leg=false and no product_token \u2014 relay the chosen candidate's next_journey_ids to get bookable offers." }
|
|
2384
2420
|
);
|
|
2385
2421
|
var flightMoreOffersSchema = flightSchema(
|
|
2386
2422
|
"more-offers",
|
|
2387
2423
|
"More fare offers for a priceKey (carried by product_token).",
|
|
2388
2424
|
{ "product-token": { type: "string", required: true, description: "Opaque token from search." } },
|
|
2389
|
-
{
|
|
2425
|
+
{
|
|
2426
|
+
offers: { type: "array", description: "Additional fare candidates for the same flight (same shape as search offers[]); all are bookable." },
|
|
2427
|
+
current_leg: { type: "int", description: "Always 1 \u2014 alternative fares for one chosen flight, not a relay round." },
|
|
2428
|
+
total_legs: { type: "int", description: "Always 1." },
|
|
2429
|
+
is_final_leg: { type: "bool", description: "Always true." }
|
|
2430
|
+
},
|
|
2390
2431
|
{ command: "agenzo-merchant-cli flight-flink more-offers --product-token pt_...", output_summary: "Additional fare offers." }
|
|
2391
2432
|
);
|
|
2392
2433
|
var flightVerifySchema = flightSchema(
|
|
@@ -2397,7 +2438,8 @@ var flightVerifySchema = flightSchema(
|
|
|
2397
2438
|
product_token: { type: "string", description: "Authoritative token to pass to create-order." },
|
|
2398
2439
|
total_price: { type: "int", description: "Verified total price (integer)." },
|
|
2399
2440
|
currency: { type: "string", description: "Currency code." },
|
|
2400
|
-
price_changed: { type: "bool", description: "True if the price changed since search; re-confirm with the user." }
|
|
2441
|
+
price_changed: { type: "bool", description: "True if the price changed since search; re-confirm with the user." },
|
|
2442
|
+
journeys: { type: "array", description: "The COMPLETE itinerary being priced \u2014 every leg, not just the last one relayed. Use it to show the full trip on a confirmation screen." }
|
|
2401
2443
|
},
|
|
2402
2444
|
{ command: "agenzo-merchant-cli flight-flink verify --product-token pt_...", output_summary: "Returns the authoritative product_token + price_changed." }
|
|
2403
2445
|
);
|
|
@@ -2440,7 +2482,10 @@ var flightPayOrderSchema = flightSchema(
|
|
|
2440
2482
|
"order-no": { type: "string", required: true, description: "Our order reference from create-order." },
|
|
2441
2483
|
"payment-method-id": { type: "string", required: false, description: "Optional bound-card id to charge (pay_per_call only; omit to use the default card)." },
|
|
2442
2484
|
"payment-token-id": { type: "string", required: false, description: "Optional network-token id; settles via direct charge instead of EVO preauth." },
|
|
2443
|
-
"authorized-merchant-trans-id": { type: "string", required: false, description: "Resume
|
|
2485
|
+
"authorized-merchant-trans-id": { type: "string", required: false, description: "Resume an EVO-card 3DS challenge with an already-authorised preauth trans id." },
|
|
2486
|
+
authenticate: { type: "bool", required: false, default: false, description: "Opt-in to require cardholder 3DS on the network-token direct charge (payment-token-id, EVO/Mastercard). On step-up the response is AUTHENTICATION_REQUIRED with three_ds_url + charge_no; resume via authorized-charge-no. Default off = frictionless." },
|
|
2487
|
+
"return-url": { type: "string", required: false, description: "Optional 3DS/passkey return URL for the network-token authenticate path; falls back to the platform EVO_3DS_RETURN_URL." },
|
|
2488
|
+
"authorized-charge-no": { type: "string", required: false, description: "Resume a network-token 3DS challenge: charge_no from a prior AUTHENTICATION_REQUIRED response (settled via resume_token), then triggers ticketing on success." },
|
|
2444
2489
|
"evo-explicit": { type: "bool", required: false, default: false, description: "[\u65B9\u6848 B/R16] Explicit opt-in to settle this pay_per_call order via the EVO bound-card fallback rail. Set true ONLY when the user explicitly chose EVO; forwarded to the pay body as evo_explicit=true. Without it, a pay_per_call settlement lacking --payment-token-id is hard-gated server-side." },
|
|
2445
2490
|
"idempotency-key": { type: "string", required: true, description: "Forwarded verbatim as the Idempotency-Key header." }
|
|
2446
2491
|
},
|
|
@@ -3103,6 +3148,17 @@ function formatPayOrder(data) {
|
|
|
3103
3148
|
lines.push(["Amount", `${data.price.amount} ${data.price.currency}`]);
|
|
3104
3149
|
if (data.price.quote_id) lines.push(["Quote ID", String(data.price.quote_id)]);
|
|
3105
3150
|
}
|
|
3151
|
+
if (data.charge_no) lines.push(["Charge no", String(data.charge_no)]);
|
|
3152
|
+
if (data.three_ds_url) lines.push(["3DS URL", String(data.three_ds_url)]);
|
|
3153
|
+
if (String(data.status) === "AUTHENTICATION_REQUIRED") {
|
|
3154
|
+
return [
|
|
3155
|
+
Formatter.keyValue(lines),
|
|
3156
|
+
Formatter.status(
|
|
3157
|
+
"warning",
|
|
3158
|
+
`Order ${orderRef} needs cardholder 3DS \u2014 open the 3DS URL, then resume pay-order with --authorized-charge-no ${data.charge_no ?? ""}.`
|
|
3159
|
+
)
|
|
3160
|
+
].join("\n\n");
|
|
3161
|
+
}
|
|
3106
3162
|
return [
|
|
3107
3163
|
Formatter.keyValue(lines),
|
|
3108
3164
|
Formatter.status(
|
|
@@ -3120,7 +3176,16 @@ function registerRidePayOrderCommand(parent, deps) {
|
|
|
3120
3176
|
"Bound-card id to charge via EVO preauth+capture (fallback path). Exactly one of --payment-token-id / --payment-method-id is required."
|
|
3121
3177
|
).option(
|
|
3122
3178
|
"--authorized-merchant-trans-id <id>",
|
|
3123
|
-
"Resume
|
|
3179
|
+
"Resume an EVO-card 3DS challenge: merchant trans id of an already-authorised preauth"
|
|
3180
|
+
).option(
|
|
3181
|
+
"--authenticate",
|
|
3182
|
+
"Opt-in to require cardholder 3DS on the network-token direct charge (--payment-token-id, EVO/Mastercard). When a step-up is needed the response is AUTHENTICATION_REQUIRED with three_ds_url + charge_no; resume with --authorized-charge-no. Default off = frictionless."
|
|
3183
|
+
).option(
|
|
3184
|
+
"--return-url <url>",
|
|
3185
|
+
"Optional 3DS/passkey return URL for the network-token authenticate path (falls back to the platform EVO_3DS_RETURN_URL)"
|
|
3186
|
+
).option(
|
|
3187
|
+
"--authorized-charge-no <no>",
|
|
3188
|
+
"Resume a network-token 3DS challenge: charge_no returned by a prior AUTHENTICATION_REQUIRED response (settled via ChargeService.resume_token). When set, the exactly-one-credential rule is relaxed (this is a continuation, not a fresh charge)."
|
|
3124
3189
|
).option(
|
|
3125
3190
|
"--evo-explicit",
|
|
3126
3191
|
"[\u65B9\u6848 B/R16] Explicit opt-in to settle this pay_per_call ride via the EVO bound-card fallback rail. Set ONLY when the user explicitly chose EVO; forwarded to the pay body as evo_explicit=true. Without it, a pay_per_call settlement lacking --payment-token-id is hard-gated server-side."
|
|
@@ -3136,7 +3201,10 @@ function registerRidePayOrderCommand(parent, deps) {
|
|
|
3136
3201
|
const orderId = need4(opts.orderId, "order-id");
|
|
3137
3202
|
const paymentTokenId = opts.paymentTokenId;
|
|
3138
3203
|
const paymentMethodId = opts.paymentMethodId;
|
|
3139
|
-
|
|
3204
|
+
const authorizedChargeNo = opts.authorizedChargeNo;
|
|
3205
|
+
if (authorizedChargeNo === void 0) {
|
|
3206
|
+
assertExactlyOneCredential(paymentTokenId, paymentMethodId);
|
|
3207
|
+
}
|
|
3140
3208
|
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
3141
3209
|
message: "API Key:",
|
|
3142
3210
|
type: "password"
|
|
@@ -3147,6 +3215,9 @@ function registerRidePayOrderCommand(parent, deps) {
|
|
|
3147
3215
|
if (opts.authorizedMerchantTransId !== void 0) {
|
|
3148
3216
|
body.authorized_merchant_trans_id = opts.authorizedMerchantTransId;
|
|
3149
3217
|
}
|
|
3218
|
+
if (opts.authenticate) body.authenticate = true;
|
|
3219
|
+
if (opts.returnUrl !== void 0) body.return_url = opts.returnUrl;
|
|
3220
|
+
if (authorizedChargeNo !== void 0) body.authorized_charge_no = authorizedChargeNo;
|
|
3150
3221
|
if (opts.evoExplicit) body.evo_explicit = true;
|
|
3151
3222
|
if (!isYes) {
|
|
3152
3223
|
const confirmed = await confirm3({
|
|
@@ -4536,6 +4607,34 @@ function parsePriceItems(raw) {
|
|
|
4536
4607
|
}
|
|
4537
4608
|
return parsed;
|
|
4538
4609
|
}
|
|
4610
|
+
function parseRoomGuests(raw) {
|
|
4611
|
+
const INVALID = "--room-guests must be a JSON array of {guest_name (non-empty string), room_index (optional 1-based integer)}.";
|
|
4612
|
+
let parsed;
|
|
4613
|
+
try {
|
|
4614
|
+
parsed = JSON.parse(raw);
|
|
4615
|
+
} catch {
|
|
4616
|
+
throw new CliError("PARAM_INVALID", INVALID);
|
|
4617
|
+
}
|
|
4618
|
+
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
4619
|
+
throw new CliError("PARAM_INVALID", INVALID);
|
|
4620
|
+
}
|
|
4621
|
+
return parsed.map((el, i) => {
|
|
4622
|
+
if (typeof el !== "object" || el === null || Array.isArray(el)) {
|
|
4623
|
+
throw new CliError("PARAM_INVALID", INVALID);
|
|
4624
|
+
}
|
|
4625
|
+
const item = el;
|
|
4626
|
+
if (typeof item.guest_name !== "string" || item.guest_name.trim() === "") {
|
|
4627
|
+
throw new CliError("PARAM_INVALID", INVALID);
|
|
4628
|
+
}
|
|
4629
|
+
if (item.room_index === void 0) {
|
|
4630
|
+
return { ...item, room_index: i + 1 };
|
|
4631
|
+
}
|
|
4632
|
+
if (!Number.isInteger(item.room_index) || item.room_index < 1) {
|
|
4633
|
+
throw new CliError("PARAM_INVALID", INVALID);
|
|
4634
|
+
}
|
|
4635
|
+
return item;
|
|
4636
|
+
});
|
|
4637
|
+
}
|
|
4539
4638
|
function parseTips(raw) {
|
|
4540
4639
|
const INVALID = "--tips must be a JSON array of {title (string, optional), text (string, optional)}.";
|
|
4541
4640
|
let parsed;
|
|
@@ -4621,7 +4720,10 @@ function formatCreateOrder2(data) {
|
|
|
4621
4720
|
return out.join("\n");
|
|
4622
4721
|
}
|
|
4623
4722
|
function registerHotelCreateOrderCommand(parent, deps) {
|
|
4624
|
-
const cmd = parent.command("create-order").description("Create a hotel order without charging (lock inventory, await payment)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--product-token <token>", "Chosen rate token from quote (rates[].product_token)").option("--total-amount <amount>", "Total stay price in decimal currency units (not cents)").option("--currency <currency>", "ISO 4217 currency code from the chosen rate").option("--price-items <json>", "Per-night price breakdown JSON array (copied verbatim from quote)").option("--check-in <date>", "Check-in date (YYYY-MM-DD, match quote)").option("--check-out <date>", "Check-out date (YYYY-MM-DD, strictly after check-in)").option("--room-num <n>", "Number of rooms (match quote)", "1").option("--adults <n>", "Adults per room (match quote)", "2").option("--children <n>", "Children per room (match quote)", "0").option("--nationality <code>", "Guest nationality (ISO country code)", "CN").option("--guest-name <name>", "Primary guest name").option(
|
|
4723
|
+
const cmd = parent.command("create-order").description("Create a hotel order without charging (lock inventory, await payment)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--product-token <token>", "Chosen rate token from quote (rates[].product_token)").option("--total-amount <amount>", "Total stay price in decimal currency units (not cents)").option("--currency <currency>", "ISO 4217 currency code from the chosen rate").option("--price-items <json>", "Per-night price breakdown JSON array (copied verbatim from quote)").option("--check-in <date>", "Check-in date (YYYY-MM-DD, match quote)").option("--check-out <date>", "Check-out date (YYYY-MM-DD, strictly after check-in)").option("--room-num <n>", "Number of rooms (match quote)", "1").option("--adults <n>", "Adults per room (match quote)", "2").option("--children <n>", "Children per room (match quote)", "0").option("--nationality <code>", "Guest nationality (ISO country code)", "CN").option("--guest-name <name>", "Primary guest name").option(
|
|
4724
|
+
"--room-guests <json>",
|
|
4725
|
+
"Optional per-room primary guests as a JSON array [{guest_name}], listed in room order, for booking several rooms under different names. room_index is filled in from the array position (1-based); pass it explicitly to override. Omit the flag and every room reuses --guest-name."
|
|
4726
|
+
).option("--contact-name <name>", "Booking contact name (may equal guest-name)").option("--contact-phone <phone>", "Booking contact phone number (digits)").option("--contact-country-code <code>", "Phone country calling code without '+'", "86").option("--contact-email <email>", "Booking contact email").option("--arrive-time <time>", "Expected arrival time (HH:mm, hotel local time)").option("--special-requests <text>", "Free-text special requests (non-binding)").option(
|
|
4625
4727
|
"--tips <json>",
|
|
4626
4728
|
"\u5BA2\u6237\u81EA\u6D4B\u70B95 \u63D0\u793A\u4FE1\u606F: the chosen quote rate's tips as a JSON array [{title,text}]. Stored on the order for the order-detail page ONLY \u2014 platform-local, not sent upstream."
|
|
4627
4729
|
).option("--hotel-name <name>", "Hotel name (display-only, stored for order summary)").option(
|
|
@@ -4683,6 +4785,7 @@ function registerHotelCreateOrderCommand(parent, deps) {
|
|
|
4683
4785
|
contact_phone: contactPhone,
|
|
4684
4786
|
contact_country_code: opts.contactCountryCode
|
|
4685
4787
|
};
|
|
4788
|
+
if (opts.roomGuests !== void 0) body.room_guests = parseRoomGuests(opts.roomGuests);
|
|
4686
4789
|
if (opts.contactEmail !== void 0) body.contact_email = opts.contactEmail;
|
|
4687
4790
|
if (opts.arriveTime !== void 0) body.arrive_time = opts.arriveTime;
|
|
4688
4791
|
if (opts.specialRequests !== void 0) body.special_requests = opts.specialRequests;
|
|
@@ -4864,11 +4967,14 @@ function formatPayOrder2(data) {
|
|
|
4864
4967
|
];
|
|
4865
4968
|
if (data.settlement_path) lines.push(["Settlement path", String(data.settlement_path)]);
|
|
4866
4969
|
if (data.pay_status) lines.push(["Pay status", String(data.pay_status)]);
|
|
4970
|
+
if (data.status) lines.push(["Status", String(data.status)]);
|
|
4867
4971
|
if (data.total_amount != null && data.currency) {
|
|
4868
4972
|
lines.push(["Amount", `${data.total_amount} ${data.currency}`]);
|
|
4869
4973
|
}
|
|
4870
4974
|
if (data.billing_entry_id) lines.push(["Billing entry", String(data.billing_entry_id)]);
|
|
4871
4975
|
if (data.merchant_trans_id) lines.push(["Merchant trans ID", String(data.merchant_trans_id)]);
|
|
4976
|
+
if (data.charge_no) lines.push(["Charge no", String(data.charge_no)]);
|
|
4977
|
+
if (data.three_ds_url) lines.push(["3DS URL", String(data.three_ds_url)]);
|
|
4872
4978
|
return Formatter.keyValue(lines);
|
|
4873
4979
|
}
|
|
4874
4980
|
function isPaymentTerminal(record) {
|
|
@@ -4878,7 +4984,16 @@ function isPaymentTerminal(record) {
|
|
|
4878
4984
|
function registerHotelPayOrderCommand(parent, deps) {
|
|
4879
4985
|
const cmd = parent.command("pay-order").description("Settle an existing hotel order (path decided by billing_mode: monthly_settlement or pay_per_call)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--order-id <id>", "Order ID to pay (from create-order response)").option("--payment-method-id <id>", "Optional bound-card id to charge (pay_per_call / EVO preauth)").option("--payment-token-id <id>", "Optional network-token id (unionpay/visa charge path)").option(
|
|
4880
4986
|
"--authorized-merchant-trans-id <id>",
|
|
4881
|
-
"Resume
|
|
4987
|
+
"Resume an EVO-card 3DS challenge: merchant trans id of an already-authorised preauth"
|
|
4988
|
+
).option(
|
|
4989
|
+
"--authenticate",
|
|
4990
|
+
"Opt-in to require cardholder 3DS on the network-token direct charge (--payment-token-id, EVO/Mastercard). When a step-up is needed the response is AUTHENTICATION_REQUIRED with three_ds_url + charge_no; resume with --authorized-charge-no. Default off = frictionless."
|
|
4991
|
+
).option(
|
|
4992
|
+
"--return-url <url>",
|
|
4993
|
+
"Optional 3DS/passkey return URL for the network-token authenticate path (falls back to the platform EVO_3DS_RETURN_URL)"
|
|
4994
|
+
).option(
|
|
4995
|
+
"--authorized-charge-no <no>",
|
|
4996
|
+
"Resume a network-token 3DS challenge: charge_no returned by a prior AUTHENTICATION_REQUIRED response (settled via ChargeService.resume_token)"
|
|
4882
4997
|
).option(
|
|
4883
4998
|
"--evo-explicit",
|
|
4884
4999
|
"[\u65B9\u6848 B/R16] Explicit opt-in to settle this pay_per_call order via the EVO bound-card fallback rail. Set ONLY when the user explicitly chose EVO; forwarded to the pay body as evo_explicit=true. Without it, a pay_per_call settlement lacking --payment-token-id is hard-gated server-side."
|
|
@@ -4920,6 +5035,11 @@ function registerHotelPayOrderCommand(parent, deps) {
|
|
|
4920
5035
|
if (opts.authorizedMerchantTransId !== void 0) {
|
|
4921
5036
|
body.authorized_merchant_trans_id = opts.authorizedMerchantTransId;
|
|
4922
5037
|
}
|
|
5038
|
+
if (opts.authenticate) body.authenticate = true;
|
|
5039
|
+
if (opts.returnUrl !== void 0) body.return_url = opts.returnUrl;
|
|
5040
|
+
if (opts.authorizedChargeNo !== void 0) {
|
|
5041
|
+
body.authorized_charge_no = opts.authorizedChargeNo;
|
|
5042
|
+
}
|
|
4923
5043
|
if (opts.evoExplicit) body.evo_explicit = true;
|
|
4924
5044
|
if (!isYes) {
|
|
4925
5045
|
const confirmed = await confirm8({
|
|
@@ -6151,7 +6271,7 @@ function registerListNationalitiesCommand(parent, deps) {
|
|
|
6151
6271
|
|
|
6152
6272
|
// src/flight-flink/search.ts
|
|
6153
6273
|
function registerSearchCommand(parent, deps) {
|
|
6154
|
-
const cmd = parent.command("search").description("Search flights (one-way/round-trip/multi-city, journeyId relay)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--trip-type <n>", "1=one-way, 2=round-trip, 3=multi-city").option("--journeys <json>", "JSON array of {date, origin, destination, origin_type?, destination_type?}").option("--cabin-class <c>", "economy | premium_economy | business | first", "economy").option("--adult-num <n>", "Adults (1-9)", "1").option("--child-num <n>", "Children (0-9)", "0").option("--infant-num <n>", "Infants (0-9)", "0").option("--airline <code>", "Airline 2-letter code filter").option("--transfer-number <n>", "0=any,1=direct,2=1 stop,3=2 stops", "0").option("--journey-id <json>", "
|
|
6274
|
+
const cmd = parent.command("search").description("Search flights (one-way/round-trip/multi-city, journeyId relay)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--trip-type <n>", "1=one-way, 2=round-trip, 3=multi-city").option("--journeys <json>", "JSON array of {date, origin, destination, origin_type?, destination_type?}").option("--cabin-class <c>", "economy | premium_economy | business | first", "economy").option("--adult-num <n>", "Adults (1-9)", "1").option("--child-num <n>", "Children (0-9)", "0").option("--infant-num <n>", "Infants (0-9)", "0").option("--airline <code>", "Airline 2-letter code filter").option("--transfer-number <n>", "0=any,1=direct,2=1 stop,3=2 stops", "0").option("--journey-id <json>", "Relay: the chosen offer's next_journey_ids, verbatim (round-trip/multi-city)");
|
|
6155
6275
|
attachSchemaHelp(cmd, flightSearchSchema);
|
|
6156
6276
|
cmd.action(async () => {
|
|
6157
6277
|
const opts = cmd.optsWithGlobals();
|
|
@@ -6310,7 +6430,16 @@ import { confirm as confirm11 } from "@inquirer/prompts";
|
|
|
6310
6430
|
function registerPayOrderCommand(parent, deps) {
|
|
6311
6431
|
const cmd = parent.command("pay-order").description("Settle a created order by --order-no (triggers ticketing)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--order-no <id>", "Our order reference from create-order").option("--payment-method-id <id>", "Optional bound-card id to charge (pay_per_call only)").option("--payment-token-id <id>", "Optional network-token id (unionpay/visa charge path)").option(
|
|
6312
6432
|
"--authorized-merchant-trans-id <id>",
|
|
6313
|
-
"Resume
|
|
6433
|
+
"Resume an EVO-card 3DS challenge: merchant trans id of an already-authorised preauth"
|
|
6434
|
+
).option(
|
|
6435
|
+
"--authenticate",
|
|
6436
|
+
"Opt-in to require cardholder 3DS on the network-token direct charge (--payment-token-id, EVO/Mastercard). When a step-up is needed the response is AUTHENTICATION_REQUIRED with three_ds_url + charge_no; resume with --authorized-charge-no. Default off = frictionless."
|
|
6437
|
+
).option(
|
|
6438
|
+
"--return-url <url>",
|
|
6439
|
+
"Optional 3DS/passkey return URL for the network-token authenticate path (falls back to the platform EVO_3DS_RETURN_URL)"
|
|
6440
|
+
).option(
|
|
6441
|
+
"--authorized-charge-no <no>",
|
|
6442
|
+
"Resume a network-token 3DS challenge: charge_no returned by a prior AUTHENTICATION_REQUIRED response (settled via ChargeService.resume_token)"
|
|
6314
6443
|
).option(
|
|
6315
6444
|
"--evo-explicit",
|
|
6316
6445
|
"[\u65B9\u6848 B/R16] Explicit opt-in to settle this pay_per_call order via the EVO bound-card fallback rail. Set ONLY when the user explicitly chose EVO; forwarded to the pay body as evo_explicit=true. Without it, a pay_per_call settlement lacking --payment-token-id is hard-gated server-side."
|
|
@@ -6340,6 +6469,11 @@ function registerPayOrderCommand(parent, deps) {
|
|
|
6340
6469
|
if (opts.authorizedMerchantTransId !== void 0) {
|
|
6341
6470
|
body.authorized_merchant_trans_id = opts.authorizedMerchantTransId;
|
|
6342
6471
|
}
|
|
6472
|
+
if (opts.authenticate) body.authenticate = true;
|
|
6473
|
+
if (opts.returnUrl !== void 0) body.return_url = opts.returnUrl;
|
|
6474
|
+
if (opts.authorizedChargeNo !== void 0) {
|
|
6475
|
+
body.authorized_charge_no = opts.authorizedChargeNo;
|
|
6476
|
+
}
|
|
6343
6477
|
if (opts.evoExplicit) body.evo_explicit = true;
|
|
6344
6478
|
const result = await deps.apiClient.post(
|
|
6345
6479
|
`/flight/${encodeURIComponent(orderNo)}/pay`,
|
|
@@ -6349,15 +6483,16 @@ function registerPayOrderCommand(parent, deps) {
|
|
|
6349
6483
|
);
|
|
6350
6484
|
spinner?.stop();
|
|
6351
6485
|
if (!result.success) throw CliError.fromApi(result, { auth: "api-key" });
|
|
6352
|
-
await render2(
|
|
6353
|
-
|
|
6354
|
-
opts.format,
|
|
6355
|
-
(d) => Formatter.keyValue([
|
|
6486
|
+
await render2(result.data, opts.format, (d) => {
|
|
6487
|
+
const rows = [
|
|
6356
6488
|
["Order no", String(d.order_no ?? "-")],
|
|
6357
6489
|
["Status", String(d.status ?? "-")],
|
|
6358
6490
|
["Amount", `${d.amount ?? "-"} ${d.currency ?? ""}`.trim()]
|
|
6359
|
-
]
|
|
6360
|
-
|
|
6491
|
+
];
|
|
6492
|
+
if (d.charge_no) rows.push(["Charge no", String(d.charge_no)]);
|
|
6493
|
+
if (d.three_ds_url) rows.push(["3DS URL", String(d.three_ds_url)]);
|
|
6494
|
+
return Formatter.keyValue(rows);
|
|
6495
|
+
});
|
|
6361
6496
|
});
|
|
6362
6497
|
}
|
|
6363
6498
|
|
|
@@ -6810,10 +6945,18 @@ verbs and pass data between them. For exact flags and field types, read the sche
|
|
|
6810
6945
|
## Workflow (book)
|
|
6811
6946
|
1. find-airport --keyword "<place>" \u2192 resolve to IATA city/airport codes
|
|
6812
6947
|
2. search --trip-type <1|2|3> --journeys '<json>'
|
|
6813
|
-
- journeys ALWAYS carries ALL legs
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6948
|
+
- journeys ALWAYS carries ALL legs, on every call including relay calls.
|
|
6949
|
+
- Round-trip/multi-city: keep searching until is_final_leg is true. Each round, present the
|
|
6950
|
+
candidates, let the USER pick one, and pass THAT candidate's next_journey_ids verbatim as
|
|
6951
|
+
--journey-id on the next search. Never assemble the list yourself (the top-level journey_ids
|
|
6952
|
+
is flattened across all candidates) and never send more ids than there are legs \u2014 it is
|
|
6953
|
+
rejected, because upstream would otherwise silently answer with the FIRST leg's candidates.
|
|
6954
|
+
- Only offers where price_key_ready is true carry a real product_token. Earlier-leg candidates
|
|
6955
|
+
are NOT bare flight rows: total_sale_price is already the WHOLE-TRIP total and
|
|
6956
|
+
paired_segment_ids names the legs upstream paired with it, so you can show the full
|
|
6957
|
+
itinerary and real total from the first round \u2014 they just are not bookable yet.
|
|
6958
|
+
- A relay search returning ZERO offers means the journey ids went stale OR that leg sold out
|
|
6959
|
+
(upstream reports both as an empty list). Restart from leg 1 for fresh ids.
|
|
6817
6960
|
- Code<->type consistency: tag each code with its matching type \u2014 an AIRPORT code (e.g. NRT)
|
|
6818
6961
|
uses type 2, a CITY code (e.g. TYO) uses type 1. Mislabeling (e.g. NRT with type 1, since NRT
|
|
6819
6962
|
is an airport whose city is TYO) is rejected with code 400 "destination not exist".
|
|
@@ -6849,7 +6992,7 @@ verbs and pass data between them. For exact flags and field types, read the sche
|
|
|
6849
6992
|
## Data passing
|
|
6850
6993
|
- product_token : search \u2192 verify \u2192 create-order (opaque; never fabricate or edit; verify's token wins)
|
|
6851
6994
|
- order_no : create-order \u2192 pay-order / get-order / cancel-order
|
|
6852
|
-
-
|
|
6995
|
+
- next_journey_ids : chosen offer \u2192 next search's --journey-id (relay for round-trip/multi-city)
|
|
6853
6996
|
- change_order_no / refund_order_no : *-apply \u2192 *-detail / *-confirm / pay-order (change)
|
|
6854
6997
|
|
|
6855
6998
|
## Invariants
|
|
@@ -7002,7 +7145,8 @@ Key notes:
|
|
|
7002
7145
|
Workflow (typical order):
|
|
7003
7146
|
1. find-airport Resolve a place name \u2192 IATA city/airport codes
|
|
7004
7147
|
2. search Search flights (one-way/round-trip/multi-city). journeys carries ALL legs;
|
|
7005
|
-
|
|
7148
|
+
round-trip/multi-city: relay the chosen offer's next_journey_ids into
|
|
7149
|
+
--journey-id until is_final_leg is true
|
|
7006
7150
|
3. verify Verify the fare \u2192 authoritative product_token + price_changed flag
|
|
7007
7151
|
4. create-order Create the order using verify's product_token (locks the fare, no charge)
|
|
7008
7152
|
5. pay-order Settle by --order-no (triggers ticketing); order \u2192 PAID
|