weaver-work-cli 0.1.26 → 0.1.29
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 +7 -2
- package/dist/cmd/setup/index.js +1 -1
- package/dist/internal/e10/auth/commands.js +1 -6
- package/dist/internal/e10/auth/messages.js +3 -0
- package/dist/internal/e10/auth/session.js +8 -0
- package/dist/internal/e10/auth-recovery.js +148 -0
- package/dist/internal/e10/client.js +47 -15
- package/dist/internal/e10/context.js +8 -8
- package/dist/internal/e10/index.js +1 -0
- package/dist/internal/e10/request-runtime.js +51 -9
- package/dist/shortcuts/archive/host.js +3 -2
- package/dist/shortcuts/archive/manifest.js +1 -1
- package/dist/shortcuts/archive-oa/host.js +2 -1
- package/dist/shortcuts/archive-oa/manifest.js +1 -1
- package/dist/shortcuts/asset/host.js +7 -6
- package/dist/shortcuts/blog/host.js +4 -3
- package/dist/shortcuts/caizhilian/host.js +3 -2
- package/dist/shortcuts/caizhilian/manifest.js +1 -1
- package/dist/shortcuts/calendar/host.js +2 -1
- package/dist/shortcuts/contract/host.js +34 -59
- package/dist/shortcuts/ehr/host.js +2 -1
- package/dist/shortcuts/esb/host.js +2 -1
- package/dist/shortcuts/fna/host.js +6 -3
- package/dist/shortcuts/fna/manifest.js +10 -5
- package/dist/shortcuts/fna/operations/expense-chart.js +162 -0
- package/dist/shortcuts/fna/operations/registry.js +2 -0
- package/dist/shortcuts/hrm/host.js +2 -1
- package/dist/shortcuts/im/host.js +3 -2
- package/dist/shortcuts/invoice/host.js +9 -7
- package/dist/shortcuts/invoice/manifest.js +23 -142
- package/dist/shortcuts/invoice/operations/issuing-qys.js +266 -203
- package/dist/shortcuts/invoice/operations/registry.js +1 -6
- package/dist/shortcuts/jiuchuanhui/host.js +2 -1
- package/dist/shortcuts/mail/host.js +2 -1
- package/dist/shortcuts/meeting/host.js +2 -1
- package/dist/shortcuts/meeting/operations/eb/conflict.js +78 -12
- package/dist/shortcuts/okr/host.js +2 -1
- package/dist/shortcuts/plan/host.js +2 -1
- package/dist/shortcuts/project/host.js +2 -1
- package/dist/shortcuts/workflow/host.js +3 -5
- package/dist/shortcuts/workflow/index.js +4 -1
- package/dist/shortcuts/workflow/operations/chatscene.js +4 -22
- package/dist/shortcuts/workflow/operations/form.js +281 -166
- package/dist/shortcuts/workflow/operations/read.js +39 -8
- package/dist/shortcuts/workflow/operations/registry.js +2 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +331 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +133 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +326 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +113 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +259 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoListRows.js +64 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoOutputPlanner.js +28 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.aggregate.js +70 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +267 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +392 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +165 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +448 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +348 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +222 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +66 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +502 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +540 -0
- package/dist/shortcuts/workflow/stdout-compact.js +7 -0
- package/docs/SKILL.md +1 -1
- package/docs/_catalog.md +2 -1
- package/docs/agent-invoice.md +1 -1
- package/docs/caizhilian.md +1 -1
- package/docs/e10-auth.md +1 -1
- package/docs/fna.md +7 -3
- package/docs/invoice.md +4 -6
- package/docs/todo-smart-convert/README.md +171 -0
- package/docs/todo-smart-convert/data-contract.md +236 -0
- package/docs/todo-smart-convert/mock/ai-todo-query-target.json +209 -0
- package/docs/todo-smart-convert/subgroup-rules.md +245 -0
- package/package.json +1 -1
- package/scripts/package-skill.mjs +1 -1
- package/skill-template/business-info.json +4 -1
- package/skill-template/domains/caizhilian.md +2 -1
- package/skill-template/domains/qiyecheng.md +1 -0
- package/skill-template/domains/yepiaotong.md +6 -2
- package/skill-template/skill-template.md +1 -0
- package/skills/weaver-e10-blog/SKILL.md +6 -1
- package/skills/weaver-e10-blog/references/blog-query.md +3 -1
- package/skills/weaver-e10-caizhilian/SKILL.md +18 -9
- package/skills/weaver-e10-caizhilian/references/action-flow.md +70 -0
- package/skills/weaver-e10-caizhilian/references/agent-entry.md +6 -2
- package/skills/weaver-e10-caizhilian/references/auth-and-install.md +207 -0
- package/skills/weaver-e10-caizhilian/references/file-collection.md +56 -54
- package/skills/weaver-e10-caizhilian/references/file-upload.md +4 -4
- package/skills/weaver-e10-caizhilian/references/host-executor-prompt.md +32 -0
- package/skills/weaver-e10-caizhilian/references/host-platform-integration.md +46 -0
- package/skills/weaver-e10-caizhilian/references/rule-index.md +56 -0
- package/skills/weaver-e10-caizhilian/references/setting-attach.md +5 -16
- package/skills/weaver-e10-caizhilian/references/setting-backup.md +4 -13
- package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +6 -15
- package/skills/weaver-e10-caizhilian/references/setting-storage-docs-summary.md +126 -0
- package/skills/weaver-e10-caizhilian/references/setting-storage-field-map.md +57 -0
- package/skills/weaver-e10-caizhilian/references/setting-storage.md +142 -482
- package/skills/weaver-e10-caizhilian/references/source-manifest.json +7 -7
- package/skills/weaver-e10-caizhilian/references/task-workflow.md +87 -0
- package/skills/weaver-e10-caizhilian/references/withheld.md +2 -2
- package/skills/weaver-e10-caizhilian/references/write-protocol.md +7 -0
- package/skills/weaver-e10-calendar/SKILL.md +6 -1
- package/skills/weaver-e10-esb/SKILL.md +8 -0
- package/skills/weaver-e10-esb/references/input-format.md +3 -1
- package/skills/weaver-e10-esb/references/source-manifest.json +5 -5
- package/skills/weaver-e10-hrm/SKILL.md +6 -1
- package/skills/weaver-e10-hrm/references/employee.md +1 -1
- package/skills/weaver-e10-hrm/references/org.md +1 -1
- package/skills/weaver-e10-hrm/references/position.md +1 -1
- package/skills/weaver-e10-jinchengda/SKILL.md +2 -1
- package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +1 -1
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +6 -1
- package/skills/weaver-e10-jucailin/SKILL.md +6 -1
- package/skills/weaver-e10-jucailin/references/hr-contact.md +1 -1
- package/skills/weaver-e10-jucailin/references/salary.md +1 -1
- package/skills/weaver-e10-mail/SKILL.md +6 -1
- package/skills/weaver-e10-meeting/SKILL.md +11 -6
- package/skills/weaver-e10-meeting/references/meeting-eb.md +7 -3
- package/skills/weaver-e10-meeting/references/meeting-queries.md +3 -1
- package/skills/weaver-e10-meeting/references/meeting-verification.md +4 -2
- package/skills/weaver-e10-okr/SKILL.md +6 -1
- package/skills/weaver-e10-okr/references/source-manifest.json +5 -5
- package/skills/weaver-e10-plan/SKILL.md +6 -1
- package/skills/weaver-e10-plan/references/plan-overview-and-routing.md +3 -1
- package/skills/weaver-e10-plan/references/plan-report-query.md +3 -1
- package/skills/weaver-e10-plan/references/source-manifest.json +7 -7
- package/skills/weaver-e10-qiyecheng/SKILL.md +16 -6
- package/skills/weaver-e10-qiyecheng/references/catalog.md +6 -3
- package/skills/weaver-e10-qiyecheng/references/expense-center.md +2 -0
- package/skills/weaver-e10-qiyecheng/references/expense-chart.md +78 -0
- package/skills/weaver-e10-qiyecheng/references/source-manifest.json +87 -33
- package/skills/weaver-e10-shared/SKILL.md +37 -14
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +11 -8
- package/skills/weaver-e10-shared/references/non-interactive-environment.md +4 -4
- package/skills/weaver-e10-shared/references/weaver-e10-installation.md +3 -1
- package/skills/weaver-e10-wenshuding/SKILL.md +6 -1
- package/skills/weaver-e10-wenshuding/references/source-manifest.json +3 -3
- package/skills/weaver-e10-workflow/SKILL.md +23 -1
- package/skills/weaver-e10-workflow/references/source-manifest.json +1 -2
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +282 -0
- package/skills/weaver-e10-workflow/references/workflow-create.md +30 -55
- package/skills/weaver-e10-workflow/scripts/todo-summary.cjs +695 -0
- package/skills/weaver-e10-yepiaotong/SKILL.md +19 -17
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +75 -78
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-form-fill-rules.md +179 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-workflow.md +238 -0
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +7 -7
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +11 -5
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +55 -33
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +102 -23
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +1 -1
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +53 -42
- package/skills/weaver-e10-yepiaotong/references/source-manifest.json +94 -214
- package/skills/weaver-e10-yimiaoban/SKILL.md +9 -2
- package/skills/weaver-e10-yimiaoban/references/file-user-i18n.md +1 -1
- package/skills/weaver-e10-yimiaoban/references/msg-read.md +1 -1
- package/skills/weaver-e10-yimiaoban/references/source-manifest.json +9 -9
- package/skills/weaver-e10-ziguanjia/SKILL.md +6 -1
- package/dist/shortcuts/invoice/operations/issuing.js +0 -198
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-field-rules.md +0 -161
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing-qys-ledger.md +0 -66
- package/skills/weaver-e10-yepiaotong/references/invoice-issuing.md +0 -107
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { InvoiceCliError, invoiceValidationError } from '../errors.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
3
|
+
import { asNonEmptyString, assertBusinessSuccess } from './shared.js';
|
|
4
|
+
const LEDGER_PATH = '/api/ebuilder/form/list/getListDatas';
|
|
5
|
+
const LEDGER_LIST_ID = '1201416963938369627';
|
|
6
|
+
const LEDGER_PASS_ID = '1201416959744065575';
|
|
6
7
|
const LEDGER_APP_ID = '846297243998732291';
|
|
7
|
-
const LEDGER_MENU_ID = '
|
|
8
|
-
|
|
8
|
+
const LEDGER_MENU_ID = '5416292802968839298';
|
|
9
|
+
/** urlPageTitle:合同商品信息 */
|
|
10
|
+
const LEDGER_PAGE_TITLE = '5ZCI5ZCM5ZWG5ZOB5L+h5oGv';
|
|
9
11
|
const LEDGER_PAGE_SIZE = 50;
|
|
10
12
|
const LEDGER_MAX_PAGES = 40;
|
|
11
|
-
|
|
12
|
-
/** 契约锁合同商品信息表:数据 key → 可读字段。 */
|
|
13
|
+
/** 待开票合同数据:数据 key → 可读字段。含契约锁、泛微及其他合同。 */
|
|
13
14
|
export const QYS_LEDGER_FIELDS = [
|
|
14
15
|
{ id: '1314988311673275798', key: 'contractNo', label: '合同号', kind: 'text' },
|
|
15
16
|
{ id: '1314988311673275801', key: 'contractFlow', label: '合同审批流程', kind: 'relation' },
|
|
@@ -92,15 +93,6 @@ function toCents(value, name) {
|
|
|
92
93
|
function formatCents(cents) {
|
|
93
94
|
return `${Math.floor(cents / 100)}.${String(cents % 100).padStart(2, '0')}`;
|
|
94
95
|
}
|
|
95
|
-
/** “6.0%” → 600(万分比),只接受开票接口支持的税率。 */
|
|
96
|
-
export function parseTaxRateBasisPoints(name) {
|
|
97
|
-
const match = typeof name === 'string' ? /^\s*(\d+(?:\.\d+)?)\s*%\s*$/u.exec(name) : null;
|
|
98
|
-
const basisPoints = match ? Math.round(Number(match[1]) * 100) : Number.NaN;
|
|
99
|
-
if (![0, 100, 300, 500, 600, 900, 1300].includes(basisPoints)) {
|
|
100
|
-
throw invoiceValidationError('ledger_tax_rate_invalid', `商品税率无法识别或不在允许范围内:${name ?? '空'}`);
|
|
101
|
-
}
|
|
102
|
-
return basisPoints;
|
|
103
|
-
}
|
|
104
96
|
function isPositiveCents(value) {
|
|
105
97
|
return value !== null && /^\d+(?:\.\d+)?$/u.test(value) && Number(value) > 0;
|
|
106
98
|
}
|
|
@@ -117,49 +109,136 @@ export function qysRowBlockers(row) {
|
|
|
117
109
|
blockers.push('已废弃');
|
|
118
110
|
return blockers;
|
|
119
111
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
112
|
+
function parseSpan(value) {
|
|
113
|
+
if (typeof value === 'string' && value.trim().startsWith('[')) {
|
|
114
|
+
try {
|
|
115
|
+
return optionValue(JSON.parse(value));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return optionValue(value);
|
|
122
|
+
}
|
|
123
|
+
function cellText(data, display, key) {
|
|
124
|
+
const raw = data[key] !== undefined && data[key] !== null && data[key] !== '' ? data[key] : display[key];
|
|
125
|
+
return textValue(raw);
|
|
126
|
+
}
|
|
127
|
+
function moneyText(data, display, key) {
|
|
128
|
+
const text = cellText(data, display, key);
|
|
129
|
+
return text === null ? null : text.replace(/,/g, '');
|
|
130
|
+
}
|
|
131
|
+
/** 获取待开票合同数据:getListDatas 的 data / displayData 行,转成与旧列表相同的可读字段。 */
|
|
132
|
+
export function convertPendingLedgerRow(data, display = {}) {
|
|
133
|
+
const formDataId = textValue(data.form_data_id) ?? textValue(data.id);
|
|
134
|
+
if (!formDataId)
|
|
135
|
+
throw invoiceValidationError('ledger_row_invalid', '台账行缺少 form_data_id');
|
|
136
|
+
const statusText = textValue(display.data_status);
|
|
137
|
+
return {
|
|
138
|
+
formDataId,
|
|
139
|
+
title: textValue(data.name) ?? textValue(display.name),
|
|
140
|
+
dataStatus: statusText && !/^\d+$/u.test(statusText) ? statusText : null,
|
|
141
|
+
contractNo: cellText(data, display, 'hth'),
|
|
142
|
+
contractFlow: parseSpan(display.htsplcSpan),
|
|
143
|
+
contractCategory: cellText(data, display, 'htzl'),
|
|
144
|
+
productType: parseSpan(display.cplxSpan),
|
|
145
|
+
productTypeDetail: cellText(data, display, 'cplxmx'),
|
|
146
|
+
accountingCompany: parseSpan(display.hsgs_idSpan),
|
|
147
|
+
invoiceGroupFlag: cellText(data, display, 'kpfzbs'),
|
|
148
|
+
sourceFlag: cellText(data, display, 'lybs'),
|
|
149
|
+
flowDetailId: cellText(data, display, 'lcmxid'),
|
|
150
|
+
invoiceType: parseSpan(display.fplxSpan),
|
|
151
|
+
purchaserName: cellText(data, display, 'gmfmc'),
|
|
152
|
+
purchaserTaxNo: cellText(data, display, 'gmfsh'),
|
|
153
|
+
purchaserAddress: cellText(data, display, 'gmfdz'),
|
|
154
|
+
purchaserTel: cellText(data, display, 'gmfdh'),
|
|
155
|
+
purchaserBankName: cellText(data, display, 'gmfkhx'),
|
|
156
|
+
purchaserBankAccount: cellText(data, display, 'gmfkhxzh'),
|
|
157
|
+
invoiceItemName: cellText(data, display, 'kpmc'),
|
|
158
|
+
goodsName: cellText(data, display, 'spmc'),
|
|
159
|
+
revenueCode: cellText(data, display, 'spshflbm'),
|
|
160
|
+
taxRate: parseSpan(display.spslSpan),
|
|
161
|
+
specification: cellText(data, display, 'ggxh'),
|
|
162
|
+
unit: cellText(data, display, 'dw'),
|
|
163
|
+
quantity: cellText(data, display, 'spslkwk'),
|
|
164
|
+
unitPrice: moneyText(data, display, 'spdjkwk'),
|
|
165
|
+
amount: moneyText(data, display, 'kpje'),
|
|
166
|
+
uninvoicedAmount: moneyText(data, display, 'wkpje'),
|
|
167
|
+
invoicedAmount: moneyText(data, display, 'ykpje'),
|
|
168
|
+
invoicingAmount: moneyText(data, display, 'kpzje'),
|
|
169
|
+
amountDiffers: parseSpan(display.kpjeczcySpan),
|
|
170
|
+
thirdPartyPurchase: parseSpan(display.sfsfcgSpan),
|
|
171
|
+
invoiceNo: cellText(data, display, 'fphm'),
|
|
172
|
+
invoiceFlow: parseSpan(display.kplcidSpan),
|
|
173
|
+
invoiceDate: cellText(data, display, 'kpsj'),
|
|
174
|
+
discarded: parseSpan(display.sfzfSpan),
|
|
175
|
+
discardedDate: cellText(data, display, 'zfsj'),
|
|
176
|
+
contactName: cellText(data, display, 'khlxr'),
|
|
177
|
+
contactPhone: cellText(data, display, 'khlxdh'),
|
|
178
|
+
contactEmail: cellText(data, display, 'khlxyx'),
|
|
126
179
|
};
|
|
127
|
-
|
|
180
|
+
}
|
|
181
|
+
async function fetchLedgerPage(host, pageNo, tableuid, operation) {
|
|
182
|
+
const result = await host.invoiceRequest({
|
|
128
183
|
path: LEDGER_PATH,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
...fieldFilter,
|
|
132
|
-
filter: '[]',
|
|
133
|
-
fieldFilter,
|
|
134
|
-
pageFilter: { filter: {}, filterIsNull: true, esbFilter: [] },
|
|
135
|
-
pageAppId: LEDGER_APP_ID,
|
|
136
|
-
compId: 'e00e8244de584b369417a4fea31d7bed',
|
|
137
|
-
pageId: LEDGER_PAGE_ID,
|
|
138
|
-
pageNo: String(pageNo),
|
|
139
|
-
pageSize: String(LEDGER_PAGE_SIZE),
|
|
140
|
-
tableuid: 'a74d995bddd54a4f831551b468071632',
|
|
141
|
-
refPluginPackageId: '933846626099339271',
|
|
142
|
-
},
|
|
184
|
+
query: { passid: LEDGER_PASS_ID, cid: LEDGER_PASS_ID },
|
|
185
|
+
headers: { ebbusinessid: LEDGER_LIST_ID },
|
|
143
186
|
operation,
|
|
187
|
+
body: {
|
|
188
|
+
current: pageNo,
|
|
189
|
+
pageSize: LEDGER_PAGE_SIZE,
|
|
190
|
+
requiredMatch: 1,
|
|
191
|
+
tableuid,
|
|
192
|
+
mapResult: '1',
|
|
193
|
+
recheckQuery: '1',
|
|
194
|
+
cusMenuId: LEDGER_MENU_ID,
|
|
195
|
+
urlPageTitle: LEDGER_PAGE_TITLE,
|
|
196
|
+
[`appId_${LEDGER_LIST_ID}`]: LEDGER_APP_ID,
|
|
197
|
+
searchParamData: {
|
|
198
|
+
searchType: '3',
|
|
199
|
+
quickSearchFields: {},
|
|
200
|
+
commonSearchFields: {},
|
|
201
|
+
type: 'and',
|
|
202
|
+
groupFields: {},
|
|
203
|
+
},
|
|
204
|
+
listId: LEDGER_LIST_ID,
|
|
205
|
+
isFollow: 0,
|
|
206
|
+
isShareToMe: 0,
|
|
207
|
+
filterCondition: {},
|
|
208
|
+
browser: 'Chrome',
|
|
209
|
+
},
|
|
144
210
|
});
|
|
145
|
-
assertBusinessSuccess(result, 'qys_ledger_query_failed', '
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
211
|
+
assertBusinessSuccess(result, 'qys_ledger_query_failed', '获取待开票合同数据失败');
|
|
212
|
+
const payload = result?.data;
|
|
213
|
+
const dataRows = payload?.data;
|
|
214
|
+
const displayRows = payload?.displayData;
|
|
215
|
+
if (!Array.isArray(dataRows) || !Array.isArray(displayRows)) {
|
|
216
|
+
throw new InvoiceCliError('api', 'qys_ledger_query_failed', '获取待开票合同数据的返回缺少 data.data 或 data.displayData', { exitCode: 1 });
|
|
149
217
|
}
|
|
150
|
-
return
|
|
218
|
+
return dataRows.map((data, index) => ({
|
|
219
|
+
data,
|
|
220
|
+
display: displayRows[index] && typeof displayRows[index] === 'object' ? displayRows[index] : {},
|
|
221
|
+
}));
|
|
151
222
|
}
|
|
152
|
-
/**
|
|
223
|
+
/** total / hasMore 不可靠,按本页未取满或出现重复行结束。 */
|
|
153
224
|
async function scanLedger(host, operation, visit) {
|
|
225
|
+
const tableuid = randomUUID().replace(/-/g, '');
|
|
226
|
+
const seen = new Set();
|
|
154
227
|
let scanned = 0;
|
|
155
228
|
for (let pageNo = 1; pageNo <= LEDGER_MAX_PAGES; pageNo += 1) {
|
|
156
|
-
const page = await fetchLedgerPage(host, pageNo, operation);
|
|
157
|
-
|
|
229
|
+
const page = await fetchLedgerPage(host, pageNo, tableuid, operation);
|
|
230
|
+
let fresh = 0;
|
|
231
|
+
for (const pair of page) {
|
|
232
|
+
const row = convertPendingLedgerRow(pair.data, pair.display);
|
|
233
|
+
if (seen.has(row.formDataId))
|
|
234
|
+
continue;
|
|
235
|
+
seen.add(row.formDataId);
|
|
236
|
+
fresh += 1;
|
|
158
237
|
scanned += 1;
|
|
159
|
-
if (visit(
|
|
238
|
+
if (visit(row))
|
|
160
239
|
return { scanned, complete: true };
|
|
161
240
|
}
|
|
162
|
-
if (page.length < LEDGER_PAGE_SIZE)
|
|
241
|
+
if (page.length < LEDGER_PAGE_SIZE || fresh === 0)
|
|
163
242
|
return { scanned, complete: true };
|
|
164
243
|
}
|
|
165
244
|
return { scanned, complete: false };
|
|
@@ -168,6 +247,142 @@ function matchesKeyword(row, keyword) {
|
|
|
168
247
|
const haystack = [row.contractNo, row.purchaserName, row.contractFlow?.name, row.goodsName, row.invoiceItemName, row.formDataId];
|
|
169
248
|
return haystack.some((value) => typeof value === 'string' && value.includes(keyword));
|
|
170
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* 台账常把开户行名称和账号一起写进「购买方开户行账号」(如 `招商银行福田支行 8135 8668 8310 001`)。
|
|
252
|
+
* 拆成名称与账号两段:账号取末尾(或开头)连续的数字段,原样保留其中的空格和连字符。
|
|
253
|
+
*/
|
|
254
|
+
export function splitBankNameAndAccount(bankName, bankAccount) {
|
|
255
|
+
const name = (bankName ?? '').trim();
|
|
256
|
+
const account = (bankAccount ?? '').trim();
|
|
257
|
+
const trailing = /^(.*?[^\d\s-])\s*(\d[\d\s-]*\d)$/u.exec(account);
|
|
258
|
+
const leading = trailing ? null : /^(\d[\d\s-]*\d)\s*([^\d\s-].*)$/u.exec(account);
|
|
259
|
+
const rawText = trailing ? trailing[1] : leading ? leading[2] : '';
|
|
260
|
+
const textPart = rawText
|
|
261
|
+
.replace(/[\s,,;;::]*(?:银行账号|银行帐号|账号|帐号|账户|帐户)?[\s,,;;::]*$/u, '')
|
|
262
|
+
.replace(/^[\s,,;;::]*(?:开户行|开户银行)?[\s,,;;::]*/u, '')
|
|
263
|
+
.trim();
|
|
264
|
+
const digitPart = trailing ? trailing[2] : leading ? leading[1] : '';
|
|
265
|
+
if (!textPart || !digitPart)
|
|
266
|
+
return { bankName: name, bankAccount: account, split: false };
|
|
267
|
+
return { bankName: name || textPart, bankAccount: digitPart, split: true };
|
|
268
|
+
}
|
|
269
|
+
export function isSpecialInvoiceTypeName(name) {
|
|
270
|
+
return name.includes('专票') || name.includes('专用发票');
|
|
271
|
+
}
|
|
272
|
+
/** 一张开票流程对应一个“合同号 + 购方”分组;金额只累计可开票行。 */
|
|
273
|
+
export class QysLedgerGrouper {
|
|
274
|
+
groups = new Map();
|
|
275
|
+
add(row, blocked) {
|
|
276
|
+
const contractNo = row.contractNo ?? '';
|
|
277
|
+
const purchaserName = row.purchaserName ?? '';
|
|
278
|
+
const key = `${contractNo}|${purchaserName}`;
|
|
279
|
+
let group = this.groups.get(key);
|
|
280
|
+
if (!group) {
|
|
281
|
+
group = {
|
|
282
|
+
contractNo,
|
|
283
|
+
contractFlowId: row.contractFlow?.id ?? '',
|
|
284
|
+
contractFlowName: row.contractFlow?.name ?? '',
|
|
285
|
+
purchaserName,
|
|
286
|
+
purchaserTaxNos: new Set(),
|
|
287
|
+
invoiceTypes: new Set(),
|
|
288
|
+
goodsNames: new Set(),
|
|
289
|
+
taxRates: new Set(),
|
|
290
|
+
specifications: new Set(),
|
|
291
|
+
sellerNames: new Set(),
|
|
292
|
+
bankName: null,
|
|
293
|
+
bankAccount: null,
|
|
294
|
+
formDataIds: [],
|
|
295
|
+
amountCents: 0,
|
|
296
|
+
invalidAmountRows: [],
|
|
297
|
+
blockedRows: 0,
|
|
298
|
+
};
|
|
299
|
+
this.groups.set(key, group);
|
|
300
|
+
}
|
|
301
|
+
if (row.accountingCompany?.name)
|
|
302
|
+
group.sellerNames.add(row.accountingCompany.name);
|
|
303
|
+
if (blocked) {
|
|
304
|
+
group.blockedRows += 1;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
group.formDataIds.push(row.formDataId);
|
|
308
|
+
if (!group.contractFlowId && row.contractFlow) {
|
|
309
|
+
group.contractFlowId = row.contractFlow.id;
|
|
310
|
+
group.contractFlowName = row.contractFlow.name;
|
|
311
|
+
}
|
|
312
|
+
if (row.purchaserTaxNo)
|
|
313
|
+
group.purchaserTaxNos.add(row.purchaserTaxNo);
|
|
314
|
+
if (row.invoiceType?.name)
|
|
315
|
+
group.invoiceTypes.add(row.invoiceType.name);
|
|
316
|
+
const goodsName = row.invoiceItemName ?? row.goodsName;
|
|
317
|
+
if (goodsName)
|
|
318
|
+
group.goodsNames.add(goodsName);
|
|
319
|
+
if (row.taxRate?.name)
|
|
320
|
+
group.taxRates.add(row.taxRate.name);
|
|
321
|
+
if (row.specification)
|
|
322
|
+
group.specifications.add(row.specification);
|
|
323
|
+
if (group.bankName === null && group.bankAccount === null && (row.purchaserBankName || row.purchaserBankAccount)) {
|
|
324
|
+
group.bankName = row.purchaserBankName ?? null;
|
|
325
|
+
group.bankAccount = row.purchaserBankAccount ?? null;
|
|
326
|
+
}
|
|
327
|
+
if (row.amount !== null && /^\d+(?:\.\d{1,2})?$/u.test(row.amount)) {
|
|
328
|
+
group.amountCents += toCents(row.amount, '开票金额');
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
group.invalidAmountRows.push(row.formDataId);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
result(includeEmpty) {
|
|
335
|
+
const output = [];
|
|
336
|
+
for (const group of this.groups.values()) {
|
|
337
|
+
if (!includeEmpty && group.formDataIds.length === 0)
|
|
338
|
+
continue;
|
|
339
|
+
const warnings = [];
|
|
340
|
+
const specialTypes = [...group.invoiceTypes].filter(isSpecialInvoiceTypeName);
|
|
341
|
+
const specialInvoiceWithoutTaxNo = group.purchaserTaxNos.size === 0 && specialTypes.length > 0;
|
|
342
|
+
if (specialInvoiceWithoutTaxNo) {
|
|
343
|
+
warnings.push(`购方无税号,不能开专票(台账发票类型:${specialTypes.join('、')}),请先在台账改为普票再发起`);
|
|
344
|
+
}
|
|
345
|
+
const bank = splitBankNameAndAccount(group.bankName, group.bankAccount);
|
|
346
|
+
if (bank.split) {
|
|
347
|
+
warnings.push(`台账「购买方开户行账号」混有开户行名称,已拆分为开户行名称「${bank.bankName}」、账号「${bank.bankAccount}」`);
|
|
348
|
+
}
|
|
349
|
+
if (!group.contractNo)
|
|
350
|
+
warnings.push('台账行缺少合同号,无法按合同号发起开票流程');
|
|
351
|
+
if (group.sellerNames.size > 1)
|
|
352
|
+
warnings.push(`同组销售方(核算公司)不一致:${[...group.sellerNames].join('、')}`);
|
|
353
|
+
if (group.invoiceTypes.size > 1)
|
|
354
|
+
warnings.push(`同组发票类型不一致:${[...group.invoiceTypes].join('、')}`);
|
|
355
|
+
if (group.purchaserTaxNos.size > 1)
|
|
356
|
+
warnings.push(`同组购方税号不一致:${[...group.purchaserTaxNos].join('、')}`);
|
|
357
|
+
if (group.invalidAmountRows.length)
|
|
358
|
+
warnings.push(`开票金额无法识别,未计入合计:${group.invalidAmountRows.join('、')}`);
|
|
359
|
+
if (group.blockedRows > 0) {
|
|
360
|
+
warnings.push(`同合同另有 ${group.blockedRows} 行已开票、开票中或已废弃,流程联动可能一并带出,请在 E10 核对明细`);
|
|
361
|
+
}
|
|
362
|
+
output.push({
|
|
363
|
+
contractNo: group.contractNo,
|
|
364
|
+
contractFlowId: group.contractFlowId,
|
|
365
|
+
contractFlowName: group.contractFlowName,
|
|
366
|
+
purchaserName: group.purchaserName,
|
|
367
|
+
purchaserTaxNo: [...group.purchaserTaxNos].join('、'),
|
|
368
|
+
purchaserBankName: bank.bankName,
|
|
369
|
+
purchaserBankAccount: bank.bankAccount,
|
|
370
|
+
invoiceTypes: [...group.invoiceTypes],
|
|
371
|
+
specialInvoiceWithoutTaxNo,
|
|
372
|
+
goodsNames: [...group.goodsNames],
|
|
373
|
+
taxRates: [...group.taxRates],
|
|
374
|
+
specifications: [...group.specifications],
|
|
375
|
+
sellerNames: [...group.sellerNames],
|
|
376
|
+
rowCount: group.formDataIds.length,
|
|
377
|
+
formDataIds: group.formDataIds,
|
|
378
|
+
totalAmount: formatCents(group.amountCents),
|
|
379
|
+
blockedRows: group.blockedRows,
|
|
380
|
+
warnings,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
return output;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
171
386
|
export class InvoiceIssuingQysListOperation {
|
|
172
387
|
name = 'invoice.issuing.qys.list';
|
|
173
388
|
async execute(input, { host }) {
|
|
@@ -178,6 +393,7 @@ export class InvoiceIssuingQysListOperation {
|
|
|
178
393
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
179
394
|
throw invoiceValidationError('input_invalid', 'limit 必须是 1-100 的整数');
|
|
180
395
|
const items = [];
|
|
396
|
+
const grouper = new QysLedgerGrouper();
|
|
181
397
|
let matched = 0;
|
|
182
398
|
const scan = await scanLedger(host, this.name, (row) => {
|
|
183
399
|
if (contractNo && row.contractNo !== contractNo)
|
|
@@ -185,6 +401,7 @@ export class InvoiceIssuingQysListOperation {
|
|
|
185
401
|
if (keyword && !matchesKeyword(row, keyword))
|
|
186
402
|
return false;
|
|
187
403
|
const blockers = qysRowBlockers(row);
|
|
404
|
+
grouper.add(row, blockers.length > 0);
|
|
188
405
|
if (!includeIssued && blockers.length)
|
|
189
406
|
return false;
|
|
190
407
|
matched += 1;
|
|
@@ -196,6 +413,7 @@ export class InvoiceIssuingQysListOperation {
|
|
|
196
413
|
status: 'COMPLETE',
|
|
197
414
|
data: {
|
|
198
415
|
items,
|
|
416
|
+
groups: grouper.result(includeIssued),
|
|
199
417
|
matched,
|
|
200
418
|
truncated: matched > items.length,
|
|
201
419
|
scanned: scan.scanned,
|
|
@@ -204,158 +422,3 @@ export class InvoiceIssuingQysListOperation {
|
|
|
204
422
|
};
|
|
205
423
|
}
|
|
206
424
|
}
|
|
207
|
-
export function buildQysMakeInvoicePayload(row) {
|
|
208
|
-
const warnings = [];
|
|
209
|
-
const invoiceType = row.invoiceType?.id;
|
|
210
|
-
if (!invoiceType)
|
|
211
|
-
throw invoiceValidationError('ledger_field_missing', '台账行缺少发票类型');
|
|
212
|
-
const goodsName = row.invoiceItemName ?? row.goodsName;
|
|
213
|
-
if (!goodsName)
|
|
214
|
-
throw invoiceValidationError('ledger_field_missing', '台账行缺少开票名称和商品名称');
|
|
215
|
-
if (!row.purchaserName)
|
|
216
|
-
throw invoiceValidationError('ledger_field_missing', '台账行缺少购买方名称');
|
|
217
|
-
const basisPoints = parseTaxRateBasisPoints(row.taxRate?.name);
|
|
218
|
-
const amountCents = toCents(row.amount, '开票金额');
|
|
219
|
-
if (amountCents === 0)
|
|
220
|
-
throw invoiceValidationError('ledger_amount_invalid', '开票金额必须大于 0');
|
|
221
|
-
const taxCents = Math.floor((amountCents * basisPoints + 5000) / 10000);
|
|
222
|
-
const amount = formatCents(amountCents);
|
|
223
|
-
const taxAmount = formatCents(taxCents);
|
|
224
|
-
const amountWithTax = formatCents(amountCents + taxCents);
|
|
225
|
-
if (row.quantity !== null && row.unitPrice !== null) {
|
|
226
|
-
const expected = Number(row.quantity) * Number(row.unitPrice);
|
|
227
|
-
if (!Number.isFinite(expected) || Math.abs(expected * 100 - amountCents) > 1) {
|
|
228
|
-
warnings.push(`商品数量 ${row.quantity} × 商品单价 ${row.unitPrice} 与开票金额 ${row.amount} 不一致`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
if (row.uninvoicedAmount !== null && row.uninvoicedAmount !== row.amount && Number(row.uninvoicedAmount) !== Number(row.amount)) {
|
|
232
|
-
warnings.push(`未开票金额 ${row.uninvoicedAmount} 与开票金额 ${row.amount} 不一致,本次按开票金额全额开具`);
|
|
233
|
-
}
|
|
234
|
-
if (row.dataStatus && row.dataStatus !== '提交')
|
|
235
|
-
warnings.push(`台账数据状态为“${row.dataStatus}”`);
|
|
236
|
-
const detail = {
|
|
237
|
-
goodsName,
|
|
238
|
-
taxSign: '0',
|
|
239
|
-
taxRate: basisPoints / 10000,
|
|
240
|
-
amount,
|
|
241
|
-
taxAmount,
|
|
242
|
-
amountWithTax,
|
|
243
|
-
};
|
|
244
|
-
for (const key of ['revenueCode', 'specification', 'unit', 'quantity', 'unitPrice']) {
|
|
245
|
-
if (row[key] !== null)
|
|
246
|
-
detail[key] = row[key];
|
|
247
|
-
}
|
|
248
|
-
const payload = {
|
|
249
|
-
invoiceType,
|
|
250
|
-
externalDocumentNo: `QYS-${row.formDataId}`,
|
|
251
|
-
purchaserName: row.purchaserName,
|
|
252
|
-
taxSign: '0',
|
|
253
|
-
totalAmount: amount,
|
|
254
|
-
taxAmount,
|
|
255
|
-
totalAmountWithTax: amountWithTax,
|
|
256
|
-
details: [detail],
|
|
257
|
-
};
|
|
258
|
-
for (const key of ['purchaserTaxNo', 'purchaserAddress', 'purchaserTel', 'purchaserBankName', 'purchaserBankAccount']) {
|
|
259
|
-
if (row[key] !== null)
|
|
260
|
-
payload[key] = row[key];
|
|
261
|
-
}
|
|
262
|
-
return { payload, warnings };
|
|
263
|
-
}
|
|
264
|
-
export class InvoiceIssuingQysPrepareOperation {
|
|
265
|
-
name = 'invoice.issuing.qys.prepare';
|
|
266
|
-
async execute(input, { host, continuation }) {
|
|
267
|
-
const mode = normalizeMode(input.mode);
|
|
268
|
-
const formDataId = asNonEmptyString(input.formDataId, 'formDataId');
|
|
269
|
-
if (!/^\d+$/u.test(formDataId))
|
|
270
|
-
throw invoiceValidationError('input_invalid', 'formDataId 必须是台账行的数字 ID');
|
|
271
|
-
let row;
|
|
272
|
-
const scan = await scanLedger(host, this.name, (candidate) => {
|
|
273
|
-
if (candidate.formDataId !== formDataId)
|
|
274
|
-
return false;
|
|
275
|
-
row = candidate;
|
|
276
|
-
return true;
|
|
277
|
-
});
|
|
278
|
-
if (!row) {
|
|
279
|
-
throw invoiceValidationError('ledger_row_not_found', `契约锁开票台账中未找到 formDataId=${formDataId} 的行`, {
|
|
280
|
-
scanned: scan.scanned,
|
|
281
|
-
scanComplete: scan.complete,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
const blockers = qysRowBlockers(row);
|
|
285
|
-
if (blockers.length) {
|
|
286
|
-
throw invoiceValidationError('ledger_row_not_issuable', `该台账行不能开票:${blockers.join(';')}`, { formDataId, blockers });
|
|
287
|
-
}
|
|
288
|
-
const { payload, warnings } = buildQysMakeInvoicePayload(row);
|
|
289
|
-
const normalizedPayload = normalizeMakeInvoicePayload(payload, mode);
|
|
290
|
-
const preview = {
|
|
291
|
-
...makeInvoicePreview(normalizedPayload, mode),
|
|
292
|
-
formDataId,
|
|
293
|
-
contractNo: row.contractNo ?? '',
|
|
294
|
-
contractFlowName: row.contractFlow?.name ?? '',
|
|
295
|
-
invoiceTypeName: row.invoiceType?.name ?? '',
|
|
296
|
-
goodsName: normalizedPayload.details[0].goodsName,
|
|
297
|
-
taxRate: row.taxRate?.name ?? '',
|
|
298
|
-
};
|
|
299
|
-
const session = await host.getSession();
|
|
300
|
-
const continuationToken = await continuation.issue({
|
|
301
|
-
operation: 'invoice.issuing.make.apply',
|
|
302
|
-
workflow: workflow('invoice.issuing.make', 'AWAITING_CONFIRMATION'),
|
|
303
|
-
baseUrl: session.baseUrl,
|
|
304
|
-
profile: session.profile,
|
|
305
|
-
userId: session.userId,
|
|
306
|
-
mode,
|
|
307
|
-
fingerprint: objectFingerprint(normalizedPayload),
|
|
308
|
-
preview,
|
|
309
|
-
});
|
|
310
|
-
return {
|
|
311
|
-
status: 'AWAITING_CONFIRMATION',
|
|
312
|
-
data: {
|
|
313
|
-
preview,
|
|
314
|
-
warnings,
|
|
315
|
-
ledgerRow: row,
|
|
316
|
-
normalizedPayload,
|
|
317
|
-
continuation: continuationToken,
|
|
318
|
-
expiresInSeconds: 600,
|
|
319
|
-
workflow: workflow('invoice.issuing.make', 'AWAITING_CONFIRMATION'),
|
|
320
|
-
},
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
function resultState(returnCode) {
|
|
325
|
-
if (returnCode === '00')
|
|
326
|
-
return 'SUCCESS';
|
|
327
|
-
if (returnCode === '01')
|
|
328
|
-
return 'PENDING';
|
|
329
|
-
return 'FAILED';
|
|
330
|
-
}
|
|
331
|
-
export class InvoiceIssuingResultOperation {
|
|
332
|
-
name = 'invoice.issuing.result';
|
|
333
|
-
async execute(input, { host }) {
|
|
334
|
-
const externalDocumentNo = asNonEmptyString(input.externalDocumentNo, 'externalDocumentNo');
|
|
335
|
-
const invoiceReq = { businessNo: externalDocumentNo, taxNo: SELLER_TAX_NO };
|
|
336
|
-
if (input.serialNo !== undefined && input.serialNo !== '')
|
|
337
|
-
invoiceReq.serialNo = asNonEmptyString(input.serialNo, 'serialNo');
|
|
338
|
-
const result = await host.invoiceRequest({
|
|
339
|
-
path: RESULT_PATH,
|
|
340
|
-
method: 'POST',
|
|
341
|
-
body: { invoiceReq },
|
|
342
|
-
operation: this.name,
|
|
343
|
-
timeoutMs: 60_000,
|
|
344
|
-
});
|
|
345
|
-
assertBusinessSuccess(result, 'issuing_result_failed', '查询开票结果失败');
|
|
346
|
-
const data = result?.data || {};
|
|
347
|
-
return {
|
|
348
|
-
status: 'COMPLETE',
|
|
349
|
-
data: {
|
|
350
|
-
externalDocumentNo,
|
|
351
|
-
state: resultState(data.returnCode),
|
|
352
|
-
returnCode: data.returnCode ?? '',
|
|
353
|
-
returnMessage: data.returnMessage ?? '',
|
|
354
|
-
invoiceNo: data.digitInvoiceNo || data.invoiceNo || '',
|
|
355
|
-
invoiceTime: data.invoiceTime ?? '',
|
|
356
|
-
serialNo: data.serialNo ?? '',
|
|
357
|
-
result,
|
|
358
|
-
},
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
}
|
|
@@ -6,8 +6,7 @@ import { InvoiceDeleteApplyOperation, InvoiceDeletePrepareOperation } from './de
|
|
|
6
6
|
import { InvoiceDownloadOperation } from './download.js';
|
|
7
7
|
import { InvoiceGetOperation } from './get.js';
|
|
8
8
|
import { InvoiceImportApplyOperation, InvoiceImportPrepareOperation } from './import.js';
|
|
9
|
-
import {
|
|
10
|
-
import { InvoiceIssuingQysListOperation, InvoiceIssuingQysPrepareOperation, InvoiceIssuingResultOperation, } from './issuing-qys.js';
|
|
9
|
+
import { InvoiceIssuingQysListOperation } from './issuing-qys.js';
|
|
11
10
|
import { InvoiceListOperation } from './list.js';
|
|
12
11
|
import { InvoiceOcrPreviewOperation } from './ocr-preview.js';
|
|
13
12
|
import { InvoiceReimEmployeeSuperiorsOperation, InvoiceReimFieldSearchOperation, InvoiceReimFileOcrPreviewOperation, InvoiceReimFlowCreateApplyOperation, InvoiceReimFlowCreatePrepareOperation, InvoiceReimFlowUpdateApplyOperation, InvoiceReimFlowUpdatePrepareOperation, InvoiceReimFormStructureOperation, InvoiceReimRequestsListOperation, InvoiceReimRowInfoBatchOperation, InvoiceReimRowInfoOperation, InvoiceReimWorkflowResolveOperation, } from './reim.js';
|
|
@@ -51,11 +50,7 @@ function buildRegistry() {
|
|
|
51
50
|
new InvoiceReimFlowCreateApplyOperation(),
|
|
52
51
|
new InvoiceReimFlowUpdatePrepareOperation(),
|
|
53
52
|
new InvoiceReimFlowUpdateApplyOperation(),
|
|
54
|
-
new InvoiceIssuingMakePrepareOperation(),
|
|
55
|
-
new InvoiceIssuingMakeApplyOperation(),
|
|
56
53
|
new InvoiceIssuingQysListOperation(),
|
|
57
|
-
new InvoiceIssuingQysPrepareOperation(),
|
|
58
|
-
new InvoiceIssuingResultOperation(),
|
|
59
54
|
];
|
|
60
55
|
for (const handler of handlers) {
|
|
61
56
|
if (registry.has(handler.name))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js';
|
|
1
2
|
import { requireE10Session } from '../../internal/e10/context.js';
|
|
2
3
|
import { getActiveProfile } from '../../internal/e10/auth/session.js';
|
|
3
4
|
import { E10ApiError, createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
|
|
@@ -127,7 +128,7 @@ export function createJiuchuanhuiHost(ctx, dependencies = {}) {
|
|
|
127
128
|
mapRuntimeNetworkError(error);
|
|
128
129
|
}
|
|
129
130
|
if (response.status === 401 || response.status === 302) {
|
|
130
|
-
throw jiuchuanhuiAuthError('session_expired',
|
|
131
|
+
throw jiuchuanhuiAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
|
|
131
132
|
}
|
|
132
133
|
if (response.parseError) {
|
|
133
134
|
if (response.status < 200 || response.status >= 300) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js';
|
|
2
3
|
import { requireE10Session } from '../../internal/e10/context.js';
|
|
3
4
|
import { getActiveProfile } from '../../internal/e10/auth/session.js';
|
|
4
5
|
import { E10ApiError, createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
|
|
@@ -149,7 +150,7 @@ export function createMailHost(ctx, dependencies = {}) {
|
|
|
149
150
|
throw error;
|
|
150
151
|
}
|
|
151
152
|
if (response.status === 401 || response.status === 302) {
|
|
152
|
-
throw mailAuthError('session_expired',
|
|
153
|
+
throw mailAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
|
|
153
154
|
}
|
|
154
155
|
if (response.parseError) {
|
|
155
156
|
if (response.status < 200 || response.status >= 300) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { E10_SESSION_EXPIRED_MESSAGE } from '../../internal/e10/auth/messages.js';
|
|
1
2
|
import { requireE10Session } from '../../internal/e10/context.js';
|
|
2
3
|
import { getActiveProfile } from '../../internal/e10/auth/session.js';
|
|
3
4
|
import { E10ApiError, createE10RequestRuntime } from '../../internal/e10/request-runtime.js';
|
|
@@ -142,7 +143,7 @@ export function createMeetingHost(ctx, dependencies = {}) {
|
|
|
142
143
|
mapRuntimeNetworkError(error);
|
|
143
144
|
}
|
|
144
145
|
if (response.status === 401 || response.status === 302) {
|
|
145
|
-
throw meetingAuthError('session_expired',
|
|
146
|
+
throw meetingAuthError('session_expired', E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
|
|
146
147
|
}
|
|
147
148
|
if (response.parseError) {
|
|
148
149
|
if (response.status < 200 || response.status >= 300) {
|