e2e-submit-leader-loop.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /**
  2. * 闭环关键:选人 → 镇审 → 居保 → submit-leader → 领导审 → 出盘 → 回盘 → 归档
  3. */
  4. const http = require("http");
  5. function req(method, path, body) {
  6. return new Promise((resolve) => {
  7. const data = body == null ? null : JSON.stringify(body);
  8. const headers = { Accept: "application/json" };
  9. if (data) {
  10. headers["Content-Type"] = "application/json";
  11. headers["Content-Length"] = Buffer.byteLength(data);
  12. }
  13. const r = http.request(
  14. { hostname: "localhost", port: 8088, path: "/sjnmtybt" + path, method, headers },
  15. (res) => {
  16. let raw = "";
  17. res.on("data", (c) => (raw += c));
  18. res.on("end", () => {
  19. try {
  20. resolve(JSON.parse(raw));
  21. } catch (e) {
  22. resolve({ code: res.statusCode, raw: String(raw).slice(0, 200) });
  23. }
  24. });
  25. }
  26. );
  27. r.on("error", (e) => resolve({ code: 0, error: e.message }));
  28. if (data) r.write(data);
  29. r.end();
  30. });
  31. }
  32. function check(name, cond, detail) {
  33. console.log((cond ? "PASS" : "FAIL") + " | " + name + (detail ? " | " + detail : ""));
  34. return !!cond;
  35. }
  36. (async () => {
  37. const townId = "T_YEXIE";
  38. const villageId = "V_YX_001";
  39. // 用毫秒构造近似唯一发放月,避免与其它联调脚本撞车
  40. const payMonth = "22" + String(Date.now()).slice(-4);
  41. console.log("payMonth=" + payMonth);
  42. const page0 = await req("POST", "/api/batches/page", {
  43. pageNum: 1,
  44. pageSize: 50,
  45. townId,
  46. villageId,
  47. payMonth,
  48. batchLevel: "VILLAGE",
  49. });
  50. for (const b of page0.data?.list || []) {
  51. if (b?.id && b.status !== "ARCHIVED") {
  52. await req("POST", "/api/batches/" + encodeURIComponent(b.id) + "/purge");
  53. }
  54. }
  55. const p = await req("POST", "/api/personnel", {
  56. name: "闭环测员",
  57. idNumber: "31011719900101" + String(Date.now()).slice(-4),
  58. townId,
  59. villageId,
  60. bankCardNumber: "6228480030001234567",
  61. monthlyStandard: 1280,
  62. enjoyStartMonth: "202601",
  63. });
  64. const pid = p.data?.id;
  65. check("建人员", !!pid, pid);
  66. async function ensure() {
  67. return req(
  68. "POST",
  69. "/api/batches/ensure-current-month?townId=" +
  70. encodeURIComponent(townId) +
  71. "&villageId=" +
  72. encodeURIComponent(villageId) +
  73. "&payMonth=" +
  74. encodeURIComponent(payMonth)
  75. );
  76. }
  77. let ensured = await ensure();
  78. let bid = ensured.data?.id;
  79. if (bid && ensured.data?.status && ensured.data.status !== "DRAFT" && ensured.data.status !== "REJECTED") {
  80. await req("POST", "/api/batches/" + encodeURIComponent(bid) + "/purge");
  81. ensured = await ensure();
  82. bid = ensured.data?.id;
  83. }
  84. check("建批", !!bid && ensured.code === 200, ensured.message + " id=" + bid + " st=" + ensured.data?.status);
  85. const put = await req("PUT", "/api/batches/" + encodeURIComponent(bid) + "/members", {
  86. personnelIds: [pid],
  87. });
  88. check("选人", put.code === 200, put.message);
  89. const submit = await req("POST", "/api/batches/" + encodeURIComponent(bid) + "/submit");
  90. check("提交初审", submit.code === 200, submit.message + " st=" + submit.data?.status);
  91. const town = await req("POST", "/api/batches/town-approve", {
  92. bizId: bid,
  93. action: "PASS",
  94. opinion: "同意",
  95. operator: "镇经发",
  96. });
  97. check("镇初审", town.code === 200, town.data?.status);
  98. const match = await req("POST", "/api/insurance-match/trigger", {
  99. batchId: bid,
  100. operator: "业务",
  101. });
  102. check("居保", match.code === 200, JSON.stringify(match.data).slice(0, 160));
  103. // 有 FAIL 时人工确认;禁止跳过业务条件
  104. const results = await req("GET", "/api/insurance-match/batches/" + encodeURIComponent(bid) + "/results");
  105. const fails = (results.data || []).filter(
  106. (r) => r.matchResult === "FAIL" || r.insuranceMatchResult === "FAIL" || r.matchResult === "PENDING"
  107. );
  108. for (const f of fails) {
  109. if (f.matchResult === "PENDING") continue; // PENDING 应再触发匹配,不人工糊弄
  110. await req("POST", "/api/insurance-match/manual-confirm", {
  111. personnelId: f.personnelId || f.id,
  112. batchId: bid,
  113. pass: true,
  114. operator: "业务",
  115. });
  116. }
  117. const personAfter = await req("GET", "/api/personnel/" + encodeURIComponent(pid));
  118. check(
  119. "居保后人员状态",
  120. personAfter.data?.bizStatus === "NORMAL" &&
  121. (personAfter.data?.insuranceMatchResult === "SUCCESS" ||
  122. personAfter.data?.insuranceMatchResult === "MANUAL_PASS"),
  123. "biz=" + personAfter.data?.bizStatus + " ins=" + personAfter.data?.insuranceMatchResult
  124. );
  125. const toLeader = await req("POST", "/api/batches/" + encodeURIComponent(bid) + "/submit-leader");
  126. check(
  127. "提交领导",
  128. toLeader.code === 200 && toLeader.data?.status === "PENDING_LEADER_APPROVE",
  129. toLeader.message + " st=" + toLeader.data?.status
  130. );
  131. const leader = await req("POST", "/api/batches/leader-approve", {
  132. bizId: bid,
  133. action: "PASS",
  134. opinion: "同意出盘",
  135. operator: "分管领导",
  136. });
  137. check("领导通过", leader.code === 200, leader.data?.status);
  138. const exp = await req("POST", "/api/payments/export-disk", {
  139. batchId: bid,
  140. bypassDeadline: true,
  141. });
  142. check("出盘", exp.code === 200, exp.data?.fileName || exp.message);
  143. const ret = await req("POST", "/api/return-disk/confirm", {
  144. batchId: bid,
  145. manualAllSuccess: true,
  146. operator: "业务",
  147. });
  148. check("回盘", ret.code === 200, ret.message);
  149. const ret2 = await req("POST", "/api/return-disk/confirm", {
  150. batchId: bid,
  151. manualAllSuccess: true,
  152. operator: "业务",
  153. });
  154. check("重复回盘拒绝", ret2.code !== 200, ret2.code + " " + ret2.message);
  155. const arch = await req("POST", "/api/dashboard/archive/" + encodeURIComponent(bid));
  156. check("归档", arch.code === 200 && arch.data?.status === "ARCHIVED", arch.message + " " + arch.data?.status);
  157. })();