09 10月 2026

前端订单流程

商品订单从加购到支付成功,沿下面这条链走。活动商品不另开下单接口:加购时带上活动编号,后面仍进同一个 StoreOrderController。

路由文件:app/api/route/v1.php、app/api/route/v2.php。

购物车、确认订单、创建订单、支付都要登录。商品详情和多数活动列表不用登录。支付回调 ANY /api/pay/notify/:type 不登录。

库存在创建订单时扣,不在支付成功时扣。

主链路

看商品/活动
→ POST /api/cart/add                 写入购物车或立即购买缓存,返回 cartId
→ POST /api/order/confirm           用 cartId 生成确认页,缓存订单,返回 key
→ POST /api/order/computed/:key     重算金额
→ POST /api/order/create/:key       落库并扣库存,返回 orderId
→ GET /api/order/cashier/:orderId
→ POST /api/order/pay
      余额 / 0 元 → 当场 paySuccess
      微信 / 支付宝 / 通联 → 只返回支付参数
→ ANY /api/pay/notify/:type         渠道回调后再 paySuccess
步骤接口控制器
1 加购POST /api/cart/addapp/api/controller/v1/store/StoreCartController.php → add
2 确认POST /api/order/confirmapp/api/controller/v1/order/StoreOrderController.php → confirm
3 算价POST /api/order/computed/:key同文件 → computedOrder
4 提交POST /api/order/create/:key同文件 → create
5 收银台GET /api/order/cashier/:orderId/[:type]同文件 → cashier
6 支付POST /api/order/pay同文件 → pay
7 回调ANY /api/pay/notify/:typeapp/api/controller/v1/PayController.php → notify

cartId 和 key 的交接:

  • new=1 或 is_new=1 时,add 不写 eb_store_cart。购物车放进缓存,返回的 cartId 就是缓存键。

  • confirm 读这份数据,再写入 user_order_{uid}{key}。

  • computed 和 create 都用这个 key 读缓存。

  • 创建订单加锁键是 orderCreate{key}。

1. 活动商品(下单前)

列表和详情多数不用登录。购买都回到 POST /api/cart/add,用不同字段决定购物车类型。

活动看商品下单前的参与动作cart/add 字段购物车 type
普通商品GET /api/product/detail/:id/[:type] → app/api/controller/v1/store/StoreProductController.php → detail无只传 productId0
秒杀app/api/controller/v1/activity/StoreSeckillController.php无,详情进加购secKillId1
砍价app/api/controller/v1/activity/StoreBargainController.php先 start,好友 help,砍成再加购bargainId2
拼团app/api/controller/v1/activity/StoreCombinationController.php参团前看 pink;团已结束时 add 直接失败combinationId,参团再带 pinkId3
预售app/api/controller/v1/activity/StoreAdvanceController.php → detail无advanceId6

积分商品不走这条购物车,见文末「积分订单」。

秒杀

文件:app/api/controller/v1/activity/StoreSeckillController.php

接口方法作用
GET /api/seckill/indexindex秒杀时间段
GET /api/seckilllistgetskill最近开始的两条活动
GET /api/seckill/list/:timelst某个时间段的商品
POST /api/seckill_activity_listactivity_lst按活动查商品
GET /api/seckill/detail/:iddetail按时段的商品详情
GET /api/seckill_activity_detail/:idactivity_detail不按时段的商品详情
GET /api/seckill/code/:idcode海报,不参与下单

秒杀加购后,价格、标题、规格留在缓存的 cartInfo.productInfo 上。confirm 不重新加载秒杀商品。create 若请求里的 seckill_id 为 0,用缓存购物车第一行的 seckill_id。StoreOrderCreateServices::createOrder 再用这个 id 查出 activity_id 写入订单。

库存校验:StoreCartServices::checkProductStock 的 type 1 调用 StoreSeckillServices::checkSeckillStock。

砍价

文件:app/api/controller/v1/activity/StoreBargainController.php

接口方法作用
GET /api/bargain/configconfig列表配置,未登录
GET /api/bargain/listlst商品列表,未登录
GET /api/bargain/detail/:iddetail详情,需登录
POST /api/bargain/startstart开启砍价
POST /api/bargain/start/userstart_user开启人信息
POST /api/bargain/helphelp帮砍
POST /api/bargain/help/pricehelp_price本次砍掉的金额
POST /api/bargain/help/counthelp_count进度
POST /api/bargain/help/listhelp_list帮砍记录
GET /api/bargain/user/listuser_list我参与的砍价
POST /api/bargain/user/canceluser_cancel取消砍价

