|
|
/**
|
|
|
* CC 烟雾验收
|
|
|
*
|
|
|
* pnpm cc:smoke # 跟随 .env:mock <20>?live
|
|
|
* pnpm cc:smoke -- --mode=mock # 强制 mock(不连网<E8BF9E>?
|
|
|
* pnpm cc:smoke -- --mode=live # 强制 live:需 CC_MOCK=false + 账号
|
|
|
*
|
|
|
* Exit: 0 ok | 1 配置错误 | 2 CC 业务失败 | 3 模式不匹<E4B88D>?
|
|
|
*/
|
|
|
import { getEnv, resetEnvCache } from "../src/lib/env";
|
|
|
import { getCcModeStatus } from "../src/services/cc/mode";
|
|
|
import { saveContainer } from "../src/services/cc/save-container";
|
|
|
import { getShippingLineList } from "../src/services/cc/shipping-line";
|
|
|
import { getContainerListFromCc } from "../src/services/cc/conflict";
|
|
|
|
|
|
type ModeArg = "auto" | "mock" | "live";
|
|
|
|
|
|
function parseMode(argv: string[]): ModeArg {
|
|
|
const raw = argv.find((a) => a.startsWith("--mode="))?.slice("--mode=".length);
|
|
|
if (raw === "mock" || raw === "live" || raw === "auto") return raw;
|
|
|
const idx = argv.indexOf("--mode");
|
|
|
if (idx >= 0) {
|
|
|
const v = argv[idx + 1];
|
|
|
if (v === "mock" || v === "live" || v === "auto") return v;
|
|
|
}
|
|
|
return "auto";
|
|
|
}
|
|
|
|
|
|
async function main() {
|
|
|
resetEnvCache();
|
|
|
const env = getEnv();
|
|
|
const requested = parseMode(process.argv.slice(2));
|
|
|
const status = await getCcModeStatus();
|
|
|
|
|
|
console.log(
|
|
|
JSON.stringify(
|
|
|
{
|
|
|
requested,
|
|
|
runtime: status,
|
|
|
api_base: env.CC_API_BASE,
|
|
|
saas: env.CC_SAAS_HEADER,
|
|
|
},
|
|
|
null,
|
|
|
2,
|
|
|
),
|
|
|
);
|
|
|
|
|
|
if (requested === "live") {
|
|
|
if (status.mode === "mock") {
|
|
|
console.error(
|
|
|
"FAIL: --mode=live <20>?CC_MOCK=true。设 CC_MOCK=false 并配<E5B9B6>?CC_USERNAME + 密码后再跑<E5868D>?,
|
|
|
);
|
|
|
process.exit(3);
|
|
|
}
|
|
|
if (!status.live_ready) {
|
|
|
console.error(
|
|
|
"FAIL: live 未就<EFBFBD>?<EFBFBD>?,
|
|
|
status.reason ?? "缺少 CC_USERNAME / CC_PASSWORD_PLAIN|MD5",
|
|
|
);
|
|
|
process.exit(1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (requested === "mock" && status.mode !== "mock") {
|
|
|
console.error(
|
|
|
"FAIL: --mode=mock 但当<E4BD86>?CC_MOCK=false。请临时<E4B8B4>?CC_MOCK=true,或去掉 --mode<64>?,
|
|
|
);
|
|
|
process.exit(3);
|
|
|
}
|
|
|
|
|
|
if (requested === "auto" && status.mode === "live" && !status.live_ready) {
|
|
|
console.error("FAIL:", status.reason);
|
|
|
process.exit(1);
|
|
|
}
|
|
|
|
|
|
const isLive = status.mode === "live" && status.live_ready;
|
|
|
const containerNo = `SMK${Date.now().toString().slice(-8)}`;
|
|
|
|
|
|
if (isLive) {
|
|
|
const lines = await getShippingLineList();
|
|
|
console.log(`shipping_lines: ${lines.length}`);
|
|
|
if (lines.length === 0) {
|
|
|
console.warn("WARN: GetShippingLineList 空(不阻<EFBFBD>?SaveContainer<EFBFBD>?);
|
|
|
}
|
|
|
|
|
|
const list = await getContainerListFromCc(containerNo);
|
|
|
if (!list.ok) {
|
|
|
console.error("FAIL: GetContainerList", list.error);
|
|
|
process.exit(2);
|
|
|
}
|
|
|
console.log(`conflict_probe items=${list.items.length}`);
|
|
|
} else {
|
|
|
console.log("mode=mock <20>?跳过真网 GetShippingLineList / GetContainerList");
|
|
|
}
|
|
|
|
|
|
const res = await saveContainer({
|
|
|
entity: {
|
|
|
F_TransMode: 0,
|
|
|
F_OperationType: 0,
|
|
|
F_ContainerNo: containerNo,
|
|
|
F_CabinetType: "40HQ",
|
|
|
F_ETA: "2026-07-13",
|
|
|
F_Classis: 0,
|
|
|
F_MemoRemark: `smoke-${status.mode}`,
|
|
|
},
|
|
|
shipments: [
|
|
|
{
|
|
|
row_index: 1,
|
|
|
row_status: "VALID",
|
|
|
F_FBACode: "ABQ2",
|
|
|
F_Transporter: "TRUCK",
|
|
|
F_CTNS: 1,
|
|
|
F_FBAID: "FBA19G5XJLV4",
|
|
|
},
|
|
|
],
|
|
|
});
|
|
|
|
|
|
console.log(JSON.stringify({ containerNo, result: res }, null, 2));
|
|
|
|
|
|
if (!res.ok) {
|
|
|
process.exit(2);
|
|
|
}
|
|
|
|
|
|
// 指令写能力烟雾(默认 mock<63>?
|
|
|
const { executeInstructionWrite } = await import(
|
|
|
"../src/services/cc/instruction-write"
|
|
|
);
|
|
|
const { ensureCcWriteCapabilities, listCcWriteCapabilities } = await import(
|
|
|
"../src/services/cc/write-capability"
|
|
|
);
|
|
|
await ensureCcWriteCapabilities();
|
|
|
const caps = await listCcWriteCapabilities();
|
|
|
console.log(
|
|
|
"cc_write_capabilities",
|
|
|
caps.map((c) => `${c.id}=${c.mode}`).join(", "),
|
|
|
);
|
|
|
|
|
|
for (const kind of ["transfer", "hold_split", "label"] as const) {
|
|
|
const r = await executeInstructionWrite(kind, {
|
|
|
mailId: "0",
|
|
|
containerNo: containerNo,
|
|
|
subject: `smoke ${kind}`,
|
|
|
shipments: [],
|
|
|
remark: "cc-smoke",
|
|
|
});
|
|
|
console.log(`instruction ${kind}:`, r.ok ? "PASS" : "FAIL", r.mode, r.error || "");
|
|
|
if (!r.ok) process.exit(2);
|
|
|
}
|
|
|
|
|
|
if (isLive) {
|
|
|
console.log("PASS: TEST live SaveContainer code=200 + external id");
|
|
|
console.log(
|
|
|
"NOTE: transfer/hold/label live 需 cc_write_capability.mode=live <20>?CC 侧接口可用才算该项完<E9A1B9>?,
|
|
|
);
|
|
|
} else {
|
|
|
console.log(
|
|
|
"PASS: mock SaveContainer + instruction writes <EFBFBD>?非设<EFBFBD>?TEST 烟雾验收。账号到位后:CC_MOCK=false + pnpm cc:smoke -- --mode=live",
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
main().catch((e) => {
|
|
|
console.error(e);
|
|
|
process.exit(1);
|
|
|
});
|