499 lines
18 KiB
JSON
499 lines
18 KiB
JSON
{
|
||
"$schema": "https://local.lwltapi/schemas/ltjt_form_mapping.schema.json",
|
||
"mapping_version": "2026-08-11.team_order_create.orders_add.v0.2",
|
||
"status": "live_create_and_suffix_override_repeatedly_validated_0.5.81_candidate",
|
||
"source": {
|
||
"schema": "schemas/standard_system_operation.schema.json",
|
||
"action": "team_order_create"
|
||
},
|
||
"target": {
|
||
"form_schema": "schemas/orders_add_form_schema.json",
|
||
"page": "/System/Business/orders_add.asp",
|
||
"form_id": "ListForm",
|
||
"submit_endpoint": "/System/DAT/orders.asp",
|
||
"submit_action": "DoInfoJH",
|
||
"payload_prefix": "Act=DoInfoJH&",
|
||
"response_type": "script"
|
||
},
|
||
"limits": {
|
||
"departure_dates": {
|
||
"min": 1,
|
||
"max": 1
|
||
},
|
||
"receivable_rows": {
|
||
"max": 10
|
||
},
|
||
"attachments": {
|
||
"max": 2
|
||
},
|
||
"transport_rows": {
|
||
"max": 4
|
||
},
|
||
"itinerary_days": {
|
||
"max": 15
|
||
}
|
||
},
|
||
"required_target_fields": [
|
||
"chufa_ri",
|
||
"zhuanxianming",
|
||
"TianShu",
|
||
"zutuanshe",
|
||
"chanpinming",
|
||
"gendanren",
|
||
"tuanxuhao1",
|
||
"tuanxuhao2",
|
||
"darenshu",
|
||
"xiaorenshu",
|
||
"ertrenshu",
|
||
"yingrenshu",
|
||
"quanrenshu",
|
||
"xiaoshouren"
|
||
],
|
||
"direct_fields": [
|
||
{
|
||
"target": "chufa_ri",
|
||
"source": "data.departure_dates[0]",
|
||
"transform": "date_yyyy_m_d",
|
||
"required": true,
|
||
"description": "出发日期"
|
||
},
|
||
{
|
||
"target": "zhuanxianming",
|
||
"source": "product/GetProduct-derived route / data.route.name (legacy override)",
|
||
"required": false,
|
||
"description": "专线名称;产品联动后必须在 ERP 表单中唯一落地"
|
||
},
|
||
{
|
||
"target": "TianShu",
|
||
"source": "product/GetProduct-derived trip / data.trip.label (legacy override)",
|
||
"fallback": "derive_trip_label(data.trip.days, data.trip.nights) when explicitly supplied",
|
||
"required": false,
|
||
"description": "行程天数;产品联动后必须在 ERP 表单中唯一落地"
|
||
},
|
||
{
|
||
"target": "zutuanshe",
|
||
"source": "data.customer.name (product/GetProduct-derived value is only a post-selection comparison)",
|
||
"required": true,
|
||
"description": "预订客户;必须由业务请求唯一选定,产品与客户分别解析,来源地不作为跨字段强制匹配"
|
||
},
|
||
{
|
||
"target": "chanpinming",
|
||
"source": "data.product.name",
|
||
"required": true,
|
||
"description": "产品名称"
|
||
},
|
||
{
|
||
"target": "gendanren",
|
||
"source": "ERP login default / data.op_user.name (legacy override)",
|
||
"required": false,
|
||
"description": "跟单人;生产 Skill 不要求用户输入,优先使用当前登录账号默认值"
|
||
},
|
||
{
|
||
"target": "xiaoshouren",
|
||
"source": "ERP login default / data.sales_user.name (legacy override)",
|
||
"required": false,
|
||
"description": "销售人;生产 Skill 不要求用户输入,优先使用当前登录账号默认值"
|
||
},
|
||
{
|
||
"target": "tuanxuhao1",
|
||
"source": "product/route-derived order prefix / data.order_number.prefix (legacy override)",
|
||
"required": false,
|
||
"description": "团号前缀,由产品或线路联动回填"
|
||
},
|
||
{
|
||
"target": "tuanxuhao2",
|
||
"source": "ERP/product-generated order suffix; optional data.order_number.suffix is applied only after GetProduct and customer restoration",
|
||
"required": false,
|
||
"description": "团号后缀;普通 Agent 不生成。若宿主或业务系统明确提供 suffix,插件在产品联动后精确覆盖并复核;最终空值或覆盖后不一致均阻断提交"
|
||
},
|
||
{
|
||
"target": "darenshu",
|
||
"source": "data.passenger_counts.adult",
|
||
"transform": "integer_string",
|
||
"required": true,
|
||
"description": "成人数"
|
||
},
|
||
{
|
||
"target": "xiaorenshu",
|
||
"source": "data.passenger_counts.child_bed",
|
||
"transform": "integer_string",
|
||
"required": true,
|
||
"description": "小童占床"
|
||
},
|
||
{
|
||
"target": "ertrenshu",
|
||
"source": "data.passenger_counts.child_no_bed",
|
||
"transform": "integer_string",
|
||
"required": true,
|
||
"description": "小童不占床"
|
||
},
|
||
{
|
||
"target": "yingrenshu",
|
||
"source": "data.passenger_counts.infant",
|
||
"transform": "integer_string",
|
||
"required": true,
|
||
"description": "婴儿"
|
||
},
|
||
{
|
||
"target": "quanrenshu",
|
||
"source": "data.passenger_counts.leader",
|
||
"transform": "integer_string",
|
||
"required": true,
|
||
"description": "领队"
|
||
},
|
||
{
|
||
"target": "danzhuangtai",
|
||
"source": "data.system_defaults.business_status",
|
||
"default": "预订",
|
||
"description": "订单状态 radio"
|
||
},
|
||
{
|
||
"target": "yaobeian",
|
||
"source": "data.system_defaults.filing_required",
|
||
"default": true,
|
||
"transform": "checkbox_yaobeian",
|
||
"description": "备案 checkbox;真实页面默认序列化为 yaobeian=要备案"
|
||
},
|
||
{
|
||
"target": "fabudanwei",
|
||
"source": "data.system_defaults.fabudanwei",
|
||
"description": "发布单位,由页面入口和 session 决定;本地 dry-run 可预填"
|
||
},
|
||
{
|
||
"target": "bizhong",
|
||
"source": "data.prices.currency",
|
||
"fallback": "data.system_defaults.currency",
|
||
"description": "客户/价格币种"
|
||
},
|
||
{
|
||
"target": "xiadanbeizhu",
|
||
"source": "data.special_requests",
|
||
"description": "下单备注"
|
||
}
|
||
],
|
||
"lookup_fields": [
|
||
{
|
||
"name": "customer",
|
||
"source": "data.customer (current product/GetProduct-derived form value is checked but not authoritative)",
|
||
"display_target": "zutuanshe",
|
||
"id_target": "zutuansheid",
|
||
"optional_targets": {
|
||
"contact_target": "zutuanshegzr",
|
||
"currency_target": "bizhong"
|
||
},
|
||
"endpoint_hint": "../dat/AjaxPublicFun.asp?Act=ProTravel&fabudanwei=${fabudanwei}",
|
||
"match_rule": "exact_name_or_configured_alias",
|
||
"required": true,
|
||
"submit_blocker_if_unresolved": true,
|
||
"source_region_rule": "optional source-region context is report-only; product and customer candidates are resolved independently and a mismatch never blocks DoInfoJH"
|
||
},
|
||
{
|
||
"name": "route",
|
||
"source": "data.route or current product/GetProduct-derived form value",
|
||
"display_target": "zhuanxianming",
|
||
"endpoint_hint": "../dat/AjaxPublicFun.asp?Act=GetInformation&fl=3&fls=1&fabudanwei=${fabudanwei}",
|
||
"match_rule": "exact_name_or_configured_alias",
|
||
"notes": "The LTJT page uses this lookup to set zhuanxianming and tuanxuhao1.",
|
||
"submit_blocker_if_unresolved": true
|
||
},
|
||
{
|
||
"name": "product",
|
||
"source": "data.product",
|
||
"display_target": "chanpinming",
|
||
"optional_targets": {
|
||
"pricing_metadata_target": "baojia"
|
||
},
|
||
"endpoint_hint": "../dat/AjaxPublicFun.asp?Act=ProGetProductname&fls=1&fabudanwei=${fabudanwei}; ../dat/AjaxPublicFun.asp?Act=GetProduct&cpm=${chanpinming}",
|
||
"match_rule": "exact_name_or_configured_alias",
|
||
"submit_blocker_if_unresolved": true,
|
||
"source_region_rule": "derive for diagnostics only; never compare product and customer source-region tokens as a write gate"
|
||
},
|
||
{
|
||
"name": "op_user",
|
||
"source": "data.op_user or current ERP login default",
|
||
"display_target": "gendanren",
|
||
"endpoint_hint": "../dat/AjaxPublicFun.asp?Act=ProDanwei_Yuangong&fabudanwei=${fabudanwei}",
|
||
"match_rule": "exact_staff_name_or_current_login_default",
|
||
"submit_blocker_if_unresolved": true
|
||
},
|
||
{
|
||
"name": "sales_user",
|
||
"source": "data.sales_user or current ERP login default",
|
||
"display_target": "xiaoshouren",
|
||
"endpoint_hint": "../dat/AjaxPublicFun.asp?Act=ProDanwei_Yuangong&fabudanwei=${fabudanwei}",
|
||
"match_rule": "exact_staff_name_or_current_login_default",
|
||
"submit_blocker_if_unresolved": true
|
||
}
|
||
],
|
||
"selectbox_contract": {
|
||
"row_delimiter": "◇",
|
||
"column_delimiter": "◆",
|
||
"strict_rule": "For SelectBox-bound fields, direct text assignment is not sufficient for production. Runtime must resolve exactly one existing row and apply the page's SetVal mapping.",
|
||
"critical_selectboxes": [
|
||
{
|
||
"name": "trip_days",
|
||
"target": "TianShu",
|
||
"data_source": "static options",
|
||
"match_column": 0,
|
||
"set_values": {
|
||
"TianShu": 0
|
||
}
|
||
},
|
||
{
|
||
"name": "route",
|
||
"target": "zhuanxianming",
|
||
"endpoint": "../dat/AjaxPublicFun.asp?Act=GetInformation&fl=3&fls=1&fabudanwei=${fabudanwei}",
|
||
"observed_row_count": 16,
|
||
"observed_column_count": 11,
|
||
"match_column": 1,
|
||
"set_values": {
|
||
"zhuanxianming": 1,
|
||
"tuanxuhao1": 3
|
||
}
|
||
},
|
||
{
|
||
"name": "product",
|
||
"target": "chanpinming",
|
||
"endpoint": "../dat/AjaxPublicFun.asp?Act=ProGetProductname&fls=1&fabudanwei=${fabudanwei}",
|
||
"observed_row_count": 160,
|
||
"observed_column_count": 2,
|
||
"match_column": 1,
|
||
"set_values": {
|
||
"chanpinming": 1
|
||
},
|
||
"side_effect": "../dat/AjaxPublicFun.asp?Act=GetProduct&cpm=${chanpinming}"
|
||
},
|
||
{
|
||
"name": "customer",
|
||
"target": "zutuanshe",
|
||
"endpoint": "../dat/AjaxPublicFun.asp?Act=ProTravel&fabudanwei=${fabudanwei}",
|
||
"observed_row_count": 93,
|
||
"observed_column_count": 6,
|
||
"match_column": 2,
|
||
"set_values": {
|
||
"bizhong": 0,
|
||
"zutuansheid": 1,
|
||
"zutuanshe": 2,
|
||
"lianxiren": 3,
|
||
"zutuanshegzr": 4
|
||
}
|
||
},
|
||
{
|
||
"name": "staff",
|
||
"targets": ["gendanren", "xiaoshouren"],
|
||
"endpoint": "../dat/AjaxPublicFun.asp?Act=ProDanwei_Yuangong&fabudanwei=${fabudanwei}",
|
||
"observed_row_count": 33,
|
||
"observed_column_count": 2,
|
||
"match_column": 0,
|
||
"set_values": {
|
||
"gendanren": 0,
|
||
"xiaoshouren": 0
|
||
}
|
||
}
|
||
],
|
||
"resource_selectboxes": [
|
||
{
|
||
"name": "flight",
|
||
"target_pattern": "banhao{n}",
|
||
"set_values": {
|
||
"banhao{n}": 1,
|
||
"bancheng{n}": 4,
|
||
"banchengs{n}": 5,
|
||
"banchang{n}": 6,
|
||
"banchangs{n}": 7,
|
||
"banshi{n}": 8,
|
||
"banshis{n}": 9,
|
||
"guankou{n}": 10
|
||
}
|
||
},
|
||
{
|
||
"name": "hotel",
|
||
"target_pattern": "zhusus{day}",
|
||
"observed_row_count": 572,
|
||
"observed_column_count": 5,
|
||
"set_values": {
|
||
"zhusus{day}": 1,
|
||
"zhususs{day}": 2
|
||
}
|
||
},
|
||
{
|
||
"name": "restaurant",
|
||
"target_patterns": ["zaos{day}", "zhongs{day}", "wans{day}"],
|
||
"observed_row_count": 199,
|
||
"observed_column_count": 5,
|
||
"set_values": {
|
||
"selected_restaurant_field": 1,
|
||
"meal_standard_field": 2,
|
||
"settlement_field": 3
|
||
}
|
||
},
|
||
{
|
||
"name": "attraction",
|
||
"target_pattern": "jingdian{day}_{slot}",
|
||
"observed_row_count": 190,
|
||
"observed_column_count": 5,
|
||
"set_values": {
|
||
"jingdian{day}_{slot}": 1,
|
||
"jingdians{day}_{slot}": 2,
|
||
"jingdianss{day}_{slot}": 3
|
||
}
|
||
},
|
||
{
|
||
"name": "receivable_item",
|
||
"target_pattern": "ys_xiangmu{n}",
|
||
"observed_row_count": 20,
|
||
"observed_column_count": 1
|
||
},
|
||
{
|
||
"name": "receivable_detail_or_reserved_resource",
|
||
"target_pattern": "ys_shuoming{n}",
|
||
"observed_row_count": 54,
|
||
"observed_column_count": 3,
|
||
"set_values": {
|
||
"ys_shuoming{n}": 2
|
||
}
|
||
}
|
||
],
|
||
"product_side_effect_contract": {
|
||
"trigger_function": "Find_product()",
|
||
"endpoint": "../dat/AjaxPublicFun.asp?Act=GetProduct&cpm=${chanpinming}",
|
||
"response_type": "script",
|
||
"observed_redacted_sample": {
|
||
"changed_field_count": 135,
|
||
"changed_field_groups": {
|
||
"itinerary_text": 9,
|
||
"core": 7,
|
||
"pricing_receivable": 21,
|
||
"resources": 96,
|
||
"other": 2
|
||
}
|
||
},
|
||
"must_run_before_final_serialize": true,
|
||
"must_block_on_mismatch_fields": [
|
||
"chanpinming",
|
||
"TianShu",
|
||
"zhuanxianming",
|
||
"tuanxuhao1",
|
||
"zutuanshe",
|
||
"zutuansheid"
|
||
],
|
||
"post_effect_overwrite_policy": {
|
||
"preserve_product_template_groups": [
|
||
"itinerary_text",
|
||
"resources",
|
||
"pricing_receivable_metadata"
|
||
],
|
||
"preserve_product_template_prices_and_rows": true,
|
||
"overwrite_after_product_effect": [
|
||
"departure date",
|
||
"passenger counts",
|
||
"room counts",
|
||
"staff fields",
|
||
"order suffix when explicitly supplied",
|
||
"notes when explicitly supplied",
|
||
"attachments"
|
||
]
|
||
}
|
||
}
|
||
},
|
||
"room_count_fields": {
|
||
"frenshu0": "data.room_counts.SGL",
|
||
"frenshu1": "data.room_counts.TWN",
|
||
"frenshu2": "data.room_counts.TRP",
|
||
"frenshu3": "data.room_counts.DBL",
|
||
"frenshu4": "data.room_counts.HNM",
|
||
"frenshu5": "data.room_counts.TL",
|
||
"frenshu6": "derive_room_total(data.room_counts)"
|
||
},
|
||
"receivable_rows": {
|
||
"source": "product_template_rows_after_GetProduct",
|
||
"fallback_strategy": "use data.prices only for legacy operations when the product template did not populate a category price",
|
||
"max_rows": 10,
|
||
"targets": {
|
||
"unit_name": "ys_danwei{n}",
|
||
"unit_id": "ys_danweiid{n}",
|
||
"placeholder": "ys_zhanwei{n}",
|
||
"item_name": "ys_xiangmu{n}",
|
||
"item_detail": "ys_shuoming{n}",
|
||
"settlement_method": "ys_fangshi{n}",
|
||
"currency": "ys_bizhong{n}",
|
||
"quantity": "ys_shuliang{n}",
|
||
"unit_price": "ys_danjia{n}",
|
||
"amount": "ys_jine{n}",
|
||
"paid_amount": "ys_yishoufu{n}",
|
||
"remark": "ys_beizhu{n}",
|
||
"row_id": "ys_id{n}",
|
||
"payment_type": "ys_shoufulei{n}",
|
||
"operator": "ys_caozuoren{n}",
|
||
"reviewer": "ys_shenheren{n}"
|
||
},
|
||
"defaults": {
|
||
"unit_name": "data.customer.name",
|
||
"unit_id": "data.customer.ltjt_id",
|
||
"settlement_method": "",
|
||
"paid_amount": "0",
|
||
"row_id": "",
|
||
"payment_type": "0",
|
||
"operator": "data.source.operator",
|
||
"reviewer": ""
|
||
},
|
||
"amount_formula": "quantity * unit_price"
|
||
},
|
||
"attachments": {
|
||
"source": "data.attachments",
|
||
"target_pattern": "PicFile{n}",
|
||
"requires": "ltjt_file_ref",
|
||
"max": 2,
|
||
"notes": "Local path attachments must be uploaded through LTJT's upload helper before this form payload can reference them."
|
||
},
|
||
"passenger_list": {
|
||
"text_target": "youkexinxis",
|
||
"supported_operations_in_this_mapping": [
|
||
"none"
|
||
],
|
||
"notes": "The real passenger-list import/edit workflow has not been captured yet. Do not treat PicFile0/PicFile1 as passenger-list import."
|
||
},
|
||
"unmapped_or_page_generated_fields": [
|
||
"baojia",
|
||
"zutuanshegzr",
|
||
"caozuoren",
|
||
"ddid",
|
||
"tdid",
|
||
"quanxian",
|
||
"session_id",
|
||
"ys_shenhe",
|
||
"yingfu_jing",
|
||
"yingfu_can",
|
||
"zhusuanpai",
|
||
"daoyoujiesuan",
|
||
"youyingshoukuan",
|
||
"itinerary day/service rows",
|
||
"transport lookup hidden metadata"
|
||
],
|
||
"validation_rules": [
|
||
"submit_mode must be dry_run for this local serializer.",
|
||
"action must be team_order_create.",
|
||
"departure_dates must contain exactly one date.",
|
||
"adult + child_bed + child_no_bed + infant + leader must be greater than zero.",
|
||
"expected_total, when provided, must equal the computed passenger total.",
|
||
"product must match exactly one existing LTJT product row; customer and route may be resolved by the product template and must then match exactly one existing LTJT row.",
|
||
"OP and sales must match exactly one existing LTJT staff row, using the operation override only when present and otherwise the current login default; upstream resolved=true is not enough by itself.",
|
||
"Product Find_product/GetProduct side effects must run in the browser before final serialization.",
|
||
"Product template output must be nonempty and deterministic; when the standard operation explicitly supplies trip, route, route prefix, customer, or customer id, the product template output must match it.",
|
||
"product and customer candidates must each resolve uniquely; source-region context is report-only and never blocks before DoInfoJH",
|
||
"data.order_number.suffix is optional and reserved for an explicit host/business-system override; when supplied it is applied after GetProduct and customer restoration, must remain byte-for-byte equal in tuanxuhao2, and is included in the approved payload hash",
|
||
"Product-generated receivable rows and prices must be preserved; runtime may update only passenger quantities and derived amounts, with explicit prices used only as a legacy fallback.",
|
||
"The operation does not need customer/op/sales price values when the product template and login defaults resolve them; unresolved ERP fields still block before submit.",
|
||
"receivable rows must not exceed 10.",
|
||
"attachments must already have ltjt_file_ref values.",
|
||
"passenger_list.operation must be none for this mapping version."
|
||
],
|
||
"next_browser_context_work": [
|
||
"Run the extension preflight against a formal standard operation whose product and passenger/room facts exist in LTJT; verify customer/route/price/staff values come from product and login defaults.",
|
||
"Compare product-template output with standard operation and block mismatches instead of overwriting them.",
|
||
"Replay an explicit host-injected order_number.suffix on a newly created September 2026 test object and retain the final tuanxuhao2, server response, and fresh list requery evidence.",
|
||
"Reverify product-template price-row positions if LTJT changes its product response shape.",
|
||
"Keep DoInfoJH approval hash, execution ID, write-started state, and ERP receipt re-query enabled for formal saves."
|
||
]
|
||
}
|