Travel Quote Generator
This public Hub version generates two Word documents for a team travel quote:
| Document | Audience | Script |
|---|---|---|
| Customer quote | External customer-facing itinerary, inclusions, and per-person price | assets/build_quote.js |
| Internal cost sheet | Internal cost breakdown, profit check, and risk notes | assets/build_cost.js |
Default profile: config.json uses Spring Tour branding. Other teams can replace company name, colors, logo, image source order, baseline costs, and phrasing in config without changing code.
Cost Setup Status
At the start of a quote task, check whether the local cost file exists:
node -e "const { hasLocalCost, getLocalCostPath } = require('./assets/cost_store'); console.log(hasLocalCost(), getLocalCostPath())"
Local cost path defaults to ~/.travel-quote/cost.json. It lives outside the skill directory, so package updates do not overwrite department settings.
Every new conversation should briefly mention the setup status before quoting. The setup status should remain visible even after initialization, because departments will keep iterating vehicle, ticket, and hotel prices.
- If no local cost file exists: show the setup prompt and say the quote can still proceed with public baseline estimates.
- If local cost exists: say local department costs are being used and offer “补充常用景点票价 / 调整地区用车 / 维护常用酒店 / 调整车导餐保险水 / 重设成本”.
- If the user gives new ticket or cost information during a quote, offer to save it back to local cost after the current quote is finished.
If the file does not exist, offer three choices:
- Quick form setup: ask for Shanghai 37-seat car, Shanghai 49-seat car, Hangzhou or other common destination car prices, guide, meal, insurance, water, common spot tickets, and common hotels in one compact form.
- Excel setup: generate a template with
node assets/init_cost.js template <output.xlsx>, let the user fill it, then import it withnode assets/init_cost.js import <filled.xlsx>. - Skip for now: continue with public baseline values and mention that these are estimates.
If the user says “重设成本”, “更新成本”, “补充门票”, or “reset costs”, regenerate, import, or patch the local file.
The Excel setup template includes:
固定成本: guide, meal, insurance, water, profit multiplier, and default Shanghai vehicle baselines.常用景点门票: department-confirmed ticket or activity prices.地区用车: examples for Shanghai and Hangzhou, so configurators see that vehicle prices differ by city. Only rows with numeric prices are imported.常用酒店: hotel, area, room type, default room-night price, and optional date-price JSON. Use one row per hotel room type; leave sample rows without prices so they are not imported. For multi-date prices, fill only confirmed special dates, such as{"2026-06-15":520,"2026-06-16":560,"2026-06-17":520}; other dates fall back to the default price. If business users cannot write JSON, let them put multi-date prices in the remarks and organize them before import or quote confirmation. This table stores hotel references for later room calendar pricing; still confirm lodging price before finalizing each quote.酒店填写说明: non-imported helper sheet with common hotel filling examples, including regular price, weekend/peak date prices, temporary quote prices, and multiple room types.
Cost Source Priority
For Shanghai standard costs, resolve values in this order:
- Current quote input
- Local
~/.travel-quote/cost.json - Public baseline in
config.json
Car cost uses carType to choose carTotal37 or carTotal49 unless the quote input provides fixedCosts.carTotal.
For non-Shanghai cities, resolve vehicle prices in this order:
- Current quote input
fixedCosts.carTotal - Local
regionalCarCostsfrom the地区用车setup sheet, matched by city and car type - Public car-cost ranges in
references/car-cost-policy.md
If the local regional vehicle price is marked confirmed, use it without a dispatch-warning note. If it is not confirmed, or only a public range is available, customer-facing language may say local vehicle resources are subject to final dispatch confirmation, and the internal sheet should show the estimated range.
Ticket Rules
The public assets/spot_catalog.json must not contain ticket prices, image paths, or private source URLs.
Common spot tickets come from local cost.json under spotTickets. Notes can include weekday, weekend, children, season, or group-size rules. When notes indicate multiple possible prices, confirm the applicable tier with the business user before finalizing the quote.
Temporary or new spots must be confirmed per quote. If a spot is free, still ask the business user to confirm and set ticketPriceConfirmed: true.
When ticket data is incomplete, group the confirmation instead of asking one spot at a time. Present a compact table:
| Spot | Local saved price | Public/market reference | Note | Confirmed quote price |
|---|---|---|---|---|
Ask the business user to fill or confirm the final column. If public research is needed, cite that it is only a market reference and not a supplier commitment.
Interaction Order
Prefer a front-loaded form for business users. Ask once, then only follow up on missing or risky items.
Start with this compact quote intake:
请一次性补充/确认这些信息,已确定的填具体值,不确定可写“待定”:
1. 客户/团队名:
2. 出行日期、人数、城市:
3. 天数/晚数:
4. 已选景点或希望推荐的区域/主题:
5. 是否有临时景点、门票/体验费是否已确认:
6. 餐标:
7. 多日住宿:酒店名/双人间/单间人数和价格:
8. 用车:车型/是否已有确认车价:
9. 预算、竞品价、目标报价或价格敏感度:
10. 是否需要把本次确认的成本/门票保存为常用配置:
After receiving the form:
- Travel date and people count, using plain text questions only.
- Fill known local cost and ticket values from
cost.json. - For missing tickets, vehicle prices, closures, or reservation rules, summarize market/public references and ask for final confirmation in one table.
- For multi-day trips, confirm lodging before final meal and price review.
- Present cost estimate, market reference, and a suggested quote range.
- Ask the business user to confirm the final
salePricePerPerson.
For multi-day trips, calculate price from total cost. Do not reuse a one-day default price.
Price Confirmation Rule
Do not treat pricing.profitMultiplier as the final quote. It is only a suggested-price reference for first-pass estimation.
Before generating formal Word files, the business user must confirm the final sale price. The script enforces this by requiring:
{
"salePricePerPerson": 300,
"salePriceConfirmed": true
}
If no confirmed sale price is available, run build_plan.js --dry-run to show the cost estimate and suggested reference price, then ask the user to confirm a competitive final price.
Customer Safety Boundary
Customer-facing quote files must never include internal cost language: margin, profit, loss, cost, internal calculation, supplier bottom price, group car cost, group guide cost, insurance per-person cost, or water per-person cost.
Internal cost sheets may include those details and must remain clearly marked as internal.
File Output
Do not hard-code personal usernames or machine-specific paths.
Default output should be a single session folder on the current user’s Desktop, or a user-provided workspace folder. Use folder naming like:
{route}_{people}_{MMDD}
Quote and cost sheet for the same session must be saved in the same folder.
Image Sources
Binary images are not bundled for Skill Hub upload compatibility. The default brand logo is embedded as text in assets/brand/logo_embedded.js and restored at document generation time. Spot images are fetched at runtime and cached under assets/cache/spot_images/.
Configured runtime source order lives in config.json. Do not rely on bundled local scenic images.
["springtour", "wiki"]
The Spring Tour source is enabled by default as an example/default profile source and can be disabled or replaced in config.
Script Usage
Install dependencies:
cd assets
npm install
Generate a dry-run plan:
node build_plan.js --dry-run '{"people":20,"route":"上海精选一日游","selectedSpotIds":["fengxian-museum"]}'
Generate both Word files:
node build_plan.js '{"people":20,"route":"上海精选一日游","selectedSpotIds":["fengxian-museum"],"salePricePerPerson":300,"salePriceConfirmed":true,"outputDir":"../outputs/example"}'
Public Package Red Lines
Before publishing, verify:
- No real customer names.
- No internal cost tables or route-margin references.
- No bundled third-party scenic images.
- No
node_modules,outputs,.DS_Store, or image cache files. assets/spot_catalog.jsonhas no ticket prices, image paths, or private source URLs.