share、poster、posterInfo 是分享和海报,不参与下单。

拼团

文件:app/api/controller/v1/activity/StoreCombinationController.php

接口方法作用
GET /api/combination/listlst商品列表,未登录
GET /api/combination/banner_listbanner_list轮播,未登录
GET /api/combination/detail/:iddetail详情,未登录
GET /api/combination/pink/:idpink开团信息,需登录
POST /api/combination/removeremove取消开团

poster、posterInfo、code 是海报,不参与下单。拼团记录在支付成功后由 StorePinkServices::createPink 创建。

预售

接口文件方法
GET /api/advance/listapp/api/controller/v1/store/StoreProductController.phpadvanceList
GET /api/advance/detail/:idapp/api/controller/v1/activity/StoreAdvanceController.phpdetail

同文件还有 index,当前 v1.php 未给预售首页单独配这条路由。到期下架走定时任务:GET /api/crontab/advance_off → app/api/controller/v1/CrontabController.php → downAdvance。

2. 购物车

文件:app/api/controller/v1/store/StoreCartController.php。路由在 app/api/route/v1.php,都要登录。

接口方法作用
POST /api/cart/addadd加购或立即购买。new=1 或 is_new=1 为立即购买
GET /api/cart/listlst购物车列表
POST /api/cart/numnum改数量
POST /api/cart/deldel删除
GET /api/cart/countcount数量和金额

add 的入参:

字段含义
productId普通商品编号,必填
cartNum数量,默认 1
uniqueId规格唯一值
new / is_new1 立即购买,0 加入购物车
secKillId秒杀编号,有值则 type = 1
bargainId砍价编号,有值则 type = 2
combinationId拼团编号,有值则 type = 3
pinkId拼团团队 id。团已结束则 add 失败
advanceId预售编号,有值则 type = 6

判断顺序是秒杀、砍价、拼团、预售。都没有时 type = 0,并调用 StoreCartServices::checkVipGoodsBuy。

接着进入 app/services/order/StoreCartServices.php:

  • setCart:写入 eb_store_cart,或在立即购买时写入缓存并返回缓存键。

  • checkProductStock:按 type 校验活动库存。

同一控制器还有 reChange(重选规格)。当前 v1.php 没有这条路由。改规格走 v2:

接口文件方法
POST /api/v2/reset_cartapp/api/controller/v2/store/StoreCartController.phpresetCart
GET /api/v2/cart_list同文件getCartList
POST /api/v2/set_cart_num同文件setCartNum
GET /api/v2/get_attr/:id/:typeapp/api/controller/v2/store/StoreProductController.phpgetProductAttr

PC 购物车是另一条:GET /api/pc/get_cart_list → app/api/controller/pc/CartController.php → getCartList。下单仍回到 v1 的确认和创建接口。

3. 提交订单

文件:app/api/controller/v1/order/StoreOrderController.php。

顺序接口方法接着看
配送方式POST /api/order/check_shippingcheckShippingapp/services/order/StoreOrderServices.php → checkShipping
确认页POST /api/order/confirmconfirm同文件 → getOrderConfirmData
算价POST /api/order/computed/:keycomputedOrderapp/services/order/StoreOrderComputedServices.php → computedOrder
创建POST /api/order/create/:keycreate先 OrderService::preOrder 冻结积分,再 app/services/order/StoreOrderCreateServices.php → createOrder
再次购买POST /api/order/againagainStoreOrderServices::againOrder,把旧单商品重新放进购物车

确认页 confirm

入参:cartId、new、addressId、shipping_type(默认 1)、is_gift。

cartId 不是字符串或为空时失败。运费模板 id 1 不存在时失败。

getOrderConfirmData 读购物车(立即购买读缓存,普通加购读 eb_store_cart),算出确认页数据,并把购物车快照写入 user_order_{uid}{key}。返回体里的 key 就是后面两步的路径参数。

这里不接收 seckill_id。活动身份已经在购物车缓存里。

算价 computedOrder

入参:addressId、couponId、payType、useIntegral、mark、combinationId、pinkId、seckill_id、bargainId、shipping_type、is_gift。

