@agenzo/merchant-cli 0.5.1 → 0.6.0
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/README.md +10 -12
- package/dist/index.js +312 -121
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -41,6 +41,15 @@ var CODE_NUM = {
|
|
|
41
41
|
QUOTE_EXPIRED: 4202,
|
|
42
42
|
BOOKING_FAILED: 4203,
|
|
43
43
|
CANCELLATION_NOT_ALLOWED: 4204,
|
|
44
|
+
PRICE_MISMATCH: 4205,
|
|
45
|
+
VEHICLE_CLASS_MISMATCH: 4206,
|
|
46
|
+
PAYMENT_METHOD_REQUIRED: 4207,
|
|
47
|
+
QUOTE_CACHE_UNAVAILABLE: 4208,
|
|
48
|
+
ARREARS_OUTSTANDING: 4209,
|
|
49
|
+
CONTACT_REQUIRED: 4210,
|
|
50
|
+
INVALID_PHONE: 4211,
|
|
51
|
+
SEAT_LIMIT_EXCEEDED: 4213,
|
|
52
|
+
RIDE_NOT_FOUND: 4212,
|
|
44
53
|
NO_AVAILABILITY: 4301,
|
|
45
54
|
PRICE_CHANGED: 4302,
|
|
46
55
|
NAME_FORMAT_INVALID: 4303,
|
|
@@ -210,6 +219,15 @@ var STABLE_MESSAGE = {
|
|
|
210
219
|
VEHICLE_UNAVAILABLE: "No vehicle is available for the requested trip. Please try a different time or class.",
|
|
211
220
|
QUOTE_EXPIRED: "The quote has expired. Please request a new quote and retry.",
|
|
212
221
|
BOOKING_FAILED: "The booking could not be completed. Please retry.",
|
|
222
|
+
PRICE_MISMATCH: "The price does not match the quote. Re-quote and use the exact amount from the quote response.",
|
|
223
|
+
VEHICLE_CLASS_MISMATCH: "The vehicle class does not match the quote. Use the vehicle class from the quote response.",
|
|
224
|
+
PAYMENT_METHOD_REQUIRED: "Pay-per-call billing requires an active payment method. Please add a card first.",
|
|
225
|
+
QUOTE_CACHE_UNAVAILABLE: "Quote cache is temporarily unavailable. Please request a new quote and retry.",
|
|
226
|
+
ARREARS_OUTSTANDING: "You have outstanding arrears. Please settle your balance before booking a new ride.",
|
|
227
|
+
CONTACT_REQUIRED: "Passenger contact information is required. Please provide a passenger name and phone number.",
|
|
228
|
+
INVALID_PHONE: "The passenger phone number is not valid. Please provide a valid international number.",
|
|
229
|
+
SEAT_LIMIT_EXCEEDED: "The number of child/infant/toddler seats exceeds the vehicle capacity. Reduce seats or choose a larger vehicle.",
|
|
230
|
+
RIDE_NOT_FOUND: "The ride order was not found or does not belong to you.",
|
|
213
231
|
CANCELLATION_NOT_ALLOWED: "This order cannot be cancelled in its current state.",
|
|
214
232
|
NO_AVAILABILITY: "No rooms available for the selected hotel and dates.",
|
|
215
233
|
PRICE_CHANGED: "The price changed since the quote. Re-quote and confirm.",
|
|
@@ -896,7 +914,9 @@ var quoteSchema = {
|
|
|
896
914
|
"passenger-count": { type: "int", required: false, description: "Number of passengers" },
|
|
897
915
|
"luggage-count": { type: "int", required: false, description: "Number of luggage items" },
|
|
898
916
|
"passenger-email": { type: "string", required: false, description: "Passenger email address" },
|
|
899
|
-
"children-count": { type: "int", required: false, description: "Number of children" }
|
|
917
|
+
"children-count": { type: "int", required: false, description: "Number of children" },
|
|
918
|
+
"infant-count": { type: "int", required: false, description: "Number of infants (passenger breakdown; affects seat pricing)" },
|
|
919
|
+
"toddler-count": { type: "int", required: false, description: "Number of toddlers (passenger breakdown; affects seat pricing)" }
|
|
900
920
|
},
|
|
901
921
|
response: {
|
|
902
922
|
vehicle_classes: {
|
|
@@ -1241,7 +1261,7 @@ var hotelCreateOrderSchema = {
|
|
|
1241
1261
|
cli: CLI_NAME,
|
|
1242
1262
|
noun: HOTEL_NOUN,
|
|
1243
1263
|
verb: "create-order",
|
|
1244
|
-
description: "Create
|
|
1264
|
+
description: "Create a hotel order WITHOUT charging any account (re-check availability + createOrder upstream), using a product_token and price_items from a recent quote. The order enters AWAITING_PAYMENT \u2014 no money is moved until pay-order. check-in/check-out, guest counts, total-amount and price-items must match the quote",
|
|
1245
1265
|
flags: {
|
|
1246
1266
|
"product-token": { type: "string", required: true, description: "Chosen rate token from quote (quote.response.rates[].product_token). Pass verbatim" },
|
|
1247
1267
|
"total-amount": { type: "float", required: true, description: "Total price for the stay (quote.response.rates[].total_price.amount)", constraints: "DECIMAL units (NOT cents), 0.01\u2013999999999.99. Must equal the chosen rate total_price.amount" },
|
|
@@ -1260,69 +1280,74 @@ var hotelCreateOrderSchema = {
|
|
|
1260
1280
|
"contact-email": { type: "string", required: false, description: "Booking contact email" },
|
|
1261
1281
|
"arrive-time": { type: "string", required: false, description: "Expected arrival time", constraints: "HH:mm, hotel local time" },
|
|
1262
1282
|
"special-requests": { type: "string", required: false, description: "Free-text special requests (non-binding)" },
|
|
1263
|
-
"payment-method-id": { type: "string", required: false, description: "pay_per_call only: charge this SPECIFIC already-bound card instead of the platform auto-selected default/most-recent one. Ignored for monthly_settlement.", constraints: "Must be an ACTIVE card belonging to this developer, else PAYMENT_METHOD_REQUIRED" },
|
|
1264
1283
|
"idempotency-key": {
|
|
1265
1284
|
type: "string",
|
|
1266
1285
|
required: true,
|
|
1267
|
-
description: "Unique key forwarded verbatim as the Idempotency-Key header; never auto-generated. Derive from business intent (e.g. hash(user_id + product_token + check_in)) and reuse the SAME key when retrying the
|
|
1286
|
+
description: "Unique key forwarded verbatim as the Idempotency-Key header; never auto-generated. Derive from business intent (e.g. hash(user_id + product_token + check_in)) and reuse the SAME key when retrying the same order creation",
|
|
1268
1287
|
constraints: "1-128 chars [A-Za-z0-9_-]"
|
|
1269
1288
|
}
|
|
1270
1289
|
},
|
|
1271
1290
|
response: {
|
|
1272
|
-
order_id: { type: "string", description: "Our order reference (coOrderCode). Use as --order-id in get / cancel." },
|
|
1291
|
+
order_id: { type: "string", description: "Our order reference (coOrderCode). Use as --order-id in pay-order / get / cancel." },
|
|
1273
1292
|
fc_order_code: { type: "string", description: "Supplier order reference. Needed as --fc-order-code in cancel and checkout." },
|
|
1274
|
-
total_amount: { type: "float", description: "Amount
|
|
1275
|
-
currency: { type: "string", description: "ISO 4217 currency code
|
|
1293
|
+
total_amount: { type: "float", description: "Amount to be paid in pay-order (DECIMAL units). The order is locked in AWAITING_PAYMENT \u2014 no charge has been made." },
|
|
1294
|
+
currency: { type: "string", description: "ISO 4217 currency code for the payment." }
|
|
1276
1295
|
},
|
|
1277
1296
|
example: {
|
|
1278
1297
|
command: `agenzo-merchant-cli hotel-redaug create-order --product-token <tok> --total-amount 10.00 --currency CNY --price-items '[{"sale_date":"2026-08-20","sale_price":10.00,"breakfast_num":0}]' --check-in 2026-08-20 --check-out 2026-08-21 --adults 2 --guest-name "Zhang San" --contact-name "Zhang San" --contact-phone 13800138000 --idempotency-key create-h1n2`,
|
|
1279
|
-
output_summary: "Returns {order_id, fc_order_code, total_amount, currency}. The order is
|
|
1298
|
+
output_summary: "Returns {order_id, fc_order_code, total_amount, currency}. The order is AWAITING_PAYMENT (no charge). Use order_id as --order-id in pay-order to settle."
|
|
1280
1299
|
},
|
|
1281
1300
|
error_recovery: {
|
|
1282
1301
|
NO_AVAILABILITY: "Availability vanished between quote and create-order. Re-quote the same hotel; if still empty, quote another hotel or change dates. Use a NEW idempotency-key for the new product_token.",
|
|
1283
1302
|
PRICE_CHANGED: "The price/price_items no longer match upstream. Re-quote to get fresh total_price and price_items, confirm the new price with the user, then create-order with the new values and a NEW idempotency-key.",
|
|
1284
|
-
NAME_FORMAT_INVALID: "The supplier requires the guest name in a specific format (commonly Latin first/last name for international properties). Re-collect guest-name in Latin letters and retry with
|
|
1285
|
-
PAYMENT_METHOD_REQUIRED: "pay_per_call developer has no ACTIVE bound card at all, OR the explicitly-passed --payment-method-id is missing/not ACTIVE/does not belong to this developer. Direct the user to bind a card, drop --payment-method-id to auto-select, or pass a valid one.",
|
|
1286
|
-
ACCOUNT_INSUFFICIENT_BALANCE: "monthly_settlement developer settlement credit is insufficient (check via admin-cli accounts get). Direct the user to top up offline; do NOT retry until funded.",
|
|
1287
|
-
ACCOUNT_NOT_FOUND: "monthly_settlement developer has no settlement account. Direct the user to complete contract signing.",
|
|
1288
|
-
ACCOUNT_SUSPENDED: "The settlement account is suspended. Direct the user to contact support; do NOT retry.",
|
|
1303
|
+
NAME_FORMAT_INVALID: "The supplier requires the guest name in a specific format (commonly Latin first/last name for international properties). Re-collect guest-name in Latin letters and retry with the SAME idempotency-key.",
|
|
1289
1304
|
PARAM_IDEMPOTENCY_KEY_REQUIRED: "Add a unique --idempotency-key derived from business intent and retry.",
|
|
1290
1305
|
PARAM_IDEMPOTENCY_KEY_CONFLICT: "The same idempotency-key was used with different parameters. Retry with the original parameters, or generate a NEW key for the new parameters.",
|
|
1291
|
-
UPSTREAM_ERROR: "Transient upstream error during checkBooking or createOrder.
|
|
1306
|
+
UPSTREAM_ERROR: "Transient upstream error during checkBooking or createOrder. Retry once after ~2s backoff with the SAME idempotency-key."
|
|
1292
1307
|
}
|
|
1293
1308
|
};
|
|
1294
1309
|
var hotelPayOrderSchema = {
|
|
1295
1310
|
cli: CLI_NAME,
|
|
1296
1311
|
noun: HOTEL_NOUN,
|
|
1297
1312
|
verb: "pay-order",
|
|
1298
|
-
description:
|
|
1313
|
+
description: 'Settle an existing AWAITING_PAYMENT order created by create-order. Takes only --order-id; the billing path is decided server-side by the order billing_mode. monthly_settlement deducts from the developer credit account then confirms with the supplier; pay_per_call verifies the user EVO payment \u2014 the EVO merchantTransID IS the order_id (the user pays via EVO under the order_id), so the platform queries EVO for that order_id and requires an exact amount/currency match before confirming (the response settlement_path is then "pay_per_call"). On success the order becomes PAID. Supports --watch to poll on PAYMENT_NOT_COMPLETED until PAID',
|
|
1299
1314
|
flags: {
|
|
1300
|
-
"order-id": { type: "string", required: true, description: "Order to
|
|
1315
|
+
"order-id": { type: "string", required: true, description: "Order to settle (create-order.response.order_id). For pay_per_call this is also the EVO merchantTransID the user paid under." },
|
|
1301
1316
|
"idempotency-key": {
|
|
1302
1317
|
type: "string",
|
|
1303
1318
|
required: true,
|
|
1304
|
-
description: "Unique key forwarded verbatim as the Idempotency-Key header; never auto-generated. Derive from business intent and reuse the SAME key when retrying the same
|
|
1319
|
+
description: "Unique key forwarded verbatim as the Idempotency-Key header; never auto-generated. Derive from business intent (e.g. hash(order_id + attempt)) and reuse the SAME key when retrying the same payment",
|
|
1305
1320
|
constraints: "1-128 chars [A-Za-z0-9_-]"
|
|
1306
1321
|
},
|
|
1307
|
-
watch: { type: "bool", required: false, default: false, description: "
|
|
1322
|
+
watch: { type: "bool", required: false, default: false, description: "Poll automatically on PAYMENT_NOT_COMPLETED until PAID or timeout. Each iteration emits one NDJSON line" },
|
|
1308
1323
|
"watch-interval": { type: "int", required: false, default: 5, description: "Seconds between poll attempts in --watch mode" },
|
|
1309
1324
|
"watch-timeout": { type: "int", required: false, default: 300, description: "Total seconds before giving up in --watch mode" }
|
|
1310
1325
|
},
|
|
1311
1326
|
response: {
|
|
1312
1327
|
order_id: { type: "string", description: "Order reference." },
|
|
1313
|
-
settlement_path: { type: "string", description: "
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1328
|
+
settlement_path: { type: "string", description: "Which billing path was used: 'monthly_settlement' or 'pay_per_call' (same tokens as billing_mode)." },
|
|
1329
|
+
amount: { type: "float", description: "Settled amount in DECIMAL units." },
|
|
1330
|
+
currency: { type: "string", description: "ISO 4217 currency code of the settlement." },
|
|
1331
|
+
pay_status: { type: "int", description: "Upstream pay status (1 = paid). The order internal status is now PAID." },
|
|
1332
|
+
settled_at: { type: "string", description: "ISO 8601 settlement timestamp. On idempotent replay, the original first settled_at is returned unchanged." }
|
|
1317
1333
|
},
|
|
1318
1334
|
example: {
|
|
1319
1335
|
command: "agenzo-merchant-cli hotel-redaug pay-order --order-id hho_01KWC63Z5CD6CKBM33Q7SC2ZDT --idempotency-key pay-h1n2",
|
|
1320
|
-
output_summary: '
|
|
1336
|
+
output_summary: 'Settlement path is chosen server-side by billing_mode. monthly_settlement: deducts from the credit account, confirms with the supplier. Returns {order_id, settlement_path:"monthly_settlement", amount, currency, pay_status:1, settled_at}. Order becomes PAID. For pay_per_call the user must have already paid via EVO using the order_id as the merchantTransID; the same command settles it (settlement_path:"pay_per_call").'
|
|
1321
1337
|
},
|
|
1322
1338
|
error_recovery: {
|
|
1323
|
-
|
|
1339
|
+
PAYMENT_NOT_COMPLETED: "pay_per_call only: EVO has not yet confirmed the payment for this order_id. Retry with the SAME idempotency-key after a delay, or use --watch to poll automatically until PAID.",
|
|
1340
|
+
PAYMENT_NOT_FOUND: "No EVO transaction found for this order_id. Confirm the user paid via EVO using the order_id as the merchantTransID; do NOT retry blindly.",
|
|
1341
|
+
PAYMENT_AMOUNT_MISMATCH: "The EVO-confirmed amount/currency does not match the order. The user must pay the exact order amount in the exact currency under the order_id. Do NOT retry until corrected.",
|
|
1342
|
+
PAYMENT_QUERY_FAILED: "EVO gateway query failed (transport/timeout). Retry once after ~5s with the SAME idempotency-key.",
|
|
1343
|
+
BILLING_MODE_MISMATCH: "The order billing_mode is not a recognized settlement mode (only monthly_settlement and pay_per_call are valid). Check the developer billing_mode; do NOT retry blindly.",
|
|
1344
|
+
INVALID_ORDER_STATE: "The order is not in AWAITING_PAYMENT (it may already be PAID or CANCELLED). Check status via get; do NOT retry pay-order.",
|
|
1324
1345
|
ORDER_NOT_FOUND: "No order for this --order-id. Verify it is the order_id returned by create-order. Do NOT retry.",
|
|
1325
|
-
|
|
1346
|
+
ACCOUNT_INSUFFICIENT_BALANCE: "Settlement credit is insufficient (check via admin-cli accounts get). Direct the user to top up offline.",
|
|
1347
|
+
ACCOUNT_NOT_FOUND: "Developer has no settlement account. Direct the user to complete contract signing.",
|
|
1348
|
+
ACCOUNT_SUSPENDED: "The settlement account is suspended. Direct the user to contact support; do NOT retry.",
|
|
1349
|
+
PAYORDER_FAILED: "Upstream payOrder failed after a successful deduction; the deduction was reversed and the order stays AWAITING_PAYMENT. Retry with the SAME idempotency-key after a delay.",
|
|
1350
|
+
PAYORDER_FAILED_AFTER_PAYMENT: "EVO payment confirmed but upstream payOrder failed. The order is recoverable (the EVO payment under the order_id is preserved). Contact support for reconciliation; do NOT retry automatically.",
|
|
1326
1351
|
PARAM_IDEMPOTENCY_KEY_REQUIRED: "Add a unique --idempotency-key and retry.",
|
|
1327
1352
|
PARAM_IDEMPOTENCY_KEY_CONFLICT: "Same idempotency-key used with different parameters. Use the original parameters, or generate a NEW key."
|
|
1328
1353
|
}
|
|
@@ -1736,6 +1761,69 @@ var hotelDetailSchema = {
|
|
|
1736
1761
|
PARAM_INVALID: "Ensure --hotel-id is a non-empty string, then retry."
|
|
1737
1762
|
}
|
|
1738
1763
|
};
|
|
1764
|
+
var ORDERS_NOUN = "orders";
|
|
1765
|
+
var unifiedOrdersListSchema = {
|
|
1766
|
+
cli: CLI_NAME,
|
|
1767
|
+
noun: ORDERS_NOUN,
|
|
1768
|
+
verb: "list",
|
|
1769
|
+
description: 'List orders across ALL providers (ride + hotel) in one call. Use this for generic "my orders" / "order history" requests. Prefer ride-elife/hotel-redaug list-orders when the user names a specific business.',
|
|
1770
|
+
flags: {
|
|
1771
|
+
"order-type": { type: "string", required: false, description: "Filter by provider: ride | hotel" },
|
|
1772
|
+
status: { type: "string", required: false, description: "Filter by NORMALIZED status (NOT the domain-specific status): PENDING | CONFIRMED | COMPLETED | CANCELLED | FAILED" },
|
|
1773
|
+
page: { type: "int", required: false, default: 1, description: "Page number", constraints: ">= 1" },
|
|
1774
|
+
"page-size": { type: "int", required: false, default: 20, description: "Items per page", constraints: ">= 1" }
|
|
1775
|
+
},
|
|
1776
|
+
response: {
|
|
1777
|
+
orders: {
|
|
1778
|
+
type: "array",
|
|
1779
|
+
description: "Slim cross-provider order-index items. For business-specific fields (vehicle_class, hotel_name, etc.), call `orders get --order-id <id>` or the domain-specific `get`.",
|
|
1780
|
+
items: {
|
|
1781
|
+
order_id: { type: "string", description: "Order id (rio_... for ride, hho_... for hotel). Pass to `orders get`." },
|
|
1782
|
+
order_type: { type: "string", description: "'ride' or 'hotel'" },
|
|
1783
|
+
status: { type: "string", description: "Normalized status: PENDING | CONFIRMED | COMPLETED | CANCELLED | FAILED" },
|
|
1784
|
+
amount: { type: "float|null", description: "Order amount in DECIMAL currency units (NOT cents)" },
|
|
1785
|
+
currency: { type: "string|null", description: "ISO 4217 currency code" },
|
|
1786
|
+
created_at: { type: "string|null", description: "ISO 8601 datetime" },
|
|
1787
|
+
updated_at: { type: "string|null", description: "ISO 8601 datetime" }
|
|
1788
|
+
}
|
|
1789
|
+
},
|
|
1790
|
+
total: { type: "int", description: "Total matching orders across all providers" },
|
|
1791
|
+
page: { type: "int", description: "Current page" },
|
|
1792
|
+
page_size: { type: "int", description: "Items per page" }
|
|
1793
|
+
},
|
|
1794
|
+
example: {
|
|
1795
|
+
command: "agenzo-merchant-cli orders list --page 1 --page-size 10",
|
|
1796
|
+
output_summary: "Returns a paginated, cross-provider list of orders (both ride and hotel). If the user then asks about one order, use its order_id with `orders get`."
|
|
1797
|
+
},
|
|
1798
|
+
error_recovery: {
|
|
1799
|
+
INVALID_REQUEST: "The --status value is not one of PENDING/CONFIRMED/COMPLETED/CANCELLED/FAILED. Fix and retry.",
|
|
1800
|
+
INTERNAL_ERROR: "Transient backend error. Retry once after a short delay.",
|
|
1801
|
+
PARAM_INVALID: "Ensure --page / --page-size are positive integers, then retry."
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
var unifiedOrdersGetSchema = {
|
|
1805
|
+
cli: CLI_NAME,
|
|
1806
|
+
noun: ORDERS_NOUN,
|
|
1807
|
+
verb: "get",
|
|
1808
|
+
description: "Get a single order detail by id, regardless of which provider (ride/hotel) it belongs to. The platform resolves order_id -> provider internally and returns that provider's own detail shape.",
|
|
1809
|
+
flags: {
|
|
1810
|
+
"order-id": { type: "string", required: true, description: "Order id from `orders list` (rio_... for ride, hho_... for hotel)" }
|
|
1811
|
+
},
|
|
1812
|
+
response: {
|
|
1813
|
+
"(varies by order_type)": {
|
|
1814
|
+
type: "object",
|
|
1815
|
+
description: "The response shape is delegated to the owning provider and therefore varies: a ride order returns the same shape as `ride-elife get`; a hotel order returns the same shape as `hotel-redaug get`. Treat the result as an opaque object and surface whatever fields it contains \u2014 do NOT assume a fixed schema."
|
|
1816
|
+
}
|
|
1817
|
+
},
|
|
1818
|
+
example: {
|
|
1819
|
+
command: "agenzo-merchant-cli orders get --order-id hho_01K...",
|
|
1820
|
+
output_summary: "Returns the order's detail, delegated to its owning provider (ride or hotel)."
|
|
1821
|
+
},
|
|
1822
|
+
error_recovery: {
|
|
1823
|
+
ORDER_NOT_FOUND: "The order_id does not exist or does not belong to this developer/org. Verify the id from `orders list`. Do NOT retry blindly.",
|
|
1824
|
+
INTERNAL_ERROR: "The order's provider detail lookup is temporarily unavailable. Retry once after a short delay."
|
|
1825
|
+
}
|
|
1826
|
+
};
|
|
1739
1827
|
|
|
1740
1828
|
// src/ride-elife/quote.ts
|
|
1741
1829
|
function need(value, flag) {
|
|
@@ -2285,7 +2373,9 @@ var SERVICE_REGISTRY = [
|
|
|
2285
2373
|
},
|
|
2286
2374
|
workflow: ["quote", "book", "get (poll for status)", "cancel (optional)"],
|
|
2287
2375
|
since: "2026-06-01",
|
|
2288
|
-
discovery: {
|
|
2376
|
+
discovery: {
|
|
2377
|
+
help_command: "agenzo-merchant-cli ride-elife --help"
|
|
2378
|
+
}
|
|
2289
2379
|
},
|
|
2290
2380
|
{
|
|
2291
2381
|
service_id: "svc_01J0HT5REDAUG0001",
|
|
@@ -2337,7 +2427,9 @@ var SERVICE_REGISTRY = [
|
|
|
2337
2427
|
"cancel / checkout (optional)"
|
|
2338
2428
|
],
|
|
2339
2429
|
since: "2026-06-25",
|
|
2340
|
-
discovery: {
|
|
2430
|
+
discovery: {
|
|
2431
|
+
help_command: "agenzo-merchant-cli hotel-redaug --help"
|
|
2432
|
+
}
|
|
2341
2433
|
}
|
|
2342
2434
|
];
|
|
2343
2435
|
function findService(serviceId) {
|
|
@@ -2433,78 +2525,30 @@ function registerServicesListCommand(parent, deps) {
|
|
|
2433
2525
|
}
|
|
2434
2526
|
|
|
2435
2527
|
// src/services/get.ts
|
|
2436
|
-
function buildVerbsSummary(data) {
|
|
2437
|
-
const verbs = Array.isArray(data.verbs) ? data.verbs : [];
|
|
2438
|
-
const verbDescriptions = data.verb_descriptions ?? {};
|
|
2439
|
-
const schema = data.schema_content;
|
|
2440
|
-
const schemaVerbs = schema?.verbs;
|
|
2441
|
-
return verbs.map((verb) => {
|
|
2442
|
-
const item = {
|
|
2443
|
-
verb,
|
|
2444
|
-
description: verbDescriptions[verb] ?? String(schemaVerbs?.[verb]?.description ?? "")
|
|
2445
|
-
};
|
|
2446
|
-
const annotations = schemaVerbs?.[verb]?.annotations;
|
|
2447
|
-
if (annotations) item.annotations = annotations;
|
|
2448
|
-
return item;
|
|
2449
|
-
});
|
|
2450
|
-
}
|
|
2451
|
-
function toServiceLayerView(data) {
|
|
2452
|
-
const schema = data.schema_content;
|
|
2453
|
-
const view = {
|
|
2454
|
-
service_id: data.service_id,
|
|
2455
|
-
cli_noun: data.cli_noun,
|
|
2456
|
-
category: data.category,
|
|
2457
|
-
name: data.name,
|
|
2458
|
-
summary: data.description ?? schema?.summary,
|
|
2459
|
-
status: data.status ?? "available",
|
|
2460
|
-
provider: data.provider,
|
|
2461
|
-
version: data.version
|
|
2462
|
-
};
|
|
2463
|
-
if (schema?.selection_hints) view.selection_hints = schema.selection_hints;
|
|
2464
|
-
const discovery = data.discovery;
|
|
2465
|
-
view.schema_ref = schema?.schema_ref ?? {
|
|
2466
|
-
help_command: discovery?.help_command,
|
|
2467
|
-
...discovery?.schema_url ? { schema_url: discovery.schema_url } : {}
|
|
2468
|
-
};
|
|
2469
|
-
if (schema?.conventions) view.conventions = schema.conventions;
|
|
2470
|
-
if (schema?.workflow) {
|
|
2471
|
-
view.workflow = schema.workflow;
|
|
2472
|
-
} else if (Array.isArray(data.workflow)) {
|
|
2473
|
-
view.workflow = { description: data.workflow.join(" \u2192 ") };
|
|
2474
|
-
}
|
|
2475
|
-
view.verbs_summary = buildVerbsSummary(data);
|
|
2476
|
-
if (schema?.cross_service_recovery) view.cross_service_recovery = schema.cross_service_recovery;
|
|
2477
|
-
return view;
|
|
2478
|
-
}
|
|
2479
2528
|
function formatServiceGet(s) {
|
|
2480
2529
|
const lines = [
|
|
2481
2530
|
["Service ID", String(s.service_id ?? "")],
|
|
2482
|
-
["CLI Noun", String(s.cli_noun ?? "")],
|
|
2483
|
-
["Category", String(s.category ?? "")],
|
|
2484
2531
|
["Name", String(s.name ?? "")],
|
|
2485
|
-
["
|
|
2486
|
-
["
|
|
2532
|
+
["Description", String(s.description ?? s.summary ?? "")],
|
|
2533
|
+
["Category", String(s.category ?? "")],
|
|
2534
|
+
["Version", String(s.version ?? "")],
|
|
2487
2535
|
["Provider", String(s.provider ?? "")],
|
|
2488
|
-
["
|
|
2536
|
+
["CLI Noun", String(s.cli_noun ?? "")],
|
|
2537
|
+
["Verbs", Array.isArray(s.verbs) ? s.verbs.join(", ") : ""]
|
|
2489
2538
|
];
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
for (const key of [
|
|
2493
|
-
"selection_hints",
|
|
2494
|
-
"schema_ref",
|
|
2495
|
-
"conventions",
|
|
2496
|
-
"workflow",
|
|
2497
|
-
"verbs_summary",
|
|
2498
|
-
"cross_service_recovery"
|
|
2499
|
-
]) {
|
|
2500
|
-
if (s[key] !== void 0) {
|
|
2501
|
-
sections.push(`${key}:
|
|
2502
|
-
${JSON.stringify(s[key], null, 2)}`);
|
|
2503
|
-
}
|
|
2539
|
+
if (Array.isArray(s.workflow) && s.workflow.length > 0) {
|
|
2540
|
+
lines.push(["Workflow", s.workflow.join(" \u2192 ")]);
|
|
2504
2541
|
}
|
|
2505
|
-
|
|
2542
|
+
const block = Formatter.keyValue(lines);
|
|
2543
|
+
const verbDescriptions = s.verb_descriptions;
|
|
2544
|
+
if (verbDescriptions && Object.keys(verbDescriptions).length > 0) {
|
|
2545
|
+
const detail = Object.entries(verbDescriptions).map(([verb, desc]) => ` ${verb}: ${desc}`).join("\n");
|
|
2546
|
+
return `${block}
|
|
2506
2547
|
|
|
2507
|
-
|
|
2548
|
+
Verb descriptions:
|
|
2549
|
+
${detail}`;
|
|
2550
|
+
}
|
|
2551
|
+
return block;
|
|
2508
2552
|
}
|
|
2509
2553
|
function gateCapability(data, localCaps) {
|
|
2510
2554
|
const noun = String(data.cli_noun ?? "");
|
|
@@ -2525,7 +2569,7 @@ function gateCapability(data, localCaps) {
|
|
|
2525
2569
|
return out;
|
|
2526
2570
|
}
|
|
2527
2571
|
function registerServiceGetCommand(parent, deps) {
|
|
2528
|
-
const cmd = parent.command("get <service-id>").description("Retrieve a single merchant service
|
|
2572
|
+
const cmd = parent.command("get <service-id>").description("Retrieve a single merchant service by id (includes full schema)").option("--api-key <key>", "API Key for authentication (X-Api-Key)");
|
|
2529
2573
|
cmd.action(async (serviceId) => {
|
|
2530
2574
|
const opts = cmd.optsWithGlobals();
|
|
2531
2575
|
const format = resolveFormat(opts.format);
|
|
@@ -2554,7 +2598,7 @@ function registerServiceGetCommand(parent, deps) {
|
|
|
2554
2598
|
`Service '${serviceId}' is not available in this CLI. Run "services list" to see available services.`
|
|
2555
2599
|
);
|
|
2556
2600
|
}
|
|
2557
|
-
const resolved =
|
|
2601
|
+
const resolved = data;
|
|
2558
2602
|
const configManager = new ConfigManager();
|
|
2559
2603
|
const commandResult = {
|
|
2560
2604
|
data: resolved,
|
|
@@ -2564,6 +2608,105 @@ function registerServiceGetCommand(parent, deps) {
|
|
|
2564
2608
|
});
|
|
2565
2609
|
}
|
|
2566
2610
|
|
|
2611
|
+
// src/orders/list.ts
|
|
2612
|
+
var DEFAULT_PAGE2 = "1";
|
|
2613
|
+
var DEFAULT_PAGE_SIZE2 = "20";
|
|
2614
|
+
function positiveInt2(value, flag) {
|
|
2615
|
+
const n = Number(value);
|
|
2616
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
|
|
2617
|
+
throw new CliError("PARAM_INVALID", `--${flag} must be a positive integer.`);
|
|
2618
|
+
}
|
|
2619
|
+
return String(n);
|
|
2620
|
+
}
|
|
2621
|
+
function formatOrders2(data) {
|
|
2622
|
+
const orders = data.orders ?? [];
|
|
2623
|
+
if (orders.length === 0) {
|
|
2624
|
+
return Formatter.status("info", "No orders found");
|
|
2625
|
+
}
|
|
2626
|
+
const headers = ["Order ID", "Type", "Status", "Amount", "Currency"];
|
|
2627
|
+
const rows = orders.map((o) => [
|
|
2628
|
+
String(o.order_id ?? "-"),
|
|
2629
|
+
String(o.order_type ?? "-"),
|
|
2630
|
+
String(o.status ?? "-"),
|
|
2631
|
+
String(o.amount ?? "-"),
|
|
2632
|
+
String(o.currency ?? "-")
|
|
2633
|
+
]);
|
|
2634
|
+
const summary = [
|
|
2635
|
+
["Total", String(data.total ?? "-")],
|
|
2636
|
+
["Page", String(data.page ?? "-")],
|
|
2637
|
+
["Page size", String(data.page_size ?? "-")]
|
|
2638
|
+
];
|
|
2639
|
+
return `${Formatter.table(headers, rows)}
|
|
2640
|
+
${Formatter.keyValue(summary)}`;
|
|
2641
|
+
}
|
|
2642
|
+
function registerOrdersListCommand(parent, deps) {
|
|
2643
|
+
const cmd = parent.command("list").description("List orders across ALL providers (ride + hotel), with optional type/status filters").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--order-type <type>", "Filter by order type: ride | hotel").option("--status <status>", "Filter by normalized status: PENDING | CONFIRMED | COMPLETED | CANCELLED | FAILED").option("--page <page>", "Page number", DEFAULT_PAGE2).option("--page-size <size>", "Page size", DEFAULT_PAGE_SIZE2);
|
|
2644
|
+
attachSchemaHelp(cmd, unifiedOrdersListSchema);
|
|
2645
|
+
cmd.action(async () => {
|
|
2646
|
+
const opts = cmd.optsWithGlobals();
|
|
2647
|
+
const format = resolveFormat(opts.format);
|
|
2648
|
+
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
2649
|
+
message: "API Key:",
|
|
2650
|
+
type: "password"
|
|
2651
|
+
});
|
|
2652
|
+
const params = {
|
|
2653
|
+
page: positiveInt2(opts.page ?? DEFAULT_PAGE2, "page"),
|
|
2654
|
+
page_size: positiveInt2(opts.pageSize ?? DEFAULT_PAGE_SIZE2, "page-size")
|
|
2655
|
+
};
|
|
2656
|
+
if (opts.orderType !== void 0) params.order_type = opts.orderType;
|
|
2657
|
+
if (opts.status !== void 0) params.status = opts.status;
|
|
2658
|
+
const spinner = format === "json" ? null : createSpinner("Fetching orders...");
|
|
2659
|
+
const result = await deps.apiClient.get(
|
|
2660
|
+
"/orders",
|
|
2661
|
+
{ type: "api-key", key: apiKey },
|
|
2662
|
+
params
|
|
2663
|
+
);
|
|
2664
|
+
spinner?.stop();
|
|
2665
|
+
if (!result.success) {
|
|
2666
|
+
throw CliError.fromApi(result, { auth: "api-key" });
|
|
2667
|
+
}
|
|
2668
|
+
const data = result.data;
|
|
2669
|
+
const configManager = new ConfigManager();
|
|
2670
|
+
const commandResult = {
|
|
2671
|
+
data,
|
|
2672
|
+
text: () => formatOrders2(data)
|
|
2673
|
+
};
|
|
2674
|
+
await renderWithContext(commandResult, { format }, configManager);
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
// src/orders/get.ts
|
|
2679
|
+
function registerOrdersGetCommand(parent, deps) {
|
|
2680
|
+
const cmd = parent.command("get").description("Get a single order detail by id, regardless of provider (ride/hotel)").option("--api-key <key>", "API Key for authentication (X-Api-Key)").requiredOption("--order-id <id>", "Order id (e.g. rio_... or hho_...)");
|
|
2681
|
+
attachSchemaHelp(cmd, unifiedOrdersGetSchema);
|
|
2682
|
+
cmd.action(async () => {
|
|
2683
|
+
const opts = cmd.optsWithGlobals();
|
|
2684
|
+
const format = resolveFormat(opts.format);
|
|
2685
|
+
const apiKey = await PromptEngine.resolveInput(opts.apiKey, {
|
|
2686
|
+
message: "API Key:",
|
|
2687
|
+
type: "password"
|
|
2688
|
+
});
|
|
2689
|
+
const spinner = format === "json" ? null : createSpinner("Fetching order...");
|
|
2690
|
+
const result = await deps.apiClient.get(
|
|
2691
|
+
`/orders/${encodeURIComponent(opts.orderId)}`,
|
|
2692
|
+
{ type: "api-key", key: apiKey }
|
|
2693
|
+
);
|
|
2694
|
+
spinner?.stop();
|
|
2695
|
+
if (!result.success) {
|
|
2696
|
+
throw CliError.fromApi(result, { auth: "api-key" });
|
|
2697
|
+
}
|
|
2698
|
+
const data = result.data;
|
|
2699
|
+
const configManager = new ConfigManager();
|
|
2700
|
+
const commandResult = {
|
|
2701
|
+
data,
|
|
2702
|
+
text: () => Formatter.keyValue(
|
|
2703
|
+
Object.entries(data).map(([k, v]) => [k, typeof v === "object" ? JSON.stringify(v) : String(v)])
|
|
2704
|
+
)
|
|
2705
|
+
};
|
|
2706
|
+
await renderWithContext(commandResult, { format }, configManager);
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2567
2710
|
// src/hotel-redaug/search.ts
|
|
2568
2711
|
function need5(value, flag) {
|
|
2569
2712
|
if (value === void 0) {
|
|
@@ -2585,7 +2728,7 @@ function coord(value, flag, min, max) {
|
|
|
2585
2728
|
}
|
|
2586
2729
|
return n;
|
|
2587
2730
|
}
|
|
2588
|
-
function
|
|
2731
|
+
function positiveInt3(value, flag) {
|
|
2589
2732
|
const n = num3(value, flag);
|
|
2590
2733
|
if (!Number.isInteger(n) || n <= 0) {
|
|
2591
2734
|
throw new CliError("PARAM_INVALID", `--${flag} must be a positive integer.`);
|
|
@@ -2662,8 +2805,8 @@ function registerHotelSearchCommand(parent, deps) {
|
|
|
2662
2805
|
if (!(checkOut > checkIn)) {
|
|
2663
2806
|
throw new CliError("PARAM_INVALID", "--check-out must be strictly after --check-in.");
|
|
2664
2807
|
}
|
|
2665
|
-
const page =
|
|
2666
|
-
const pageSize =
|
|
2808
|
+
const page = positiveInt3(opts.page, "page");
|
|
2809
|
+
const pageSize = positiveInt3(opts.pageSize, "page-size");
|
|
2667
2810
|
const body = {};
|
|
2668
2811
|
if (hasDestination) {
|
|
2669
2812
|
body.destination_id = need5(opts.destinationId, "destination-id");
|
|
@@ -2861,15 +3004,19 @@ function formatCreateOrder(data) {
|
|
|
2861
3004
|
const rows = rooms.map((r) => [String(r.room_index ?? "-"), String(r.guest_name ?? "-")]);
|
|
2862
3005
|
out.push("", Formatter.table(headers, rows));
|
|
2863
3006
|
}
|
|
3007
|
+
out.push(
|
|
3008
|
+
"",
|
|
3009
|
+
Formatter.status(
|
|
3010
|
+
"info",
|
|
3011
|
+
`Order created with status AWAITING_PAYMENT \u2014 proceed with 'hotel-redaug pay-order --order-id ${data.order_id ?? "<order_id>"}' to settle.`
|
|
3012
|
+
)
|
|
3013
|
+
);
|
|
2864
3014
|
return out.join("\n");
|
|
2865
3015
|
}
|
|
2866
3016
|
function registerHotelCreateOrderCommand(parent, deps) {
|
|
2867
|
-
const cmd = parent.command("create-order").description("Create
|
|
2868
|
-
"--payment-method-id <id>",
|
|
2869
|
-
"pay_per_call only: charge this SPECIFIC already-bound card instead of the platform auto-selected one"
|
|
2870
|
-
).option(
|
|
3017
|
+
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("--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("--hotel-name <name>", "Hotel name (display-only, stored for order summary)").option(
|
|
2871
3018
|
"--idempotency-key <key>",
|
|
2872
|
-
"Idempotency key forwarded verbatim as the Idempotency-Key header
|
|
3019
|
+
"Idempotency key forwarded verbatim as the Idempotency-Key header"
|
|
2873
3020
|
);
|
|
2874
3021
|
attachSchemaHelp(cmd, hotelCreateOrderSchema);
|
|
2875
3022
|
cmd.action(async () => {
|
|
@@ -2911,10 +3058,10 @@ function registerHotelCreateOrderCommand(parent, deps) {
|
|
|
2911
3058
|
if (opts.contactEmail !== void 0) body.contact_email = opts.contactEmail;
|
|
2912
3059
|
if (opts.arriveTime !== void 0) body.arrive_time = opts.arriveTime;
|
|
2913
3060
|
if (opts.specialRequests !== void 0) body.special_requests = opts.specialRequests;
|
|
2914
|
-
if (opts.
|
|
3061
|
+
if (opts.hotelName !== void 0) body.hotel_name = opts.hotelName;
|
|
2915
3062
|
if (!isYes) {
|
|
2916
3063
|
const confirmed = await confirm3({
|
|
2917
|
-
message: `Create
|
|
3064
|
+
message: `Create this hotel order for ${totalAmount} ${currency} (check-in ${checkIn}, check-out ${checkOut})? This locks the rate but does NOT charge anything yet.`,
|
|
2918
3065
|
default: false
|
|
2919
3066
|
});
|
|
2920
3067
|
if (!confirmed) {
|
|
@@ -3073,20 +3220,23 @@ var DEFAULT_PAY_WATCH_TIMEOUT_SECONDS = 300;
|
|
|
3073
3220
|
function formatPayOrder(data) {
|
|
3074
3221
|
const lines = [
|
|
3075
3222
|
["Order ID", String(data.order_id ?? "-")],
|
|
3076
|
-
["Order status", String(data.
|
|
3223
|
+
["Order status", String(data.order_status ?? "-")]
|
|
3077
3224
|
];
|
|
3078
3225
|
if (data.settlement_path) lines.push(["Settlement path", String(data.settlement_path)]);
|
|
3079
|
-
if (data.
|
|
3080
|
-
|
|
3226
|
+
if (data.pay_status) lines.push(["Pay status", String(data.pay_status)]);
|
|
3227
|
+
if (data.total_amount != null && data.currency) {
|
|
3228
|
+
lines.push(["Amount", `${data.total_amount} ${data.currency}`]);
|
|
3081
3229
|
}
|
|
3230
|
+
if (data.billing_entry_id) lines.push(["Billing entry", String(data.billing_entry_id)]);
|
|
3231
|
+
if (data.merchant_trans_id) lines.push(["Merchant trans ID", String(data.merchant_trans_id)]);
|
|
3082
3232
|
return Formatter.keyValue(lines);
|
|
3083
3233
|
}
|
|
3084
3234
|
function isPaymentTerminal(record) {
|
|
3085
|
-
const status = record.
|
|
3235
|
+
const status = record.order_status;
|
|
3086
3236
|
return status === "PAID";
|
|
3087
3237
|
}
|
|
3088
3238
|
function registerHotelPayOrderCommand(parent, deps) {
|
|
3089
|
-
const cmd = parent.command("pay-order").description("
|
|
3239
|
+
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(
|
|
3090
3240
|
"--idempotency-key <key>",
|
|
3091
3241
|
"Idempotency key forwarded verbatim as the Idempotency-Key header"
|
|
3092
3242
|
).option("--watch", "Poll until PAID or timeout (NDJSON output)", false).option(
|
|
@@ -3121,11 +3271,11 @@ function registerHotelPayOrderCommand(parent, deps) {
|
|
|
3121
3271
|
const body = {};
|
|
3122
3272
|
if (!isYes) {
|
|
3123
3273
|
const confirmed = await confirm4({
|
|
3124
|
-
message: `
|
|
3125
|
-
default:
|
|
3274
|
+
message: `Settle hotel order ${orderId}? This moves money via the order's configured billing mode (monthly_settlement or pay_per_call).`,
|
|
3275
|
+
default: false
|
|
3126
3276
|
});
|
|
3127
3277
|
if (!confirmed) {
|
|
3128
|
-
throw new CliError("CLIENT_ABORTED", "
|
|
3278
|
+
throw new CliError("CLIENT_ABORTED", "Payment aborted by user.");
|
|
3129
3279
|
}
|
|
3130
3280
|
}
|
|
3131
3281
|
const path = `/hotel/${encodeURIComponent(orderId)}/pay`;
|
|
@@ -3168,7 +3318,19 @@ function registerHotelPayOrderCommand(parent, deps) {
|
|
|
3168
3318
|
return;
|
|
3169
3319
|
}
|
|
3170
3320
|
} else {
|
|
3171
|
-
|
|
3321
|
+
const errorCode = result.code ?? result.errorCode;
|
|
3322
|
+
const errorCodeStr = String(errorCode);
|
|
3323
|
+
if (errorCodeStr === "PAYMENT_NOT_COMPLETED" || errorCodeStr === "1933") {
|
|
3324
|
+
const errorLine = {
|
|
3325
|
+
watch_status: "pending",
|
|
3326
|
+
error_code: errorCodeStr === "1933" ? "PAYMENT_NOT_COMPLETED" : errorCodeStr,
|
|
3327
|
+
message: result.errorMessage ?? "Payment not yet completed"
|
|
3328
|
+
};
|
|
3329
|
+
lastRecord = errorLine;
|
|
3330
|
+
ndjsonWriteLine(errorLine);
|
|
3331
|
+
} else {
|
|
3332
|
+
throw CliError.fromApi(result, { auth: "api-key" });
|
|
3333
|
+
}
|
|
3172
3334
|
}
|
|
3173
3335
|
if (Date.now() + watchInterval * 1e3 >= deadline) {
|
|
3174
3336
|
const timeoutLine = {
|
|
@@ -3567,16 +3729,16 @@ function registerHotelGetCheckoutCommand(parent, deps) {
|
|
|
3567
3729
|
}
|
|
3568
3730
|
|
|
3569
3731
|
// src/hotel-redaug/list-orders.ts
|
|
3570
|
-
var
|
|
3571
|
-
var
|
|
3572
|
-
function
|
|
3732
|
+
var DEFAULT_PAGE3 = "1";
|
|
3733
|
+
var DEFAULT_PAGE_SIZE3 = "20";
|
|
3734
|
+
function positiveInt4(value, flag) {
|
|
3573
3735
|
const n = Number(value);
|
|
3574
3736
|
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
|
|
3575
3737
|
throw new CliError("PARAM_INVALID", `--${flag} must be a positive integer.`);
|
|
3576
3738
|
}
|
|
3577
3739
|
return String(n);
|
|
3578
3740
|
}
|
|
3579
|
-
function
|
|
3741
|
+
function formatOrders3(data) {
|
|
3580
3742
|
const orders = data.orders ?? [];
|
|
3581
3743
|
if (orders.length === 0) {
|
|
3582
3744
|
return Formatter.status("info", "No hotel orders found");
|
|
@@ -3600,7 +3762,7 @@ function formatOrders2(data) {
|
|
|
3600
3762
|
${Formatter.keyValue(summary)}`;
|
|
3601
3763
|
}
|
|
3602
3764
|
function registerHotelListOrdersCommand(parent, deps) {
|
|
3603
|
-
const cmd = parent.command("list-orders").description("List the developer's hotel orders with optional status filtering and pagination").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--status <status>", "Filter by order status (omitted entirely when absent \u2192 all statuses)").option("--page <page>", "Page number",
|
|
3765
|
+
const cmd = parent.command("list-orders").description("List the developer's hotel orders with optional status filtering and pagination").option("--api-key <key>", "API Key for authentication (X-Api-Key)").option("--status <status>", "Filter by order status (omitted entirely when absent \u2192 all statuses)").option("--page <page>", "Page number", DEFAULT_PAGE3).option("--page-size <size>", "Page size", DEFAULT_PAGE_SIZE3);
|
|
3604
3766
|
attachSchemaHelp(cmd, hotelListOrdersSchema);
|
|
3605
3767
|
cmd.action(async () => {
|
|
3606
3768
|
const opts = cmd.optsWithGlobals();
|
|
@@ -3610,8 +3772,8 @@ function registerHotelListOrdersCommand(parent, deps) {
|
|
|
3610
3772
|
type: "password"
|
|
3611
3773
|
});
|
|
3612
3774
|
const params = {
|
|
3613
|
-
page:
|
|
3614
|
-
page_size:
|
|
3775
|
+
page: positiveInt4(opts.page ?? DEFAULT_PAGE3, "page"),
|
|
3776
|
+
page_size: positiveInt4(opts.pageSize ?? DEFAULT_PAGE_SIZE3, "page-size")
|
|
3615
3777
|
};
|
|
3616
3778
|
if (opts.status !== void 0) params.status = opts.status;
|
|
3617
3779
|
const spinner = format === "json" ? null : createSpinner("Fetching orders...");
|
|
@@ -3628,7 +3790,7 @@ function registerHotelListOrdersCommand(parent, deps) {
|
|
|
3628
3790
|
const configManager = new ConfigManager();
|
|
3629
3791
|
const commandResult = {
|
|
3630
3792
|
data,
|
|
3631
|
-
text: () =>
|
|
3793
|
+
text: () => formatOrders3(data)
|
|
3632
3794
|
};
|
|
3633
3795
|
await renderWithContext(commandResult, { format }, configManager);
|
|
3634
3796
|
});
|
|
@@ -4182,7 +4344,31 @@ async function main() {
|
|
|
4182
4344
|
const flag = thisCommand.opts().format;
|
|
4183
4345
|
process.env.AGENZO_FORMAT = resolveFormat(flag);
|
|
4184
4346
|
});
|
|
4185
|
-
const rideCmd = program.command("ride-elife").description(
|
|
4347
|
+
const rideCmd = program.command("ride-elife").description(
|
|
4348
|
+
`Ride ordering (eLife) \u2014 quote a fare, book it, poll status, and cancel.
|
|
4349
|
+
|
|
4350
|
+
Workflow (typical order):
|
|
4351
|
+
1. quote Get fare quotes between two points \u2192 vehicle_classes[] each with a quote_id
|
|
4352
|
+
2. book Book one vehicle_class using its quote_id \u2192 ride_id (write; needs --idempotency-key)
|
|
4353
|
+
3. get Poll ride status by --order-id=<ride_id> until terminal (or use --watch for NDJSON)
|
|
4354
|
+
4. cancel (optional) Cancel a ride by --order-id (write; may incur a fee)
|
|
4355
|
+
list-orders (standalone) List the developer's previous ride orders
|
|
4356
|
+
|
|
4357
|
+
Key notes:
|
|
4358
|
+
\u2022 Coordinates are NOT geocoded by the backend \u2014 supply --pickup-lat/lng and --dropoff-lat/lng.
|
|
4359
|
+
book must repeat the SAME pickup/dropoff coordinates+names and pickup-time used in quote;
|
|
4360
|
+
the quote_id does NOT carry them forward.
|
|
4361
|
+
\u2022 quote_id from quote is opaque and provider-specific \u2014 pass it unchanged to book, never reuse
|
|
4362
|
+
it across services.
|
|
4363
|
+
\u2022 vehicle_class values are case-sensitive literals (Sedan / SUV / MPV-5 / MPV-7 / Van / Luxury /
|
|
4364
|
+
Train) \u2014 pass back to book verbatim.
|
|
4365
|
+
\u2022 --pickup-time is UTC epoch seconds or the literal "now"; convert the user's local time to UTC.
|
|
4366
|
+
\u2022 All amounts are DECIMAL currency units (e.g. 42.50 = $42.50), never minor units (cents).
|
|
4367
|
+
\u2022 Billing mode is decided server-side: pay_per_call needs a PAID --payment-order-id (from
|
|
4368
|
+
payment-cli); monthly_settlement forbids it (settled against the developer's account).
|
|
4369
|
+
\u2022 Write verbs (book / cancel) require --idempotency-key; reuse the SAME key when retrying the
|
|
4370
|
+
same intent.`
|
|
4371
|
+
);
|
|
4186
4372
|
registerQuoteCommand(rideCmd, deps);
|
|
4187
4373
|
registerBookCommand(rideCmd, deps);
|
|
4188
4374
|
registerRideGetCommand(rideCmd, deps);
|
|
@@ -4191,6 +4377,11 @@ async function main() {
|
|
|
4191
4377
|
const servicesCmd = program.command("services").description("Merchant service discovery");
|
|
4192
4378
|
registerServicesListCommand(servicesCmd, { discoveryClient, program });
|
|
4193
4379
|
registerServiceGetCommand(servicesCmd, { discoveryClient, program });
|
|
4380
|
+
const ordersCmd = program.command("orders").description(
|
|
4381
|
+
'Unified cross-provider order index (spans ride + hotel). Use for generic "my orders" requests; use ride-elife/hotel-redaug commands once the business is known.'
|
|
4382
|
+
);
|
|
4383
|
+
registerOrdersListCommand(ordersCmd, deps);
|
|
4384
|
+
registerOrdersGetCommand(ordersCmd, deps);
|
|
4194
4385
|
const hotelCmd = program.command("hotel-redaug").description(
|
|
4195
4386
|
`Hotel booking (Redaug) \u2014 international hotel search, quote, create-order, pay-order, cancel, and check-out.
|
|
4196
4387
|
|