weaver-work-cli 0.1.8 → 0.1.21

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 (271) hide show
  1. package/README.md +25 -17
  2. package/dist/cmd/action.js +76 -0
  3. package/dist/cmd/index.js +2 -0
  4. package/dist/cmd/refs/index.js +103 -0
  5. package/dist/cmd/register.js +31 -0
  6. package/dist/cmd/root.js +1 -0
  7. package/dist/cmd/setup/index.js +25 -5
  8. package/dist/cmd/skills/index.js +37 -5
  9. package/dist/core/connector.js +54 -0
  10. package/dist/core/context.js +2 -1
  11. package/dist/core/input.js +48 -0
  12. package/dist/core/output.js +298 -3
  13. package/dist/core/refs.js +435 -0
  14. package/dist/core/state.js +26 -0
  15. package/dist/internal/e10/auth/commands.js +34 -19
  16. package/dist/internal/e10/auth/session.js +74 -2
  17. package/dist/internal/e10/auth/xiaoe.js +359 -94
  18. package/dist/internal/e10/context.js +18 -6
  19. package/dist/internal/e10/request-runtime.js +8 -1
  20. package/dist/internal/skills/install.js +148 -28
  21. package/dist/internal/skills/reader.js +12 -9
  22. package/dist/shortcuts/blog/continuation.js +74 -0
  23. package/dist/shortcuts/blog/errors.js +60 -0
  24. package/dist/shortcuts/blog/host.js +175 -0
  25. package/dist/shortcuts/blog/index.js +324 -0
  26. package/dist/shortcuts/blog/manifest.js +415 -0
  27. package/dist/shortcuts/blog/operations/comment.js +125 -0
  28. package/dist/shortcuts/blog/operations/comments.js +31 -0
  29. package/dist/shortcuts/blog/operations/edit.js +131 -0
  30. package/dist/shortcuts/blog/operations/export.js +46 -0
  31. package/dist/shortcuts/blog/operations/like.js +80 -0
  32. package/dist/shortcuts/blog/operations/publish.js +157 -0
  33. package/dist/shortcuts/blog/operations/query-user.js +58 -0
  34. package/dist/shortcuts/blog/operations/query.js +96 -0
  35. package/dist/shortcuts/blog/operations/registry.js +54 -0
  36. package/dist/shortcuts/blog/operations/remind.js +176 -0
  37. package/dist/shortcuts/blog/operations/shared.js +330 -0
  38. package/dist/shortcuts/blog/operations/types.js +16 -0
  39. package/dist/shortcuts/blog/operations.js +9 -0
  40. package/dist/shortcuts/caizhilian/continuation.js +70 -0
  41. package/dist/shortcuts/caizhilian/errors.js +53 -0
  42. package/dist/shortcuts/caizhilian/host.js +190 -0
  43. package/dist/shortcuts/caizhilian/index.js +186 -0
  44. package/dist/shortcuts/caizhilian/manifest.js +42 -0
  45. package/dist/shortcuts/caizhilian/operations/api.js +801 -0
  46. package/dist/shortcuts/caizhilian/operations/confirm.js +75 -0
  47. package/dist/shortcuts/caizhilian/operations/files.js +306 -0
  48. package/dist/shortcuts/caizhilian/operations/form.js +170 -0
  49. package/dist/shortcuts/caizhilian/operations/handlers/collab.js +611 -0
  50. package/dist/shortcuts/caizhilian/operations/handlers/document.js +890 -0
  51. package/dist/shortcuts/caizhilian/operations/handlers/file-collection.js +1227 -0
  52. package/dist/shortcuts/caizhilian/operations/handlers/file-upload.js +192 -0
  53. package/dist/shortcuts/caizhilian/operations/handlers/fileops.js +570 -0
  54. package/dist/shortcuts/caizhilian/operations/handlers/folder.js +1024 -0
  55. package/dist/shortcuts/caizhilian/operations/handlers/search.js +318 -0
  56. package/dist/shortcuts/caizhilian/operations/handlers/setting-attach.js +294 -0
  57. package/dist/shortcuts/caizhilian/operations/handlers/setting-backup.js +423 -0
  58. package/dist/shortcuts/caizhilian/operations/handlers/setting-encrypt.js +238 -0
  59. package/dist/shortcuts/caizhilian/operations/handlers/setting-storage.js +364 -0
  60. package/dist/shortcuts/caizhilian/operations/handlers/system.js +106 -0
  61. package/dist/shortcuts/caizhilian/operations/registry.js +151 -0
  62. package/dist/shortcuts/caizhilian/operations/shared.js +408 -0
  63. package/dist/shortcuts/caizhilian/operations/specs.js +698 -0
  64. package/dist/shortcuts/caizhilian/operations/types.js +57 -0
  65. package/dist/shortcuts/caizhilian/operations.js +21 -0
  66. package/dist/shortcuts/contract/continuation.js +70 -0
  67. package/dist/shortcuts/contract/errors.js +62 -0
  68. package/dist/shortcuts/contract/host.js +205 -0
  69. package/dist/shortcuts/contract/index.js +318 -0
  70. package/dist/shortcuts/contract/manifest.js +596 -0
  71. package/dist/shortcuts/contract/operations/clause-reference.js +78 -0
  72. package/dist/shortcuts/contract/operations/form-info.js +371 -0
  73. package/dist/shortcuts/contract/operations/read.js +118 -0
  74. package/dist/shortcuts/contract/operations/registry.js +43 -0
  75. package/dist/shortcuts/contract/operations/request.js +300 -0
  76. package/dist/shortcuts/contract/operations/shared.js +133 -0
  77. package/dist/shortcuts/contract/operations/subject.js +157 -0
  78. package/dist/shortcuts/contract/operations/template.js +81 -0
  79. package/dist/shortcuts/contract/operations/types.js +7 -0
  80. package/dist/shortcuts/contract/operations/workflow.js +52 -0
  81. package/dist/shortcuts/contract/operations/write.js +131 -0
  82. package/dist/shortcuts/contract/operations.js +8 -0
  83. package/dist/shortcuts/hrm/index.js +83 -2
  84. package/dist/shortcuts/hrm/manifest.js +16 -9
  85. package/dist/shortcuts/hrm/operations/employee.js +160 -30
  86. package/dist/shortcuts/hrm/operations/org.js +17 -3
  87. package/dist/shortcuts/hrm/operations/position.js +18 -2
  88. package/dist/shortcuts/hrm/operations/registry.js +2 -0
  89. package/dist/shortcuts/hrm/operations/resolve.js +449 -0
  90. package/dist/shortcuts/index.js +5 -1
  91. package/dist/shortcuts/invoice/index.js +74 -36
  92. package/dist/shortcuts/invoice/manifest.js +674 -4
  93. package/dist/shortcuts/invoice/markdown.js +172 -0
  94. package/dist/shortcuts/invoice/operations/add.js +3 -3
  95. package/dist/shortcuts/invoice/operations/delete.js +2 -2
  96. package/dist/shortcuts/invoice/operations/get.js +10 -2
  97. package/dist/shortcuts/invoice/operations/import.js +2 -2
  98. package/dist/shortcuts/invoice/operations/registry.js +8 -1
  99. package/dist/shortcuts/invoice/operations/reim-auto.js +719 -0
  100. package/dist/shortcuts/invoice/operations/reim.js +85 -2
  101. package/dist/shortcuts/invoice/operations/shared.js +75 -8
  102. package/dist/shortcuts/invoice/operations/update.js +2 -2
  103. package/dist/shortcuts/invoice/operations/upload-and-validate.js +93 -0
  104. package/dist/shortcuts/invoice/operations/validate-preview.js +2 -1
  105. package/dist/shortcuts/invoice/projection.js +328 -0
  106. package/dist/shortcuts/meeting/host.js +18 -1
  107. package/dist/shortcuts/meeting/manifest.js +30 -18
  108. package/dist/shortcuts/meeting/operations/eb/catalog.js +390 -0
  109. package/dist/shortcuts/meeting/operations/eb/conflict.js +389 -0
  110. package/dist/shortcuts/meeting/operations/eb/factory.js +389 -0
  111. package/dist/shortcuts/meeting/operations/eb/index.js +22 -0
  112. package/dist/shortcuts/meeting/operations/env.js +8 -1
  113. package/dist/shortcuts/meeting/operations/registry.js +2 -0
  114. package/dist/shortcuts/meeting/operations/signs.js +216 -2
  115. package/dist/shortcuts/workflow/endpoints.js +2 -1
  116. package/dist/shortcuts/workflow/errors.js +8 -2
  117. package/dist/shortcuts/workflow/host.js +11 -4
  118. package/dist/shortcuts/workflow/operations/form.js +1016 -590
  119. package/dist/shortcuts/workflow/operations/read.js +913 -231
  120. package/dist/shortcuts/workflow/operations/shared.js +21 -0
  121. package/dist/shortcuts/workflow/operations/write.js +750 -52
  122. package/dist/shortcuts/workflow/operations.js +36 -10
  123. package/docs/_catalog.md +6 -0
  124. package/docs/agent-invoice.md +5 -1
  125. package/docs/agent-io-channel-design.md +468 -0
  126. package/docs/agent-skill-install.md +9 -4
  127. package/docs/blog.md +123 -0
  128. package/docs/caizhilian.md +304 -0
  129. package/docs/contract.md +91 -0
  130. package/docs/e10-auth.md +4 -2
  131. package/docs/hrm.md +53 -11
  132. package/docs/invoice.md +5 -1
  133. package/docs/meeting.md +1 -1
  134. package/docs/operation-manual.md +15 -3
  135. package/docs/skill-review-2026-09-19.md +2 -2
  136. package/package.json +1 -1
  137. package/scripts/package-skill.mjs +32 -20
  138. package/scripts/xiaoe_env.py +118 -0
  139. package/skill-template/business-info.json +113 -14
  140. package/skill-template/domains/blog.md +24 -0
  141. package/skill-template/domains/caizhilian.md +22 -0
  142. package/skill-template/domains/hrm.md +2 -1
  143. package/skill-template/domains/jinchengda.md +23 -0
  144. package/skill-template/domains/meeting.md +1 -1
  145. package/skill-template/domains/workflow.md +1 -1
  146. package/skill-template/skill-template.md +1 -1
  147. package/skills/weaver-e10-blog/SKILL.md +111 -0
  148. package/skills/weaver-e10-blog/references/blog-comment.md +51 -0
  149. package/skills/weaver-e10-blog/references/blog-comments.md +39 -0
  150. package/skills/weaver-e10-blog/references/blog-default-permission.md +38 -0
  151. package/skills/weaver-e10-blog/references/blog-disabled-capabilities.md +11 -0
  152. package/skills/weaver-e10-blog/references/blog-edit.md +51 -0
  153. package/skills/weaver-e10-blog/references/blog-export.md +42 -0
  154. package/skills/weaver-e10-blog/references/blog-like.md +50 -0
  155. package/skills/weaver-e10-blog/references/blog-publish.md +52 -0
  156. package/skills/weaver-e10-blog/references/blog-query-user.md +45 -0
  157. package/skills/weaver-e10-blog/references/blog-query.md +49 -0
  158. package/skills/weaver-e10-blog/references/blog-remind.md +51 -0
  159. package/skills/weaver-e10-blog/references/blog-resolve-users.md +38 -0
  160. package/skills/weaver-e10-blog/references/source-manifest.json +1540 -0
  161. package/skills/weaver-e10-caizhilian/SKILL.md +217 -0
  162. package/skills/weaver-e10-caizhilian/references/agent-entry.md +106 -0
  163. package/skills/weaver-e10-caizhilian/references/collaboration.md +112 -0
  164. package/skills/weaver-e10-caizhilian/references/document.md +111 -0
  165. package/skills/weaver-e10-caizhilian/references/file-collection.md +173 -0
  166. package/skills/weaver-e10-caizhilian/references/file-upload.md +309 -0
  167. package/skills/weaver-e10-caizhilian/references/files.md +120 -0
  168. package/skills/weaver-e10-caizhilian/references/folder.md +122 -0
  169. package/skills/weaver-e10-caizhilian/references/org-browser.md +104 -0
  170. package/skills/weaver-e10-caizhilian/references/setting-attach.md +440 -0
  171. package/skills/weaver-e10-caizhilian/references/setting-backup.md +372 -0
  172. package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +399 -0
  173. package/skills/weaver-e10-caizhilian/references/setting-storage.md +603 -0
  174. package/skills/weaver-e10-caizhilian/references/source-manifest.json +5694 -0
  175. package/skills/weaver-e10-caizhilian/references/withheld.md +93 -0
  176. package/skills/weaver-e10-caizhilian/references/write-protocol.md +120 -0
  177. package/skills/weaver-e10-calendar/SKILL.md +4 -3
  178. package/skills/weaver-e10-ebuilder-form/SKILL.md +4 -9
  179. package/skills/weaver-e10-ebuilder-form/references/context-routing.md +0 -9
  180. package/skills/weaver-e10-ebuilder-form/references/custom-api.md +1 -5
  181. package/skills/weaver-e10-ebuilder-form/references/fields-browser.md +1 -5
  182. package/skills/weaver-e10-ebuilder-form/references/list-nlist.md +1 -5
  183. package/skills/weaver-e10-ebuilder-form/references/openapi-read.md +1 -5
  184. package/skills/weaver-e10-ebuilder-form/references/openapi-write.md +1 -5
  185. package/skills/weaver-e10-esb/SKILL.md +2 -2
  186. package/skills/weaver-e10-esb/references/source-manifest.json +9 -9
  187. package/skills/weaver-e10-hrm/SKILL.md +104 -9
  188. package/skills/weaver-e10-hrm/references/employee.md +89 -15
  189. package/skills/weaver-e10-hrm/references/org.md +114 -5
  190. package/skills/weaver-e10-hrm/references/position.md +14 -7
  191. package/skills/weaver-e10-hrm/references/source-manifest.json +1 -1
  192. package/skills/weaver-e10-jinchengda/SKILL.md +167 -0
  193. package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +82 -0
  194. package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +69 -0
  195. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +78 -0
  196. package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +27 -0
  197. package/skills/weaver-e10-jinchengda/references/contract-request-status.md +71 -0
  198. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +94 -0
  199. package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +89 -0
  200. package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +77 -0
  201. package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +66 -0
  202. package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +94 -0
  203. package/skills/weaver-e10-jinchengda/references/source-manifest.json +259 -0
  204. package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -11
  205. package/skills/weaver-e10-jucailin/SKILL.md +4 -3
  206. package/skills/weaver-e10-mail/SKILL.md +4 -11
  207. package/skills/weaver-e10-meeting/SKILL.md +66 -32
  208. package/skills/weaver-e10-meeting/references/meeting-change.md +5 -2
  209. package/skills/weaver-e10-meeting/references/meeting-create.md +2 -1
  210. package/skills/weaver-e10-meeting/references/meeting-eb.md +114 -0
  211. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +9 -8
  212. package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +35 -7
  213. package/skills/weaver-e10-meeting/references/meeting-update.md +1 -1
  214. package/skills/weaver-e10-okr/SKILL.md +6 -11
  215. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  216. package/skills/weaver-e10-plan/SKILL.md +3 -3
  217. package/skills/weaver-e10-plan/references/plan-collect-and-compose.md +1 -1
  218. package/skills/weaver-e10-plan/references/plan-overview-and-routing.md +1 -1
  219. package/skills/weaver-e10-plan/references/source-manifest.json +13 -13
  220. package/skills/weaver-e10-qiyecheng/SKILL.md +4 -10
  221. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +9 -9
  222. package/skills/weaver-e10-shared/SKILL.md +42 -34
  223. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +16 -43
  224. package/skills/weaver-e10-shared/references/json-output-contract.md +20 -11
  225. package/skills/weaver-e10-shared/references/non-interactive-environment.md +21 -14
  226. package/skills/weaver-e10-shijingran/SKILL.md +2 -1
  227. package/skills/weaver-e10-shijingran/references/source-manifest.json +9 -9
  228. package/skills/weaver-e10-skill-maker/SKILL.md +4 -10
  229. package/skills/weaver-e10-skill-maker/references/business-skill-generation.md +5 -3
  230. package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +12 -27
  231. package/skills/weaver-e10-skill-maker/references/module-gap-audit-and-repair.md +17 -5
  232. package/skills/weaver-e10-skill-maker/references/source-update-detection.md +4 -27
  233. package/skills/weaver-e10-skill-maker/references/weaver-skill-style.md +1 -1
  234. package/skills/weaver-e10-wenshuding/SKILL.md +5 -16
  235. package/skills/weaver-e10-wenshuding/references/source-manifest.json +7 -7
  236. package/skills/weaver-e10-workflow/SKILL.md +41 -46
  237. package/skills/weaver-e10-workflow/references/source-manifest.json +39 -75
  238. package/skills/weaver-e10-workflow/references/workflow-batch.md +90 -29
  239. package/skills/weaver-e10-workflow/references/workflow-create.md +83 -109
  240. package/skills/weaver-e10-workflow/references/workflow-memory.md +19 -9
  241. package/skills/weaver-e10-workflow/references/workflow-operate.md +2 -2
  242. package/skills/weaver-e10-workflow/references/workflow-query.md +40 -27
  243. package/skills/weaver-e10-workflow/references/workflow-share.md +18 -2
  244. package/skills/weaver-e10-workflow/references/workflow-view.md +3 -4
  245. package/skills/weaver-e10-yepiaotong/SKILL.md +74 -39
  246. package/skills/weaver-e10-yepiaotong/references/invoice-detail.md +22 -1
  247. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +3 -1
  248. package/skills/weaver-e10-yepiaotong/references/invoice-output-view.md +135 -0
  249. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +15 -3
  250. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +1 -1
  251. package/skills/weaver-e10-yepiaotong/references/invoice-summarize.py +217 -0
  252. package/skills/weaver-e10-yepiaotong/references/invoice-upload-and-validate.md +88 -0
  253. package/skills/weaver-e10-yepiaotong/references/invoice-validation-preview.md +7 -2
  254. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +89 -9
  255. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +1 -0
  256. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +70 -49
  257. package/skills/weaver-e10-yepiaotong/references/reim-fast-path.md +119 -0
  258. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +55 -36
  259. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +4 -0
  260. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +149 -0
  261. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +125 -5
  262. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +430 -63
  263. package/skills/weaver-e10-yimiaoban/SKILL.md +4 -12
  264. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
  265. package/skills/weaver-e10-ziguanjia/SKILL.md +2 -1
  266. package/skills/weaver-e10-ziguanjia/references/ziguanjia-agent-entry.md +3 -3
  267. package/tools/weaver-skill-detector-1.0.13/SKILL.md +9 -9
  268. package/tools/weaver-skill-detector-1.0.13/references/checklist.md +3 -3
  269. package/tools/weaver-skill-detector-1.0.13/scripts/__pycache__/validate_skill.cpython-313.pyc +0 -0
  270. package/tools/weaver-skill-detector-1.0.13/scripts/validate_skill.py +98 -91
  271. package/scripts/sync-connector-skills.mjs +0 -172
