同城商城搭建联调阶段,常见误区是把「调起支付通道」和「下单写单」绑在同一次点击里:一点支付,同时创建订单、调起收款、改库存。任一环节失败,用户都看到「支付失败」,研发却难定位是下单问题还是通道问题。
正确做法是支付通道与下单收款拆开测:先保证订单写入口稳定,再测通道调起与回调,最后做端到端小额单。
结论:订单单写、收款可重试、回调防重复
用户提交购物车 -> order-service 创建订单 (status=created) -> 返回 order_id + payable_amount -> payment-service 创建支付意图 (intent_id) -> 客户端调起通道 -> 回调 -> 验签 -> 更新订单 status=paid禁止在未创建订单前直接调支付;也禁止回调里才第一次写订单主表。
下单流程:单一写入口
defcreate_mall_order(user_id:str,cart_lines:list)->dict:snapshot=catalog.quote(cart_lines)# 价格快照写入订单行order_id=order_repo.insert({"user_id":user_id,"status":"created","amount":snapshot.total,"lines":snapshot.lines,})return{"order_id":order_id,"amount":snapshot.total}商品改价只影响新单;历史订单行保持下单时快照,避免对账时「页面一个数、导出另一个数」。
支付意图:与订单绑定、可单独重试
defcreate_payment_intent(order_id:str)->dict:order=order_repo.get(order_id)iforder.statusnotin("created","pay_pending"):raiseBusinessError("order not payable")intent_id=payment_repo.create_intent(order_id=order_id,amount=order.amount,idempotency_key=f"pay:{order_id}:{order.pay_attempt}",)order_repo.update_status(order_id,"pay_pending")return{"intent_id":intent_id,"client_payload":build_channel_payload(intent_id)}用户关闭支付窗口后再次点击,应复用或递增pay_attempt,而不是新建影子订单。
回调:验签 + 幂等 + 状态机
defon_payment_notify(payload:dict,signature:str):verify_signature(payload,signature)intent=payment_repo.get(payload["intent_id"])withorder_repo.lock(intent.order_id):order=order_repo.get(intent.order_id)iforder.status=="paid":return"OK"# 幂等ifpayload["status"]!="success":order_repo.update_status(intent.order_id,"pay_failed")return"OK"order_repo.update_status(intent.order_id,"paid")inventory_service.commit(intent.order_id)return"OK"拆开测的三段验收
段 1|仅下单:不调通道,订单created可查,库存预占正确。
段 2|仅支付意图 + 沙箱回调:固定order_id,验证回调幂等与验签。
段 3|端到端小额单:正式或准生产环境,导出字段与订单行一致。
与商城页面的关系
页面团队可先验收展示与购物车;支付团队用固定order_id测意图与回调。不必等 UI 定稿才第一次写订单服务。
常见踩坑
坑 1:前端本地改「已支付」
以回调后服务端状态为准,禁止 UI 抢先。
坑 2:支付金额由前端传入
金额必须来自订单服务,通道侧与订单侧交叉校验。
坑 3:退款走另一套订单库
售后宜关联原order_id,不新建平行表。
光合同城边界
光合同城同城电商成品含订单写入口与可配置支付对接底座,支持支付意图与下单分开验收;私有化源码交付。具体国家/通道按需定制对接;商务结算规则由客户确定;系统侧不抽成客户平台订单。
小结
同城商城搭建联调时,把支付意图与下单流程拆开测,定位快、返工少;端到端通过后再做页面美化,比「一点支付碰运气」稳得多。
联调现场怎么拆问题
很多团队第一次联调会把「购物车能加」和「通道能扣款」当成同一张验收表。更实用的拆法是:先在测试环境只走下单接口,固定两件商品、固定金额,确认订单表里状态为已创建且订单行价格与商品快照一致。第二步才用同一订单号创建支付意图,在沙箱里走完回调,看状态是否变成已支付而不会重复扣库存。
第三段才是端到端:用户从页面点支付。若第三段失败,回查前两段哪一段红了,而不是从零猜测。财务同事宜在第二段就参与:导出表格是否与订单应付金额一致。这一步通过,后面换页面皮肤不会动到对账口径。上线前还可模拟回调重复投递、支付失败回调,看订单是否仍停在可重试状态。
交付验收宜归档:下单段、支付段、端到端段各一张签字表,附测试订单号与导出样例,便于第二城复制同一套拆法。