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, };