/** * 闭环关键:选人 → 镇审 → 居保 → submit-leader → 领导审 → 出盘 → 回盘 → 归档 */ const http = require("http"); function req(method, path, body) { return new Promise((resolve) => { const data = body == null ? null : JSON.stringify(body); const headers = { Accept: "application/json" }; if (data) { headers["Content-Type"] = "application/json"; headers["Content-Length"] = Buffer.byteLength(data); } const r = http.request( { hostname: "localhost", port: 8088, path: "/sjnmtybt" + path, method, headers }, (res) => { let raw = ""; res.on("data", (c) => (raw += c)); res.on("end", () => { try { resolve(JSON.parse(raw)); } catch (e) { resolve({ code: res.statusCode, raw: String(raw).slice(0, 200) }); } }); } ); r.on("error", (e) => resolve({ code: 0, error: e.message })); if (data) r.write(data); r.end(); }); } function check(name, cond, detail) { console.log((cond ? "PASS" : "FAIL") + " | " + name + (detail ? " | " + detail : "")); return !!cond; } (async () => { const townId = "T_YEXIE"; const villageId = "V_YX_001"; // 用毫秒构造近似唯一发放月,避免与其它联调脚本撞车 const payMonth = "22" + String(Date.now()).slice(-4); console.log("payMonth=" + payMonth); const page0 = await req("POST", "/api/batches/page", { pageNum: 1, pageSize: 50, townId, villageId, payMonth, batchLevel: "VILLAGE", }); for (const b of page0.data?.list || []) { if (b?.id && b.status !== "ARCHIVED") { await req("POST", "/api/batches/" + encodeURIComponent(b.id) + "/purge"); } } const p = await req("POST", "/api/personnel", { name: "闭环测员", idNumber: "31011719900101" + String(Date.now()).slice(-4), townId, villageId, bankCardNumber: "6228480030001234567", monthlyStandard: 1280, enjoyStartMonth: "202601", }); const pid = p.data?.id; check("建人员", !!pid, pid); async function ensure() { return req( "POST", "/api/batches/ensure-current-month?townId=" + encodeURIComponent(townId) + "&villageId=" + encodeURIComponent(villageId) + "&payMonth=" + encodeURIComponent(payMonth) ); } let ensured = await ensure(); let bid = ensured.data?.id; if (bid && ensured.data?.status && ensured.data.status !== "DRAFT" && ensured.data.status !== "REJECTED") { await req("POST", "/api/batches/" + encodeURIComponent(bid) + "/purge"); ensured = await ensure(); bid = ensured.data?.id; } check("建批", !!bid && ensured.code === 200, ensured.message + " id=" + bid + " st=" + ensured.data?.status); const put = await req("PUT", "/api/batches/" + encodeURIComponent(bid) + "/members", { personnelIds: [pid], }); check("选人", put.code === 200, put.message); const submit = await req("POST", "/api/batches/" + encodeURIComponent(bid) + "/submit"); check("提交初审", submit.code === 200, submit.message + " st=" + submit.data?.status); const town = await req("POST", "/api/batches/town-approve", { bizId: bid, action: "PASS", opinion: "同意", operator: "镇经发", }); check("镇初审", town.code === 200, town.data?.status); const match = await req("POST", "/api/insurance-match/trigger", { batchId: bid, operator: "业务", }); check("居保", match.code === 200, JSON.stringify(match.data).slice(0, 160)); // 有 FAIL 时人工确认;禁止跳过业务条件 const results = await req("GET", "/api/insurance-match/batches/" + encodeURIComponent(bid) + "/results"); const fails = (results.data || []).filter( (r) => r.matchResult === "FAIL" || r.insuranceMatchResult === "FAIL" || r.matchResult === "PENDING" ); for (const f of fails) { if (f.matchResult === "PENDING") continue; // PENDING 应再触发匹配,不人工糊弄 await req("POST", "/api/insurance-match/manual-confirm", { personnelId: f.personnelId || f.id, batchId: bid, pass: true, operator: "业务", }); } const personAfter = await req("GET", "/api/personnel/" + encodeURIComponent(pid)); check( "居保后人员状态", personAfter.data?.bizStatus === "NORMAL" && (personAfter.data?.insuranceMatchResult === "SUCCESS" || personAfter.data?.insuranceMatchResult === "MANUAL_PASS"), "biz=" + personAfter.data?.bizStatus + " ins=" + personAfter.data?.insuranceMatchResult ); const toLeader = await req("POST", "/api/batches/" + encodeURIComponent(bid) + "/submit-leader"); check( "提交领导", toLeader.code === 200 && toLeader.data?.status === "PENDING_LEADER_APPROVE", toLeader.message + " st=" + toLeader.data?.status ); const leader = await req("POST", "/api/batches/leader-approve", { bizId: bid, action: "PASS", opinion: "同意出盘", operator: "分管领导", }); check("领导通过", leader.code === 200, leader.data?.status); const exp = await req("POST", "/api/payments/export-disk", { batchId: bid, bypassDeadline: true, }); check("出盘", exp.code === 200, exp.data?.fileName || exp.message); const ret = await req("POST", "/api/return-disk/confirm", { batchId: bid, manualAllSuccess: true, operator: "业务", }); check("回盘", ret.code === 200, ret.message); const ret2 = await req("POST", "/api/return-disk/confirm", { batchId: bid, manualAllSuccess: true, operator: "业务", }); check("重复回盘拒绝", ret2.code !== 200, ret2.code + " " + ret2.message); const arch = await req("POST", "/api/dashboard/archive/" + encodeURIComponent(bid)); check("归档", arch.code === 200 && arch.data?.status === "ARCHIVED", arch.message + " " + arch.data?.status); })();