seckill_id、combinationId、bargainId 在这里用来把订单当成活动单,跳过优惠券和商城积分抵扣,不负责把活动 id 写入订单表。

算完商城价格后,结果写入缓存 user_order_integral_{key}。

key 若已经是该用户的订单号,直接返回已有订单,不再重算。

创建 create

入参包括地址、优惠券、支付方式、备注、拼团、秒杀、砍价、预售、配送方式、自提人、门店、发票、自定义表单、礼物标记。方法内把 useIntegral 固定写成 1。

顺序:

  1. 用 key 读 user_order_{uid}{key}。缓存不存在则失败。

  2. StoreOrderCreateServices::getNewOrderId('cp') 预生成订单号。

  3. CacheService::lock('orderCreate' . $key) 里调用 createOrder。

  4. 创建抛错且已经冻结积分时,OrderService::cancelOrder 解冻。

  5. 成功返回 orderId 和 key。

createOrder 里写入 eb_store_order。秒杀订单的 seckill_id 在这里落库:请求值为 0 时,取缓存购物车第一行的 seckill_id,后面的行不覆盖。再用 StoreSeckillServices::value(['id' => $seckillId], 'activity_id') 取活动 id。

购物车快照由 StoreOrderCartInfoServices::setCartInfo 另存,不负责写订单上的活动字段。

扣库存:StoreOrderCreateServices::decGoodsStock。秒杀再进 StoreSeckillServices::decSeckillStock,同时减秒杀 SKU、秒杀库存和关联的普通商品库存。退款回库存在 StoreOrderRefundServices::regressionStock,秒杀对应 incSeckillStock。

确认页还会调用

接口文件方法
GET /api/address/listapp/api/controller/v1/user/UserAddressController.phpaddress_list
GET /api/address/default同文件address_default
POST /api/address/edit同文件address_edit
GET /api/coupons/order/:priceapp/api/controller/v1/store/StoreCouponsController.phporder
GET /api/pay/configapp/api/controller/v1/PayController.phpconfig

pay/config 返回微信支付、支付宝、余额、线下支付、好友代付,是否开启看系统配置。

4. 支付和回调

POST /api/order/pay → StoreOrderController::pay。

入参:uni(订单号)、paytype、quitUrl、type。type = 1 时付款人取当前登录用户,否则取订单上的 uid(好友代付)。

方法内先写 2 秒的 PAY_LOCK_{uni},避免重复支付。已删除、已支付、拼团已结束的订单在这里拒绝。应付金额先改写订单的 is_channel、pay_uid,代付时还会换成新的 cp 订单号。

四条去向:

情况控制器之后是否进渠道回调
应付金额小于等于 0app/services/order/StoreOrderSuccessServices.php → zeroYuanPayment → paySuccess否
yue 余额app/services/pay/YuePayServices.php → yueOrderPay → 商品单走 paySuccess否
offline 线下StoreOrderServices::setOrderTypePayOffline,并通知管理员否,等后台确认收款
微信 / 支付宝 / 通联app/services/pay/OrderPayServices.php → beforePay是

余额不足时 yueOrderPay 返回 pay_deficiency,不改支付状态。会员卡余额支付走 OtherOrderServices::paySuccess,不进商品订单的 paySuccess。

beforePay 按订单有没有 member_type 决定回调业务名:商品订单是 product,会员卡是 member。然后 Pay::pay 向渠道下单,把前端调起支付需要的参数返回给 pay。

渠道回调

渠道付完后请求这条,不需要登录:

ANY /api/pay/notify/:type
→ app/api/controller/v1/PayController.php → notify

:type:

type处理
alipayPay('ali_pay')->handleNotify()
v3wechatPay('v3_wechat_pay')->handleNotify()
wechat配置了 pay_wechat_type 走 v3,否则走默认微信支付
routineMiniProgramService::handleNotify()
路径中含 allinPay('allin_pay')->handleNotify($type)

控制器只按渠道拆报文。支付成功后的业务不在控制器里:

crmeb\services\pay\Pay::handleNotify
→ 事件 NotifyListener(注册在 app/event.php)
→ app/listener/pay/NotifyListener.php → handle
→ crmeb/utils/Hook.php
      类 PayNotifyServices,前缀 wechat,再加上 attach
