房型与售卖产品为什么要分开设计
在金边做了12年开发,酒店预订这类项目我们接过不少,柬埔寨、菲律宾、越南的客户都有。很多第一次接触酒店系统的人会把“房型”直接当成可售商品,这在简单场景下能跑,但一旦涉及价格策略、取消规则、早餐份数、渠道差异,数据结构就会被逼进死胡同。我们踩过这个坑之后,后续所有酒店类项目都坚持两层模型:物理房型记录房间本身的属性——面积、床型、设施、楼层;售卖产品绑定动态经营属性——价格策略、取消政策、早餐数量、适用渠道。同一个物理房型可以派生出多个售卖产品,比如“含双早可免费取消”和“不含早不可取消”就是两个产品,库存却共享同一物理房间池。
落到表结构上,核心三张表可以这样规划:
- room_type:物理房型基础信息,字段包括 room_type_id、name、hotel_id
- sellable_product:售卖产品,字段包括 product_id、room_type_id、policy_id、breakfast
- inventory:每日库存,字段包括 product_id、date、total_rooms、booked_rooms
这个拆法最直接的好处是:价格和取消政策调整不需要动物理房型数据,渠道对接时也能把不同售卖产品映射到不同OTA产品代码上。我们在柬埔寨本地一个连锁酒店项目里,同一个物理房型拆出了六个售卖产品,分别对应不同渠道和不同政策组合,如果当初把房型直接当商品卖,后面改起来会非常痛苦。
价格日历的动态合并逻辑
酒店价格不是固定值,而是按日期段叠加规则生成的结果。系统需要支持日期段价格模板:先设定基础价,再对特定日期段覆盖新价格。模板之间要有优先级关系,节假日模板覆盖周末模板,周末模板覆盖平日模板,最终落成每一天的唯一价格。这个逻辑我们在柬埔寨新年、泰国泼水节这类东南亚本地节假日的场景下反复验证过,节假日模板的优先级必须高于其他所有模板,否则运营人员手动调价的工作量会非常大。
缓存层用Redis Sorted Set处理价格和房量的查询,key设计为 product_id:date,score存价格,member存库存状态。用户搜索时按日期范围批量拉取,再用库存信息过滤掉无房日期。这样一次搜索请求不需要反复查数据库,热点数据查询延迟控制在个位数毫秒级,具体数值取决于部署环境和网络链路,这里不给绝对数字。但有一点是确定的:如果每次搜索都穿透到数据库,在OTA渠道批量查询的场景下,数据库连接池很快就会被拖垮。
库存预占与超卖防护
超卖是酒店预订系统的红线。我们采用预占库存机制,而不是下单支付成功后才扣库存。用户提交订单的那一刻,系统在Redis中对对应日期的库存执行原子递减(DECR),返回值大于等于0才算预占成功。同时发送延迟消息,15分钟内未支付自动释放库存,避免恶意占房或犹豫期过长影响真实销售。这个15分钟的窗口是我们和多家酒店客户反复讨论后定的默认值,不同客户可以根据自己的客群习惯调整。
高并发场景下,Redis Cluster配合Lua脚本保证多日期库存扣减的原子性。扣减结果异步同步到数据库,最终一致性通过Binlog监听补偿来兜底。这里有一个工程细节:Redis扣减成功后数据库写入失败的概率虽然低,但必须有对账任务定时比对Redis与数据库的库存差异,发现偏差立即校正。我们在一个菲律宾的度假村项目里就遇到过这种情况,对账任务在凌晨发现了三间房的偏差,原因是某次数据库主从切换时异步写入丢失,如果没有对账机制,这三间房可能就会在第二天被超卖。
支付状态机与取消退款规则
订单支付环节需要对接多种渠道——微信、支付宝、银联、信用卡预授权,东南亚市场还涉及本地钱包和银行转账。支付通道本身由客户提供资源,我们团队负责对接,不提供支付通道。这个边界必须说清楚:客户自己去找支付服务商拿通道、签合同、谈费率,我们做的是技术侧的接口对接和状态同步。系统层面用支付状态机管理订单生命周期:待支付、已支付、已取消、退款中、已退款、已完成,所有状态变更通过事件驱动记录,确保可追溯。
取消政策直接关系收益,需要支持多级规则配置:
- 免费取消:入住前X天可免费取消,全额退款
- 阶梯扣款:入住前7天取消扣首晚房费,3天内取消扣全款
- 不可取消:订单确认后不退款
退款规则引擎在用户发起取消时解析当前时间与政策,自动计算应退金额,触发退款流程并释放库存。涉及信用卡预授权时,需要调用支付网关的撤销或请款接口,保证资金流和订单流一致。每晚定时任务对当日取消订单进行对账,防止资金差错积累。这个对账任务的重要性我们在越南一个酒店客户那里体会很深——他们用的是本地银行的预授权通道,接口超时率不低,如果不对账,资金差错会在月底对账时集中爆发。
会员、优惠券与评价的工程实现
会员体系基于等级和积分两套模型。等级决定折扣权益,积分可抵扣房费。升级降级通过配置化规则引擎实现,指标包括累计消费、入住间夜数、活跃度,不需要改代码就能调整规则。这一点对东南亚市场的客户尤其重要,因为他们的运营策略调整频率远高于国内,如果每次调规则都要改代码发版,迭代节奏根本跟不上。
优惠券模块支持直减券、折扣券、满减券,可按渠道、房型、新老用户条件发放。下单时营销引擎匹配最优优惠组合并计算折后价,避免多重优惠叠加造成资损。评价功能采用审核后发布机制,评价数据异步更新到酒店评分和排序权重,不拖慢主流程响应。
针对东南亚市场的一个实际需求是套餐打包:系统预留接口对接景区门票、餐饮等本地服务,实现交叉营销。我们在柬埔寨和泰国的客户都有类似的诉求,尤其是度假型酒店,住客的二次消费场景很多。如果平台涉及数字娱乐相关的福利发放,比如会员积分兑换数字娱乐奖品,系统内建合规风控,确保兑换流程符合监管要求。
后台运营、财务对账与OTA渠道对接
后台运营系统面向酒店商家提供房态管理、价格调整、订单处理、账单查询。多门店集团客户需要多角色权限管控,不同门店的运营人员只能操作自己门店的数据。财务对账模块汇聚支付流水、退款流水、分账明细,与支付渠道返回的对账单通过自动勾兑算法比对差异,生成差异报告供运营人员处理。
OTA渠道对接是系统开放性的关键。需要适配多个OTA的标准接口,统一渠道适配层将内部房态、价格、订单数据转换为各渠道的标准格式,通过异步队列下发变更。接口限流和熔断策略防止渠道侧故障反向拖垮本系统。这个适配层是我们做过最多次迭代的模块之一,因为每个OTA的接口文档质量、字段定义、更新频率都不一样,适配层必须足够抽象,否则每接一个新渠道都要动核心业务代码。
轻量级BI分析基于订单和用户行为数据,提供入住率预测、热销房型排行等看板。告警机制实时监控库存负数、支付超时等异常。整个系统的技术重心始终在高并发下的数据一致性、可扩展性和运营灵活性三点上。这三点不是并列关系,数据一致性是底线,可扩展性决定系统能活多久,运营灵活性决定客户愿不愿意一直用。
开发交付的实际情况
这类系统的开发周期取决于范围:小项目几天可以交付,大项目大约2个月。电商类系统我们有成品,开箱即用,交付速度更快;酒店预订如果业务模型接近标准电商,可以基于成品二次开发,如果涉及复杂的OTA双向同步或定制化分账规则,则需要独立评估。我们团队28人,每年交付约100个项目,客户覆盖柬埔寨、菲律宾、越南、老挝、泰国、印尼、马来西亚,主攻电商、娱乐、金融交易、地产和物流。酒店预订在电商大类里属于对实时性和一致性要求最高的场景之一,这也是为什么我们在成品基础上对酒店模块做了专门强化。
报价方面,我们按功能清单逐项评估,面谈或Telegram详谈,不提供固定报价。付款方式为先付30%启动,验收后结清尾款。服务语言为中文,TG分钟级响应,系统bug修复免费,新增功能按工作量收费。支付通道由客户提供资源,团队负责对接,不提供支付通道。成品系统在东南亚已有几十家客户在运营使用,但具体客户名称和运营数据不对外披露。有一点需要说明:我们不做客户运营层面的承诺,比如“上线后订单量提升多少”这类话我们不会说,我们能保证的是系统本身的稳定性和数据一致性,运营结果取决于客户的团队和资源投入。
