feat: add shared child batch creation

This commit is contained in:
inman committed 2026-09-09 17:24:16 +08:00
1 parent 515b545b32
commit 6ac90f838a
32 files changed
+958 -90

No files matched your search

+20 -1
View File
@@ -6,6 +6,7 @@ export type BusinessRouteId =
| 'team_order_batch_create'
| 'shared_plan_create'
| 'shared_child_order_create'
| 'shared_child_order_batch_create'
| 'passenger_list_import_independent'
| 'passenger_list_import_shared_child'
| 'arrangement_guide_create'
@@ -74,7 +75,7 @@ export function effectiveParserModeForRoute(route: BusinessRouteDefinition, conf
return route.parserPolicy === 'program_only' ? 'program' : 'ai';
}
const PROGRAM_VERSION = 'ltjt-program-parser-v1.0.6';
const PROGRAM_VERSION = 'ltjt-program-parser-v1.0.7';
export const BUSINESS_INPUT_CONTRACT_VERSION = 'business-input-templates-0.5.126';
const lookupFields = ({ customerRequired = true } = {}): ProgramFieldDefinition[] => [
@@ -157,6 +158,24 @@ export const BUSINESS_ROUTES: readonly BusinessRouteDefinition[] = Object.freeze
{ key: 'special_requests', label: '特殊要求', kind: 'text' }
]
},
{
routeId: 'shared_child_order_batch_create',
releaseOrder: 19,
directive: '散拼团多个新增子单',
aliases: [],
action: 'shared_child_order_batch_create',
programVersion: PROGRAM_VERSION,
inputContractVersion: BUSINESS_INPUT_CONTRACT_VERSION,
parserPolicy: 'program_only',
fields: [
{ key: 'customer', label: '预订客户', aliases: ['预定客户'], required: true, kind: 'named_ref' },
{ key: 'departure_range', label: '出发日期', aliases: ['发团日期'], required: true, kind: 'date_range' },
{ key: 'product', label: '产品名称', aliases: ['产品搜索'], required: true, kind: 'named_ref' },
{ key: 'leader', label: '领队', aliases: ['领队姓名'], kind: 'named_ref' },
{ key: 'passenger_counts', label: '人数', aliases: ['预估人数'], required: true, kind: 'passenger_counts' },
{ key: 'special_requests', label: '特殊要求', kind: 'text' }
]
},
{
routeId: 'passenger_list_import_independent',
releaseOrder: 10,
+1 -1
View File
@@ -5,7 +5,7 @@ import { writeEmergencyDiagnostic } from './diagnostics.js';
const { Pool } = pg;
let pool: pg.Pool | null = null;
export const REQUIRED_SCHEMA_VERSION = '021_admin_task_data_plane_isolation';
export const REQUIRED_SCHEMA_VERSION = '022_shared_child_order_batch_create';
export interface DatabaseReadiness {
ready: boolean;
+2 -2
View File
@@ -3,7 +3,7 @@ import { resolve } from 'node:path';
import { createHash } from 'node:crypto';
interface ExternalContractModule {
validateAgentOperation(operation: unknown): string[];
validateProgramOperation(operation: unknown): string[];
}
let contractModulePromise: Promise<ExternalContractModule> | null = null;
@@ -18,7 +18,7 @@ async function loadContractModule(): Promise<ExternalContractModule> {
export async function validateParsedOperation(operation: unknown): Promise<string[]> {
const contract = await loadContractModule();
return contract.validateAgentOperation(operation);
return contract.validateProgramOperation(operation);
}
const EXPORT_TYPE_ORDER = [
+10
View File
@@ -64,6 +64,7 @@ const NEXT_OCCURRENCE_DATE_ROUTES = new Set<BusinessRouteId>([
'team_order_batch_create',
'shared_plan_create',
'shared_child_order_create',
'shared_child_order_batch_create',
'order_update_shared_plan',
'order_update_shared_child',
'order_update_independent',
@@ -773,6 +774,15 @@ function buildOperation(route: BusinessRouteDefinition, values: Map<string, unkn
if (parent) data.existing_refs = { kind: 'shared_plan', identifier: parent, parent_group_no: parent };
return { ok: true, operation: operation(route.action, data) };
}
case 'shared_child_order_batch_create':
return { ok: true, operation: operation(route.action, {
customer: values.get('customer'),
product: values.get('product'),
...(values.get('leader') ? { leader: values.get('leader') } : {}),
recurrence: values.get('departure_range'),
passenger_counts: values.get('passenger_counts'),
...(special ? { special_requests: special } : {})
}) };
case 'passenger_list_import_independent':
case 'passenger_list_import_shared_child': {
const parsedList = values.get('passenger_tsv') as JsonRecord;
+4 -2
View File
@@ -138,7 +138,8 @@ function identifierLine(
const groupNumbers = groupNumbersFrom(receipt, result, refs);
const orderNumbers = orderNumbersFrom(receipt, result, refs);
const explicit = firstText(receipt.identifier, result.identifier, refs.identifier);
const child = action === 'shared_child_order_create' || refs.kind === 'shared_child_order';
const child = ['shared_child_order_create', 'shared_child_order_batch_create'].includes(action)
|| refs.kind === 'shared_child_order';
if (child && orderNumbers.length) {
return {
text: `子单号:${orderNumbers.join('、')}`,
@@ -330,6 +331,7 @@ function actionTitle(action: string): string {
team_order_batch_create: '批量下单成功',
shared_plan_create: '散拼计划创建成功',
shared_child_order_create: '新子单成功',
shared_child_order_batch_create: '批量新增子单成功',
arrangement_guide: '导游安排成功',
arrangement_vehicle: '用车安排成功',
arrangement_hotel: '酒店安排成功',
@@ -529,7 +531,7 @@ export function buildCustomerSuccessReply(
textValue = [actionTitle(action), identity.text, names.length ? `文件:${names.join('、')}` : '文件已保存到任务附件'].filter(Boolean).join('\n');
profile = 'standard-file-delivery-v1';
fields = { ...fields, file_names: names, attachment_count: attachments.length };
} else if (['team_order_create', 'team_order_batch_create', 'shared_plan_create', 'shared_child_order_create'].includes(action)) {
} else if (['team_order_create', 'team_order_batch_create', 'shared_plan_create', 'shared_child_order_create', 'shared_child_order_batch_create'].includes(action)) {
textValue = [actionTitle(action), identity.text].filter(Boolean).join('\n');
profile = 'standard-newbooking-v1';
} else {