@besile/scm-cli 2026.3.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.
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 WFS
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Material Orders +list shortcut
7
+ */
8
+ import { scmClient, ordersLogger } from '../../internal/index.js';
9
+
10
+ export const MaterialOrdersList = {
11
+ service: 'material-orders',
12
+ command: '+list',
13
+ description: '查询物料订单列表',
14
+ risk: 'read',
15
+ scopes: [],
16
+ hasFormat: true,
17
+ flags: [
18
+ { name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
19
+ { name: 'page-no', type: 'number', default: 1, description: '页码' },
20
+ { name: 'page-size', type: 'number', default: 20, description: '每页条数' },
21
+ // 订单信息
22
+ { name: 'order-no', type: 'string', description: '物料订单号' },
23
+ { name: 'status', type: 'string', description: '物料订单状态: 0-待采购|1-采购中|2-部分到货|3-已到货|4-已取消' },
24
+ { name: 'cooperation-mode', type: 'string', description: '合作模式: 0-CMT|1-FOB' },
25
+ // 商品信息
26
+ { name: 'goods-full-code', type: 'string', description: '大货款号' },
27
+ { name: 'goods-batch', type: 'string', description: '大货批次' },
28
+ { name: 'goods-type', type: 'string', description: '大货类型: 0-首单|1-加单|2-翻单' },
29
+ // 供应商
30
+ { name: 'supplier-name', type: 'string', description: '供应商名称' },
31
+ // 人员
32
+ { name: 'purchaser-id-list', type: 'string', description: '采购员 ID 列表 (逗号分隔)' },
33
+ { name: 'pd-user-id-list', type: 'string', description: 'PD ID 列表 (逗号分隔)' },
34
+ { name: 'designer-name', type: 'string', description: '设计师名称' },
35
+ // 时间
36
+ { name: 'type', type: 'string', description: '时间查询类型: 0-上市|1-下单|2-交期|3-调整|4-关单|5-生产下单|6-工厂接单|7-计划到货|8-实际到货|9-需求到货' },
37
+ { name: 'start-time', type: 'string', description: '开始时间 (ISO 8601)' },
38
+ { name: 'end-time', type: 'string', description: '结束时间 (ISO 8601)' },
39
+ ],
40
+
41
+ async execute(internal, runtime) {
42
+ const f = runtime.flags;
43
+ const openId = f['open-id'];
44
+ const token = await scmClient.getToken(openId, null, null);
45
+
46
+ const filter = {
47
+ pageNo: parseInt(f['page-no']) || 1,
48
+ pageSize: Math.min(parseInt(f['page-size']) || 20, 100),
49
+ };
50
+
51
+ // 订单信息
52
+ if (f['order-no']) filter.orderNo = f['order-no'];
53
+ if (f['status'] !== undefined) filter.status = parseInt(f['status']);
54
+ if (f['cooperation-mode'] !== undefined) filter.cooperationMode = parseInt(f['cooperation-mode']);
55
+ // 商品信息
56
+ if (f['goods-full-code']) filter.goodsFullCode = f['goods-full-code'];
57
+ if (f['goods-batch']) filter.goodsBatch = f['goods-batch'];
58
+ if (f['goods-type'] !== undefined) filter.goodsType = parseInt(f['goods-type']);
59
+ // 供应商
60
+ if (f['supplier-name']) filter.supplierName = f['supplier-name'];
61
+ // 人员
62
+ if (f['purchaser-id-list']) filter.purchaserIdList = f['purchaser-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
63
+ if (f['pd-user-id-list']) filter.pdUserIdList = f['pd-user-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
64
+ if (f['designer-name']) filter.designerName = f['designer-name'];
65
+ // 时间
66
+ if (f['type'] !== undefined) filter.type = parseInt(f['type']);
67
+ if (f['start-time']) filter.startTime = f['start-time'];
68
+ if (f['end-time']) filter.endTime = f['end-time'];
69
+
70
+ const body = { domain: 'goods_material', action: 'query', filter };
71
+ const endpoint = '/admin-api/api/ai-scm/execute';
72
+ const result = await scmClient.invoke(endpoint, { method: 'POST', body }, { token });
73
+
74
+ ordersLogger.info('查询物料订单', { openId, total: result?.total });
75
+ return result || {};
76
+ },
77
+ };
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 WFS
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Production Orders shortcuts
7
+ */
8
+ import { ProductionOrdersList } from './list.js';
9
+ import { ProductionOrdersQuery } from './query.js';
10
+
11
+ export function Shortcuts() {
12
+ return [ProductionOrdersList, ProductionOrdersQuery];
13
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 WFS
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Production Orders +list shortcut
7
+ */
8
+ import { scmClient, ordersLogger } from '../../internal/index.js';
9
+
10
+ /**
11
+ * +list shortcut — list production orders with pagination
12
+ */
13
+ export const ProductionOrdersList = {
14
+ service: 'production-orders',
15
+ command: '+list',
16
+ description: '查询大货生产订单列表(支持分页)',
17
+ risk: 'read',
18
+ scopes: [],
19
+ hasFormat: true,
20
+ flags: [
21
+ { name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
22
+ { name: 'page-no', type: 'number', default: 1, description: '页码,从 1 开始' },
23
+ { name: 'page-size', type: 'number', default: 20, description: '每页条数,最大 100' },
24
+ ],
25
+
26
+ async execute(internal, runtime) {
27
+ const { 'open-id': openId, 'page-no': pageNo, 'page-size': pageSize } = runtime.flags;
28
+ const token = await scmClient.getToken(openId, null, null);
29
+
30
+ const body = {
31
+ domain: 'production_order',
32
+ action: 'query',
33
+ filter: {
34
+ pageNo: parseInt(pageNo) || 1,
35
+ pageSize: Math.min(parseInt(pageSize) || 20, 100),
36
+ },
37
+ };
38
+
39
+ const endpoint = '/admin-api/api/ai-scm/execute';
40
+ const result = await scmClient.invoke(endpoint, {
41
+ method: 'POST',
42
+ body,
43
+ }, { token });
44
+
45
+ ordersLogger.info('查询生产订单', { openId, total: result?.total });
46
+ return result || {};
47
+ },
48
+ };
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 WFS
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Production Orders +query shortcut
7
+ */
8
+ import { scmClient, ordersLogger } from '../../internal/index.js';
9
+
10
+ /**
11
+ * +query shortcut — full production orders query with all filters
12
+ */
13
+ export const ProductionOrdersQuery = {
14
+ service: 'production-orders',
15
+ command: '+query',
16
+ description: '查询大货生产订单(支持全部筛选条件)',
17
+ risk: 'read',
18
+ scopes: [],
19
+ hasFormat: true,
20
+ flags: [
21
+ { name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
22
+ { name: 'page-no', type: 'number', default: 1, description: '页码' },
23
+ { name: 'page-size', type: 'number', default: 20, description: '每页条数' },
24
+ // 订单状态
25
+ { name: 'prod-status', type: 'string', description: '生产订单状态: -1-全部|0-待确定|1-待同步|2-在途中|3-已完成|100-已取消' },
26
+ { name: 'confirm-supplier', type: 'string', description: '确认供应商: 0-未确认|1-已确认' },
27
+ { name: 'supplier-order-status', type: 'string', description: '供应商订单状态' },
28
+ { name: 'quotation-status', type: 'string', description: '报价单状态' },
29
+ { name: 'wash-status', type: 'string', description: '洗唛订单状态' },
30
+ // 商品信息
31
+ { name: 'goods-full-code', type: 'string', description: '大货款号' },
32
+ { name: 'goods-batch', type: 'string', description: '大货批次' },
33
+ { name: 'goods-type', type: 'string', description: '大货类型: 0-首单|1-加单|2-翻单' },
34
+ // 供应商
35
+ { name: 'supplier-name', type: 'string', description: '供应商名称' },
36
+ { name: 'cooperation-mode', type: 'string', description: '合作模式: 0-CMT|1-FOB' },
37
+ // 人员
38
+ { name: 'designer-name', type: 'string', description: '设计师名称' },
39
+ // 时间
40
+ { name: 'type', type: 'string', description: '时间类型: 0-上市|1-下单|2-交期...' },
41
+ { name: 'start-time', type: 'string', description: '开始时间 (ISO 8601)' },
42
+ { name: 'end-time', type: 'string', description: '结束时间 (ISO 8601)' },
43
+ // 状态标识
44
+ { name: 'qc-inspection', type: 'string', description: 'QC 质检结果' },
45
+ // 分类
46
+ { name: 'sale-area', type: 'string', description: '销售地区 ID 列表(逗号分隔)' },
47
+ ],
48
+
49
+ async execute(internal, runtime) {
50
+ const f = runtime.flags;
51
+ const openId = f['open-id'];
52
+
53
+ const token = await scmClient.getToken(openId, null, null);
54
+
55
+ const filter = {
56
+ pageNo: parseInt(f['page-no']) || 1,
57
+ pageSize: Math.min(parseInt(f['page-size']) || 20, 100),
58
+ };
59
+
60
+ // Optional filters
61
+ if (f['prod-status'] !== undefined) filter.prodStatus = parseInt(f['prod-status']);
62
+ if (f['confirm-supplier'] !== undefined) filter.confirmSupplier = parseInt(f['confirm-supplier']);
63
+ if (f['supplier-order-status'] !== undefined) filter.supplierOrderStatus = parseInt(f['supplier-order-status']);
64
+ if (f['quotation-status'] !== undefined) filter.quotationStatus = parseInt(f['quotation-status']);
65
+ if (f['wash-status'] !== undefined) filter.washStatus = parseInt(f['wash-status']);
66
+ if (f['goods-full-code']) filter.goodsFullCode = f['goods-full-code'];
67
+ if (f['goods-batch']) filter.goodsBatch = f['goods-batch'];
68
+ if (f['goods-type'] !== undefined) filter.goodsType = parseInt(f['goods-type']);
69
+ if (f['supplier-name']) filter.supplierName = f['supplier-name'];
70
+ if (f['cooperation-mode'] !== undefined) filter.cooperationMode = parseInt(f['cooperation-mode']);
71
+ if (f['designer-name']) filter.designerName = f['designer-name'];
72
+ if (f['type'] !== undefined) filter.type = parseInt(f['type']);
73
+ if (f['start-time']) filter.startTime = f['start-time'];
74
+ if (f['end-time']) filter.endTime = f['end-time'];
75
+ if (f['qc-inspection'] !== undefined) filter.qcInspection = parseInt(f['qc-inspection']);
76
+ if (f['sale-area']) filter.saleArea = f['sale-area'].split(',').map(Number);
77
+
78
+ const body = { domain: 'production_order', action: 'query', filter };
79
+
80
+ const endpoint = '/admin-api/api/ai-scm/execute';
81
+ const result = await scmClient.invoke(endpoint, { method: 'POST', body }, { token });
82
+
83
+ ordersLogger.info('查询生产订单', { openId, total: result?.total });
84
+ return result || {};
85
+ },
86
+ };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 WFS
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * QC Orders shortcuts
7
+ */
8
+ import { QcOrdersList } from './list.js';
9
+
10
+ export function Shortcuts() {
11
+ return [QcOrdersList];
12
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 WFS
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * QC Orders +list shortcut
7
+ */
8
+ import { scmClient, ordersLogger } from '../../internal/index.js';
9
+
10
+ export const QcOrdersList = {
11
+ service: 'qc-orders',
12
+ command: '+list',
13
+ description: '查询 QC 质检订单列表',
14
+ risk: 'read',
15
+ scopes: [],
16
+ hasFormat: true,
17
+ flags: [
18
+ { name: 'open-id', type: 'string', required: true, description: '飞书用户 openId' },
19
+ { name: 'page-no', type: 'number', default: 1, description: '页码' },
20
+ { name: 'page-size', type: 'number', default: 10, description: '每页条数' },
21
+ // 订单状态
22
+ { name: 'qc-order-status', type: 'string', description: 'QC 订单状态: -1-全部|0-待分配|1-已分配|2-已完成|3-已取消' },
23
+ // 商品信息
24
+ { name: 'goods-full-code', type: 'string', description: '大货款号' },
25
+ { name: 'goods-type', type: 'string', description: '大货类型: 1-大货|2-翻单|3-补料' },
26
+ { name: 'goods-grade-list', type: 'string', description: '商品分级列表 (逗号分隔)' },
27
+ // 供应商
28
+ { name: 'supplier-name', type: 'string', description: '供应商名称' },
29
+ // 人员
30
+ { name: 'mid-manager', type: 'string', description: '中查管理人员' },
31
+ { name: 'check-goods', type: 'string', description: '查货人员' },
32
+ { name: 'tail-manager', type: 'string', description: '尾查管理人员' },
33
+ { name: 'qc-user-id-list', type: 'string', description: 'QC 用户 ID 列表 (逗号分隔)' },
34
+ { name: 'prod-manager-id-list', type: 'string', description: '生产经理 ID 列表 (逗号分隔)' },
35
+ { name: 'purchaser-id-list', type: 'string', description: '采购员 ID 列表 (逗号分隔)' },
36
+ // 时间
37
+ { name: 'time-type', type: 'string', description: '时间类型: 0-预约验货|1-下单|2-接单|3-分配|4-完成|5-交期' },
38
+ { name: 'start-time', type: 'string', description: '开始时间 (ISO 8601)' },
39
+ { name: 'end-time', type: 'string', description: '结束时间 (ISO 8601)' },
40
+ ],
41
+
42
+ async execute(internal, runtime) {
43
+ const f = runtime.flags;
44
+ const openId = f['open-id'];
45
+ const token = await scmClient.getToken(openId, null, null);
46
+
47
+ const filter = {
48
+ pageNo: parseInt(f['page-no']) || 1,
49
+ pageSize: Math.min(parseInt(f['page-size']) || 10, 100),
50
+ };
51
+
52
+ // 订单状态
53
+ if (f['qc-order-status'] !== undefined) filter.qcOrderStatus = parseInt(f['qc-order-status']);
54
+ // 商品信息
55
+ if (f['goods-full-code']) filter.goodsFullCode = f['goods-full-code'];
56
+ if (f['goods-type'] !== undefined) filter.goodsType = parseInt(f['goods-type']);
57
+ if (f['goods-grade-list']) filter.goodsGradeList = f['goods-grade-list'].split(',').map(s => s.trim());
58
+ // 供应商
59
+ if (f['supplier-name']) filter.supplierName = f['supplier-name'];
60
+ // 人员
61
+ if (f['mid-manager']) filter.midManager = f['mid-manager'];
62
+ if (f['check-goods']) filter.checkGoods = f['check-goods'];
63
+ if (f['tail-manager']) filter.tailManager = f['tail-manager'];
64
+ if (f['qc-user-id-list']) filter.qcUserIdList = f['qc-user-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
65
+ if (f['prod-manager-id-list']) filter.prodManagerIdList = f['prod-manager-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
66
+ if (f['purchaser-id-list']) filter.purchaserIdList = f['purchaser-id-list'].split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
67
+ // 时间
68
+ if (f['time-type'] !== undefined) filter.timeType = parseInt(f['time-type']);
69
+ if (f['start-time']) filter.startTime = f['start-time'];
70
+ if (f['end-time']) filter.endTime = f['end-time'];
71
+
72
+ const body = { domain: 'qc_order', action: 'query', filter };
73
+ const endpoint = '/admin-api/api/ai-scm/execute';
74
+ const result = await scmClient.invoke(endpoint, { method: 'POST', body }, { token });
75
+
76
+ ordersLogger.info('查询 QC 订单', { openId, total: result?.total });
77
+ return result || {};
78
+ },
79
+ };
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2026 WFS
4
+ * SPDX-License-Identifier: MIT
5
+ *
6
+ * Shortcuts registration — registers all shortcuts to the command tree
7
+ *
8
+ * Inspired by lark-cli's shortcuts/register.go
9
+ */
10
+
11
+ import { shortcutAction } from './common/runner.js';
12
+
13
+ /**
14
+ * Register all shortcuts for a domain
15
+ *
16
+ * @param {Object} program - Commander program
17
+ * @param {string} domain - Domain name (e.g., 'production-orders')
18
+ * @param {Array} shortcuts - Array of Shortcut definitions
19
+ * @param {Object} internalCtx - Internal context
20
+ */
21
+ function registerDomainShortcuts(program, domain, shortcuts, internalCtx) {
22
+ // Find or create domain subcommand
23
+ let domainCmd = program.commands.find(c => c.name() === domain);
24
+
25
+ if (!domainCmd) {
26
+ domainCmd = program
27
+ .command(domain)
28
+ .description(`${domain} commands`);
29
+ }
30
+
31
+ for (const shortcut of shortcuts) {
32
+ // Build command name without + prefix
33
+ const cmdName = shortcut.command.replace(/^\+/, '');
34
+
35
+ // Create command with description
36
+ const cmd = domainCmd
37
+ .command(cmdName)
38
+ .description(shortcut.description);
39
+
40
+ // Add flags
41
+ for (const flag of (shortcut.flags || [])) {
42
+ let flagSpec = `--${flag.name}`;
43
+ if (flag.type === 'boolean') {
44
+ flagSpec = `--${flag.name}`;
45
+ } else {
46
+ flagSpec += ` <${flag.name}>`;
47
+ }
48
+
49
+ const description = flag.description || '';
50
+ const defaultVal = flag.default !== undefined ? String(flag.default) : undefined;
51
+
52
+ if (flag.type === 'boolean') {
53
+ cmd.option(`--${flag.name}`, description, defaultVal);
54
+ } else if (flag.required) {
55
+ cmd.requiredOption(`${flagSpec} [required]`, description);
56
+ } else {
57
+ cmd.option(`${flagSpec}`, description, defaultVal);
58
+ }
59
+ }
60
+
61
+ // Add --format flag if hasFormat
62
+ if (shortcut.hasFormat !== false) {
63
+ cmd.option('--format <format>', 'Output format: table|json|pretty', 'table');
64
+ }
65
+
66
+ // Register action
67
+ cmd.action(shortcutAction(shortcut, internalCtx));
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Register all shortcuts to the commander program
73
+ *
74
+ * @param {Object} program - Root commander program
75
+ * @param {Object} shortcutsMap - Map of domain -> Shortcut[] (from domain/index.js)
76
+ * @param {Object} internalCtx - Internal context
77
+ */
78
+ export function registerShortcuts(program, shortcutsMap, internalCtx) {
79
+ for (const [domain, shortcuts] of Object.entries(shortcutsMap)) {
80
+ registerDomainShortcuts(program, domain, shortcuts, internalCtx);
81
+ }
82
+ }