@itpay/cli 2.1.19 → 2.1.29
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 +2 -2
- package/dist/src/commands/buy.js +3 -3
- package/dist/src/commands/cart.js +15 -15
- package/dist/src/commands/catalog.js +10 -7
- package/dist/src/commands/checkout.js +8 -11
- package/dist/src/commands/docs.js +3 -14
- package/dist/src/commands/guidance.js +41 -25
- package/dist/src/commands/install.js +2 -2
- package/dist/src/commands/order.js +4 -3
- package/dist/src/commands/orders.js +4 -9
- package/dist/src/commands/pay.js +1 -1
- package/dist/src/commands/rail_catalog.js +160 -11
- package/dist/src/commands/refund.js +5 -5
- package/dist/src/commands/services.js +658 -361
- package/dist/src/commands/skill.js +1 -1
- package/dist/src/commands/vault.js +27 -20
- package/dist/src/main.js +39 -24
- package/dist/src/render/markdown.js +0 -3
- package/dist/src/state/account_auth.js +9 -5
- package/dist/src/state/cart_session.js +4 -1
- package/dist/src/state/config.js +1 -1
- package/dist/src/state/task_journal.js +2 -0
- package/docs/agent/buyer/cart-checkout.json +5 -4
- package/docs/agent/buyer/catalog-list.json +24 -6
- package/docs/agent/buyer/identity-and-sessions.json +16 -15
- package/docs/agent/buyer/install-and-setup.json +5 -4
- package/docs/agent/buyer/orders-refunds.json +11 -5
- package/docs/agent/buyer/payment-flow.json +3 -3
- package/docs/agent/buyer/purchased-content.json +18 -4
- package/docs/agent/buyer/quickstart.json +22 -14
- package/docs/agent/buyer/rail-booking.json +125 -171
- package/docs/agent/buyer/rail-fast-checkout.json +21 -44
- package/docs/agent/buyer/render-hosts.json +9 -6
- package/docs/agent/buyer/service-feedback.json +2 -1
- package/docs/cli-reference/agent-types.md +1 -1
- package/docs/cli-reference/commands/auth.md +2 -0
- package/docs/cli-reference/commands/buy.md +1 -1
- package/docs/cli-reference/commands/cart/add.md +1 -1
- package/docs/cli-reference/commands/cart/clear.md +1 -1
- package/docs/cli-reference/commands/cart/index.md +1 -1
- package/docs/cli-reference/commands/cart/next.md +1 -1
- package/docs/cli-reference/commands/cart/remove.md +1 -1
- package/docs/cli-reference/commands/cart/show.md +1 -1
- package/docs/cli-reference/commands/catalog/index.md +1 -1
- package/docs/cli-reference/commands/catalog/list.md +1 -1
- package/docs/cli-reference/commands/checkout.md +1 -1
- package/docs/cli-reference/commands/device.md +8 -7
- package/docs/cli-reference/commands/docs/index.md +1 -1
- package/docs/cli-reference/commands/docs/list.md +1 -1
- package/docs/cli-reference/commands/docs/search.md +1 -1
- package/docs/cli-reference/commands/docs/show.md +1 -1
- package/docs/cli-reference/commands/install.md +2 -2
- package/docs/cli-reference/commands/next.md +1 -1
- package/docs/cli-reference/commands/order.md +1 -1
- package/docs/cli-reference/commands/pay.md +1 -1
- package/docs/cli-reference/commands/readyz.md +1 -1
- package/docs/cli-reference/commands/refund/cancel.md +1 -1
- package/docs/cli-reference/commands/refund/create.md +1 -1
- package/docs/cli-reference/commands/refund/get.md +2 -2
- package/docs/cli-reference/commands/refund/index.md +1 -1
- package/docs/cli-reference/commands/refund/list.md +1 -1
- package/docs/cli-reference/commands/refund/watch.md +1 -1
- package/docs/cli-reference/commands/services/action.md +3 -3
- package/docs/cli-reference/commands/services/checkout.md +1 -1
- package/docs/cli-reference/commands/services/events.md +1 -1
- package/docs/cli-reference/commands/services/get.md +1 -1
- package/docs/cli-reference/commands/services/index.md +1 -1
- package/docs/cli-reference/commands/services/invoke.md +5 -13
- package/docs/cli-reference/commands/services/list.md +1 -1
- package/docs/cli-reference/commands/services/next.md +12 -10
- package/docs/cli-reference/commands/services/page.md +9 -7
- package/docs/cli-reference/commands/services/quote.md +1 -1
- package/docs/cli-reference/commands/services/read-result.md +16 -9
- package/docs/cli-reference/commands/services/run.md +4 -2
- package/docs/cli-reference/commands/services/start.md +1 -1
- package/docs/cli-reference/conventions.md +2 -2
- package/package.json +7 -5
- package/skills/itpay/SKILL.md +77 -238
- package/docs/reviews/agent-ux-handoff-2026-09-23/IMPLEMENTATION-EVIDENCE.md +0 -174
- package/docs/skill-bundle-rollout/01-mcp-authentication.md +0 -134
- package/docs/skill-bundle-rollout/02-platform-bundle-repositories.md +0 -210
- package/docs/skill-bundle-rollout/03-platform-publishing.md +0 -161
- package/docs/skill-bundle-rollout/04-first-wave-platforms.md +0 -70
- package/docs/skill-bundle-rollout/05-sync-operations.md +0 -62
- package/docs/skill-bundle-rollout/README.md +0 -151
- /package/bin/{itp → itp.mjs} +0 -0
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
// The committed rail.catalog.v3 may ship positional rows (journeys, plans,
|
|
3
|
-
// profiles keyed by journey_columns plus shared ride_table / *_index tables)
|
|
4
|
-
// instead of per-journey objects. The summary path needs only ref + route
|
|
5
|
-
// text + default layer; the full packed document is passed through verbatim
|
|
6
|
-
// for JSON output — decoding is for the human-readable summary and selectors.
|
|
1
|
+
import { CLI_VERSION, cliDistribution } from "../state/config.js";
|
|
7
2
|
export class RailCatalogEncodingError extends Error {
|
|
8
3
|
constructor(encoding) {
|
|
9
|
-
super(`catalog encoding ${JSON.stringify(encoding)} is not supported by
|
|
10
|
-
`
|
|
4
|
+
super(`catalog encoding ${JSON.stringify(encoding)} is not supported by CLI ${CLI_VERSION} ` +
|
|
5
|
+
`(${cliDistribution()}); obtain a compatible exact version through this installation channel. ` +
|
|
6
|
+
`The committed catalog is intact`);
|
|
11
7
|
this.name = "rail_catalog_encoding";
|
|
12
8
|
}
|
|
13
9
|
}
|
|
10
|
+
function scopeFromProfiles(value) {
|
|
11
|
+
const profiles = Array.isArray(value) ? value : [];
|
|
12
|
+
const selected = profiles.find((p) => Array.isArray(p) && Array.isArray(p[1]) && p[1].includes("balanced")) ?? profiles[0];
|
|
13
|
+
if (!Array.isArray(selected))
|
|
14
|
+
return { origin: "legacy_unknown", destination: "legacy_unknown",
|
|
15
|
+
duration_basis: "legacy_unknown", arrival_basis: "legacy_unknown", cost_basis: "legacy_unknown",
|
|
16
|
+
duration_minutes: null, estimated_total_cost: null, cost_incomplete: true };
|
|
17
|
+
const extras = selected[10] && typeof selected[10] === "object" ? selected[10] : {};
|
|
18
|
+
const total = typeof selected[9] === "number" && extras.ci !== true ? selected[9] / 100 : null;
|
|
19
|
+
return {
|
|
20
|
+
origin: extras.os ?? "legacy_unknown", destination: extras.ds ?? "legacy_unknown",
|
|
21
|
+
duration_basis: extras.db ?? "legacy_unknown", arrival_basis: extras.ab ?? "legacy_unknown",
|
|
22
|
+
cost_basis: extras.cb ?? "legacy_unknown", duration_minutes: selected[8] ?? null,
|
|
23
|
+
estimated_total_cost: total, cost_incomplete: extras.ci === true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
14
26
|
function asString(v) {
|
|
15
27
|
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
16
28
|
}
|
|
@@ -20,6 +32,125 @@ function asIndex(v, bound) {
|
|
|
20
32
|
}
|
|
21
33
|
return v;
|
|
22
34
|
}
|
|
35
|
+
function asObject(value) {
|
|
36
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
37
|
+
}
|
|
38
|
+
function datedTime(date, value) {
|
|
39
|
+
const raw = asString(value);
|
|
40
|
+
if (!raw)
|
|
41
|
+
return null;
|
|
42
|
+
if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(raw))
|
|
43
|
+
return raw.replace("T", " ").slice(0, 16);
|
|
44
|
+
const short = raw.match(/^(\d{2}:\d{2})(?:\+(\d+))?$/);
|
|
45
|
+
const day = asString(date);
|
|
46
|
+
if (!short || !day)
|
|
47
|
+
return null;
|
|
48
|
+
if (!short[2])
|
|
49
|
+
return `${day} ${short[1]}`;
|
|
50
|
+
const shifted = new Date(`${day}T00:00:00Z`);
|
|
51
|
+
if (Number.isNaN(shifted.getTime()))
|
|
52
|
+
return null;
|
|
53
|
+
shifted.setUTCDate(shifted.getUTCDate() + Number(short[2]));
|
|
54
|
+
return `${shifted.toISOString().slice(0, 10)} ${short[1]}`;
|
|
55
|
+
}
|
|
56
|
+
function elapsedMinutes(departure, arrival) {
|
|
57
|
+
if (!departure || !arrival)
|
|
58
|
+
return null;
|
|
59
|
+
const start = Date.parse(departure.replace(" ", "T") + "Z");
|
|
60
|
+
const end = Date.parse(arrival.replace(" ", "T") + "Z");
|
|
61
|
+
return Number.isFinite(start) && Number.isFinite(end) && end >= start ? (end - start) / 60_000 : null;
|
|
62
|
+
}
|
|
63
|
+
function seatOffer(row, names) {
|
|
64
|
+
if (!Array.isArray(row))
|
|
65
|
+
return null;
|
|
66
|
+
const extras = asObject(row[7]);
|
|
67
|
+
const code = asString(row[1]);
|
|
68
|
+
return {
|
|
69
|
+
offer_ref: row[0], seat_type: code ?? null, seat_name: code ? names[code] ?? code : null,
|
|
70
|
+
inventory_status: row[2] ?? null, quantity: row[3] ?? null, unit_price_fen: row[4] ?? null,
|
|
71
|
+
eligible: row[5] === true, requires_quote: row[6] === true,
|
|
72
|
+
price_source: extras.s ?? "sale_price", quote_price_unverified: extras.u === true,
|
|
73
|
+
conflicted: extras.c === true,
|
|
74
|
+
...(Array.isArray(extras.o) ? { price_observations_fen: extras.o } : {}),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function decodeRide(row, wait, stations, services) {
|
|
78
|
+
if (!Array.isArray(row)) {
|
|
79
|
+
const ride = asObject(row);
|
|
80
|
+
if (!Object.keys(ride).length)
|
|
81
|
+
throw new Error("rail catalog: malformed ride row");
|
|
82
|
+
const refs = Array.isArray(ride.service_refs) ? ride.service_refs : [];
|
|
83
|
+
const codes = [...new Set(refs.map((ref) => asObject(services[asString(ref) ?? ""]).tc)
|
|
84
|
+
.filter((code) => typeof code === "string" && code.length > 0))];
|
|
85
|
+
const departure = datedTime(ride.boarding_date, ride.departure_at ?? ride.departure);
|
|
86
|
+
const arrival = datedTime(ride.boarding_date, ride.arrival_at ?? ride.arrival);
|
|
87
|
+
return { train_codes: codes, train_code: codes.join("/"),
|
|
88
|
+
from_station: stations[asString(ride.from_station_code) ?? ""] ?? ride.from_station ?? null,
|
|
89
|
+
to_station: stations[asString(ride.to_station_code) ?? ""] ?? ride.to_station ?? null,
|
|
90
|
+
boarding_date: ride.boarding_date ?? null,
|
|
91
|
+
departure, arrival, duration_minutes: elapsedMinutes(departure, arrival),
|
|
92
|
+
wait_minutes: typeof wait === "number" ? wait : ride.wait_minutes ?? null,
|
|
93
|
+
same_run: ride.same_run === true, onboard_stops: Array.isArray(ride.onboard_stops) ? ride.onboard_stops : [],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const extras = asObject(row[8]);
|
|
97
|
+
const refs = Array.isArray(row[4]) ? row[4] : [];
|
|
98
|
+
const codes = [...new Set(refs.map((ref) => asObject(services[asString(ref) ?? ""]).tc)
|
|
99
|
+
.filter((code) => typeof code === "string" && code.length > 0))];
|
|
100
|
+
const base = row[0];
|
|
101
|
+
const departure = datedTime(base, extras.dep);
|
|
102
|
+
const arrival = datedTime(base, extras.arr);
|
|
103
|
+
return {
|
|
104
|
+
train_codes: codes, train_code: codes.join("/"),
|
|
105
|
+
from_station: stations[asString(row[2]) ?? ""] ?? row[2] ?? null,
|
|
106
|
+
to_station: stations[asString(row[3]) ?? ""] ?? row[3] ?? null,
|
|
107
|
+
boarding_date: base ?? null,
|
|
108
|
+
departure, arrival, duration_minutes: elapsedMinutes(departure, arrival),
|
|
109
|
+
wait_minutes: typeof wait === "number" ? wait : typeof row[5] === "number" ? row[5] : null,
|
|
110
|
+
same_run: row[6] === true, onboard_stops: Array.isArray(row[7]) ? row[7] : [],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function decodePlans(rawPlans, rawProfiles, packed, catalog, services, names, stations) {
|
|
114
|
+
const plans = Array.isArray(rawPlans) ? rawPlans : [];
|
|
115
|
+
const profiles = Array.isArray(rawProfiles) ? rawProfiles : [];
|
|
116
|
+
const preferred = profiles.find((profile) => Array.isArray(profile) && Array.isArray(profile[1]) && profile[1].includes("balanced")) ?? profiles[0];
|
|
117
|
+
const profile = Array.isArray(preferred) ? preferred : [];
|
|
118
|
+
const serviceIndex = Array.isArray(catalog.service_index) ? catalog.service_index : [];
|
|
119
|
+
const selectedPlan = packed && typeof profile[2] === "number" ? plans[asIndex(profile[2], plans.length)] :
|
|
120
|
+
plans.find((plan) => Array.isArray(plan) && plan[0] === profile[2]);
|
|
121
|
+
const selectedRef = Array.isArray(selectedPlan) ? selectedPlan[0] : null;
|
|
122
|
+
const decoded = plans.map((plan) => {
|
|
123
|
+
if (!Array.isArray(plan))
|
|
124
|
+
throw new Error("rail catalog: malformed ticket plan");
|
|
125
|
+
const refs = (Array.isArray(plan[1]) ? plan[1] : []).map((ref) => packed && typeof ref === "number" ? serviceIndex[asIndex(ref, serviceIndex.length)] : ref);
|
|
126
|
+
const extras = asObject(plan[7]);
|
|
127
|
+
const legs = refs.map((ref, index) => {
|
|
128
|
+
const service = asObject(services[asString(ref) ?? ""]);
|
|
129
|
+
const offers = Array.isArray(service.of) ? service.of : [];
|
|
130
|
+
const selectedOffer = plan[0] === selectedRef && Array.isArray(profile[3]) ? profile[3][index] : undefined;
|
|
131
|
+
const chosen = packed && typeof selectedOffer === "number" ? offers[asIndex(selectedOffer, offers.length)] :
|
|
132
|
+
offers.find((offer) => Array.isArray(offer) && offer[0] === selectedOffer);
|
|
133
|
+
return {
|
|
134
|
+
service_ref: ref ?? null, train_code: service.tc ?? null,
|
|
135
|
+
from_station: stations[asString(service.f) ?? ""] ?? service.f ?? null,
|
|
136
|
+
to_station: stations[asString(service.t) ?? ""] ?? service.t ?? null,
|
|
137
|
+
departure: datedTime(service.d, service.dep), arrival: datedTime(service.d, service.arr),
|
|
138
|
+
seat_options: offers.map((offer) => seatOffer(offer, names)).filter((offer) => offer !== null),
|
|
139
|
+
...(chosen ? { selected_seat: seatOffer(chosen, names) } : {}),
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
const amount = asObject(plan[3]);
|
|
143
|
+
return {
|
|
144
|
+
ticket_plan_ref: plan[0], passenger_count: plan[2] ?? null,
|
|
145
|
+
purchase_support: plan[6] ?? "none", rail_amount_verified: plan[4] === true,
|
|
146
|
+
rail_amount_fen: { default: amount.def ?? null, minimum: amount.min ?? null, maximum: amount.max ?? null },
|
|
147
|
+
service_fee_fen: plan[5] ?? null, quote_price_unverified: extras.qu === true,
|
|
148
|
+
legs,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
const selected = decoded.find((plan) => plan.ticket_plan_ref === selectedRef);
|
|
152
|
+
return { plans: decoded, ...(selected ? { selected } : {}) };
|
|
153
|
+
}
|
|
23
154
|
// _cn_route_text port: "南头 C7608 → 广州南换乘71分 → G2944 重庆西" — kept
|
|
24
155
|
// byte-identical with the planner so a packed journey renders the same text
|
|
25
156
|
// its object form carried.
|
|
@@ -72,6 +203,9 @@ export function decodeRailCatalogJourneys(catalog) {
|
|
|
72
203
|
const encoding = catalog["encoding"];
|
|
73
204
|
const layerMap = catalog["choice_layers"]?.["journey_layer"] ?? {};
|
|
74
205
|
const layerOf = (ref) => layerMap[ref] === "backup" ? "backup" : "main";
|
|
206
|
+
const stations = asObject(catalog.stations);
|
|
207
|
+
const services = asObject(catalog.services);
|
|
208
|
+
const seatNames = asObject(catalog.seat_names);
|
|
75
209
|
if (encoding === undefined || encoding === null) {
|
|
76
210
|
const rows = Array.isArray(catalog["journeys"]) ? catalog["journeys"] : [];
|
|
77
211
|
return {
|
|
@@ -79,10 +213,17 @@ export function decodeRailCatalogJourneys(catalog) {
|
|
|
79
213
|
journeys: rows.map((j) => {
|
|
80
214
|
const rec = (j ?? {});
|
|
81
215
|
const ref = asString(rec["ref"]) ?? asString(rec["journey_id"]) ?? "?";
|
|
216
|
+
const calculationScope = scopeFromProfiles(rec["profiles"]);
|
|
217
|
+
const rides = (Array.isArray(rec.rides) ? rec.rides : []).map((ride) => decodeRide(ride, null, stations, services));
|
|
218
|
+
const ticketPlans = decodePlans(rec.plans, rec.profiles, false, catalog, services, seatNames, stations);
|
|
82
219
|
return {
|
|
83
220
|
ref,
|
|
84
221
|
route: asString(rec["route"]) ?? asString(rec["route_text"]) ?? asString(rec["summary"]) ?? "",
|
|
85
222
|
defaultLayer: layerOf(ref),
|
|
223
|
+
rides,
|
|
224
|
+
...(calculationScope ? { calculation_scope: calculationScope } : {}),
|
|
225
|
+
ticket_plans: ticketPlans.plans,
|
|
226
|
+
...(ticketPlans.selected ? { selected_plan: ticketPlans.selected } : {}),
|
|
86
227
|
};
|
|
87
228
|
}),
|
|
88
229
|
};
|
|
@@ -95,8 +236,6 @@ export function decodeRailCatalogJourneys(catalog) {
|
|
|
95
236
|
throw new RailCatalogEncodingError(`${String(encoding)} (unexpected journey_columns)`);
|
|
96
237
|
}
|
|
97
238
|
const rideTable = (Array.isArray(catalog["ride_table"]) ? catalog["ride_table"] : []);
|
|
98
|
-
const stations = (catalog["stations"] ?? {});
|
|
99
|
-
const services = (catalog["services"] ?? {});
|
|
100
239
|
const journeys = (Array.isArray(catalog["journeys"]) ? catalog["journeys"] : []);
|
|
101
240
|
return {
|
|
102
241
|
packed: true,
|
|
@@ -106,7 +245,17 @@ export function decodeRailCatalogJourneys(catalog) {
|
|
|
106
245
|
const ref = asString(row[0]) ?? "?";
|
|
107
246
|
const route = asString(row[1]) ??
|
|
108
247
|
(Array.isArray(row[2]) ? regenerateRoute(row[2], rideTable, stations, services) : "");
|
|
109
|
-
|
|
248
|
+
const rides = (Array.isArray(row[2]) ? row[2] : []).map((pair) => {
|
|
249
|
+
if (!Array.isArray(pair) || pair.length !== 2)
|
|
250
|
+
throw new Error("shared_rows: malformed ride pair");
|
|
251
|
+
return decodeRide(rideTable[asIndex(pair[0], rideTable.length)], pair[1], stations, services);
|
|
252
|
+
});
|
|
253
|
+
const calculationScope = scopeFromProfiles(row[6]);
|
|
254
|
+
const ticketPlans = decodePlans(row[3], row[6], true, catalog, services, seatNames, stations);
|
|
255
|
+
return { ref, route, defaultLayer: layerOf(ref), rides,
|
|
256
|
+
...(calculationScope ? { calculation_scope: calculationScope } : {}),
|
|
257
|
+
ticket_plans: ticketPlans.plans,
|
|
258
|
+
...(ticketPlans.selected ? { selected_plan: ticketPlans.selected } : {}) };
|
|
110
259
|
}),
|
|
111
260
|
};
|
|
112
261
|
}
|
|
@@ -12,11 +12,11 @@ export async function runRefund(backend, config, options) {
|
|
|
12
12
|
plainResult: Object.entries(envelope.result).map(([key, value]) => `${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`),
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
|
-
function refundStateEnvelope(refund, status) {
|
|
15
|
+
export function refundStateEnvelope(refund, status) {
|
|
16
16
|
const terminal = ["succeeded", "failed", "cancelled", "rejected"].includes(refund.status);
|
|
17
17
|
let instruction = refund.decision_mode === "manual"
|
|
18
18
|
? "先告诉用户退款已进入人工审核,原交付保持冻结;人工审核不等于拒绝,等待服务器决定,不要重复申请或承诺结果。"
|
|
19
|
-
: "先告诉用户退款申请已经记录,原交付已冻结;自动路径表示系统会继续处理,但只有最终 succeeded
|
|
19
|
+
: "先告诉用户退款申请已经记录,原交付已冻结;自动路径表示系统会继续处理,但只有最终 succeeded 才能确认退款成功。然后只跟踪同一退款,不读取交付、不创建授权或重复申请。";
|
|
20
20
|
if (!refund.access_locked)
|
|
21
21
|
instruction = "先告诉用户退款当前没有锁定交付;按服务器事实解释当前状态,不要自行推断退款结果、到账时间或交付资格。";
|
|
22
22
|
if (refund.status === "succeeded")
|
|
@@ -73,7 +73,7 @@ export async function runListRefunds(backend, options) {
|
|
|
73
73
|
: "该订单没有退款记录;确认用户确实要求退款后再创建。",
|
|
74
74
|
next: selected
|
|
75
75
|
? { command: `itpay refund get ${selected.refund_request_id} --json`, reason: active ? "读取活跃退款" : "读取最新退款" }
|
|
76
|
-
:
|
|
76
|
+
: null,
|
|
77
77
|
recovery: [],
|
|
78
78
|
};
|
|
79
79
|
writeCommandEnvelope(envelope, {
|
|
@@ -96,13 +96,13 @@ export async function runGetRefund(backend, refundID, options = {}) {
|
|
|
96
96
|
export async function runCancelRefund(backend, refundID, reason, options = {}) {
|
|
97
97
|
const refund = await backend.cancelRefund(refundID, reason?.trim() || "buyer_cancelled");
|
|
98
98
|
const envelope = {
|
|
99
|
-
status:
|
|
99
|
+
status: refund.status,
|
|
100
100
|
result: {
|
|
101
101
|
refund_request_id: refund.refund_request_id,
|
|
102
102
|
order_id: refund.order_id,
|
|
103
103
|
access_locked: refund.access_locked,
|
|
104
104
|
},
|
|
105
|
-
instruction: "
|
|
105
|
+
instruction: refund.status === "cancelled" ? "Backend确认退款已取消;如需交付,重新进入原订单核对当前权限,旧grant不自动复活;后端要求时取得新的授权。" : "Backend未确认取消;按返回的退款权威状态核对原订单,不重复提交取消。",
|
|
106
106
|
next: { command: `itpay order ${refund.order_id} --json`, reason: "确认订单访问状态" },
|
|
107
107
|
recovery: [],
|
|
108
108
|
};
|