→ app/services/pay/PayNotifyServices.php → wechatProduct
→ app/services/order/StoreOrderSuccessServices.php → paySuccess

Hook 把前缀 wechat 和 attach 拼成方法名。attach = product 才是 wechatProduct。

PayNotifyServices 另外两个方法不是商品订单:

方法业务
wechatUserRecharge余额充值,UserRechargeServices::rechargeSuccess
wechatMember会员卡,OtherOrderServices::paySuccess

商品订单已支付或订单不存在时,wechatProduct 直接返回成功,避免渠道重复通知。

paySuccess 做什么

文件:app/services/order/StoreOrderSuccessServices.php,方法 paySuccess。

  1. 订单写成已支付:paid = 1,写入 pay_type、pay_time,有渠道单号时写入 trade_no。

  2. 拼团订单且未退款时,StorePinkServices::createPink。

  3. 非线下支付时,LuckLotteryServices::setCacheLotteryNum 缓存抽奖次数。

  4. 触发事件:

    • OrderPaySuccessListener

    • NoticeListener(用户支付成功、管理员支付成功)

    • OutPushListener(对外推送)

    • CustomNoticeListener、CustomEventListener

OrderPaySuccessListener 在 app/listener/order/OrderPaySuccessListener.php 的 handle:

  • 写订单状态「用户付款成功」

  • 普通商品赠送购买优惠券(秒杀、砍价、拼团不赠)

  • 发票标为已支付,满足配置时延迟自动开票

  • 虚拟商品自动发货(拼团除外)

  • 微信、支付宝、通联写入资金流水

  • 小票打印、支付成功消息、分销等级、商品支付日志

不要当成商品支付回调

接口文件方法实际用途
ANY /api/order_call_backStoreOrderController.phpcallBack商家寄件回调
ANY /api/transfer/notify/:typePayController.phptransferNotify商户转账回调
POST /api/sms/pay/notifyapp/api/controller/v1/PublicController.phpsms_pay_notify短信购买通知

5. 支付之后

仍在 app/api/controller/v1/order/StoreOrderController.php。

接口方法作用
GET /api/order/datadata订单数量统计
GET /api/order/listlst订单列表
GET /api/order/detail/:uni/[:cartId]detail订单详情
GET /api/order/express/:uni/[:type]express查看物流
POST /api/order/taketake确认收货,进 StoreOrderTakeServices::takeOrder
POST /api/order/commentcomment评价
POST /api/order/productproduct按购物车唯一值取订单商品,评价页使用
POST /api/order/cancelcancel未支付取消,进 StoreOrderServices::cancelOrder
POST /api/order/deldel用户删除订单
GET /api/order/friend_detailfriendDetail好友代付详情
GET /api/order/gift_detail/:oidgiftDetail礼物详情
POST /api/order/receive_gift/:oidreceiveGift领取礼物
GET /api/order/refund_detail/:uni/[:cartId]refund_detail退款详情(旧)
GET /api/order/refund/reasonrefund_reason退款理由
GET /api/order/refund/cart_info/:idrefundCartInfo退款中间页商品
POST /api/order/refund/cart_inforefundCartInfoList退款商品列表
POST /api/order/refund/apply/:idapplyRefund申请退款,进 StoreOrderRefundServices

同文件还有 refund_express。正在使用的退货物流接口不是它,见下一节。

POST /api/order/refund/verify 路由指向 StoreOrderController/refund_verify,这个类里没有该方法。

未支付超时取消不走用户操作:GET /api/crontab/order_cancel → app/api/controller/v1/CrontabController.php → orderUnpaidCancel → StoreOrderServices::orderUnpaidCancel。

退款单

文件:app/api/controller/v1/order/StoreOrderRefundController.php。

接口方法作用
GET /api/order/refund/listrefundList退款单列表
GET /api/order/refund/detail/:unirefundDetail退款单详情
POST /api/order/refund/cancel/:unicancelApply取消退款申请
POST /api/order/refund/expressapplyExpress填写退货物流
GET /api/order/refund/del/:unidelRefund删除退款单

申请退款先走 StoreOrderController::applyRefund,之后的列表、详情、取消、退货物流走这个控制器。

发票(v2)

文件:app/api/controller/v2/order/StoreOrderInvoiceController.php。

