企业网站 / 预约资源

Odoo 企业版网站预约为什么不是“资源够用就能约上”:组合容量、shareable 资源与 booking line 分摊讲透

很多团队把网站预约理解成“选个时间 + 选个资源”这么简单;但企业版 Appointment 真正解决的是容量组合、linked resource 联动、前台人数上限与提交瞬间 booking line 分摊的一致性。本文从 `_slots_fill_resources_availability()`、`_slot_availability_select_best_resources()` 到 `appointment_form_submit()` 把这条链路讲透。

企业 网站
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

很多人第一次做 Odoo 企业版网站预约,都会把问题想成一句话:

只要这个时间段还有资源,客户就应该能约上。

但标准企业版并不是这么粗暴。它真正处理的是四件事同时成立:

  1. 这个时间段里,哪些资源本身可用;
  2. 这些资源和它们的 linked resources 组合起来,能不能凑出客户要的人数 asked_capacity
  3. 前台应该展示“哪几个资源看起来可选”,而不是把所有候选都丢给客户;
  4. 客户提交表单的那一刻,要把总容量拆成一组 booking_line,确保日历事件、占用容量和后续冲突检查都对得上。

所以企业版 Appointment 解决的不是“有没有空”,而是:

网站前台的可预约结果,必须和后台真正落库的容量占用保持同一套口径。

这也是为什么你会看到前台明明只选了一个时段,后台却可能生成多条 appointment.booking.line

先抓主链路

1)前台不是先看“资源数”,而是先看“容量是否可能凑够”

appointment.type._slots_fill_resources_availability() 里,系统会先遍历某个 slot 下当前可用的资源,再调用 _get_resources_remaining_capacity() 计算每个资源及其联动资源的剩余容量。

这里关键不是“资源还活着”,而是:

  • 该资源在这个时段有没有撞 booking;
  • 如果开启 manage_capacity,它自己还剩多少容量;
  • 如果资源之间存在 linked relationship,组合后总容量够不够支撑 asked_capacity

如果某个资源单独看还能用,但总剩余容量凑不出客户要的 3 人、4 人,它就不会进入最终的 capacity_info

2)系统会主动挑“最合适的一组资源”,不是简单全选

真正决定“这个 slot 展示哪组资源”的,是 appointment.type._slot_availability_select_best_resources()

它的策略很有代表性:

  • 如果没开 manage_capacity,通常直接选排序后的第一个资源;
  • 如果存在“刚好等于 asked_capacity 的完美匹配”,优先用这一个,避免浪费大资源;
  • 如果单个资源不够,就通过 appointment.resource._get_filtered_possible_capacity_combinations() 枚举 linked resource 的组合;
  • 能找到“正好够用”的组合时,优先用精确组合;找不到才退而求其次,选容量更大的最优组合。

这说明企业版不是按“谁空着就给谁”,而是在做一次轻量的容量匹配。

对业务来说,这很重要:如果你有大会议室 + 小隔间、主设备 + 附属工位、摄影棚 + 灯光位这样的组合资源,不做这一步就会经常出现“大资源被小预约浪费掉”的情况。

3)客户看到的人数上限,和后台真实能分摊的结果不是两套逻辑

很多预约系统的坑在于:前台显示一个人数下拉框,提交时再用另一套规则校验,结果客户经常在最后一步被打回。

企业版 Appointment 尽量避免这个问题。

前台 slot 选择阶段根据容量信息给出可选人数和可选资源;到 appointment_form_submit() 真正提交时,又会重新取一次选中资源在该时段的剩余容量,防止并发下被别人抢走。

如果 resources_remaining_capacity['total_remaining_capacity'] < asked_capacity,系统不会硬创建事件,而是回跳到预约页并给出 failed-resource 状态。这就是典型的“展示一次、落单前再校验一次”的双重防线。

4)真正落库时,asked_capacity 会被拆成多条 booking line

最容易被忽略的是 appointment_form_submit() 最后的 booking_line_values 构造。

当预约类型按资源排程时,代码不是只写一条“总容量=4”的记录,而是按选中的资源逐个分摊:

  • capacity_reserved 代表这次预约从该资源上预留了多少容量;
  • capacity_used 则按是否 shareable 与是否启用 manage_capacity 决定实际占用口径。

也就是说:

  • shareable 资源 + manage_capacity 开启时,占多少就记多少;
  • 非 shareable 资源即使只预约了部分容量,也可能直接按整资源占用;
  • 这样后续冲突检测、Gantt 展示、资源不可用判断,都会沿用同一套 booking line 数据。

这一步决定了前台“选 3 人”最后到底是落成“2+1”还是“3+1 但只用 3”的占用形态。

这套设计为什么合理

它优先保证“前台承诺”和“后台占用”一致

网站预约最怕的不是没有空位,而是前台说能约、后台落不下来。企业版先在 slot 阶段挑最优资源组合,再在提交时重新核验,最后把容量拆成 booking lines。三段逻辑虽然复杂,但目标很统一:同一个预约不能在不同阶段换规则。

它兼容“可共享资源”和“独占资源”混搭

如果所有资源都只是“一个房间一次一单”,系统根本不需要 capacity_reserved / capacity_used 这种细粒度结构。企业版之所以这么做,是因为它要同时兼容:

  • 一张桌子 4 个座位,可拆给 1~4 人;
  • 一台设备一旦被占用就整台锁死;
  • 主资源和附属资源必须联动;
  • 一个预约跨多资源共同完成。

这就是它必须引入组合容量和 booking line 分摊的根本原因。

实战上最容易踩的几个坑

坑 1:只给资源设置 capacity,却没想清楚 shareable

很多实施会把容量填成 4、8、12,以为这样前台人数就自动合理。实际上如果 shareable 没开或业务上不该开,系统可能仍按整资源占用。最后看起来像“明明还剩 2 个名额,为什么下一个客户还是约不上”。

坑 2:linked resources 配错后,前台会出现“看得见、选不上”的错觉

资源组合能力来自 _get_possible_capacity_combinations()。如果主资源和附属资源关系没配全,前台可能能看到某些 slot,但人数一加大就突然消失,团队会误以为是时区或缓存问题,实际上是组合容量根本没算出来。

坑 3:自定义前端只改展示,不复用提交校验

有些项目会魔改预约页,把资源列表和人数控件做得很花。但如果只改前台展示,不保留 appointment_form_submit() 那套并发校验与失败回跳,最终会把“最后一步失败”问题重新引回来。

给实施和二开的建议

  1. 先画资源关系图,再配 Appointment。 先分清哪些资源是独占、哪些可共享、哪些要联动,不要直接在表单里边试边猜。
  2. asked_capacity 当业务变量,不要当 UI 变量。 它贯穿 slot 计算、最终校验和 booking line 落库,不只是前台一个人数下拉框。
  3. 二开时优先复用 booking line 结构。 不要另外造一套“资源占用表”,否则后续冲突判断会分裂。
  4. 压测并发抢位。 特别是热门培训、摄影棚、面谈室场景,要验证提交瞬间的二次校验是否符合预期。

一句话总结

Odoo 企业版网站预约不是“这个时段有空资源就能约”。

它的真实设计是:先根据 shareable / linked resource / asked_capacity 算出最合适的资源组合,再在提交时重做容量校验,并把结果拆成可追踪的 booking lines。

你理解了这条链,才能真正解释为什么同一个 slot 对 1 人可约、对 4 人却不可约;也才能在做企业级预约项目时,把“资源管理”而不是“时间选择”设计对。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。