PHP实现商场代付功能:从原理到实践全解析
在电商或线下商场场景中,"代付"是一个常见需求——比如用户A为用户B购买商品,由用户B实际支付;或企业为员工统一采购后由企业账户结算,本文将结合PHP开发实践,从功能原理、核心流程、代码实现到安全注意事项,详细拆解商场代付功能的开发方案。
代付功能的核心原理与需求分析
什么是代付功能?
代付(Payment on Behalf)是指第三方(代付方)为交易中的付款方(被代付方)垫付资金,完成支付流程的业务模式,在商场场景中,常见场景包括:
- 亲友代付:用户A为用户B下单,由B支付;
- 企业代付:企业为员工采购,由企业账户统一结算;
- 礼品卡代付:使用礼品卡余额为他人订单支付。
核心需求拆解
实现代付功能需明确以下关键点:
- 身份标识:区分付款方(被代付人)和代付方,需记录双方用户ID/手机号/订单关联关系;
- 资金流向:代付方资金如何进入商户账户(需对接支付渠道);
- 订单状态管理:代付支付成功后,订单状态需同步更新(如"待支付"→"已支付"→"已发货");
- 安全控制:防止代付方误付、恶意代付,或被代付方拒绝支付后的订单处理。
代付功能的核心流程设计
代付功能的本质是在标准支付流程中增加"代付关系校验"和"资金垫付"环节,核心流程如下:
sequenceDiagram
participant 用户 as 用户(被代付人)
participant 系统 as 商城系统
participant 代付方 as 代付方(如亲友/企业)
participant 支付渠道 as 支付渠道(微信/支付宝)
用户->>系统: 下单并选择"代付",填写被代付人信息
系统->>系统: 生成代付订单,标记"待代付"状态,关联双方用户ID
系统->>代付方: 发送代付通知(短信/站内信)
代付方->>系统: 进入代付页面,确认代付金额
代付方->>支付渠道: 发起支付(调用支付接口)
支付渠道->>支付渠道: 处理支付(输入密码/指纹验证)
支付渠道->>系统: 同步支付结果(或通过回调通知)
系统->>系统: 更新订单状态为"已支付",记录代付方ID
系统->>用户: 发送支付成功通知
系统->>仓库: 触发发货流程
PHP实现代付功能的核心代码
数据库设计:存储代付关系
首先需设计订单表和代付关系表,核心字段如下:
订单表(orders):
CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL COMMENT '订单号', `user_id` int(11) NOT NULL COMMENT '被代付人用户ID', `total_amount` decimal(10,2) NOT NULL COMMENT '订单金额', `status` tinyint(1) DEFAULT '0' COMMENT '状态:0-待代付,1-已支付,2-已取消', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `order_no` (`order_no`) );
代付关系表(proxy_payments):
CREATE TABLE `proxy_payments` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order_id` int(11) NOT NULL COMMENT '关联订单ID', `proxy_user_id` int(11) NOT NULL COMMENT '代付方用户ID', `proxy_amount` decimal(10,2) NOT NULL COMMENT '代付金额', `status` tinyint(1) DEFAULT '0' COMMENT '状态:0-待支付,1-支付成功,2-支付失败', `pay_time` datetime DEFAULT NULL COMMENT '支付时间', PRIMARY KEY (`id`), KEY `order_id` (`order_id`) );
下单时选择代付(前端+后端交互)
前端在下单页面增加"代付"选项,用户填写被代付人手机号/用户ID,后端校验并生成代付订单。
PHP后端代码(生成代付订单):
<?php
// 生成代付订单
function createProxyOrder($userId, $totalAmount, $proxyUserId) {
// 1. 生成唯一订单号
$orderNo = 'PROX' . date('YmdHis') . mt_rand(1000, 9999);
// 2. 开启事务(保证订单和代付关系数据一致)
$db = Db::getInstance();
$db->beginTransaction();
try {
// 3. 插入订单表(状态为"待代付")
$orderId = $db->insert('orders', [
'order_no' => $orderNo,
'user_id' => $userId,
'total_amount' => $totalAmount,
'status' => 0 // 0-待代付
]);
// 4. 插入代付关系表
$db->insert('proxy_payments', [
'order_id' => $orderId,
'proxy_user_id' => $proxyUserId,
'proxy_amount' => $totalAmount,
'status' => 0 // 0-待支付
]);
// 5. 提交事务
$db->commit();
return [
'code' => 200,
'data' => [
'order_no' => $orderNo,
'proxy_user_id' => $proxyUserId
]
];
} catch (Exception $e) {
$db->rollBack();
return [
'code' => 500,
'msg' => '生成代付订单失败:' . $e->getMessage()
];
}
}
// 示例调用
$userId = 1001; // 被代付人ID
$totalAmount = 99.00;
$proxyUserId = 1002; // 代付方ID
$result = createProxyOrder($userId, $totalAmount, $proxyUserId);
echo json_encode($result);
代付方发起支付(对接支付渠道)
代付方收到通知后,进入代付页面,调用支付接口(以微信支付为例),需注意:代付支付需使用代付方的支付账户(如微信openid),而非被代付人。
PHP调用微信支付统一下单接口:
<?php
require_once 'WxPay.Api.php';
function createWxProxyPayment($orderNo, $proxyUserId, $amount) {
// 1. 获取代付方的openid(需提前绑定)
$proxyUser = getUserInfo($proxyUserId);
$openid = $proxyUser['wx_openid'];
if (!$openid) {
return ['code' => 400, 'msg' => '代付方未绑定微信'];
}
// 2. 构造微信支付参数
$input = new WxPayUnifiedOrder();
$input->SetBody("商场代付 - 订单号:{$orderNo}");
$input->SetOut_trade_no($orderNo); // 使用原订单号(需确保唯一)
$input->SetTotal_fee($amount * 100); // 金额单位:分
$input->SetNotify_url("https://yourdomain.com/wxpay_notify.php"); // 回调地址
$input->SetTrade_type("JSAPI"); // 公众号/小程序支付
$input->SetOpenid($openid); // 代付方的openid
// 3. 调用统一下单接口
$order = WxPayApi::unifiedOrder($input);
if ($order['return_code'] == 'SUCCESS' && $order['result_code'] == 'SUCCESS') {
// 4. 返回前端调起支付需要的参数
$jsApiParameters = WxPayJsApi::jsApi($order);
return [
'code' => 200,
'data' => $jsApiParameters
];
} else {
return [
'code' => 500,
'msg' => '微信支付下单失败:' . $order['return_msg']
];
}
}
// 示例调用
$orderNo = 'PROX20231120123456';
$proxyUserId = 1002;
$amount = 99.00;
$result = createWxProxyPayment($orderNo, $proxyUserId, $amount);
echo json_encode($result);



还没有评论,来说两句吧...