标准结账(Standard Checkout)链路说明

本文档说明 标准多步结账checkout_type = standard)的完整业务流程:从进入结账到支付成功,含 每步做什么MySQL / Redis 交互API 如何调用。与当前仓库代码一致;冲突时以代码为准。

相关:cart-checkout-token-visit-id.md(token / 购物车 Redis)、promotion-discount-checkout.md(优惠计算)。

目录


1. 背景与目标

  • 店铺配置 storeConfig.checkout_process = standard(或未配置,默认 standard)时,用户走 Liquid 多页表单:联系信息 → 物流 → 支付 → 支付网关。
  • 每步 GET 渲染 + POST 提交,服务端 302 redirect 到下一步(非 JSON API 驱动)。
  • 创单时机:第一步 contact_information POST 提交邮箱+地址时。
  • 快捷支付(PayPal EC 等)强制走 standard URL(CheckoutService::generateCheckoutUrlByConfig)。

2. 入口:如何获得 checkout_token 与结账 URL

2.1 常见入口

入口路径 / 动作说明
购物车结账POST /cartCartService::getCheckoutUrl() → 写 checkoutcart Redis → redirect
Buy Now商品页 buynowCartService::createBuynow() checkout_token(不写 Cookie)
Instant CheckoutGET /express/checkout?sku_code=&quantity=CartHandlerService::createInstant()
邮件 / 弃单恢复带 token 的 checkout URL复用已有 checkout_token

2.2 URL 形态

/{storeId}-{token前6位}/checkouts/{checkout_token}?step=contact_information
  • store_random{storeId}-{checkout_token 前 6 位}CheckoutService
  • step 可选值:contact_information | shipping_method | payment_method | payment_gateway
  • 成功页:/checkouts/success/{checkout_token}

2.3 进入结账时的 Redis 写入

Key内容
{storeId}:guestcart:{visit_id}{storeId}:customercart:{customer_id}购物车行 JSON 数组
{storeId}:checkoutcart:{checkout_token}{ type: cart|buynow|..., cart_token 或 cart_data }

事件CartService::getCheckoutUrl() / createBuynow 触发 BeginCheckout

token / Cookie 细节见 cart-checkout-token-visit-id.md


3. 业务流程总览

sequenceDiagram
    participant U as 用户浏览器
    participant H as home/Order::checkout
    participant CS as CartService
    participant OS as OrderService

    U->>H: GET /checkouts/{token}?step=contact_information
    H->>CS: getList + getCheckoutStep
    H-->>U: Liquid 联系信息页

    U->>H: POST previous_step=contact_information
    H->>OS: saveContactInformation → createOrder
    OS-->>H: order_id
    H-->>U: 302 ?step=shipping_method

    U->>H: POST previous_step=shipping_method
    H->>OS: saveShippingMethod + saveOtherInformation + saveDiyOffer
    H-->>U: 302 ?step=payment_method

    U->>H: POST previous_step=payment_method
    H->>OS: savePaymentMethod + billing
    H-->>U: 302 ?step=payment_gateway

    U->>H: GET payment_gateway
    H-->>U: 支付 Script / 跳转三方

    U->>H: 支付回调 / success
    H-->>U: /checkouts/success/{token}

步骤守卫OrderService::getCheckoutStep() 根据订单上 has_contact_information / has_shipping_method / has_payment_method 自动纠正 step;缺前置则 redirect。


4. 逐步明细

4.1 Step 1:contact_information(联系信息)

GET 渲染

路由GET /{store_random}/checkouts/{checkout_token}?step=contact_information
Controllerapp/home/controller/Order.php::checkout

动作ServiceRedisMySQL
权限checkCheckoutPermission
校验快照CartService::_checkCheckoutCartcheckoutcarto_order(若 type=order)
计价 cartCartService::getList读 guest/customer cart + checkoutcart有单时 reconcile o_order / o_order_product
步骤OrderService::getCheckoutStep读 order flags
渲染Liquid 模板 contact_information

POST 提交

表单字段Order.php 139–199 行):

字段校验
email游客必填 email;会员用登录邮箱
first_name / last_name至少填一个
country_id必填
address1必填
phone, zip, province, city, area, company, address2可选
remember_me可选,会员保存地址簿

