网站租赁最容易让人误判的一点,是把商品页上的“available”当成最终可下单结论。企业版源码把这件事拆成了三层:商品页组合信息里的 availability 投影、购物车改租期时的整单回滚,以及支付前 _check_cart_is_ready_to_be_paid() 的最终拦截。
主要参考源码:
enterprise/website_sale_renting/controllers/main.pyenterprise/website_sale_renting/models/product_template.pyenterprise/website_sale_renting/models/sale_order.py
一、前台看到的 availability 只是展示层投影
控制器 product() 会把 start_date / end_date 放进上下文,随后 _get_additionnal_combination_info() 根据当前时区、定价周期和默认租期给商品页补一组 renting 信息,包括默认起止时间、当前时长和价格。它的职责首先是让页面解释得通,而不是替代后端订单校验。
renting_product_availabilities() 又把某个区间内的可租数量作为 JSON 返回给前端日历组件。它适合做选择器和提示,不适合直接当成支付许可。
二、购物车改期不是覆盖,而是“先写入,再回滚”
_cart_update_renting_period() 会先尝试把新租期写到 sale.order,然后立即调用 _available_dates_for_renting() 复核。如果失败,就把 rental_start_date 与 rental_return_date 回滚,并写入 shop_warning。
这说明购物车的职责不是说“用户刚选的新时间一定成立”,而是把整单上所有租赁行拿来做一次新的联合验证。只要购物车里有一条租赁行撑不住,整单租期就退回旧值。
三、结账前还有最后一道闸门
即便商品页能显示可租、购物车改期也一度成功,支付前 _check_cart_is_ready_to_be_paid() 还会再次调用 _available_dates_for_renting()。如果区间已经失效,就抛 ValidationError,要求先更新购物车。
这条链路跨了:
- 网站商品页;
- 网站购物车;
sale.order租赁整单;- 库存/资源 availability 口径。
因此真正能进支付的不是“某一次页面看到的 availability”,而是整单在当前瞬间还能通过后端复核。
四、为什么 _verify_cart_after_update() 还要清理整单标记
当租赁行被删掉后,_verify_cart_after_update() 会把 is_rental_order、rental_start_date、rental_return_date 清空。这个动作看起来小,实际是在防止一个已不是租赁单的购物车继续带着租赁上下文跑税费、地址和支付链路。
五、结论
网站租赁不是“页面显示可租就能下单”,而是页面投影 -> 购物车整单复核 -> 支付前最终复核的三级链路。只理解第一层,就会在改期、并发和支付前校验里反复踩坑。
DISCUSSION
评论区