yindie-erp-mcp 2.0.5 → 2.0.6
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/dist/client.js +4 -3
- package/dist/tool-helpers.js +65 -1
- package/dist/tool-meta.js +147 -95
- package/dist/tools-merged.js +16 -5
- package/dist/tools-write.js +16 -6
- package/dist/tools.js +96 -10
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { basename, join } from 'node:path';
|
|
4
|
+
import { parseJsonSafe } from './tool-helpers.js';
|
|
4
5
|
/** ERP API 客户端 */
|
|
5
6
|
export class YindieClient {
|
|
6
7
|
/** 后端根地址 */
|
|
@@ -86,7 +87,7 @@ export class YindieClient {
|
|
|
86
87
|
const response = await fetch(url, init);
|
|
87
88
|
const contentType = response.headers.get('content-type') ?? '';
|
|
88
89
|
if (contentType.includes('application/json')) {
|
|
89
|
-
const result = (await response.
|
|
90
|
+
const result = (await parseJsonSafe(await response.text()));
|
|
90
91
|
if (result.code === 401 && !retried) {
|
|
91
92
|
this.token = await this.relogin();
|
|
92
93
|
return this.download(method, path, fileName, options, true);
|
|
@@ -125,7 +126,7 @@ export class YindieClient {
|
|
|
125
126
|
init.body = JSON.stringify(body);
|
|
126
127
|
}
|
|
127
128
|
const response = await fetch(url, init);
|
|
128
|
-
const result = (await response.
|
|
129
|
+
const result = (await parseJsonSafe(await response.text()));
|
|
129
130
|
if (result.code === 401 && !retried) {
|
|
130
131
|
this.token = await this.relogin();
|
|
131
132
|
return this.request(method, path, body, params, true);
|
|
@@ -151,7 +152,7 @@ export class YindieClient {
|
|
|
151
152
|
};
|
|
152
153
|
const form = await formFactory();
|
|
153
154
|
const response = await fetch(url, { method: 'POST', headers, body: form });
|
|
154
|
-
const result = (await response.
|
|
155
|
+
const result = (await parseJsonSafe(await response.text()));
|
|
155
156
|
if (result.code === 401 && !retried) {
|
|
156
157
|
this.token = await this.relogin();
|
|
157
158
|
return this.requestForm(path, formFactory, true);
|
package/dist/tool-helpers.js
CHANGED
|
@@ -5,17 +5,81 @@ export const payloadField = z.string().describe('JSON 请求体,字段与后
|
|
|
5
5
|
export const idsField = z.string().describe('主键 ID,多个用英文逗号分隔');
|
|
6
6
|
/** 单个主键字段,字符串避免雪花 ID 精度丢失 */
|
|
7
7
|
export const idField = z.string().describe('主键 ID');
|
|
8
|
+
/** 样衣类型白名单 */
|
|
9
|
+
export const SAMPLE_TYPES = new Set(['proto', 'pre_prod', 'bulk', 'mass']);
|
|
10
|
+
/** ≥16 位数字字面量改成字符串,避免雪花 ID 精度丢失 */
|
|
11
|
+
export function preserveSnowflakeIds(text) {
|
|
12
|
+
return text.replace(/([:\[,]\s*)(\d{16,})(\s*[,\]}])/g, '$1"$2"$3');
|
|
13
|
+
}
|
|
14
|
+
/** 解析保真后的 JSON */
|
|
15
|
+
export function parseJsonSafe(text) {
|
|
16
|
+
return JSON.parse(preserveSnowflakeIds(text));
|
|
17
|
+
}
|
|
18
|
+
/** 校验对象内 id 类字段不为 number */
|
|
19
|
+
function assertNoNumberIds(value, path = '') {
|
|
20
|
+
if (value == null || typeof value !== 'object') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
value.forEach((item, i) => assertNoNumberIds(item, `${path}[${i}]`));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
for (const [key, child] of Object.entries(value)) {
|
|
28
|
+
const here = path ? `${path}.${key}` : key;
|
|
29
|
+
if (typeof child === 'number' && (key === 'id' || key === 'ids' || /Id$/.test(key))) {
|
|
30
|
+
throw new Error(`雪花 ID 必须字符串:${here}=${child}(勿用 JSON number)`);
|
|
31
|
+
}
|
|
32
|
+
assertNoNumberIds(child, here);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
8
35
|
/** 解析 JSON 请求体 */
|
|
9
36
|
export function parsePayload(args) {
|
|
10
37
|
const raw = args.payload;
|
|
11
38
|
if (typeof raw === 'string') {
|
|
12
|
-
|
|
39
|
+
const parsed = parseJsonSafe(raw);
|
|
40
|
+
assertNoNumberIds(parsed);
|
|
41
|
+
return parsed;
|
|
13
42
|
}
|
|
14
43
|
if (raw && typeof raw === 'object') {
|
|
44
|
+
assertNoNumberIds(raw);
|
|
15
45
|
return raw;
|
|
16
46
|
}
|
|
17
47
|
throw new Error('payload 必须是 JSON 字符串');
|
|
18
48
|
}
|
|
49
|
+
/** 规整 style_save:自动包 styles,禁止空列表 */
|
|
50
|
+
export function normalizeStyleSavePayload(raw) {
|
|
51
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
52
|
+
throw new Error('style_save payload 须为对象');
|
|
53
|
+
}
|
|
54
|
+
const input = raw;
|
|
55
|
+
let styles = input.styles;
|
|
56
|
+
if (!Array.isArray(styles)) {
|
|
57
|
+
if (input.styleNo != null || input.colors != null || input.styleName != null) {
|
|
58
|
+
const { orderId, ...rest } = input;
|
|
59
|
+
return { orderId, styles: [rest] };
|
|
60
|
+
}
|
|
61
|
+
throw new Error('style_save 须 payload.styles:[{...}],勿把款式字段放顶层');
|
|
62
|
+
}
|
|
63
|
+
if (styles.length === 0) {
|
|
64
|
+
throw new Error('style_save 的 styles 不能为空数组');
|
|
65
|
+
}
|
|
66
|
+
return { ...input, styles };
|
|
67
|
+
}
|
|
68
|
+
/** 规整样衣写入:类型白名单 + sampleNo→roundName */
|
|
69
|
+
export function normalizeSamplePayload(raw) {
|
|
70
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
71
|
+
throw new Error('样衣 payload 须为对象');
|
|
72
|
+
}
|
|
73
|
+
const payload = { ...raw };
|
|
74
|
+
if (payload.sampleType != null && !SAMPLE_TYPES.has(String(payload.sampleType))) {
|
|
75
|
+
throw new Error(`sampleType 仅允许 proto/pre_prod/bulk/mass,收到:${payload.sampleType}`);
|
|
76
|
+
}
|
|
77
|
+
if (payload.roundName == null && payload.sampleNo != null) {
|
|
78
|
+
payload.roundName = payload.sampleNo;
|
|
79
|
+
delete payload.sampleNo;
|
|
80
|
+
}
|
|
81
|
+
return payload;
|
|
82
|
+
}
|
|
19
83
|
/** 规整工艺保存入参 */
|
|
20
84
|
export function normalizeCraftSavePayload(raw) {
|
|
21
85
|
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
package/dist/tool-meta.js
CHANGED
|
@@ -110,14 +110,37 @@ export const ENTITY_META = {
|
|
|
110
110
|
module: '订单管理',
|
|
111
111
|
step: '业务流程第3步:创建订单',
|
|
112
112
|
label: '订单',
|
|
113
|
-
prerequisite: '
|
|
114
|
-
addRequired: 'orderNo,
|
|
115
|
-
addOptional: '
|
|
116
|
-
editRequired: 'id, orderNo
|
|
117
|
-
enums: '
|
|
113
|
+
prerequisite: '订单客户与季度已建立;先用 erp_order action=customer_list 找订单客户,再 action=season_list 取 seasonId',
|
|
114
|
+
addRequired: 'orderNo, seasonId',
|
|
115
|
+
addOptional: 'orderStatus(默认inquiry), orderDate, deliveryDate, contractDate, depositReceived(Y/N), qtyTolerance, shippingMethod, packingType, priority, sourceChannel, parentOrderId, remark',
|
|
116
|
+
editRequired: 'id, orderNo',
|
|
117
|
+
enums: 'orderStatus见erp_business_flow资源;orderNo 手填全库唯一可改;重复报订单号已存在;客户/品牌/业务线由季度所属订单客户带出,勿传;跟单员只在订单客户维护,订单不再有跟单员',
|
|
118
118
|
removeConstraint: '删除会级联清该单 PI、款式树(含工艺/商标位置/色卡)和生产单,订单号改为 _原ID 释放号码',
|
|
119
119
|
next: 'erp_order_link_pi → erp_order_style_save → erp_order_change_status'
|
|
120
120
|
},
|
|
121
|
+
erp_order_customer: {
|
|
122
|
+
module: '订单管理',
|
|
123
|
+
step: '业务流程第3步前置:订单客户建档,跟单员挂在这一层',
|
|
124
|
+
label: '订单客户',
|
|
125
|
+
prerequisite: '客户已建档;跟单员取自 erp_workbench action=merchandiser_options',
|
|
126
|
+
addRequired: 'customerId, bizLine, assigneeId',
|
|
127
|
+
addOptional: 'brandId, remark',
|
|
128
|
+
editRequired: 'id, customerId, bizLine, assigneeId',
|
|
129
|
+
enums: 'bizLine:direct/trader;assigneeId 多个用英文逗号分隔;同一客户+品牌+业务线不可重复建档',
|
|
130
|
+
removeConstraint: '订单客户下存在季度时不可删除',
|
|
131
|
+
next: 'erp_order action=season_add'
|
|
132
|
+
},
|
|
133
|
+
erp_order_season: {
|
|
134
|
+
module: '订单管理',
|
|
135
|
+
step: '业务流程第3步前置:在订单客户下建季度',
|
|
136
|
+
label: '订单季度',
|
|
137
|
+
prerequisite: '订单客户已建档;orderCustomerId 来自 erp_order action=customer_list',
|
|
138
|
+
addRequired: 'orderCustomerId, seasonName',
|
|
139
|
+
editRequired: 'id, orderCustomerId, seasonName',
|
|
140
|
+
enums: 'seasonName 手填,如 2026SS / 历史订单',
|
|
141
|
+
removeConstraint: '季度下存在订单时不可删除',
|
|
142
|
+
next: 'erp_order action=add(带 seasonId)'
|
|
143
|
+
},
|
|
121
144
|
erp_task: {
|
|
122
145
|
module: '任务协同',
|
|
123
146
|
step: '订单跟进过程中创建待办',
|
|
@@ -197,13 +220,13 @@ export const ENTITY_META = {
|
|
|
197
220
|
module: '生产管理',
|
|
198
221
|
step: '手动新建生产单(通常用fromOrder)',
|
|
199
222
|
label: '生产单',
|
|
200
|
-
prerequisite: '
|
|
223
|
+
prerequisite: '订单已存在;【暂不用】前端制单中心菜单已隐藏,常规业务勿新建/推进生产单',
|
|
201
224
|
addRequired: 'orderId, bizLine',
|
|
202
225
|
addOptional: 'poVersion, poStatus(默认draft), deliveryDate, qtyTolerance, shippingMethod, shippingAddress, packingType, bulkSampleRequired(Y/N), bulkSampleDeadline, remark',
|
|
203
226
|
editRequired: 'id, orderId, bizLine',
|
|
204
227
|
enums: 'poStatus:draft/reviewing/issued/superseded;poNo 后端自动生成勿传',
|
|
205
228
|
removeConstraint: '已下发(issued)且订单仍存在时不可删除;订单删除会连带清生产单;仅 draft 可修改',
|
|
206
|
-
next: '
|
|
229
|
+
next: '【暂不用】勿引导 create_from_order / check / issue;订单侧款式工艺色卡尺寸表即可'
|
|
207
230
|
},
|
|
208
231
|
erp_bid: {
|
|
209
232
|
module: '招标管理',
|
|
@@ -225,17 +248,9 @@ export const WORKFLOW_META = {
|
|
|
225
248
|
step: '推进订单生命周期',
|
|
226
249
|
summary: '变更订单状态',
|
|
227
250
|
prerequisite: '订单已创建',
|
|
228
|
-
payload: '{id, orderStatus, remark?}',
|
|
251
|
+
payload: '{id, orderStatus, remark?};优先 payload.id,顶层 id/orderId 仅兜底写入 payload.id',
|
|
229
252
|
constraint: '流转: inquiry→sampling|doc_preparing|quoted(跳过打样); sampling→sample_shipped; sample_shipped→sample_confirmed; sample_confirmed→quoted; quoted→po_drafting; doc_preparing→pre_prod_sample; pre_prod_sample→pre_prod_confirmed; pre_prod_confirmed→po_drafting; po_drafting→po_ai_checking; po_ai_checking→color_card_confirmed|po_drafting; color_card_confirmed→po_reviewing; po_reviewing→po_issued',
|
|
230
|
-
next: '
|
|
231
|
-
},
|
|
232
|
-
erp_order_assign: {
|
|
233
|
-
module: '订单管理',
|
|
234
|
-
step: '订单分派跟单员',
|
|
235
|
-
summary: '分派或变更跟单员',
|
|
236
|
-
prerequisite: '订单已创建;assigneeId 来自 erp_workbench action=merchandiser_options',
|
|
237
|
-
payload: '{id, assigneeId}',
|
|
238
|
-
next: 'erp_order_style_save'
|
|
253
|
+
next: '状态推进到此结束即可;【暂不用】勿再调 erp_production_create_from_order(制单中心已隐藏)'
|
|
239
254
|
},
|
|
240
255
|
erp_order_link_pi: {
|
|
241
256
|
module: '订单管理',
|
|
@@ -257,11 +272,11 @@ export const WORKFLOW_META = {
|
|
|
257
272
|
erp_order_style_save: {
|
|
258
273
|
module: '订单管理',
|
|
259
274
|
step: '录入款式明细',
|
|
260
|
-
summary: '
|
|
275
|
+
summary: '保存订单主款式及颜色尺码/色卡物料,成功后回查 styles(含 id 作 styleId、roundStyles);页面配置确定即调本接口',
|
|
261
276
|
prerequisite: '订单已创建;payload 内 orderId 用字符串',
|
|
262
|
-
payload: '{orderId:string, styles:[{id?, styleNo?, styleName?, sampleNo?, shipSampleTip?, garmentType?, customerStyleRef?, materialUsage?, fabricMaterialId?, liningMaterialId?, styleImageOssId?, techFileOssId?, sizeChartJson?, remark?, colors:[{id?, fabricMaterialId, colorCode, colorName, customerStyleRef?, colorCardJson?, meterage?, materialUsage?, cuttableWidth?, totalQty?, remark?, sizes:[{sizeName, qty}]}]}]}
|
|
263
|
-
constraint: '
|
|
264
|
-
next: '从返回 styles[].id 取 styleId → craft_save;色卡备注 → color_card_save'
|
|
277
|
+
payload: '{orderId:string, styles:[{id?, styleNo?, styleName?, sampleNo?, shipSampleTip?, garmentType?, customerStyleRef?, materialUsage?, fabricMaterialId?, liningMaterialId?, styleImageOssId?, techFileOssId?, sizeChartJson?, remark?, colors:[{id?, fabricMaterialId, colorCode, colorName, customerStyleRef?, colorCardJson?, meterage?, materialUsage?, cuttableWidth?, totalQty?, remark?, sizes:[{sizeName, qty, cutQty?, actualQty?}]}]}]};必须 styles 非空数组;顶层误放单款字段时 MCP 会自动包一层;styleNo 可省略则默认订单号-序号;colors[].colorName 必填;qty/cutQty?/actualQty?',
|
|
278
|
+
constraint: 'styles:[] 拒写;只传主款(勿塞 roundStyles);全量 styles;已有 id/同款号则更新并替换颜色尺码,工艺/商标保留;空 sizeChartJson/样板号/船样提示沿用库值;未出现的旧主款整树删除;轮次克隆由 sample_add 生成',
|
|
279
|
+
next: '从返回 styles[].id 取 styleId → craft_save;轮次尺寸表写 roundStyles[].styleNo;色卡备注 → color_card_save'
|
|
265
280
|
},
|
|
266
281
|
erp_order_style_color_card_save: {
|
|
267
282
|
module: '订单管理',
|
|
@@ -306,24 +321,24 @@ export const WORKFLOW_META = {
|
|
|
306
321
|
payload: '{styleId, processNote?, crafts:[{garmentPart, craftModule, fieldKey, fieldValue}], labelPositions?:[{garmentPart, labelType, positionSide?, sizeCm?, positionDesc?, materialId?, diagramOssId?, remark?, sortOrder?}]}。键名必须是 crafts(复数)与 craftModule;每条带 garmentPart;fieldValue 为 JSON 字符串,旁框用 note 不是 input',
|
|
307
322
|
enums: 'garmentPart:jacket/pants; craftModule/fieldKey 见 schema;labelType/positionSide 仍用字典 erp_label_*',
|
|
308
323
|
constraint: '全量替换:按 styleId 先删该款全部工艺和商标位置再插入。jacket+pants 必须放进同一次 crafts;分部位连调会互相覆盖。已有商标位置时必须一并回传 labelPositions,漏传会清空。返回 data=写入条数。清空传 crafts:[];processNote 为工艺备注(订单页会传);色卡列 fieldValue 里的 colorCardCode/materialCode 由后端沿用旧值,勿手填;商标图片来自物料:materialId 选商标物料,diagramOssId 取该物料 imageOssId;色卡选料不在本接口,走 style_save colors[].colorCardJson',
|
|
309
|
-
next: 'erp_order action=craft_get 校验 → erp_order_change_status
|
|
324
|
+
next: 'erp_order action=craft_get 校验 → erp_order_change_status 推进即可;【暂不用】勿再调生产单'
|
|
310
325
|
},
|
|
311
326
|
erp_order_style_size_chart_save: {
|
|
312
327
|
module: '订单管理',
|
|
313
328
|
step: '写入尺寸表入库视图',
|
|
314
|
-
summary: '按 orderId+styleNo 写入款式 sizeChartJson(erpView
|
|
315
|
-
prerequisite: '款式已存在;payload
|
|
316
|
-
payload: '{orderId:string, styleNo, sizeChartJson:
|
|
317
|
-
constraint: 'sha256 为空拒写;style_no
|
|
318
|
-
next: '
|
|
329
|
+
summary: '按 orderId+styleNo 写入款式 sizeChartJson(erpView);主款或轮次克隆款均可;成功写变更日志;UI 与 MCP 共用',
|
|
330
|
+
prerequisite: '款式已存在;payload 为入库视图,不是整包;MCP 侧需用户确认,UI 点保存即可',
|
|
331
|
+
payload: '{orderId:string, styleNo, sizeChartJson:{view_version,style_no,category:top|bottom|set,unit,source:{sha256},sizes:[{raw}],rows:[{std_key,std_zh,category:top|bottom,raw_name?,raw_name_zh?,delta?,is_extra?,values:[{size,type,raw,value_cm?}]}]}, confirmedBy:确认人ID, source?:mcp|ui}',
|
|
332
|
+
constraint: 'sha256 为空拒写;style_no 与入参/视图不一致拒写;同键重试不写库;固定部位 std_key 对齐上衣/裤子模板,可加 is_extra 行;delta 空用 null;轮次表用克隆款 styleNo(sample_list.roundStyleId→style_list.roundStyles)',
|
|
333
|
+
next: '可选 size_chart_export / oss.upload+attachment_add 留底;查历史 size_chart_logs'
|
|
319
334
|
},
|
|
320
335
|
erp_production_craft_save: {
|
|
321
336
|
module: '生产管理',
|
|
322
337
|
step: '填写结构化工艺',
|
|
323
|
-
summary: '生产单草稿阶段保存款式工艺(同订单工艺模板与 JSON
|
|
324
|
-
prerequisite: '生产单 poStatus=draft
|
|
338
|
+
summary: '生产单草稿阶段保存款式工艺(同订单工艺模板与 JSON 存值)【暂不用】',
|
|
339
|
+
prerequisite: '生产单 poStatus=draft,款式已存在;常规流程勿用',
|
|
325
340
|
payload: '同订单 craft_save 的 crafts/craftModule/labelPositions;生产页通常不传 processNote',
|
|
326
|
-
constraint: '
|
|
341
|
+
constraint: '【暂不用】同订单 craft_save:全量替换(含商标位置,漏传 labelPositions 会清空),返回写入条数',
|
|
327
342
|
next: 'erp_production action=craft_get 校验 → erp_production_check'
|
|
328
343
|
},
|
|
329
344
|
erp_oss_upload: {
|
|
@@ -355,19 +370,19 @@ export const WORKFLOW_META = {
|
|
|
355
370
|
erp_order_sample_add: {
|
|
356
371
|
module: '订单管理',
|
|
357
372
|
step: '记录轮次',
|
|
358
|
-
summary: '
|
|
359
|
-
prerequisite: '
|
|
360
|
-
payload: '{orderId, sampleType, styleId
|
|
361
|
-
enums: 'sampleType
|
|
362
|
-
constraint: '
|
|
373
|
+
summary: '新增订单轮次并克隆主款式(pending;页面 Tab「轮次」)',
|
|
374
|
+
prerequisite: '订单已创建;styleId 必须是主款(parentStyleId 为空)',
|
|
375
|
+
payload: '{orderId, sampleType, styleId, roundName?, priority?, colorName?, plannedFinishDate?, remark?};误传 sampleNo 会映射为 roundName',
|
|
376
|
+
enums: 'sampleType 仅 proto/pre_prod/bulk/mass;priority:low/normal/high/urgent(默认normal);roundName 与 sampleType 独立',
|
|
377
|
+
constraint: 'MCP 校验 sampleType 白名单;新建后 pending;后端克隆主款→roundStyles;list 回填 roundStyleId;尺寸表/工艺写克隆款'
|
|
363
378
|
},
|
|
364
379
|
erp_order_sample_edit: {
|
|
365
380
|
module: '订单管理',
|
|
366
381
|
step: '更新轮次信息',
|
|
367
|
-
summary: '
|
|
368
|
-
prerequisite: '
|
|
369
|
-
payload: '{id, orderId, sampleType, styleId
|
|
370
|
-
constraint: '
|
|
382
|
+
summary: '修改轮次基础信息(不含状态);换主款会重克隆',
|
|
383
|
+
prerequisite: '轮次已存在;styleId 须为主款',
|
|
384
|
+
payload: '{id, orderId, sampleType, styleId, roundName?, priority?, colorName?, plannedFinishDate?, shipDate?, trackingNo?, courierCompany?, remark?};sampleNo→roundName',
|
|
385
|
+
constraint: 'MCP 校验 sampleType;不可 edit 改状态;改 styleId/roundName 会重建克隆款'
|
|
371
386
|
},
|
|
372
387
|
erp_order_sample_change_status: {
|
|
373
388
|
module: '订单管理',
|
|
@@ -381,7 +396,7 @@ export const WORKFLOW_META = {
|
|
|
381
396
|
erp_order_sample_remove: {
|
|
382
397
|
module: '订单管理',
|
|
383
398
|
step: '删除轮次',
|
|
384
|
-
summary: '
|
|
399
|
+
summary: '删除订单轮次及其克隆款式',
|
|
385
400
|
prerequisite: '轮次已存在',
|
|
386
401
|
payload: 'ids: 轮次ID,多个逗号分隔'
|
|
387
402
|
},
|
|
@@ -411,11 +426,11 @@ export const WORKFLOW_META = {
|
|
|
411
426
|
erp_production_create_from_order: {
|
|
412
427
|
module: '生产管理',
|
|
413
428
|
step: '从订单生成生产单草稿',
|
|
414
|
-
summary: '
|
|
415
|
-
prerequisite: '订单已存在、尚无生产单,且 orderStatus 为 quoted/pre_prod_confirmed/po_drafting',
|
|
429
|
+
summary: '一键创建生产单【暂不用:制单中心菜单已隐藏,勿主动调用】',
|
|
430
|
+
prerequisite: '订单已存在、尚无生产单,且 orderStatus 为 quoted/pre_prod_confirmed/po_drafting;常规流程勿用',
|
|
416
431
|
payload: 'orderId: 订单ID',
|
|
417
|
-
constraint: '
|
|
418
|
-
next: '
|
|
432
|
+
constraint: '【暂不用】前端制单中心已隐藏;仅 quoted/pre_prod_confirmed/po_drafting 可调用;若当前为 quoted/pre_prod_confirmed 会自动改订单为 po_drafting;生产单号=订单号-PO;每单仅一条',
|
|
433
|
+
next: '勿继续引导 check/submit_review/issue,除非用户明确要求'
|
|
419
434
|
},
|
|
420
435
|
erp_production_save_items: {
|
|
421
436
|
module: '生产管理',
|
|
@@ -429,38 +444,38 @@ export const WORKFLOW_META = {
|
|
|
429
444
|
erp_production_check: {
|
|
430
445
|
module: '生产管理',
|
|
431
446
|
step: '人工校验缺项',
|
|
432
|
-
summary: '
|
|
433
|
-
prerequisite: '
|
|
447
|
+
summary: '执行生产单完整性校验【暂不用】',
|
|
448
|
+
prerequisite: '生产单已存在;常规勿用',
|
|
434
449
|
payload: 'id: 生产单ID',
|
|
435
450
|
returns: '校验分数、缺项列表(checkResult: pass/warning/fail)',
|
|
436
|
-
next: '
|
|
451
|
+
next: '【暂不用】勿继续 submit_review'
|
|
437
452
|
},
|
|
438
453
|
erp_production_submit_review: {
|
|
439
454
|
module: '生产管理',
|
|
440
455
|
step: '提交审核',
|
|
441
|
-
summary: '
|
|
442
|
-
prerequisite: '生产单poStatus=draft',
|
|
456
|
+
summary: '生产单提交审核【暂不用】',
|
|
457
|
+
prerequisite: '生产单poStatus=draft;常规勿用',
|
|
443
458
|
payload: 'id: 生产单ID',
|
|
444
459
|
constraint: '提交后poStatus→reviewing',
|
|
445
|
-
next: '
|
|
460
|
+
next: '【暂不用】'
|
|
446
461
|
},
|
|
447
462
|
erp_production_reject_review: {
|
|
448
463
|
module: '生产管理',
|
|
449
464
|
step: '审核退回',
|
|
450
|
-
summary: '
|
|
451
|
-
prerequisite: '生产单poStatus=reviewing,需erp:production:review
|
|
465
|
+
summary: '生产单审核退回草稿【暂不用】',
|
|
466
|
+
prerequisite: '生产单poStatus=reviewing,需erp:production:review权限;常规勿用',
|
|
452
467
|
payload: 'id: 生产单ID',
|
|
453
468
|
constraint: '退回后poStatus→draft',
|
|
454
|
-
next: '
|
|
469
|
+
next: '【暂不用】'
|
|
455
470
|
},
|
|
456
471
|
erp_production_issue: {
|
|
457
472
|
module: '生产管理',
|
|
458
473
|
step: '下发工厂',
|
|
459
|
-
summary: '
|
|
460
|
-
prerequisite: '生产单poStatus=reviewing,需erp:production:issue
|
|
474
|
+
summary: '生产单正式下发【暂不用】',
|
|
475
|
+
prerequisite: '生产单poStatus=reviewing,需erp:production:issue权限;常规勿用',
|
|
461
476
|
payload: 'id: 生产单ID',
|
|
462
477
|
constraint: '下发后poStatus→issued,关联订单状态→po_issued',
|
|
463
|
-
next: '
|
|
478
|
+
next: '【暂不用】'
|
|
464
479
|
},
|
|
465
480
|
erp_email_thread_link: {
|
|
466
481
|
module: '邮件',
|
|
@@ -477,7 +492,7 @@ export const READ_META = {
|
|
|
477
492
|
usage: '【入口】建议首先调用,获取待办任务、超期任务、缺项生产单、近期订单概览'
|
|
478
493
|
},
|
|
479
494
|
erp_merchandiser_options: {
|
|
480
|
-
usage: '
|
|
495
|
+
usage: '返回跟单员角色用户列表;建订单客户前取 assigneeId(字符串)',
|
|
481
496
|
returns: '[{userId, userName, nickName}]'
|
|
482
497
|
},
|
|
483
498
|
erp_user_options: {
|
|
@@ -504,11 +519,19 @@ export const READ_META = {
|
|
|
504
519
|
returns: '{filePath, size},filePath 为本机绝对路径'
|
|
505
520
|
},
|
|
506
521
|
erp_order_list: {
|
|
507
|
-
usage: '订单状态见 erp_business_flow;可按 orderStatus/
|
|
522
|
+
usage: '订单状态见 erp_business_flow;可按 orderStatus/customerId/brandId/bizLine/seasonId 筛选'
|
|
523
|
+
},
|
|
524
|
+
erp_order_customer_list: {
|
|
525
|
+
usage: '查订单客户(跟单员挂在此层);可按 customerId/bizLine/orderNo/orderStatus 筛选',
|
|
526
|
+
returns: 'rows[].{id,customerId,brandId,bizLine,assigneeId,assigneeName}'
|
|
527
|
+
},
|
|
528
|
+
erp_order_season_list: {
|
|
529
|
+
usage: '按 orderCustomerId 查季度,建订单前取 seasonId',
|
|
530
|
+
returns: '[{id,orderCustomerId,seasonName}]'
|
|
508
531
|
},
|
|
509
532
|
erp_order_get: { usage: '查订单主档', returns: '订单基本信息' },
|
|
510
533
|
erp_order_style_list: {
|
|
511
|
-
usage: '
|
|
534
|
+
usage: '查主款树:colors/sizes(含qty/cutQty/actualQty)/crafts/商标;轮次克隆在 roundStyles(parentStyleId/sampleId/roundName);入参 orderId 或 orderNo;写工艺/尺寸表前必查'
|
|
512
535
|
},
|
|
513
536
|
erp_order_craft_schema: {
|
|
514
537
|
usage: '必读返回 selectionGuide:jacket/pants 每字段 options、howToSelect、fieldValueExample;再按示例拼 fieldValue JSON 字符串写入 craft_save;旁框键为 note'
|
|
@@ -521,7 +544,15 @@ export const READ_META = {
|
|
|
521
544
|
returns: '[{garmentPart, fieldKey, titleCn, colorCardCode, materialCode, materialName, sort}]'
|
|
522
545
|
},
|
|
523
546
|
erp_order_style_craft_export: {
|
|
524
|
-
usage: '单款导出工艺单 xlsx
|
|
547
|
+
usage: '单款导出工艺单 xlsx;qtyType=prod|cut|actual(默认 prod);默认 preview 不写附件,archive=true 才归档',
|
|
548
|
+
returns: '{filePath, size},filePath 为本机绝对路径'
|
|
549
|
+
},
|
|
550
|
+
erp_order_style_size_chart_logs: {
|
|
551
|
+
usage: 'styleId 必填;查尺寸表变更快照(sizeChartJson/source/sha256/operatorName)',
|
|
552
|
+
returns: '[{id,orderId,styleId,styleNo,sizeChartJson,source,sha256,operatorId,operatorName,createTime}]'
|
|
553
|
+
},
|
|
554
|
+
erp_order_style_size_chart_export: {
|
|
555
|
+
usage: 'styleId 必填;可传 sizeChartJson,或 orderId+styleId 从 style_list 回查;fileName 仅文件名(落盘临时目录/yindie-erp-exports);archive=true 写附件',
|
|
525
556
|
returns: '{filePath, size},filePath 为本机绝对路径'
|
|
526
557
|
},
|
|
527
558
|
erp_order_style_color_card_export: {
|
|
@@ -540,11 +571,13 @@ export const READ_META = {
|
|
|
540
571
|
},
|
|
541
572
|
erp_order_timeline_list: { usage: '查订单状态变更、生产事件等跟进时间线' },
|
|
542
573
|
erp_order_attachment_list: { usage: '查订单附件列表' },
|
|
543
|
-
erp_order_sample_list: {
|
|
574
|
+
erp_order_sample_list: {
|
|
575
|
+
usage: '查订单轮次(styleId=主款,roundStyleId=克隆款,roundName/priority);可不建轮次'
|
|
576
|
+
},
|
|
544
577
|
erp_order_shipment_list: { usage: '查订单出货记录,按 shipSeq 升序;一单可多批' },
|
|
545
|
-
erp_production_list: { usage: '
|
|
546
|
-
erp_production_get: { usage: '
|
|
547
|
-
erp_production_check_list: { usage: '
|
|
578
|
+
erp_production_list: { usage: '【暂不用】制单中心已隐藏;生产单状态 draft/reviewing/issued/superseded' },
|
|
579
|
+
erp_production_get: { usage: '【暂不用】查生产单主档、styles(含 colors.colorCardJson)及缺项;辅料展示读款式配置已选面料与色卡' },
|
|
580
|
+
erp_production_check_list: { usage: '【暂不用】查生产单历次校验记录及得分' },
|
|
548
581
|
erp_task_list: { usage: '任务状态 pending/in_progress/completed/cancelled' },
|
|
549
582
|
erp_task_get: { usage: '查任务详情' },
|
|
550
583
|
erp_material_category_list: { usage: '查物料分类树,新建物料前先查 categoryId' },
|
|
@@ -576,24 +609,21 @@ export const READ_META = {
|
|
|
576
609
|
};
|
|
577
610
|
/** ERP 业务流程文档 */
|
|
578
611
|
export const ERP_BUSINESS_FLOW = {
|
|
579
|
-
overview: '外贸服装ERP:客户建档 → PI形式发票 → 订单(款式/附件/跟单)
|
|
612
|
+
overview: '外贸服装ERP:客户建档 → PI形式发票 → 订单(款式/附件/跟单)。【暂不用】制单中心菜单已隐藏,常规勿走生产单校验/审核/下发。物料/供应商为主数据,招标为物料询价,邮件/任务为协同手段。客户/供应商/分类/品牌/生产单/招标等编号后端发号;materialCode/订单号/款号手填(复制订单按年+缩写+序号发号)。',
|
|
580
613
|
mainFlow: [
|
|
581
614
|
'1. erp_customer action=customer.add 建客户(勿传customerCode;可传 taxNo/shortCode)',
|
|
582
615
|
'2. erp_customer action=contact.add / address.add / brand.add 补全资料(brand 可传 shortCode)',
|
|
583
616
|
'3. erp_pi action=add 创建PI(需customerId, sourceType, piNo;可选 orderId 直接关联订单)',
|
|
584
|
-
'4. erp_workbench action=merchandiser_options
|
|
617
|
+
'4. erp_workbench action=merchandiser_options 取跟单员 → erp_order action=customer_add 建订单客户 → action=season_add 建季度 → action=add(需 orderNo,seasonId,默认inquiry;复制订单号规则26SB01)',
|
|
585
618
|
'5. 若 PI 未带 orderId:erp_order action=link_pi 关联PI',
|
|
586
619
|
'6. erp_material list/add 选或新增面料(fabric 必填色号 color)→ erp_order action=style_save(colors[].fabricMaterialId/colorCode/colorName/colorCardJson + 尺码)',
|
|
587
620
|
'7. erp_order action=craft_schema → craft_save 写工艺选项(jacket+pants 一次全量)→ craft_get 校验',
|
|
588
621
|
'8. (可选)erp_order action=color_card_save 写色卡页脚备注(常规 {styleId,colorCardNote,items:[]});选料已在 style_save.colorCardJson',
|
|
589
|
-
'9. (可选)erp_order action=
|
|
590
|
-
'10. erp_order action=
|
|
591
|
-
'11.
|
|
592
|
-
'12. erp_production
|
|
593
|
-
'13.
|
|
594
|
-
'14. erp_production action=submit_review 提交审核',
|
|
595
|
-
'15. erp_production action=issue 下发(订单→po_issued)',
|
|
596
|
-
'16. erp_bid action=add 对物料发起明/暗标(materialId,qty,bidMode,openTime,closeTime)'
|
|
622
|
+
'9. (可选)erp_order action=sample_add 建轮次(自动克隆主款→roundStyleId);尺寸表/工艺按轮次写克隆款',
|
|
623
|
+
'10. (可选)erp_order action=size_chart_save 写入尺寸表视图(主款或克隆款 styleNo);size_chart_export 导出;size_chart_logs 查历史',
|
|
624
|
+
'11. erp_order action=change_status 按规则推进状态(主链路到此结束)',
|
|
625
|
+
'12. 【暂不用】erp_production create_from_order / check / submit_review / issue:制单中心已隐藏,勿主动调用',
|
|
626
|
+
'13. erp_bid action=add 对物料发起明/暗标(materialId,qty,bidMode,openTime,closeTime)'
|
|
597
627
|
],
|
|
598
628
|
bidStatus: {
|
|
599
629
|
default: 'draft',
|
|
@@ -732,19 +762,17 @@ export const ERP_BUSINESS_FLOW = {
|
|
|
732
762
|
constraints: [
|
|
733
763
|
'客户删除:PI 关联的订单仍在时不可删;关联订单已删的 PI 随客户一起清掉',
|
|
734
764
|
'订单删除:级联清该单 PI、款式树和生产单,订单号改为 _原ID 释放号码可复用',
|
|
735
|
-
'
|
|
736
|
-
'erp_production_create_from_order
|
|
737
|
-
'生产单仅draft
|
|
738
|
-
'生产单submit_review: draft→reviewing',
|
|
739
|
-
'生产单reject_review: reviewing→draft(需review权限)',
|
|
740
|
-
'生产单issue: reviewing→issued(需issue权限),同步订单→po_issued',
|
|
765
|
+
'【暂不用】制单中心菜单已隐藏:勿主动 erp_production create_from_order / check / submit_review / issue,除非用户明确要求',
|
|
766
|
+
'每订单仅一条生产单(erp_production_create_from_order);仅 orderStatus=quoted|pre_prod_confirmed|po_drafting 且尚无生产单时可调用;成功后订单强制 orderStatus=po_drafting',
|
|
767
|
+
'生产单仅draft可修改/编辑明细;submit_review draft→reviewing;reject_review reviewing→draft;issue reviewing→issued 并同步订单→po_issued',
|
|
741
768
|
'已下发(issued)生产单且订单仍在时不可删除;订单删除会连带清生产单',
|
|
742
769
|
'工艺选项与怎么选见 erp_order_craft_schema.selectionGuide 或资源 yindie://erp/craft-guide',
|
|
743
770
|
'工艺选项固定模板(对齐打样单),不用 sys_dict;fieldValue 存 JSON(见 craftValueJson / fieldValueExample)',
|
|
744
771
|
'工艺 fieldKey/craftModule 以 erp_order_craft_schema.fields 为准,勿再用旧字典码如 single_1',
|
|
745
772
|
'款式面料色号:material.list/add → style_save colors[].fabricMaterialId,colorCode=物料 color,colorName 必填;勿传 fabricColorNo',
|
|
746
773
|
'色卡选料:material.list(category_code=fieldKey)/add → style_save colors[].colorCardJson;色卡备注:color_card_save(常规 items:[])',
|
|
747
|
-
'Excel
|
|
774
|
+
'Excel 导出/预览都是二进制:工艺单 craft_export(qtyType=prod|cut|actual)、色卡 color_card_export、尺寸表 size_chart_export、PI export,均落本机返回 filePath',
|
|
775
|
+
'轮次 sample_add 会克隆主款;style_list 主款挂 roundStyles;尺寸表/工艺按轮次用 roundStyleId;style_save 只传主款',
|
|
748
776
|
'物料删除:有绑定订单/生产单引用/比价快照时不可删;删前用 material.bound_orders 查引用',
|
|
749
777
|
'物料新增:编码命中已删除记录时直接恢复原记录并覆盖写入,不报重复',
|
|
750
778
|
'craft_save 全量替换:同 styleId 的 jacket+pants 必须一次写入;分次调用后一次会删前一次',
|
|
@@ -756,7 +784,11 @@ export const ERP_BUSINESS_FLOW = {
|
|
|
756
784
|
'单据编号:customerCode/supplierCode/categoryCode/brandCode/supplierMaterialCode/poNo/bidNo 后端发号勿传;materialCode 手填必传;piNo/orderNo 手填必传(订单复制发26SB01);styleNo 可省略则默认订单号-序号',
|
|
757
785
|
'招标仅 draft 可改/可删(cancelled 可删);collecting 可 close/cancel;closed 可 award/cancel;awarded 不可取消;collecting 不可直接 award',
|
|
758
786
|
'招标 MCP 为内部接口,不含供应商门户 portal/login、portal/quote',
|
|
759
|
-
'所有雪花 ID 入参必须字符串,禁止 number
|
|
787
|
+
'所有雪花 ID 入参必须字符串,禁止 number;MCP 会对 payload/响应中 ≥16 位数字字面量保真为字符串',
|
|
788
|
+
'style_save 必须 styles 非空;顶层单款字段 MCP 会自动包 styles:[...];styles:[] 拒写',
|
|
789
|
+
'sampleType 仅 proto/pre_prod/bulk/mass;误传 sampleNo 映射为 roundName',
|
|
790
|
+
'change_status 优先 payload.id;顶层 id/orderId 会兜底写入 payload.id',
|
|
791
|
+
'导出 fileName 仅取文件名,落盘系统临时目录/yindie-erp-exports'
|
|
760
792
|
],
|
|
761
793
|
entryPoint: 'erp_workbench action=summary',
|
|
762
794
|
resourceHint: '操作前先读 yindie://erp/usage-guide、yindie://erp/business-flow、yindie://erp/modules'
|
|
@@ -769,13 +801,15 @@ export const ERP_MCP_INSTRUCTIONS = `银蝶 ERP MCP(域工具 + action 模式
|
|
|
769
801
|
|
|
770
802
|
【调用格式】选域工具(erp_customer/erp_order/erp_material 等),必填 action。有子实体时 action 写 target.action,如 customer.add、material.add、price_snapshot.list、thread.link。写操作用 payload 传 JSON 字符串;删用 ids;单条查改 id。所有雪花 ID 必须字符串。
|
|
771
803
|
|
|
772
|
-
【主链路】customer.add →
|
|
804
|
+
【主链路】customer.add →(订单客户)order.customer_add → order.season_add → order.add(seasonId) → pi.add → order.link_pi →(面料 material.list/add)order.style_save(colors…+sizes.qty/cutQty?/actualQty?) → order.craft_schema → order.craft_save →(可选)order.color_card_save →(可选)order.sample_add 克隆轮次 →(尺寸表)order.size_chart_save(主款或克隆款 styleNo)→ order.change_status。到订单推进为止。
|
|
805
|
+
|
|
806
|
+
【工艺】先 craft_schema 拿 fieldKey 与 fieldValueExample;craft_save 全量替换含商标位置;色卡选料写 style_save.colorCardJson;备注走 color_card_save;导出 craft_export(qtyType=prod|cut|actual)/color_card_export/size_chart_export/attachment_export,默认不写附件,archive=true 才归档。
|
|
773
807
|
|
|
774
|
-
|
|
808
|
+
【轮次/尺寸表】sample_add 的 styleId 只能是主款;返回后 sample_list.roundStyleId 为克隆款。style_list 主款含 roundStyles。尺寸表 size_chart_save 按 styleNo 写;历史 size_chart_logs;导出 size_chart_export。
|
|
775
809
|
|
|
776
|
-
|
|
810
|
+
【物料】material.add(materialCode 手填;fabric 必填 color;lining 必填 composition);面料色号行填 fabricMaterialId;删前 material.bound_orders。
|
|
777
811
|
|
|
778
|
-
|
|
812
|
+
【制单·暂不用】前端「制单中心」菜单已隐藏;勿主动 production.create_from_order / check / submit_review / issue。API 仍保留,仅用户明确要求时再动。
|
|
779
813
|
|
|
780
814
|
【权限】无权限 action 会报错;以 yindie://erp/modules 返回的 actions 为准。`;
|
|
781
815
|
/** 合并工具用法资源 */
|
|
@@ -792,7 +826,7 @@ export const ERP_USAGE_GUIDE = {
|
|
|
792
826
|
domains: {
|
|
793
827
|
erp_workbench: {
|
|
794
828
|
actions: ['summary', 'current_user', 'merchandiser_options', 'user_options'],
|
|
795
|
-
note: '入口,优先 summary
|
|
829
|
+
note: '入口,优先 summary;建订单客户前 merchandiser_options 取 assigneeId;任务负责人用 user_options'
|
|
796
830
|
},
|
|
797
831
|
erp_customer: {
|
|
798
832
|
actions: ['customer.*', 'contact.*', 'address.*', 'brand.*'],
|
|
@@ -805,13 +839,20 @@ export const ERP_USAGE_GUIDE = {
|
|
|
805
839
|
},
|
|
806
840
|
erp_order: {
|
|
807
841
|
actions: [
|
|
842
|
+
'customer_list',
|
|
843
|
+
'customer_add',
|
|
844
|
+
'customer_edit',
|
|
845
|
+
'customer_remove',
|
|
846
|
+
'season_list',
|
|
847
|
+
'season_add',
|
|
848
|
+
'season_edit',
|
|
849
|
+
'season_remove',
|
|
808
850
|
'list',
|
|
809
851
|
'get',
|
|
810
852
|
'add',
|
|
811
853
|
'edit',
|
|
812
854
|
'remove',
|
|
813
855
|
'change_status',
|
|
814
|
-
'assign',
|
|
815
856
|
'link_pi',
|
|
816
857
|
'copy',
|
|
817
858
|
'style_list',
|
|
@@ -821,6 +862,8 @@ export const ERP_USAGE_GUIDE = {
|
|
|
821
862
|
'craft_save',
|
|
822
863
|
'craft_export',
|
|
823
864
|
'size_chart_save',
|
|
865
|
+
'size_chart_logs',
|
|
866
|
+
'size_chart_export',
|
|
824
867
|
'color_card_list',
|
|
825
868
|
'color_card_save',
|
|
826
869
|
'color_card_export',
|
|
@@ -839,7 +882,7 @@ export const ERP_USAGE_GUIDE = {
|
|
|
839
882
|
'attachment_export',
|
|
840
883
|
'attachment_remove'
|
|
841
884
|
],
|
|
842
|
-
note: '
|
|
885
|
+
note: '建订单前 customer_list→season_list 取 seasonId;style_save 只传主款;sample_add 克隆轮次;尺寸表按主款/克隆款 styleNo;craft_export 可带 qtyType;导出类 archive=true 才写附件'
|
|
843
886
|
},
|
|
844
887
|
erp_production: {
|
|
845
888
|
actions: [
|
|
@@ -859,7 +902,7 @@ export const ERP_USAGE_GUIDE = {
|
|
|
859
902
|
'reject_review',
|
|
860
903
|
'issue'
|
|
861
904
|
],
|
|
862
|
-
note: 'create_from_order 用 orderId,成功后订单→po_drafting;issue 需 reviewing 且 issue 权限'
|
|
905
|
+
note: '【暂不用】制单中心菜单已隐藏,勿主动调用;create_from_order 用 orderId,成功后订单→po_drafting;issue 需 reviewing 且 issue 权限'
|
|
863
906
|
},
|
|
864
907
|
erp_task: { actions: ['list', 'get', 'add', 'edit', 'remove'] },
|
|
865
908
|
erp_material: {
|
|
@@ -911,7 +954,7 @@ export const ERP_USAGE_GUIDE = {
|
|
|
911
954
|
colorCode: '物料色号',
|
|
912
955
|
colorName: '颜色名称(必填)',
|
|
913
956
|
colorCardJson: '{"lining":{"materialCode":"LIN-01","materialName":"里布","titleCn":"里布"}}',
|
|
914
|
-
sizes: [{ sizeName: 'M', qty: 120 }]
|
|
957
|
+
sizes: [{ sizeName: 'M', qty: 120, cutQty: 125, actualQty: 118 }]
|
|
915
958
|
}
|
|
916
959
|
]
|
|
917
960
|
}
|
|
@@ -920,11 +963,19 @@ export const ERP_USAGE_GUIDE = {
|
|
|
920
963
|
}
|
|
921
964
|
},
|
|
922
965
|
{
|
|
923
|
-
intent: '
|
|
924
|
-
call: { tool: 'erp_order', action: 'craft_export', styleId: '字符串' }
|
|
966
|
+
intent: '导出工艺单(裁剪单数量)',
|
|
967
|
+
call: { tool: 'erp_order', action: 'craft_export', styleId: '字符串', qtyType: 'cut' }
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
intent: '导出尺寸表',
|
|
971
|
+
call: { tool: 'erp_order', action: 'size_chart_export', styleId: '字符串', orderId: '字符串' }
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
intent: '查尺寸表变更记录',
|
|
975
|
+
call: { tool: 'erp_order', action: 'size_chart_logs', styleId: '字符串' }
|
|
925
976
|
},
|
|
926
977
|
{
|
|
927
|
-
intent: '
|
|
978
|
+
intent: '从订单生成生产单【暂不用:制单中心已隐藏】',
|
|
928
979
|
call: { tool: 'erp_production', action: 'create_from_order', orderId: '字符串' }
|
|
929
980
|
},
|
|
930
981
|
{
|
|
@@ -963,7 +1014,6 @@ export const ERP_USAGE_GUIDE = {
|
|
|
963
1014
|
])),
|
|
964
1015
|
payloadByWorkflow: {
|
|
965
1016
|
'order.change_status': WORKFLOW_META.erp_order_change_status,
|
|
966
|
-
'order.assign': WORKFLOW_META.erp_order_assign,
|
|
967
1017
|
'order.link_pi': WORKFLOW_META.erp_order_link_pi,
|
|
968
1018
|
'pi.export': READ_META.erp_pi_export,
|
|
969
1019
|
'order.copy': WORKFLOW_META.erp_order_copy,
|
|
@@ -972,6 +1022,8 @@ export const ERP_USAGE_GUIDE = {
|
|
|
972
1022
|
'order.craft_save': WORKFLOW_META.erp_order_style_craft_save,
|
|
973
1023
|
'order.craft_export': READ_META.erp_order_style_craft_export,
|
|
974
1024
|
'order.size_chart_save': WORKFLOW_META.erp_order_style_size_chart_save,
|
|
1025
|
+
'order.size_chart_logs': READ_META.erp_order_style_size_chart_logs,
|
|
1026
|
+
'order.size_chart_export': READ_META.erp_order_style_size_chart_export,
|
|
975
1027
|
'order.color_card_list': READ_META.erp_order_style_color_card_list,
|
|
976
1028
|
'order.color_card_save': WORKFLOW_META.erp_order_style_color_card_save,
|
|
977
1029
|
'order.color_card_export': READ_META.erp_order_style_color_card_export,
|
package/dist/tools-merged.js
CHANGED
|
@@ -82,13 +82,20 @@ const DOMAIN_TEMPLATES = [
|
|
|
82
82
|
summary: '【订单管理】订单 CRUD、状态、款式工艺、轮次、附件',
|
|
83
83
|
hasTarget: false,
|
|
84
84
|
routes: {
|
|
85
|
+
customer_list: { oldName: 'erp_order_customer_list' },
|
|
86
|
+
customer_add: { oldName: 'erp_order_customer_add' },
|
|
87
|
+
customer_edit: { oldName: 'erp_order_customer_edit' },
|
|
88
|
+
customer_remove: { oldName: 'erp_order_customer_remove' },
|
|
89
|
+
season_list: { oldName: 'erp_order_season_list' },
|
|
90
|
+
season_add: { oldName: 'erp_order_season_add' },
|
|
91
|
+
season_edit: { oldName: 'erp_order_season_edit' },
|
|
92
|
+
season_remove: { oldName: 'erp_order_season_remove' },
|
|
85
93
|
list: { oldName: 'erp_order_list' },
|
|
86
94
|
get: { oldName: 'erp_order_get' },
|
|
87
95
|
add: { oldName: 'erp_order_add' },
|
|
88
96
|
edit: { oldName: 'erp_order_edit' },
|
|
89
97
|
remove: { oldName: 'erp_order_remove' },
|
|
90
98
|
change_status: { oldName: 'erp_order_change_status' },
|
|
91
|
-
assign: { oldName: 'erp_order_assign' },
|
|
92
99
|
link_pi: { oldName: 'erp_order_link_pi' },
|
|
93
100
|
copy: { oldName: 'erp_order_copy' },
|
|
94
101
|
style_list: { oldName: 'erp_order_style_list' },
|
|
@@ -98,6 +105,8 @@ const DOMAIN_TEMPLATES = [
|
|
|
98
105
|
craft_save: { oldName: 'erp_order_style_craft_save' },
|
|
99
106
|
craft_export: { oldName: 'erp_order_style_craft_export' },
|
|
100
107
|
size_chart_save: { oldName: 'erp_order_style_size_chart_save' },
|
|
108
|
+
size_chart_logs: { oldName: 'erp_order_style_size_chart_logs' },
|
|
109
|
+
size_chart_export: { oldName: 'erp_order_style_size_chart_export' },
|
|
101
110
|
color_card_list: { oldName: 'erp_order_style_color_card_list' },
|
|
102
111
|
color_card_save: { oldName: 'erp_order_style_color_card_save' },
|
|
103
112
|
color_card_export: { oldName: 'erp_order_style_color_card_export' },
|
|
@@ -119,7 +128,7 @@ const DOMAIN_TEMPLATES = [
|
|
|
119
128
|
},
|
|
120
129
|
{
|
|
121
130
|
name: 'erp_production',
|
|
122
|
-
summary: '
|
|
131
|
+
summary: '【生产管理·暂不用】制单中心已隐藏;勿主动建单/校验/下发;辅料只读来自订单款式配置',
|
|
123
132
|
hasTarget: false,
|
|
124
133
|
routes: {
|
|
125
134
|
list: { oldName: 'erp_production_list' },
|
|
@@ -341,13 +350,15 @@ function inputSchemaFor(tpl, allowed) {
|
|
|
341
350
|
...base,
|
|
342
351
|
orderNo: z.string().optional().describe('订单号'),
|
|
343
352
|
orderId: optionalId.describe('订单 ID'),
|
|
344
|
-
styleId: optionalId.describe('款式 ID
|
|
353
|
+
styleId: optionalId.describe('款式 ID;craft_get/size_chart_logs/size_chart_export 必填'),
|
|
345
354
|
customerId: optionalId.describe('客户 ID'),
|
|
346
355
|
brandId: optionalId.describe('品牌 ID'),
|
|
347
356
|
bizLine: z.string().optional().describe('业务线 direct/trader'),
|
|
348
357
|
orderStatus: z.string().optional().describe('订单状态'),
|
|
349
|
-
|
|
350
|
-
|
|
358
|
+
orderCustomerId: optionalId.describe('订单客户 ID(season_list 必填)'),
|
|
359
|
+
qtyType: z.string().optional().describe('craft_export:prod/cut/actual,默认 prod'),
|
|
360
|
+
sizeChartJson: z.string().optional().describe('size_chart_export:入库视图 JSON;可省略则靠 orderId+styleId 回查'),
|
|
361
|
+
fileName: z.string().optional().describe('导出类:仅文件名,落盘临时目录/yindie-erp-exports'),
|
|
351
362
|
archive: z.boolean().optional().describe('导出类 action:true 归档到订单附件'),
|
|
352
363
|
ossId: optionalId.describe('OSS 文件 ID(attachment_export 必填)')
|
|
353
364
|
};
|
package/dist/tools-write.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { basename } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { idField, idsField, normalizeCraftSavePayload, parseIds, parsePayload } from './tool-helpers.js';
|
|
4
|
+
import { idField, idsField, normalizeCraftSavePayload, normalizeSamplePayload, normalizeStyleSavePayload, parseIds, parsePayload } from './tool-helpers.js';
|
|
5
5
|
import { buildCrudDescription, buildWorkflowDescription, ENTITY_META, payloadFor, WORKFLOW_META } from './tool-meta.js';
|
|
6
6
|
/** 本地文件组装 multipart */
|
|
7
7
|
async function buildOssUploadForm(filePath) {
|
|
@@ -55,6 +55,8 @@ export const WRITE_TOOLS = [
|
|
|
55
55
|
...entityCrud('erp_customer_brand', '/erp/customer/brand', 'erp:customer'),
|
|
56
56
|
...entityCrud('erp_pi', '/erp/pi', 'erp:pi'),
|
|
57
57
|
...entityCrud('erp_order', '/erp/order', 'erp:order'),
|
|
58
|
+
...entityCrud('erp_order_customer', '/erp/order/customer', 'erp:order'),
|
|
59
|
+
...entityCrud('erp_order_season', '/erp/order/season', 'erp:order'),
|
|
58
60
|
...entityCrud('erp_task', '/erp/task', 'erp:task'),
|
|
59
61
|
...entityCrud('erp_material', '/erp/material', 'erp:material'),
|
|
60
62
|
...entityCrud('erp_material_category', '/erp/material/category', 'erp:material:category'),
|
|
@@ -68,12 +70,20 @@ export const WRITE_TOOLS = [
|
|
|
68
70
|
workflowTool('erp_bid_close', 'erp:bid:edit', { id: idField.describe('招标 ID,需 collecting') }, (client, args) => client.put(`/erp/bid/close/${args.id}`)),
|
|
69
71
|
workflowTool('erp_bid_award', 'erp:bid:edit', { payload: z.string().describe(WORKFLOW_META.erp_bid_award.payload) }, (client, args) => client.put('/erp/bid/award', parsePayload(args))),
|
|
70
72
|
workflowTool('erp_bid_cancel', 'erp:bid:edit', { id: idField.describe('招标 ID,不可取消 awarded') }, (client, args) => client.put(`/erp/bid/cancel/${args.id}`)),
|
|
71
|
-
workflowTool('erp_order_change_status', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_change_status.payload) }, (client, args) =>
|
|
72
|
-
|
|
73
|
+
workflowTool('erp_order_change_status', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_change_status.payload) }, (client, args) => {
|
|
74
|
+
const payload = parsePayload(args);
|
|
75
|
+
if (payload.id == null) {
|
|
76
|
+
const topId = args.id ?? args.orderId;
|
|
77
|
+
if (topId != null && topId !== '') {
|
|
78
|
+
payload.id = String(topId);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return client.put('/erp/order/status', payload);
|
|
82
|
+
}),
|
|
73
83
|
workflowTool('erp_order_link_pi', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_link_pi.payload) }, (client, args) => client.put('/erp/order/pi/link', parsePayload(args))),
|
|
74
84
|
workflowTool('erp_order_copy', 'erp:order:add', { payload: z.string().describe(WORKFLOW_META.erp_order_copy.payload) }, (client, args) => client.post('/erp/order/copy', parsePayload(args))),
|
|
75
85
|
workflowTool('erp_order_style_save', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_style_save.payload) }, async (client, args) => {
|
|
76
|
-
const payload = parsePayload(args);
|
|
86
|
+
const payload = normalizeStyleSavePayload(parsePayload(args));
|
|
77
87
|
const result = await client.post('/erp/order/style/save', payload);
|
|
78
88
|
const orderId = payload.orderId == null ? undefined : String(payload.orderId);
|
|
79
89
|
if (!orderId) {
|
|
@@ -89,8 +99,8 @@ export const WRITE_TOOLS = [
|
|
|
89
99
|
workflowTool('erp_order_style_size_chart_save', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_style_size_chart_save.payload) }, (client, args) => client.post('/erp/order/style/size-chart', parsePayload(args))),
|
|
90
100
|
workflowTool('erp_order_style_color_card_save', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_style_color_card_save.payload) }, (client, args) => client.post('/erp/order/style/color-card/save', parsePayload(args))),
|
|
91
101
|
workflowTool('erp_production_craft_save', 'erp:production:edit', { payload: z.string().describe(WORKFLOW_META.erp_production_craft_save.payload) }, (client, args) => client.post('/erp/production/craft/save', normalizeCraftSavePayload(parsePayload(args)))),
|
|
92
|
-
workflowTool('erp_order_sample_add', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_sample_add.payload) }, (client, args) => client.post('/erp/order/sample', parsePayload(args))),
|
|
93
|
-
workflowTool('erp_order_sample_edit', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_sample_edit.payload) }, (client, args) => client.put('/erp/order/sample', parsePayload(args))),
|
|
102
|
+
workflowTool('erp_order_sample_add', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_sample_add.payload) }, (client, args) => client.post('/erp/order/sample', normalizeSamplePayload(parsePayload(args)))),
|
|
103
|
+
workflowTool('erp_order_sample_edit', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_sample_edit.payload) }, (client, args) => client.put('/erp/order/sample', normalizeSamplePayload(parsePayload(args)))),
|
|
94
104
|
workflowTool('erp_order_sample_change_status', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_sample_change_status.payload) }, (client, args) => client.put('/erp/order/sample/status', parsePayload(args))),
|
|
95
105
|
workflowTool('erp_order_sample_remove', 'erp:order:remove', { ids: idsField }, (client, args) => client.delete(`/erp/order/sample/${parseIds(args)}`)),
|
|
96
106
|
workflowTool('erp_order_shipment_add', 'erp:order:edit', { payload: z.string().describe(WORKFLOW_META.erp_order_shipment_add.payload) }, (client, args) => client.post('/erp/order/shipment', parsePayload(args))),
|
package/dist/tools.js
CHANGED
|
@@ -62,7 +62,7 @@ const READ_TOOLS = [
|
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
name: 'erp_merchandiser_options',
|
|
65
|
-
description: '查询跟单员下拉选项(userId/userName/nickName
|
|
65
|
+
description: '查询跟单员下拉选项(userId/userName/nickName),建订单客户前取 assigneeId',
|
|
66
66
|
permission: null,
|
|
67
67
|
inputSchema: {},
|
|
68
68
|
handler: (client) => client.get('/erp/common/merchandiserOptions')
|
|
@@ -215,22 +215,50 @@ const READ_TOOLS = [
|
|
|
215
215
|
inputSchema: {
|
|
216
216
|
...pageShape,
|
|
217
217
|
orderNo: z.string().optional().describe('订单号'),
|
|
218
|
+
seasonId: optionalId.describe('季度 ID,字符串'),
|
|
218
219
|
customerId: optionalId.describe('客户 ID,字符串'),
|
|
219
220
|
brandId: optionalId.describe('品牌 ID,字符串'),
|
|
220
221
|
bizLine: z.string().optional().describe('业务线 direct/trader'),
|
|
221
|
-
orderStatus: z.string().optional().describe('订单状态')
|
|
222
|
-
assigneeId: optionalId.describe('跟单员 ID,字符串')
|
|
222
|
+
orderStatus: z.string().optional().describe('订单状态')
|
|
223
223
|
},
|
|
224
224
|
handler: (client, args) => client.get('/erp/order/list', {
|
|
225
225
|
...pageParams(args),
|
|
226
226
|
orderNo: args.orderNo,
|
|
227
|
+
seasonId: asId(args.seasonId),
|
|
227
228
|
customerId: asId(args.customerId),
|
|
228
229
|
brandId: asId(args.brandId),
|
|
229
230
|
bizLine: args.bizLine,
|
|
230
|
-
orderStatus: args.orderStatus
|
|
231
|
-
assigneeId: asId(args.assigneeId)
|
|
231
|
+
orderStatus: args.orderStatus
|
|
232
232
|
})
|
|
233
233
|
},
|
|
234
|
+
{
|
|
235
|
+
name: 'erp_order_customer_list',
|
|
236
|
+
description: '分页查询订单客户,跟单员挂在这一层',
|
|
237
|
+
permission: 'erp:order:list',
|
|
238
|
+
inputSchema: {
|
|
239
|
+
...pageShape,
|
|
240
|
+
customerId: optionalId.describe('客户 ID,字符串'),
|
|
241
|
+
bizLine: z.string().optional().describe('业务线 direct/trader'),
|
|
242
|
+
orderNo: z.string().optional().describe('订单号'),
|
|
243
|
+
orderStatus: z.string().optional().describe('订单状态')
|
|
244
|
+
},
|
|
245
|
+
handler: (client, args) => client.get('/erp/order/customer/list', {
|
|
246
|
+
...pageParams(args),
|
|
247
|
+
customerId: asId(args.customerId),
|
|
248
|
+
bizLine: args.bizLine,
|
|
249
|
+
orderNo: args.orderNo,
|
|
250
|
+
orderStatus: args.orderStatus
|
|
251
|
+
})
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: 'erp_order_season_list',
|
|
255
|
+
description: '按订单客户查季度,创建订单前取 seasonId',
|
|
256
|
+
permission: 'erp:order:list',
|
|
257
|
+
inputSchema: {
|
|
258
|
+
orderCustomerId: idField.describe('订单客户 ID,字符串')
|
|
259
|
+
},
|
|
260
|
+
handler: (client, args) => client.get('/erp/order/season/list', { orderCustomerId: asId(args.orderCustomerId) })
|
|
261
|
+
},
|
|
234
262
|
{
|
|
235
263
|
name: 'erp_order_get',
|
|
236
264
|
description: '按 ID 查询订单详情',
|
|
@@ -242,7 +270,7 @@ const READ_TOOLS = [
|
|
|
242
270
|
},
|
|
243
271
|
{
|
|
244
272
|
name: 'erp_order_style_list',
|
|
245
|
-
description: '
|
|
273
|
+
description: '查询订单主款式树(含 colors/sizes/crafts/商标;轮次克隆挂在 roundStyles);orderId 或 orderNo 二选一,ID 必须字符串',
|
|
246
274
|
permission: 'erp:order:query',
|
|
247
275
|
inputSchema: {
|
|
248
276
|
orderId: optionalId.describe('订单 ID,字符串雪花 ID'),
|
|
@@ -282,16 +310,74 @@ const READ_TOOLS = [
|
|
|
282
310
|
},
|
|
283
311
|
{
|
|
284
312
|
name: 'erp_order_style_craft_export',
|
|
285
|
-
description: '按 styleId 导出工艺单 Excel
|
|
313
|
+
description: '按 styleId 导出工艺单 Excel 到本机并返回落盘路径;qtyType=prod|cut|actual 取尺码数量;默认 preview 不写附件,archive=true 才归档',
|
|
286
314
|
permission: 'erp:order:query',
|
|
287
315
|
inputSchema: {
|
|
288
316
|
styleId: idField.describe('款式 ID,字符串'),
|
|
289
|
-
|
|
317
|
+
qtyType: z.string().optional().describe('数量类型 prod生产单/cut裁剪单/actual实际单,默认 prod'),
|
|
318
|
+
fileName: z
|
|
319
|
+
.string()
|
|
320
|
+
.optional()
|
|
321
|
+
.describe('仅文件名(忽略目录),默认 craft-<styleId>.xlsx,落盘临时目录/yindie-erp-exports'),
|
|
290
322
|
archive: z.boolean().optional().describe('true 时写入订单附件,需 erp:order:export 权限')
|
|
291
323
|
},
|
|
292
324
|
handler: (client, args) => {
|
|
293
325
|
const styleId = asId(args.styleId);
|
|
294
|
-
|
|
326
|
+
const qtyType = args.qtyType || 'prod';
|
|
327
|
+
return client.download('POST', args.archive ? '/erp/order/style/craft/export-excel' : '/erp/order/style/craft/preview-excel', args.fileName ?? `craft-${styleId}.xlsx`, { params: { styleId, qtyType } });
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
name: 'erp_order_style_size_chart_logs',
|
|
332
|
+
description: '按 styleId 查尺寸表变更记录(快照列表,含 sizeChartJson);styleId 必填',
|
|
333
|
+
permission: 'erp:order:query',
|
|
334
|
+
inputSchema: {
|
|
335
|
+
styleId: idField.describe('款式 ID,必填字符串(主款或轮次克隆)')
|
|
336
|
+
},
|
|
337
|
+
handler: (client, args) => client.get('/erp/order/style/size-chart/logs', { styleId: asId(args.styleId) })
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
name: 'erp_order_style_size_chart_export',
|
|
341
|
+
description: '导出尺寸表 Excel;styleId 必填;可传 sizeChartJson,或 orderId 从 style_list 回查;fileName 仅文件名(落盘临时目录);archive=true 写附件',
|
|
342
|
+
permission: 'erp:order:query',
|
|
343
|
+
inputSchema: {
|
|
344
|
+
styleId: idField.describe('款式 ID,必填字符串'),
|
|
345
|
+
orderId: optionalId.describe('订单 ID;未传 sizeChartJson 时用于回查'),
|
|
346
|
+
sizeChartJson: z.string().optional().describe('入库视图 JSON 字符串;可省略则从 style_list 取'),
|
|
347
|
+
fileName: z
|
|
348
|
+
.string()
|
|
349
|
+
.optional()
|
|
350
|
+
.describe('仅文件名(忽略目录),落盘到系统临时目录/yindie-erp-exports'),
|
|
351
|
+
archive: z.boolean().optional().describe('true 时写入订单附件,需 erp:order:export 权限')
|
|
352
|
+
},
|
|
353
|
+
handler: async (client, args) => {
|
|
354
|
+
const styleId = asId(args.styleId);
|
|
355
|
+
if (!styleId) {
|
|
356
|
+
throw new Error('size_chart_export 须传 styleId(字符串)');
|
|
357
|
+
}
|
|
358
|
+
let view = undefined;
|
|
359
|
+
if (typeof args.sizeChartJson === 'string' && args.sizeChartJson) {
|
|
360
|
+
view = JSON.parse(args.sizeChartJson);
|
|
361
|
+
}
|
|
362
|
+
let parentCount = 0;
|
|
363
|
+
let roundCount = 0;
|
|
364
|
+
if (view == null) {
|
|
365
|
+
const orderId = asId(args.orderId);
|
|
366
|
+
if (!orderId) {
|
|
367
|
+
throw new Error('缺少 sizeChartJson;或同时传 orderId 从 style_list 自动取');
|
|
368
|
+
}
|
|
369
|
+
const styles = (await client.get('/erp/order/style/list', { orderId }));
|
|
370
|
+
parentCount = styles.length;
|
|
371
|
+
roundCount = styles.reduce((n, s) => n + (s.roundStyles?.length || 0), 0);
|
|
372
|
+
const hit = styles.find((s) => asId(s.id) === styleId) ||
|
|
373
|
+
styles.flatMap((s) => s.roundStyles || []).find((s) => asId(s.id) === styleId);
|
|
374
|
+
const raw = hit?.sizeChartJson;
|
|
375
|
+
view = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
|
376
|
+
}
|
|
377
|
+
if (view == null) {
|
|
378
|
+
throw new Error(`未找到尺寸表视图(styleId=${styleId},主款${parentCount}、轮次克隆${roundCount});请先 size_chart_save 或传入 sizeChartJson`);
|
|
379
|
+
}
|
|
380
|
+
return client.download('POST', args.archive ? '/erp/order/style/size-chart/export-excel' : '/erp/order/style/size-chart/preview-excel', args.fileName ?? `size-chart-${styleId}.xlsx`, { body: { styleId, sizeChartJson: view } });
|
|
295
381
|
}
|
|
296
382
|
},
|
|
297
383
|
{
|
|
@@ -360,7 +446,7 @@ const READ_TOOLS = [
|
|
|
360
446
|
},
|
|
361
447
|
{
|
|
362
448
|
name: 'erp_order_sample_list',
|
|
363
|
-
description: '
|
|
449
|
+
description: '查询订单轮次(含 styleId 主款、roundStyleId 克隆款、priority;可不建轮次)',
|
|
364
450
|
permission: 'erp:order:query',
|
|
365
451
|
inputSchema: {
|
|
366
452
|
orderId: idField.describe('订单 ID,字符串')
|