@stalfh233/omc-fake-platform 0.4.88 → 0.4.91

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.
Files changed (2) hide show
  1. package/dist/workflow.js +37 -18
  2. package/package.json +2 -2
package/dist/workflow.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { businessRefusal, malformedEnvelope, NOT_HANDLED } from "./state.js";
2
- const PENDING_STATES = new Set(["NOTSTARTED", "INPROGRESS"]);
2
+ // DRAFT: a portal draft-save start item is state DRAFT (live r15 readback) and
3
+ // still appears in the caller's todo face until submitted.
4
+ const PENDING_STATES = new Set(["NOTSTARTED", "INPROGRESS", "DRAFT"]);
3
5
  const ACTIVITY_TYPES = new Set(["START", "END", "CONNECTION", "PARTICIPANT", "SUB_INSTANCE", "CIRCULATE", "SYSTEM_ACTIVITY", "AGENT_ACTIVITY"]);
4
6
  const POINT = /^-?\d+(?:\.\d+)?,\s-?\d+(?:\.\d+)?$/;
5
7
  /**
@@ -102,13 +104,25 @@ export function startWorkflowDraft(state, input) {
102
104
  const sequence = state.workItems.size + 1;
103
105
  const instanceId = `wf-${sequence}`;
104
106
  const startId = `wi-${sequence}`;
107
+ // Live 1.1.25: saveWorkflow creates a DRAFT instance row plus a DRAFT start
108
+ // work item (read back from biz_workflow_instance/biz_workitem on the r15
109
+ // scratch model). The DRAFT state is load-bearing: the instance-list endpoint
110
+ // hides DRAFT rows (see the route above), so a purge that only reads that list
111
+ // misses exactly this case.
112
+ state.workflowInstances.set(instanceId, {
113
+ id: instanceId,
114
+ workflowCode: input.workflowCode,
115
+ schemaCode: input.schemaCode,
116
+ bizObjectId: input.bizObjectId,
117
+ status: "DRAFT",
118
+ });
105
119
  state.workItems.set(startId, {
106
120
  id: startId,
107
121
  instanceId,
108
122
  activityCode: "fill",
109
123
  activityName: "填写申请单",
110
124
  participant: "tester",
111
- state: "INPROGRESS",
125
+ state: "DRAFT",
112
126
  workflowCode: input.workflowCode,
113
127
  schemaCode: input.schemaCode,
114
128
  bizObjectId: input.bizObjectId,
@@ -376,7 +390,12 @@ export const workflowRoute = (ctx, input) => {
376
390
  // WorkflowInstanceController.list_instances — the instance list a purge
377
391
  // must empty before the model cascade can run (r14: a surviving instance's
378
392
  // work item outlives its template and NPEs the global todo search).
379
- let rows = [...ctx.state.workflowInstances.values()];
393
+ //
394
+ // Live-faithful detail (r15, decompiled 8.6.26): the controller always
395
+ // sets currentUserId, and BizWorkflowinstanceServiceImpl adds
396
+ // `state != DRAFT` for any non-empty user — so DRAFT instances are NEVER
397
+ // in this list. A purge must find them through their work items.
398
+ let rows = [...ctx.state.workflowInstances.values()].filter((row) => String(row.status ?? "").toUpperCase() !== "DRAFT");
380
399
  if (q.workflowCode)
381
400
  rows = rows.filter((row) => row.workflowCode === q.workflowCode);
382
401
  const size = Number(q.size ?? 10);
@@ -395,6 +414,13 @@ export const workflowRoute = (ctx, input) => {
395
414
  const id = String(q.workflowInstanceId ?? "");
396
415
  if (!id)
397
416
  return businessRefusal(40000, "流程实例id为空");
417
+ const instance = ctx.state.workflowInstances.get(id);
418
+ // Live 1.1.25 (r15): deleting an instance whose business row is already
419
+ // gone makes the engine NPE while rendering the "workflow removed"
420
+ // notice (`bizObject should not be null`) → 50000, and the instance row
421
+ // stays. Mirror it so purge's stale-instance path is exercised offline.
422
+ if (instance && !ctx.state.dataRows.has(String(instance.bizObjectId ?? "")))
423
+ return businessRefusal(50000, "服务异常");
398
424
  const existed = ctx.state.workflowInstances.delete(id);
399
425
  return existed;
400
426
  }
@@ -432,8 +458,9 @@ export const workflowRoute = (ctx, input) => {
432
458
  { id: "role-finance", name: "财务负责人", code: "SYS260515031207258", roleType: "SYS", corpId: "corp-1" },
433
459
  ];
434
460
  case "/api/api/organization/department/tree": {
435
- // Platform semantics (1.1.25): no deptIds → roots; deptIds=<id> → that
436
- // department's WHOLE SUBTREE, not one level.
461
+ // Platform semantics (re-verified r15, 1.1.25): no deptIds → roots ONLY;
462
+ // deptIds=<id> → DIRECT CHILDREN only. The old "whole subtree" fake made
463
+ // the one-level walker look correct, hiding third-level departments.
437
464
  const all = [
438
465
  { id: "dept-1", name: "总所", code: "1", corpId: "corp-1", parentId: null },
439
466
  { id: "dept-2", name: "业务部", code: "1_1", corpId: "corp-1", parentId: "dept-1" },
@@ -442,18 +469,7 @@ export const workflowRoute = (ctx, input) => {
442
469
  const requested = String(q.deptIds ?? "");
443
470
  if (requested === "")
444
471
  return { departmentList: all.filter((dept) => dept.parentId === null) };
445
- const subtree = [];
446
- const queue = [requested];
447
- while (queue.length > 0) {
448
- const current = queue.shift();
449
- for (const dept of all) {
450
- if (dept.parentId !== current || subtree.some((seen) => seen.id === dept.id))
451
- continue;
452
- subtree.push(dept);
453
- queue.push(dept.id);
454
- }
455
- }
456
- return { departmentList: subtree };
472
+ return { departmentList: all.filter((dept) => dept.parentId === requested) };
457
473
  }
458
474
  case "/api/api/organization/user/search": {
459
475
  // UserController.search: @RequestBody {wd,page,size} → PageVO<UserVO>.
@@ -671,7 +687,10 @@ export const workflowRoute = (ctx, input) => {
671
687
  const members = [...ctx.state.orgMembers.values()].filter((member) => member.roleId === roleId);
672
688
  const page = Number(q.page ?? 0);
673
689
  const size = Number(q.size ?? 500);
674
- return { totalElements: members.length, totalPages: size > 0 ? Math.ceil(members.length / size) : 0, content: members.slice(page * size, page * size + size).map((member) => ({ id: member.userId, name: member.name, unitType: member.unitType, departmentId: "dept-1" })) };
690
+ // Live 1.1.25 row: departmentId is null, the department rides
691
+ // parentDepartmentName[0].deptId, and ouScope is what role-participant
692
+ // resolution filters on (r15).
693
+ return { totalElements: members.length, totalPages: size > 0 ? Math.ceil(members.length / size) : 0, content: members.slice(page * size, page * size + size).map((member) => ({ id: member.userId, name: member.name, unitType: member.unitType, departmentId: null, departmentName: "总所", parentDepartmentName: [{ deptId: "dept-1", deptPath: "总所", deptName: "总所" }], ouScope: member.ouScope })) };
675
694
  }
676
695
  case "/api/api/organization/role/get_ouscope": {
677
696
  const member = ctx.state.orgMembers.get(`${String(q.roleId ?? "")}#${String(q.userId ?? "")}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stalfh233/omc-fake-platform",
3
- "version": "0.4.88",
3
+ "version": "0.4.91",
4
4
  "description": "OMC 的内存假 CloudPivot 平台(wire 接缝的第二个适配器)+ HTTP 假服务器——@stalfh233/omc-cli 的测试与 bench 基准基座",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,7 +18,7 @@
18
18
  "build": "tsc --project tsconfig.build.json"
19
19
  },
20
20
  "dependencies": {
21
- "omc-core": "0.4.88"
21
+ "omc-core": "0.4.91"
22
22
  },
23
23
  "engines": {
24
24
  "node": ">=22.13"