@@ -1,5 +1,5 @@
1
1
  import { InvoiceCliError, invoiceConfirmationError, invoicePartialError, invoiceValidationError, isInvoiceNetworkError } from '../errors.js';
2
- import { asNonEmptyString, asObject, assertBusinessSuccess, normalizeIdList, objectFingerprint, sessionMatches, workflow, } from './shared.js';
2
+ import { asNonEmptyString, asObject, assertBusinessSuccess, normalizeIdList, objectFingerprint, reqBase, sessionMatches, workflow, } from './shared.js';
3
3
  function integerInput(value, name, options = {}) {
4
4
  const min = options.min ?? 1;
5
5
  const max = options.max ?? 200;
@@ -39,7 +39,7 @@ function resultEnvelope(value, workflowName) {
39
39
  };
40
40
  }
41
41
  const UNSAFE_JSON_INTEGER_ID = /("id"\s*:\s*)(-?\d{16,})(?=\s*[,}\]])/g;
42
- function quoteEmployeeIdsInJsonText(text) {
42
+ export function quoteEmployeeIdsInJsonText(text) {
43
43
  return text.replace(UNSAFE_JSON_INTEGER_ID, '$1"$2"');
44
44
  }
45
45
  function employeeIdString(value) {
@@ -244,6 +244,54 @@ export class InvoiceReimRowInfoOperation {
244
244
  return resultEnvelope(result, 'invoice.reim.row-info');
245
245
  }
246
246
  }
247
+ export class InvoiceReimRowInfoBatchOperation {
248
+ name = 'invoice.reim.row-info-batch';
249
+ async execute(input, { host }) {
250
+ const invoiceIds = normalizeIdList(input.invoiceIds, 'invoiceIds');
251
+ const session = await host.getSession();
252
+ const cdzt = optionalString(input.cdzt, 'cdzt') || session.userId;
253
+ const requestid = input.requestid === undefined ? '' : String(input.requestid);
254
+ const results = [];
255
+ const CONCURRENCY = 4;
256
+ let cursor = 0;
257
+ const workers = Array.from({ length: Math.min(CONCURRENCY, invoiceIds.length) }, async () => {
258
+ while (cursor < invoiceIds.length) {
259
+ const index = cursor;
260
+ cursor += 1;
261
+ const invoiceId = invoiceIds[index];
262
+ try {
263
+ const result = await host.invoiceFormRequest({
264
+ path: '/api/secondev/fna/expense/dataInfo/getRowInfo',
265
+ method: 'POST',
266
+ query: { sf_request_type: 'fetch' },
267
+ fields: { cdzt, requestid, invoiceId },
268
+ operation: this.name,
269
+ });
270
+ assertBusinessSuccess(result, 'reim_row_info_failed', `获取发票 ${invoiceId} 行预填失败`);
271
+ const data = result && typeof result === 'object' && 'data' in result ? result.data : result;
272
+ results[index] = { invoiceId, status: 'success', data: data };
273
+ }
274
+ catch (error) {
275
+ const message = error instanceof Error ? error.message : '未知错误';
276
+ results[index] = { invoiceId, status: 'fail', error: message };
277
+ }
278
+ }
279
+ });
280
+ await Promise.all(workers);
281
+ const succeeded = results.filter(r => r.status === 'success');
282
+ const failed = results.filter(r => r.status === 'fail');
283
+ return {
284
+ status: failed.length === results.length ? 'PARTIAL' : 'COMPLETE',
285
+ data: {
286
+ results,
287
+ succeeded: succeeded.length,
288
+ failed: failed.length,
289
+ total: results.length,
290
+ workflow: workflow('invoice.reim.row-info-batch', failed.length ? 'PARTIAL' : 'COMPLETE'),
291
+ },
292
+ };
293
+ }
294
+ }
247
295
  export class InvoiceReimEmployeeSuperiorsOperation {
248
296
  name = 'invoice.reim.employee-superiors';
249
297
  async execute(_input, { host }) {
@@ -278,6 +326,40 @@ export class InvoiceReimFlowCreatePrepareOperation {
278
326
  name = 'invoice.reim.flow.create.prepare';
279
327
  async execute(input, { host, continuation }) {
280
328
  const payload = ensureFlowCreatePayload(input);
329
+ // 挂单预检:提取 detail_rows 中的 invoiceId,查询是否已被其他报销单关联
330
+ const invoiceIds = payload.detail_rows
331
+ .map((row) => row?.invoiceId)
332
+ .filter((id) => typeof id === 'string' && id.trim() !== '');
333
+ const assignedWarnings = [];
334
+ if (invoiceIds.length > 0) {
335
+ try {
336
+ const detailResult = await host.invoiceRequest({
337
+ path: '/api/inc/get',
338
+ method: 'POST',
339
+ body: { ids: invoiceIds, mask: 0, userFlag: '1', isDelFlag: '1', req_base: reqBase() },
340
+ operation: 'invoice.reim.flow.create.prepare',
341
+ });
342
+ const infos = Array.isArray(detailResult?.infos) ? detailResult.infos : [];
343
+ for (const entry of infos) {
344
+ if (entry?.ret?.ret !== 0 || !entry.info)
345
+ continue;
346
+ const info = entry.info;
347
+ const fid = String(info.fid ?? info.id ?? '');
348
+ const number = String(info.number ?? fid);
349
+ const listReim = info?.oreim?.list_reim;
350
+ if (Array.isArray(listReim) && listReim.length > 0) {
351
+ const names = listReim
352
+ .map((r) => typeof r?.name === 'string' ? r.name : '')
353
+ .filter((n) => n.trim())
354
+ .join('、');
355
+ assignedWarnings.push(`发票 ${number} 已挂在报销单:${names || '(未知)'},继续创建可能导致重复报销`);
356
+ }
357
+ }
358
+ }
359
+ catch {
360
+ // 预检失败不阻断主流程
361
+ }
362
+ }
281
363
  const session = await host.getSession();
282
364
  const continuationToken = await continuation.issue({
283
365
  operation: 'invoice.reim.flow.create.apply',
@@ -294,6 +376,7 @@ export class InvoiceReimFlowCreatePrepareOperation {
294
376
  preview: flowPreview(payload),
295
377
  continuation: continuationToken,
296
378
  expiresInSeconds: 600,
379
+ warnings: assignedWarnings.length > 0 ? assignedWarnings : undefined,
297
380
  workflow: workflow('invoice.reim.flow.create', 'AWAITING_CONFIRMATION'),
298
381
  },
299
382
  };
@@ -312,12 +312,16 @@ export async function getDetailsByFids(fids, host) {
312
312
  body: { ids: fids, mask: 0, userFlag: '1', isDelFlag: '1', req_base: reqBase() },
313
313
  });
314
314
  }
315
- export function preview(info) {
315
+ export function invoiceDetailUrl(baseUrl, fid) {
316
+ return `${baseUrl.replace(/\/+$/, '')}/sp/inc/incDetail?fid=${fid}`;
317
+ }
318
+ export function preview(info, baseUrl) {
316
319
  const p = info.comm_info?.pro || {};
317
320
  const price = info.comm_info?.price || {};
318
321
  const rawFid = info.fid ?? info.id;
322
+ const fid = rawFid === undefined || rawFid === null ? '' : String(rawFid);
319
323
  return {
320
- fid: rawFid === undefined || rawFid === null ? '' : String(rawFid),
324
+ fid,
321
325
  code: info.code || '',
322
326
  number: info.number || '',
323
327
  date: p.date || '',
@@ -327,11 +331,12 @@ export function preview(info) {
327
331
  valid: p.valid,
328
332
  reimbursement: p.sreim,
329
333
  status: p.status,
334
+ ...(baseUrl && fid ? { detailUrl: invoiceDetailUrl(baseUrl, fid) } : {}),
330
335
  };
331
336
  }
332
- export function validationPreview(info, scope, targetFid) {
337
+ export function validationPreview(info, scope, targetFid, baseUrl) {
333
338
  const p = info?.comm_info?.pro || {};
334
- const item = preview(info);
339
+ const item = preview(info, baseUrl);
335
340
  return {
336
341
  ...item,
337
342
  fid: targetFid,
@@ -341,6 +346,7 @@ export function validationPreview(info, scope, targetFid) {
341
346
  validation: p.valid,
342
347
  invoiceStatus: p.status,
343
348
  saved: false,
349
+ ...(baseUrl && targetFid ? { detailUrl: invoiceDetailUrl(baseUrl, targetFid) } : {}),
344
350
  };
345
351
  }
346
352
  export function workflow(name, state) {
@@ -751,13 +757,20 @@ export async function listInvoices(input, host, flag) {
751
757
  continue;
752
758
  if (!LIST_FIELDS.has(key))
753
759
  throw invoiceValidationError('input_field_unsupported', `列表查询不支持字段:${key}`);
754
- body[key] = key === 'sreim' ? normalizeSreim(value) : value;
760
+ body[key] = normalizeListField(key, value);
755
761
  }
762
+ const session = await host.getSession();
756
763
  const result = await host.invoiceRequest({ path: '/api/inc/sync', method: 'POST', body });
764
+ const items = (result.infos || []).map((item) => {
765
+ const fid = item?.fid ?? item?.id;
766
+ if (fid)
767
+ item.detailUrl = invoiceDetailUrl(session.baseUrl, String(fid));
768
+ return item;
769
+ });
757
770
  return {
758
771
  status: 'COMPLETE',
759
772
  data: {
760
- items: result.infos || [],
773
+ items,
761
774
  total: result.total ?? 0,
762
775
  totalAmount: result.totalTn ?? '0',
763
776
  totalAmountExcludingTax: result.totalAm ?? '0',
@@ -766,6 +779,60 @@ export async function listInvoices(input, host, flag) {
766
779
  },
767
780
  };
768
781
  }
782
+ /** 列表查询里 E10 只接受秒级 epoch 的时间字段(契约声明为 integer)。 */
783
+ const EPOCH_FIELDS = new Set(['date_begin', 'date_end', 'create_tm_begin', 'create_tm_end']);
784
+ /** 列表查询里契约声明为 integer 的标量字段。 */
785
+ const INTEGER_FIELDS = new Set(['page_size', 'start_pos', 'req_type', 'mask', 'mext']);
786
+ /**
787
+ * 把日期入参归一成 E10 需要的秒级 epoch。
788
+ * 同时接受 `YYYY-MM-DD`(按东八区零点换算,与 `invoice.reim.candidates.list` 一致)和已是秒级 epoch 的数字/数字串,
789
+ * 避免把字符串日期原样透传给 `/api/inc/sync` 后被打成不透明的 400 系统错误。
790
+ */
791
+ export function epochSeconds(value, name) {
792
+ if (typeof value === 'number') {
793
+ if (Number.isInteger(value) && value >= 0)
794
+ return value;
795
+ throw invoiceValidationError('input_invalid', `${name} 必须是 YYYY-MM-DD 或秒级时间戳`);
796
+ }
797
+ const text = typeof value === 'string' ? value.trim() : '';
798
+ if (DATE_PATTERN.test(text)) {
799
+ const seconds = Math.floor(Date.parse(`${text}T00:00:00+08:00`) / 1000);
800
+ if (!Number.isFinite(seconds))
801
+ throw invoiceValidationError('input_invalid', `${name} 不是有效日期`);
802
+ return seconds;
803
+ }
804
+ if (/^\d+$/u.test(text)) {
805
+ const seconds = Number(text);
806
+ if (Number.isSafeInteger(seconds))
807
+ return seconds;
808
+ }
809
+ throw invoiceValidationError('input_invalid', `${name} 必须是 YYYY-MM-DD 或秒级时间戳`);
810
+ }
811
+ /** `epochSeconds` 的可选版本:undefined / null / 空串 一律视为未传。 */
812
+ export function optionalEpochSeconds(value, name) {
813
+ if (value === undefined || value === null || value === '')
814
+ return undefined;
815
+ return epochSeconds(value, name);
816
+ }
817
+ /** 列表查询的整数标量归一:数字串转数字,非法值就地报 input_invalid 而不是透传到 E10 变成 400。 */
818
+ function listInteger(key, value) {
819
+ const parsed = typeof value === 'number'
820
+ ? value
821
+ : (typeof value === 'string' && /^\d+$/u.test(value.trim()) ? Number(value.trim()) : Number.NaN);
822
+ if (!Number.isInteger(parsed) || parsed < 0) {
823
+ throw invoiceValidationError('input_invalid', `${key} 必须是非负整数`);
824
+ }
825
+ return parsed;
826
+ }
827
+ function normalizeListField(key, value) {
828
+ if (key === 'sreim')
829
+ return normalizeSreim(value);
830
+ if (EPOCH_FIELDS.has(key))
831
+ return epochSeconds(value, key);
832
+ if (INTEGER_FIELDS.has(key))
833
+ return listInteger(key, value);
834
+ return value;
835
+ }
769
836
  function normalizeSreim(value) {
770
837
  const normalized = typeof value === 'number' && Number.isInteger(value) ? String(value) : value;
771
838
  if (typeof normalized !== 'string' || !/^[0-4]$/u.test(normalized)) {
@@ -833,8 +900,8 @@ export async function assertNotDuplicate(info, host) {
833
900
  throw error;
834
901
  }
835
902
  }
836
- export function addPreview(info, scope) {
837
- return { ...preview(info), type: info.comm_info?.pro?.type, scope };
903
+ export function addPreview(info, scope, baseUrl) {
904
+ return { ...preview(info, baseUrl), type: info.comm_info?.pro?.type, scope };
838
905
  }
839
906
  function getPath(value, fieldPath) {
840
907
  return fieldPath.split('.').reduce((current, key) => current?.[key], value);
@@ -22,11 +22,11 @@ export class InvoiceUpdatePrepareOperation {
22
22
  scope,
23
23
  fingerprint: objectFingerprint(info),
24
24
  changes: effectiveChanges,
25
- preview: preview(info),
25
+ preview: preview(info, session.baseUrl),
26
26
  });
27
27
  return {
28
28
  status: 'AWAITING_CONFIRMATION',
29
- data: { invoice: preview(info), changes: diffs, continuation: continuationToken, expiresInSeconds: 600, workflow: workflow('invoice.update', 'AWAITING_CONFIRMATION') },
29
+ data: { invoice: preview(info, session.baseUrl), changes: diffs, continuation: continuationToken, expiresInSeconds: 600, workflow: workflow('invoice.update', 'AWAITING_CONFIRMATION') },
30
30
  };
31
31
  }
32
32
  }
@@ -0,0 +1,93 @@
1
+ import { InvoiceCliError } from '../errors.js';
2
+ import { toErrorEnvelope } from '../../../core/errors.js';
3
+ import { detailInfo, getDetail, identityFingerprint, normalizeScope, operateType, previewOcr, reqBase, uploadInvoiceFile, validationPreview, workflow, } from './shared.js';
4
+ /**
5
+ * 一站式:上传附件 → OCR 识别 → 查验,合并为单条命令。
6
+ *
7
+ * 输入:file / url + scope
8
+ * 输出:upload 对象 + OCR 识别结果 + 查验结果(每张发票)
9
+ */
10
+ export class InvoiceUploadAndValidateOperation {
11
+ name = 'invoice.upload-and-validate';
12
+ async execute(input, { host }) {
13
+ const scope = normalizeScope(input.scope);
14
+ const session = await host.getSession();
15
+ // ── Step 1: 上传 ──
16
+ let upload;
17
+ try {
18
+ upload = await uploadInvoiceFile(input, host, { ocr: true });
19
+ }
20
+ catch (error) {
21
+ throw new InvoiceCliError('api', 'upload_failed', `上传失败:${error.message}`, {
22
+ details: { stage: 'upload' },
23
+ exitCode: 1,
24
+ });
25
+ }
26
+ // ── Step 2: OCR 识别 ──
27
+ let ocr;
28
+ try {
29
+ ocr = await previewOcr(upload, host);
30
+ }
31
+ catch (error) {
32
+ const cause = toErrorEnvelope(error);
33
+ throw new InvoiceCliError('partial', 'artifact_uploaded', `文件已上传但 OCR 失败:${cause.message}`, {
34
+ code: cause.code,
35
+ partialData: { upload, workflow: workflow(this.name, 'OCR_FAILED') },
36
+ details: { stage: 'ocr', cause },
37
+ exitCode: 11,
38
+ });
39
+ }
40
+ // ── Step 3: 逐张查验 ──
41
+ const validations = [];
42
+ const validationErrors = [];
43
+ for (const item of ocr.invoices) {
44
+ const info = item?.info;
45
+ const fid = info?.fid ?? info?.id;
46
+ if (!fid) {
47
+ validationErrors.push({ fid: null, error: 'OCR 结果中缺少 fid' });
48
+ continue;
49
+ }
50
+ try {
51
+ const detail = await getDetail({ fid: String(fid) }, host);
52
+ const detailData = detailInfo(detail);
53
+ const result = await host.invoiceRequest({
54
+ path: '/api/inc/valid',
55
+ method: 'POST',
56
+ body: {
57
+ info: detailData,
58
+ flag: 100,
59
+ is_cut: 0,
60
+ is_save: 1,
61
+ operate_type: operateType(scope),
62
+ needLog: true,
63
+ req_base: reqBase({ numericTrace: true }),
64
+ },
65
+ });
66
+ if (!result?.info) {
67
+ validationErrors.push({ fid: String(fid), error: '查验接口未返回发票信息' });
68
+ continue;
69
+ }
70
+ if (identityFingerprint(result.info) !== identityFingerprint(detailData)) {
71
+ validationErrors.push({ fid: String(fid), error: '查验返回的票面身份字段与目标发票不一致' });
72
+ continue;
73
+ }
74
+ validations.push(validationPreview(result.info, scope, String(fid), session.baseUrl));
75
+ }
76
+ catch (error) {
77
+ validationErrors.push({ fid: String(fid), error: error.message });
78
+ }
79
+ }
80
+ return {
81
+ status: 'COMPLETE',
82
+ data: {
83
+ upload,
84
+ ocrCount: ocr.invoices.length,
85
+ invoices: ocr.invoices,
86
+ validations,
87
+ validationErrors,
88
+ results: ocr.results,
89
+ workflow: workflow(this.name, 'COMPLETE'),
90
+ },
91
+ };
92
+ }
93
+ }
@@ -4,6 +4,7 @@ export class InvoiceValidatePreviewOperation {
4
4
  name = 'invoice.validate.preview';
5
5
  async execute(input, { host }) {
6
6
  const scope = normalizeScope(input.scope);
7
+ const session = await host.getSession();
7
8
  const detail = await getDetail({ fid: input.fid }, host);
8
9
  const info = detailInfo(detail);
9
10
  const result = await host.invoiceRequest({
@@ -28,7 +29,7 @@ export class InvoiceValidatePreviewOperation {
28
29
  return {
29
30
  status: 'COMPLETE',
30
31
  data: {
31
- preview: validationPreview(result.info, scope, input.fid),
32
+ preview: validationPreview(result.info, scope, input.fid, session.baseUrl),
32
33
  info: result.info,
33
34
  saved: false,
34
35
  result,