Service 链

CustomerService::checkDeny(email)
→ OrderService::saveContactInformation(cart, params, checkout_token)

saveContactInformation 内部(无单时创单):

顺序操作MySQLRedis
1黑名单
2createOrderinsert o_order(checkout_type 默认 standard)、o_order_product、UTM、o_order_property_tag
3saveCheckoutCartcheckoutcart.typeorder
4savePreCoupon更新 o_order.coupon_*读/删 pre_use_coupon
5saveProducts写/刷新 o_order_product
6saveShippingAddresso_order_shipping_address
7saveCustomerSysinfoo_order_customer_sysinfo
8可选自动注册o_customerdel customer cache

事件OrderCreaterecoveryForAdmin;新顾客 CustomerUpdate

响应:302 → ?step=shipping_method(可带 generate_lead=1add_order=1 等 query)。


4.2 Step 2:shipping_method(物流)

GET 渲染

加载:ShippingZoneHandlerService 物流列表、InsuranceService 运费险、TipService 小费、OrderDiyOfferHandleService::getOfferList(积分/Seel 等)。

POST 提交

表单字段(201–278 行):

字段说明
shipping_id必填,物流方案 ID
insurance运费险金额
tip_price小费
note订单备注
offer_from_nameJSON,订单级 diy_offer(积分抵扣等)
checkoutinfo附加表单 JSON
payment_id + token可选,快捷支付 Express Checkout

Service 链

OrderService::saveShippingMethod(cart, shipping_id, token)
→ OrderService::saveOtherInformation(cart, token, params)   // insurance/tip/note/additional_info
→ OrderDiyOfferHandleService::saveDiyOffer(token, offer_from_name)
→ [可选] OrderService::savePaymentMethod + 支付 Script ECPayment
操作MySQLRedis
saveShippingMethodo_order.current_shipping_priceo_order_shipping_zone_plan(+product)、客服关联
saveOtherInformationo_order insurance/tip/note/additional_info
saveDiyOffero_order_diy_offer

事件AddShippingInfo

响应:302 → ?step=payment_method;若走快捷支付可能直接调起支付 Script。


4.3 Step 3:payment_method(支付方式)

POST 提交

表单字段(280–335 行):

字段说明
payment_id必填
billingAddress1 = 同收货地址;否则传账单地址字段
账单地址字段同 contact_information 地址结构

Service 链

orderZeroPayment(order_id)          // 0 元单直接成功
→ OrderBillingAddressService::saveOrderBillingAddress
→ OrderService::savePaymentMethod
操作MySQLRedis
savePaymentMethodo_order.payment_*current_payment_price可能 clearCart 删 guestcart
billingo_order_billing_address

事件AddPaymentInfo

响应:302 → ?step=payment_gateway


4.4 Step 4:payment_gateway(支付网关)

GET 渲染

Liquid 模板加载对应支付 Script(PaymentService::initPaymentData 等),展示 iframe / 跳转按钮。

支付执行

路径说明
GET|POST /checkouts/payment/:interface/:interface_action支付通道页
GET|POST /checkouts/client|server/:interface/callback异步/同步回调
homeapi POST /:store_random/checkouts/:checkout_token/paymentform获取支付表单 JSON

支付成功后:OrderService::orderPaySuccess → 更新 o_order.financial_status、写 o_order_transactionclearCartByCheckoutToken

事件OrderPaidOrderPaidForCustomer 等。


4.5 成功页

路由GET /checkouts/success/{checkout_token}Order::success
渲染订单摘要;可能触发像素/分析事件。


5. homeapi 辅助 API(标准结账共用)

前缀均为 homeapi 域名;store_random 与 checkout URL 一致。

5.1 优惠券

方法路径参数作用DB/Redis
GET/coupon/check/:checkout_tokencode, email仅校验,不写库读券缓存
GET/coupon/use/:checkout_tokencode, email用券o_order + saveProducts;Redis pre_use_coupon
DELETE/coupon/cancel/:checkout_token取消券o_order.coupon_*
POST/couponsbody购物车阶段预存券 CookieRedis pre_use_coupon

调用示例

GET /coupon/use/{checkout_token}?code=SAVE10&email=user@example.com

