weaver-work-cli 0.1.8 → 0.1.20
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.
- package/README.md +11 -11
- package/dist/cmd/action.js +76 -0
- package/dist/cmd/index.js +2 -0
- package/dist/cmd/refs/index.js +103 -0
- package/dist/cmd/register.js +31 -0
- package/dist/cmd/root.js +1 -0
- package/dist/cmd/setup/index.js +25 -5
- package/dist/cmd/skills/index.js +37 -5
- package/dist/core/connector.js +54 -0
- package/dist/core/context.js +2 -1
- package/dist/core/input.js +48 -0
- package/dist/core/output.js +298 -3
- package/dist/core/refs.js +432 -0
- package/dist/core/state.js +26 -0
- package/dist/internal/e10/auth/commands.js +2 -2
- package/dist/internal/e10/auth/session.js +14 -0
- package/dist/internal/e10/auth/xiaoe.js +116 -51
- package/dist/internal/e10/request-runtime.js +5 -0
- package/dist/internal/skills/install.js +148 -28
- package/dist/internal/skills/reader.js +12 -9
- package/dist/shortcuts/blog/continuation.js +74 -0
- package/dist/shortcuts/blog/errors.js +60 -0
- package/dist/shortcuts/blog/host.js +175 -0
- package/dist/shortcuts/blog/index.js +324 -0
- package/dist/shortcuts/blog/manifest.js +415 -0
- package/dist/shortcuts/blog/operations/comment.js +125 -0
- package/dist/shortcuts/blog/operations/comments.js +31 -0
- package/dist/shortcuts/blog/operations/edit.js +131 -0
- package/dist/shortcuts/blog/operations/export.js +46 -0
- package/dist/shortcuts/blog/operations/like.js +80 -0
- package/dist/shortcuts/blog/operations/publish.js +157 -0
- package/dist/shortcuts/blog/operations/query-user.js +58 -0
- package/dist/shortcuts/blog/operations/query.js +96 -0
- package/dist/shortcuts/blog/operations/registry.js +54 -0
- package/dist/shortcuts/blog/operations/remind.js +176 -0
- package/dist/shortcuts/blog/operations/shared.js +330 -0
- package/dist/shortcuts/blog/operations/types.js +16 -0
- package/dist/shortcuts/blog/operations.js +9 -0
- package/dist/shortcuts/caizhilian/continuation.js +70 -0
- package/dist/shortcuts/caizhilian/errors.js +53 -0
- package/dist/shortcuts/caizhilian/host.js +190 -0
- package/dist/shortcuts/caizhilian/index.js +186 -0
- package/dist/shortcuts/caizhilian/manifest.js +42 -0
- package/dist/shortcuts/caizhilian/operations/api.js +801 -0
- package/dist/shortcuts/caizhilian/operations/confirm.js +75 -0
- package/dist/shortcuts/caizhilian/operations/files.js +306 -0
- package/dist/shortcuts/caizhilian/operations/form.js +170 -0
- package/dist/shortcuts/caizhilian/operations/handlers/collab.js +611 -0
- package/dist/shortcuts/caizhilian/operations/handlers/document.js +890 -0
- package/dist/shortcuts/caizhilian/operations/handlers/file-collection.js +346 -0
- package/dist/shortcuts/caizhilian/operations/handlers/file-upload.js +192 -0
- package/dist/shortcuts/caizhilian/operations/handlers/fileops.js +570 -0
- package/dist/shortcuts/caizhilian/operations/handlers/folder.js +969 -0
- package/dist/shortcuts/caizhilian/operations/handlers/search.js +318 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-attach.js +294 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-backup.js +423 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-encrypt.js +238 -0
- package/dist/shortcuts/caizhilian/operations/handlers/setting-storage.js +364 -0
- package/dist/shortcuts/caizhilian/operations/handlers/system.js +106 -0
- package/dist/shortcuts/caizhilian/operations/registry.js +151 -0
- package/dist/shortcuts/caizhilian/operations/shared.js +408 -0
- package/dist/shortcuts/caizhilian/operations/specs.js +623 -0
- package/dist/shortcuts/caizhilian/operations/types.js +57 -0
- package/dist/shortcuts/caizhilian/operations.js +21 -0
- package/dist/shortcuts/contract/continuation.js +70 -0
- package/dist/shortcuts/contract/errors.js +62 -0
- package/dist/shortcuts/contract/host.js +205 -0
- package/dist/shortcuts/contract/index.js +318 -0
- package/dist/shortcuts/contract/manifest.js +596 -0
- package/dist/shortcuts/contract/operations/clause-reference.js +78 -0
- package/dist/shortcuts/contract/operations/form-info.js +371 -0
- package/dist/shortcuts/contract/operations/read.js +118 -0
- package/dist/shortcuts/contract/operations/registry.js +43 -0
- package/dist/shortcuts/contract/operations/request.js +300 -0
- package/dist/shortcuts/contract/operations/shared.js +133 -0
- package/dist/shortcuts/contract/operations/subject.js +157 -0
- package/dist/shortcuts/contract/operations/template.js +81 -0
- package/dist/shortcuts/contract/operations/types.js +7 -0
- package/dist/shortcuts/contract/operations/workflow.js +52 -0
- package/dist/shortcuts/contract/operations/write.js +131 -0
- package/dist/shortcuts/contract/operations.js +8 -0
- package/dist/shortcuts/hrm/index.js +83 -2
- package/dist/shortcuts/hrm/operations/employee.js +160 -30
- package/dist/shortcuts/hrm/operations/org.js +17 -3
- package/dist/shortcuts/hrm/operations/position.js +18 -2
- package/dist/shortcuts/index.js +5 -1
- package/dist/shortcuts/invoice/index.js +74 -36
- package/dist/shortcuts/invoice/manifest.js +674 -4
- package/dist/shortcuts/invoice/markdown.js +172 -0
- package/dist/shortcuts/invoice/operations/add.js +3 -3
- package/dist/shortcuts/invoice/operations/delete.js +2 -2
- package/dist/shortcuts/invoice/operations/get.js +10 -2
- package/dist/shortcuts/invoice/operations/import.js +2 -2
- package/dist/shortcuts/invoice/operations/registry.js +8 -1
- package/dist/shortcuts/invoice/operations/reim-auto.js +719 -0
- package/dist/shortcuts/invoice/operations/reim.js +85 -2
- package/dist/shortcuts/invoice/operations/shared.js +75 -8
- package/dist/shortcuts/invoice/operations/update.js +2 -2
- package/dist/shortcuts/invoice/operations/upload-and-validate.js +93 -0
- package/dist/shortcuts/invoice/operations/validate-preview.js +2 -1
- package/dist/shortcuts/invoice/projection.js +328 -0
- package/dist/shortcuts/meeting/host.js +18 -1
- package/dist/shortcuts/meeting/manifest.js +30 -18
- package/dist/shortcuts/meeting/operations/eb/catalog.js +390 -0
- package/dist/shortcuts/meeting/operations/eb/conflict.js +389 -0
- package/dist/shortcuts/meeting/operations/eb/factory.js +389 -0
- package/dist/shortcuts/meeting/operations/eb/index.js +22 -0
- package/dist/shortcuts/meeting/operations/env.js +8 -1
- package/dist/shortcuts/meeting/operations/registry.js +2 -0
- package/dist/shortcuts/meeting/operations/signs.js +216 -2
- package/dist/shortcuts/workflow/endpoints.js +2 -1
- package/dist/shortcuts/workflow/errors.js +8 -2
- package/dist/shortcuts/workflow/host.js +6 -3
- package/dist/shortcuts/workflow/operations/form.js +931 -589
- package/dist/shortcuts/workflow/operations/read.js +128 -205
- package/dist/shortcuts/workflow/operations/shared.js +21 -0
- package/dist/shortcuts/workflow/operations/write.js +750 -52
- package/dist/shortcuts/workflow/operations.js +36 -10
- package/docs/_catalog.md +6 -0
- package/docs/agent-invoice.md +5 -1
- package/docs/agent-io-channel-design.md +468 -0
- package/docs/agent-skill-install.md +9 -4
- package/docs/blog.md +123 -0
- package/docs/caizhilian.md +304 -0
- package/docs/contract.md +91 -0
- package/docs/e10-auth.md +2 -2
- package/docs/hrm.md +19 -9
- package/docs/invoice.md +5 -1
- package/docs/meeting.md +1 -1
- package/docs/operation-manual.md +15 -3
- package/docs/skill-review-2026-09-19.md +2 -2
- package/package.json +2 -2
- package/scripts/package-skill.mjs +32 -20
- package/skill-template/business-info.json +113 -14
- package/skill-template/domains/blog.md +24 -0
- package/skill-template/domains/caizhilian.md +22 -0
- package/skill-template/domains/jinchengda.md +23 -0
- package/skill-template/domains/meeting.md +1 -1
- package/skill-template/domains/workflow.md +1 -1
- package/skill-template/skill-template.md +1 -1
- package/skills/weaver-e10-blog/SKILL.md +111 -0
- package/skills/weaver-e10-blog/references/blog-comment.md +51 -0
- package/skills/weaver-e10-blog/references/blog-comments.md +39 -0
- package/skills/weaver-e10-blog/references/blog-default-permission.md +38 -0
- package/skills/weaver-e10-blog/references/blog-disabled-capabilities.md +11 -0
- package/skills/weaver-e10-blog/references/blog-edit.md +51 -0
- package/skills/weaver-e10-blog/references/blog-export.md +42 -0
- package/skills/weaver-e10-blog/references/blog-like.md +50 -0
- package/skills/weaver-e10-blog/references/blog-publish.md +52 -0
- package/skills/weaver-e10-blog/references/blog-query-user.md +45 -0
- package/skills/weaver-e10-blog/references/blog-query.md +49 -0
- package/skills/weaver-e10-blog/references/blog-remind.md +51 -0
- package/skills/weaver-e10-blog/references/blog-resolve-users.md +38 -0
- package/skills/weaver-e10-blog/references/source-manifest.json +1540 -0
- package/skills/weaver-e10-caizhilian/SKILL.md +216 -0
- package/skills/weaver-e10-caizhilian/references/agent-entry.md +106 -0
- package/skills/weaver-e10-caizhilian/references/collaboration.md +112 -0
- package/skills/weaver-e10-caizhilian/references/document.md +111 -0
- package/skills/weaver-e10-caizhilian/references/file-collection.md +136 -0
- package/skills/weaver-e10-caizhilian/references/file-upload.md +309 -0
- package/skills/weaver-e10-caizhilian/references/files.md +120 -0
- package/skills/weaver-e10-caizhilian/references/folder.md +118 -0
- package/skills/weaver-e10-caizhilian/references/org-browser.md +104 -0
- package/skills/weaver-e10-caizhilian/references/setting-attach.md +410 -0
- package/skills/weaver-e10-caizhilian/references/setting-backup.md +372 -0
- package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +399 -0
- package/skills/weaver-e10-caizhilian/references/setting-storage.md +603 -0
- package/skills/weaver-e10-caizhilian/references/source-manifest.json +5079 -0
- package/skills/weaver-e10-caizhilian/references/withheld.md +93 -0
- package/skills/weaver-e10-caizhilian/references/write-protocol.md +120 -0
- package/skills/weaver-e10-calendar/SKILL.md +4 -3
- package/skills/weaver-e10-ebuilder-form/SKILL.md +4 -9
- package/skills/weaver-e10-ebuilder-form/references/context-routing.md +0 -9
- package/skills/weaver-e10-ebuilder-form/references/custom-api.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/fields-browser.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/list-nlist.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/openapi-read.md +1 -5
- package/skills/weaver-e10-ebuilder-form/references/openapi-write.md +1 -5
- package/skills/weaver-e10-esb/SKILL.md +2 -2
- package/skills/weaver-e10-esb/references/source-manifest.json +9 -9
- package/skills/weaver-e10-hrm/SKILL.md +54 -6
- package/skills/weaver-e10-hrm/references/employee.md +89 -15
- package/skills/weaver-e10-hrm/references/org.md +7 -4
- package/skills/weaver-e10-hrm/references/position.md +14 -7
- package/skills/weaver-e10-hrm/references/source-manifest.json +1 -1
- package/skills/weaver-e10-jinchengda/SKILL.md +166 -0
- package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +82 -0
- package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +69 -0
- package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +78 -0
- package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +27 -0
- package/skills/weaver-e10-jinchengda/references/contract-request-status.md +71 -0
- package/skills/weaver-e10-jinchengda/references/contract-request-write.md +94 -0
- package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +89 -0
- package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +77 -0
- package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +66 -0
- package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +94 -0
- package/skills/weaver-e10-jinchengda/references/source-manifest.json +259 -0
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -11
- package/skills/weaver-e10-jucailin/SKILL.md +4 -3
- package/skills/weaver-e10-mail/SKILL.md +4 -11
- package/skills/weaver-e10-meeting/SKILL.md +66 -32
- package/skills/weaver-e10-meeting/references/meeting-change.md +5 -2
- package/skills/weaver-e10-meeting/references/meeting-create.md +2 -1
- package/skills/weaver-e10-meeting/references/meeting-eb.md +114 -0
- package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +9 -8
- package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +35 -7
- package/skills/weaver-e10-meeting/references/meeting-update.md +1 -1
- package/skills/weaver-e10-okr/SKILL.md +6 -11
- package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
- package/skills/weaver-e10-plan/SKILL.md +3 -3
- package/skills/weaver-e10-plan/references/plan-collect-and-compose.md +1 -1
- package/skills/weaver-e10-plan/references/plan-overview-and-routing.md +1 -1
- package/skills/weaver-e10-plan/references/source-manifest.json +13 -13
- package/skills/weaver-e10-qiyecheng/SKILL.md +4 -10
- package/skills/weaver-e10-qiyecheng/references/source-manifest.json +9 -9
- package/skills/weaver-e10-shared/SKILL.md +36 -25
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +10 -31
- package/skills/weaver-e10-shared/references/json-output-contract.md +20 -11
- package/skills/weaver-e10-shijingran/SKILL.md +2 -1
- package/skills/weaver-e10-shijingran/references/source-manifest.json +9 -9
- package/skills/weaver-e10-skill-maker/SKILL.md +4 -10
- package/skills/weaver-e10-skill-maker/references/business-skill-generation.md +5 -3
- package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +12 -27
- package/skills/weaver-e10-skill-maker/references/module-gap-audit-and-repair.md +17 -5
- package/skills/weaver-e10-skill-maker/references/source-update-detection.md +4 -27
- package/skills/weaver-e10-wenshuding/SKILL.md +5 -16
- package/skills/weaver-e10-wenshuding/references/source-manifest.json +7 -7
- package/skills/weaver-e10-workflow/SKILL.md +32 -37
- package/skills/weaver-e10-workflow/references/source-manifest.json +39 -75
- package/skills/weaver-e10-workflow/references/workflow-batch.md +90 -29
- package/skills/weaver-e10-workflow/references/workflow-create.md +79 -109
- package/skills/weaver-e10-workflow/references/workflow-memory.md +19 -9
- package/skills/weaver-e10-workflow/references/workflow-operate.md +2 -2
- package/skills/weaver-e10-workflow/references/workflow-query.md +38 -20
- package/skills/weaver-e10-workflow/references/workflow-share.md +18 -2
- package/skills/weaver-e10-workflow/references/workflow-view.md +3 -4
- package/skills/weaver-e10-yepiaotong/SKILL.md +75 -39
- package/skills/weaver-e10-yepiaotong/references/invoice-detail.md +22 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +3 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-output-view.md +135 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +15 -3
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +1 -1
- package/skills/weaver-e10-yepiaotong/references/invoice-summarize.py +217 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-upload-and-validate.md +88 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-validation-preview.md +7 -2
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +89 -9
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +1 -0
- package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +70 -49
- package/skills/weaver-e10-yepiaotong/references/reim-fast-path.md +119 -0
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +55 -36
- package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +4 -0
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +149 -0
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +125 -5
- package/skills/weaver-e10-yepiaotong/references/source-manifest.json +430 -63
- package/skills/weaver-e10-yimiaoban/SKILL.md +4 -12
- package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
- package/skills/weaver-e10-ziguanjia/SKILL.md +2 -1
- package/skills/weaver-e10-ziguanjia/references/ziguanjia-agent-entry.md +3 -3
- package/tools/weaver-skill-detector-1.0.13/SKILL.md +9 -9
- package/tools/weaver-skill-detector-1.0.13/references/checklist.md +3 -3
- package/tools/weaver-skill-detector-1.0.13/scripts/__pycache__/validate_skill.cpython-313.pyc +0 -0
- package/tools/weaver-skill-detector-1.0.13/scripts/validate_skill.py +98 -91
- 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
|
|
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
|
|
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
|
|
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
|
|
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,
|