Files
LWLT-AI/archive/handoff/2026-07-12/legacy-erp-handoff/tools/erp_operation_handlers.js
2026-07-13 19:57:46 +08:00

318 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const orderRegistry = require('./erp_order_registry');
const updateOrderParser = require('./erp_update_order_parser');
function registryPathFromOptions(options = {}) {
return options.registryPath || (options.config && options.config.paths && options.config.paths.orderRegistry) || '';
}
function findOrderRecord(identifier, options = {}) {
return orderRegistry.findOrderByIdentifier(identifier, {
registryPath: registryPathFromOptions(options) || undefined,
});
}
function isConfirmationType(value) {
const text = String(value || '').toLowerCase();
if (!text) return false;
if (/job|beian|备案|ob/.test(text)) return false;
return /confirm|confirmation|确认/.test(text);
}
function filterConfirmationSources(sources = []) {
return sources.filter((source) => isConfirmationType(source.type || source.key || source.label || source.path));
}
function requestedExportTypeSet(task = {}) {
const values = Array.isArray(task.exportTypes) && task.exportTypes.length
? task.exportTypes
: ['xingyou-confirm'];
return new Set(values.map((value) => String(value || '').toLowerCase()));
}
function sourceMatchesRequestedExport(source = {}, requested = new Set()) {
const text = String(source.type || source.key || source.label || source.path || '').toLowerCase();
if (/job|beian|teams_beian/.test(text)) return requested.has('job') || requested.has('job-order');
if (/liantai|orders_confirm_new|联泰/.test(text)) return requested.has('liantai') || requested.has('liantai-confirm');
if (/xingyou|orders_confirm_news|兴游|星游/.test(text)) {
return requested.has('xingyou') || requested.has('xingyou-confirm') || requested.has('confirmation') || requested.has('confirm');
}
return requested.has('confirmation') || requested.has('confirm');
}
function filterRequestedConfirmationSources(sources = [], task = {}) {
const requested = requestedExportTypeSet(task);
return filterConfirmationSources(sources)
.filter((source) => sourceMatchesRequestedExport(source, requested));
}
function identifierPayload(record = {}) {
if (record.childOrderNo) {
return {
parentGroupNo: record.parentGroupNo || '',
childOrderNo: record.childOrderNo,
};
}
if (record.parentGroupNo && !record.childOrderNo) {
return { parentGroupNo: record.parentGroupNo };
}
return { groupNo: record.groupNo || record.identifier || '' };
}
function planFromRecord(record = {}, task = {}) {
return {
taskId: task.taskId || `operation-${task.operation || 'task'}-${record.identifier || task.identifier || ''}`,
route: record.route || '',
orderNature: record.orderNature || '',
productName: record.product || '',
productRoute: record.product || '',
bookingCustomer: record.customer || '',
channelCustomer: record.customer || '',
departureDate: record.departureDate || '',
parentGroupNo: record.parentGroupNo || '',
delivery: {
customerReceivesPdfOnly: false,
sourceOnlyExport: true,
},
originalTask: task,
};
}
function submitResultFromRecord(record = {}) {
if (record.route === 'split_child') {
return {
parentGroupNo: record.parentGroupNo || '',
parentTid: record.parentTid || record.tid || '',
childOrderNo: record.childOrderNo || record.identifier || '',
childDid: record.childDid || record.did || record.ddid || '',
};
}
const group = {
date: record.departureDate || '',
groupNo: record.groupNo || record.identifier || '',
ddid: record.ddid || record.did || '',
tid: record.tid || record.ddid || record.did || '',
};
if (record.route === 'team_batch') {
return {
dateToGroupNo: group.date ? { [group.date]: group.groupNo } : {},
groups: [group],
};
}
return {
groupNo: group.groupNo,
group,
};
}
function resolveRouteOperations(route, options = {}) {
if (options.operationsByRoute && options.operationsByRoute[route]) {
return options.operationsByRoute[route];
}
const config = options.config || {};
if (route === 'team_single') {
return require('./erp_team_single_browser_operations').createTeamSingleOperations(config);
}
if (route === 'team_batch') {
return require('./erp_team_batch_browser_operations').createTeamBatchOperations(config);
}
if (route === 'split_child') {
return require('./erp_split_child_browser_operations').createSplitChildOperations(config);
}
return {};
}
function recordNotFoundResult(task = {}) {
const identifier = task.identifier || '';
return {
status: 'blocked',
reason: 'order_record_not_found',
identifiers: identifier ? { requested: identifier } : {},
customerMessage: `没有找到订单编号 ${identifier} 的本地索引记录。请确认使用的是系统返回的团号/子单号,或先补录该订单索引。`,
};
}
function operationMissingResult(task = {}, record = {}, missing = []) {
return {
status: 'blocked',
reason: 'export_confirmation_operations_missing',
orderRecord: record,
identifiers: identifierPayload(record),
missingOperations: missing,
customerMessage: `已找到订单 ${task.identifier},但 ${record.route || '未知路线'} 的确认件导出执行器还没有启用。请先确认 ERP 浏览器执行器配置。`,
};
}
function missingDepartureDateResult(task = {}, record = {}) {
const identifier = task.identifier || record.childOrderNo || record.identifier || '';
return {
status: 'blocked',
reason: 'order_record_missing_departure_date',
orderRecord: record,
identifiers: identifierPayload(record),
customerMessage: `已找到子单 ${identifier}但导出确认件还缺少出发日期。请补充“出发日期YYYY-MM-DD”后重试避免导出错单。`,
};
}
async function runExportDocuments(route, operations, plan, submitResult, options, task = {}) {
const exportOptions = {
...options,
exportTypes: Array.isArray(task.exportTypes) && task.exportTypes.length
? task.exportTypes
: ['xingyou-confirm'],
};
if (route === 'team_batch') {
return operations.exportDocuments(plan, submitResult, null, exportOptions);
}
if (route === 'split_child') {
return operations.exportDocuments(plan, submitResult, {}, exportOptions);
}
return operations.exportDocuments(plan, submitResult, exportOptions);
}
function formatExportMessage(record = {}, artifacts = []) {
const identifiers = identifierPayload(record);
const idLine = identifiers.childOrderNo
? `子单号:${identifiers.childOrderNo}`
: `团号:${identifiers.groupNo || identifiers.parentGroupNo || record.identifier}`;
const mediaLines = artifacts
.map((artifact) => artifact && (artifact.path || artifact.pdfPath || artifact.outputPath))
.filter(Boolean)
.map((filePath) => `MEDIA:"${filePath}"`);
return [
'确认件源文件已导出。',
idLine,
'',
...mediaLines,
].join('\n').trim();
}
function updateOperationMissingResult(task = {}, record = {}, missing = []) {
return {
status: 'blocked',
operation: 'update_order',
reason: 'update_order_operations_missing',
route: record.route || '',
orderRecord: record,
identifiers: identifierPayload(record),
missingOperations: missing,
customerMessage: `已找到订单 ${task.identifier}${record.route || '未知路线'}),但该路线的修改执行器还没有接入。请先启用 ${record.route || '当前路线'} 的 updateOrder 操作后再执行修改。`,
};
}
function updatePlanNeedsClarificationResult(task = {}, record = {}, updatePlan = {}) {
return {
status: 'blocked',
operation: 'update_order',
reason: 'update_order_needs_clarification',
route: record.route || '',
orderRecord: record,
identifiers: identifierPayload(record),
missingFields: updatePlan.missingFields || ['修改内容'],
customerMessage: updatePlan.customerMessage || `已找到订单 ${task.identifier},但修改内容不够明确,请补充后再执行。`,
};
}
function formatUpdateMessage(record = {}, updateResult = {}) {
const identifiers = identifierPayload(record);
const id = identifiers.childOrderNo || identifiers.groupNo || identifiers.parentGroupNo || record.identifier || '';
const count = Array.isArray(updateResult.updatedActions) ? updateResult.updatedActions.length : 0;
if (record.route === 'split_child') {
const countText = count ? `,共执行 ${count} 项变更` : '';
return [
`已修改子单 ${id}${countText}`,
'仅修改该子单,母团下其他历史子单未修改。',
].join('\n');
}
return count
? `订单 ${id} 已完成修改,共执行 ${count} 项变更。`
: `订单 ${id} 已完成修改。`;
}
async function executeExportConfirmation(task, options = {}) {
const record = findOrderRecord(task.identifier, options);
if (!record) return recordNotFoundResult(task);
if (record.route === 'split_parent') {
return {
status: 'blocked',
reason: 'split_parent_has_no_confirmation_export',
orderRecord: record,
identifiers: identifierPayload(record),
customerMessage: `已找到母团 ${task.identifier},但母团计划本身不导出确认件。请使用具体子单号导出客户确认件。`,
};
}
if (record.route === 'split_child' && !String(record.departureDate || '').trim()) {
return missingDepartureDateResult(task, record);
}
const operations = resolveRouteOperations(record.route, options);
const missing = ['exportDocuments'].filter((name) => typeof operations[name] !== 'function');
if (missing.length) return operationMissingResult(task, record, missing);
const plan = planFromRecord(record, task);
const submitResult = submitResultFromRecord(record);
const exportResult = await runExportDocuments(record.route, operations, plan, submitResult, options, task);
const confirmationSources = filterRequestedConfirmationSources(exportResult.sources || [], task);
if (!confirmationSources.length) {
return {
status: 'blocked',
reason: 'confirmation_sources_not_found',
orderRecord: record,
identifiers: identifierPayload(record),
stageResults: { export: exportResult },
customerMessage: `已找到订单 ${task.identifier},但导出结果里没有确认件文件,请检查 ERP 导出配置。`,
};
}
const filteredExportResult = { ...exportResult, sources: confirmationSources };
const artifacts = filterRequestedConfirmationSources(filteredExportResult.sources || [], task);
return {
status: 'completed',
operation: 'export_confirmation',
route: record.route,
orderRecord: record,
identifiers: identifierPayload(record),
artifacts,
stageResults: {
export: filteredExportResult,
},
customerMessage: formatExportMessage(record, artifacts),
};
}
async function executeUpdateOrder(task, options = {}) {
const record = findOrderRecord(task.identifier, options);
if (!record) return recordNotFoundResult(task);
const updatePlan = task.updatePlan || updateOrderParser.parseUpdateOrderText(task.updateText || '');
if (!updatePlan || updatePlan.status !== 'ready') {
return updatePlanNeedsClarificationResult(task, record, updatePlan || {});
}
const operations = resolveRouteOperations(record.route, options);
const missing = ['updateOrder'].filter((name) => typeof operations[name] !== 'function');
if (missing.length) return updateOperationMissingResult(task, record, missing);
const plan = planFromRecord(record, task);
const updateResult = await operations.updateOrder(plan, updatePlan, record, options);
return {
status: updateResult.status || 'completed',
operation: 'update_order',
route: record.route,
orderRecord: record,
identifiers: identifierPayload(record),
updatePlan,
stageResults: { update: updateResult },
customerMessage: record.route === 'split_child'
? formatUpdateMessage(record, updateResult)
: (updateResult.customerMessage || formatUpdateMessage(record, updateResult)),
};
}
module.exports = {
executeExportConfirmation,
executeUpdateOrder,
findOrderRecord,
filterConfirmationSources,
planFromRecord,
submitResultFromRecord,
};