响应(outputJson)含 codeprice 等券信息;前端刷新当前 step 或依赖 GET checkout 重渲染。

5.2 支付相关

方法路径Body作用
POST/:store_random/checkouts/:checkout_token/payment同 payment_method 表单AJAX 保存支付方式
POST/:store_random/checkouts/:checkout_token/paymentformCheckoutOnePageRequest 结构获取支付表单 HTML/URL

5.3 地址辅助

方法路径说明
GET/checkouts/:checkout_token/countrylist/:type国家列表
GET/checkouts/:checkout_token/address/:type/:country_id/:path711/全家等地址

5.4 购物车(进入结账前)

方法路径说明
POST/cart(home)跳转 checkout URL
GET/cartlist购物车列表 JSON
POST/cart/diyoffers加购 diy_offer 活动

6. Redis Key 汇总(标准结账)

Key读写时机
{store}:guestcart:{visit_id}全程读;支付后可能 delete
{store}:customercart:{id}会员购物车
{store}:checkoutcart:{token}进入 checkout 写;创单后 type=order
{store}:pre_use_coupon_{identity}预用券
{store}:coupons:id:{id}券详情缓存
{store}:customer:{id}创单/更新顾客后 del
{store}:oemsaas:checkout:create:{orderId}:{listener}OrderCreate 去重

TTL 见 cart-checkout-token-visit-id.md


7. MySQL 表汇总(按阶段)

阶段主要表
创单o_order, o_order_product, o_order_product_property, o_order_shipping_address, o_order_customer_sysinfo, o_customer
物流o_order, o_order_shipping_zone_plan, o_order_shipping_zone_plan_product
附加o_order(insurance/tip/note)、o_order_diy_offer
支付o_order, o_order_billing_address, o_order_transaction
o_order, o_order_product(行 discount 重算)

8. 事件一览

时机事件
进入 checkoutBeginCheckout
创单OrderCreate, recoveryForAdmin
保存地址AddAddressInfo
保存物流AddShippingInfo
保存支付AddPaymentInfo
支付成功OrderPaid, OrderPaidForCustomer, OrderPaidForAdmin

9. 可用优惠(promotion / coupon / diy_offer / order_diy_offer)

总对照见 promotions-by-checkout-type.md

体系标准结账
diy_offergetListcartDiyOffers(minmax 时跳过其余 type)
promotiongetCartPromotion;计入 promotion_price
couponGET /coupon/use/{token};创单 savePreCoupon;每步 GET checkout 时 getList reconcile
order_diy_offershipping_method POSToffer_from_namesaveDiyOffer

计算顺序(每步 GET/POST 渲染前 getList):行价 → minmaxoffer → diy_offer → 满减 → 预券 → 替换型券处理 →(有单)税/运费 reconcile → updateDiyOfferInfo → total。

落库影响

时机字段 / 表
contact_information 创单o_order 初值 current_*saveProductsdiy_offer_iddiscount_price
shipping_methodcurrent_promotion_price reconcile;o_order_diy_offer;运费/小费/险
coupon/usecoupon_* + saveProducts 重算行价
任意 getList(有单)可能 orderModel->save(partial) + saveProducts + updateDiyOfferInfo

10. 相关文件索引

模块路径
主 Controllerapp/home/controller/Order.php
home 路由app/home/route/route.php
homeapi 路由app/homeapi/route/route.php
订单写库common/services/OrderService.php
购物车 / tokencommon/services/CartService.php
URL 生成common/services/CheckoutService.php
common/services/CouponHandlerService.php
order_diy_offercommon/services/OrderDiyOfferHandleService.php

11. 联调备忘

  • previous_step POST 字段决定处理哪一步,不是 step query。
  • 已创单后 URL 由 o_order.checkout_type 锁定;standard 单不会跳到 one-page URL。
  • 用券后若价格变,依赖下次 GET getList reconcile 或当前 step POST 内 saveProducts。
  • 订单 paid/cancel 且 cookie checkout_token 匹配时会 renew token(见 cart 文档 §3.3)。
  • 0 元单在 payment_method POST 直接跳 success,不经 gateway。

对比其它形态:one-page-checkout-flow.md · single-page-checkout-flow.md