接口方法
POST /api/v2/order/make_up_invoicemakeUp
GET /api/v2/order/invoice_listlist
GET /api/v2/order/invoice_detail/:unidetail
GET /api/v2/order/down_invoice/:iddownInvoice

用户发票抬头在 app/api/controller/v2/user/UserInvoiceController.php:invoiceList、invoice、saveInvoice、setDefaultInvoice、getDefaultInvoice、delInvoice。

6. 不走商品订单控制器的两条线

积分订单

商品浏览:app/api/controller/v1/activity/StoreIntegralController.php

接口方法
GET /api/store_integral/indexindex
GET /api/store_integral/listlst
GET /api/store_integral/detail/:iddetail

下单和售后:app/api/controller/v1/order/StoreIntegralOrderController.php。不经过 cart/add,也不进 StoreOrderController。

接口方法服务
POST /api/store_integral/order/confirmconfirmStoreIntegralOrderServices::getOrderConfirmData
POST /api/store_integral/order/createcreateStoreIntegralOrderServices::createOrder
GET /api/store_integral/order/detail/:unidetail
GET /api/store_integral/order/listlst
GET /api/store_integral/order/express/:uniexpress
POST /api/store_integral/order/taketake
POST /api/store_integral/order/deldel

会员卡和线下收款

文件:app/api/controller/v1/order/OtherOrderController.php。

接口方法作用
POST /api/user/member/card/createcreate购买会员卡
POST /api/order/offline/check/pricecomputed_offline_pay_price计算线下付款金额
POST /api/order/offline/createcreate创建线下付款单
GET /api/order/offline/pay/typepay_type线下付款方式

创建后若走微信或支付宝,回调 attach 是 member,进入 PayNotifyServices::wechatMember → OtherOrderServices::paySuccess。余额支付在 YuePayServices::yueOrderPay 的 pay_member 分支,同样进 OtherOrderServices::paySuccess。

7. 手机端店员订单

类名也叫 StoreOrderController,文件是 app/api/controller/v1/admin/StoreOrderController.php。路径前缀 /api/admin/order/,给店员发货、改价、退款、核销,不是用户下单。

接口方法
GET /api/admin/order/statisticsstatistics
GET /api/admin/order/datadata
GET /api/admin/order/listlst
GET /api/admin/refund_order/listrefundOrderList
GET /api/admin/order/detail/:orderIddetail
GET /api/admin/refund_order/detail/:unirefundOrderDetail
GET /api/admin/order/delivery/gain/:orderIddelivery_gain
POST /api/admin/order/delivery/keep/:iddelivery_keep
POST /api/admin/order/priceprice
POST /api/admin/order/remarkremark
POST /api/admin/order/agreeExpressagreeExpress
POST /api/admin/refund_order/remarkrefundRemark
POST /api/admin/order/offlineoffline
POST /api/admin/order/refundrefund
POST /api/order/order_verificorder_verific
GET /api/admin/order/express/:uni/[:type]express

8. 按文件打开的顺序

看一笔普通商品或活动商品订单时,按这个顺序打开:

  1. app/api/controller/v1/store/StoreCartController.php → add

  2. app/services/order/StoreCartServices.php → setCart、checkProductStock

  3. app/api/controller/v1/order/StoreOrderController.php → confirm

  4. app/services/order/StoreOrderServices.php → getOrderConfirmData

  5. StoreOrderController.php → computedOrder

  6. app/services/order/StoreOrderComputedServices.php → computedOrder

  7. StoreOrderController.php → create

  8. app/services/order/StoreOrderCreateServices.php → createOrder、decGoodsStock

  9. StoreOrderController.php → cashier、pay

  10. app/services/pay/OrderPayServices.php → beforePay(微信、支付宝、通联)

  11. app/services/pay/YuePayServices.php → yueOrderPay(余额)

  12. app/services/order/StoreOrderSuccessServices.php → zeroYuanPayment(0 元)

  13. app/api/controller/v1/PayController.php → notify

  14. app/listener/pay/NotifyListener.php → handle

  15. app/services/pay/PayNotifyServices.php → wechatProduct

  16. app/services/order/StoreOrderSuccessServices.php → paySuccess

  17. app/listener/order/OrderPaySuccessListener.php → handle

延伸阅读
linux+rabbitmq+thinkphp
php图片打水印
使用phpqrcode生成二维码
发表评论
最新|与我有关