{{wikiTitle}}
支付开发流程文档 v2
复制链接
编辑文档
CRMEB 支付开发流程文档
🎯 支付功能概述
基于CRMEB 5.6.4+版本的支付系统分析,项目采用统一的支付服务架构,支持多种支付方式集成。
支持的支付方式
// app/services/pay/PayServices.php
const WEIXIN_PAY = 'weixin'; // 微信支付
const YUE_PAY = 'yue'; // 余额支付
const OFFLINE_PAY = 'offline'; // 线下支付
const ALIAPY_PAY = 'alipay'; // 支付宝
const ALLIN_PAY = 'allinpay'; // 通联支付
const FRIEND = 'friend'; // 好友代付
const BANK = 'bank'; // 银行转账
🏗️ 支付系统架构
核心服务类结构
app/services/pay/
├── PayServices.php # 统一支付入口服务
├── OrderPayServices.php # 订单支付服务
├── PayNotifyServices.php # 支付回调服务
├── YuePayServices.php # 余额支付服务
└── RechargeServices.php # 充值服务
crmeb/services/pay/
├── Pay.php # 支付基础驱动
├── storage/
│ ├── WechatPay.php # 微信支付驱动
│ ├── AliPay.php # 支付宝驱动
│ ├── AllinPay.php # 通联支付驱动
│ └── V3WechatPay.php # 微信支付V3驱动
支付流程
1. 支付请求流程
graph TD
A[客户端] --> B[支付控制器]
B --> C[PayServices]
C --> D[支付驱动 WechatPay/AliPay]
D --> E[第三方支付平台]
E --> F[返回支付参数]
F --> A
2. 支付回调流程
graph TD
A[第三方支付] --> B[支付回调接口]
B --> C[PayNotifyServices]
C --> D[订单状态更新]
C --> E[支付记录更新]
D --> F[业务处理]
🔧 核心代码解析
统一支付入口 (PayServices.php)
public function pay(string $payType, string $orderId, string $price, string $successAction, string $body, array $options = [])
{
try {
// 支付类型映射处理
if (in_array($payType, ['routine', 'weixinh5', 'weixin', 'pc', 'store'])) {
$payType = 'wechat_pay';
// V3接口判断
if (sys_config('pay_wechat_type') == 1) {
$payType = 'v3_wechat_pay';
}
} elseif ($payType == 'alipay') {
$payType = 'ali_pay';
} elseif ($payType == 'allinpay') {
$payType = 'allin_pay';
}
// 创建支付实例
$pay = app()->make(Pay::class, [$payType]);
return $pay->create($orderId, $price, $successAction, $body, '', $options);
} catch (\Exception $e) {
throw new ApiException($e->getMessage());
}
}
微信支付驱动 (WechatPay.php)
public function create(string $orderId, string $totalFee, string $attach, string $body, string $detail, array $options = [])
{
$this->authSetPayType();
switch ($this->payType) {
case Order::NATIVE: // 扫码支付
return WechatService::nativePay(null, $orderId, $totalFee, $attach, $body, $detail);
case Order::APP: // APP支付
return WechatService::appPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail);
case Order::JSAPI: // 小程序/公众号支付
if (request()->isRoutine()) {
// 小程序支付
if ($options['pay_new_weixin_open']) {
return MiniProgramService::newJsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail, $options);
}
return MiniProgramService::jsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail);
}
return WechatService::jsPay($options['openid'], $orderId, $totalFee, $attach, $body, $detail);
case 'h5': // H5支付
return WechatService::paymentPrepare(null, $orderId, $totalFee, $attach, $body, $detail, 'MWEB');
default:
throw new PayException('微信支付:支付类型错误');
}
}
支付回调处理 (PayNotifyServices.php)
public function wechatProduct(string $order_id = null, string $trade_no = null, string $payType = PayServices::WEIXIN_PAY)
{
try {
$services = app()->make(StoreOrderSuccessServices::class);
$orderInfo = $services->getOne(['order_id' => $order_id]);
if (!$orderInfo) return true;
if ($orderInfo->paid) return true;
return $services->paySuccess($orderInfo->toArray(), $payType, ['trade_no' => $trade_no]);
} catch (\Exception $e) {
return false;
}
}
🛠️ 开发指南
1. 支付配置设置
在后台管理系统配置:
- 微信支付参数(APPID、商户号、API密钥、证书)
- 支付宝配置
- 通联支付配置
- 支付方式开关
2. 发起支付调用
// 在控制器中调用
public function createPayment()
{
$params = $this->request->post();
// 参数验证
validate(PaymentValidate::class)->scene('create')->check($params);
$payServices = app()->make(PayServices::class);
$result = $payServices->pay(
$params['pay_type'],
$params['order_id'],
$params['amount'],
url('api/v1/payment/notify/wechat', [], true, true),
'商品购买'
);
return $this->success($result);
}
3. 支付回调配置
// 路由配置
Route::post('api/v1/payment/notify/:type', 'api/v1/payment/notify');
// 回调控制器
public function notify($type)
{
$notifyService = app()->make(PayNotifyServices::class);
switch ($type) {
case 'wechat':
return $notifyService->wechatProduct(
$this->request->post('out_trade_no'),
$this->request->post('transaction_id')
);
case 'alipay':
// 支付宝回调处理
break;
}
return response('SUCCESS');
}
🧪 测试指南
单元测试示例
class PaymentTest extends TestCase
{
public function testWechatPaymentCreation()
{
$payService = new PayServices();
$result = $payService->pay(
'weixin',
'TEST20240117001',
'100.00',
'https://domain.com/notify',
'测试商品'
);
$this->assertArrayHasKey('timeStamp', $result);
$this->assertArrayHasKey('nonceStr', $result);
$this->assertArrayHasKey('package', $result);
}
}
沙箱环境配置
# 微信支付沙箱
WECHAT_SANDBOX=true
WECHAT_APPID=sandbox_appid
WECHAT_MCHID=sandbox_mchid
# 支付宝沙箱
ALIPAY_SANDBOX=true
ALIPAY_GATEWAY=https://openapi.alipaydev.com/gateway.do
📊 数据库设计
支付记录表 (eb_store_pay)
CREATE TABLE `eb_store_pay` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`uid` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '用户id',
`oid` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '订单id',
`order_id` varchar(32) NOT NULL DEFAULT '' COMMENT '订单号',
`out_trade_no` varchar(32) NOT NULL DEFAULT '' COMMENT '支付流水号',
`pay_type` varchar(20) NOT NULL DEFAULT '' COMMENT '支付方式',
`pay_price` decimal(10,2) UNSIGNED NOT NULL DEFAULT '0.00' COMMENT '支付金额',
`trade_no` varchar(64) DEFAULT NULL COMMENT '第三方支付流水号',
`paid` tinyint(1) UNSIGNED NOT NULL DEFAULT '0' COMMENT '支付状态',
`pay_time` int(10) UNSIGNED DEFAULT NULL COMMENT '支付时间',
`add_time` int(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `out_trade_no` (`out_trade_no`),
KEY `order_id` (`order_id`),
KEY `paid` (`paid`)
) ENGINE=InnoDB COMMENT='支付记录表';
🚀 部署运维
生产环境配置
# 微信支付配置
WECHAT_APPID=your_appid
WECHAT_MCHID=your_mchid
WECHAT_KEY=your_key
WECHAT_CERT_PATH=/path/to/cert.pem
WECHAT_KEY_PATH=/path/to/key.pem
# SSL证书配置
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/key.pem;
监控告警
// 支付监控指标
$metrics = [
'payment_success_rate' => ($successCount / $totalCount) * 100,
'payment_response_time' => microtime(true) - $startTime,
'payment_error_count' => $errorCount
];
// 日志记录
Log::info('支付监控', $metrics);
🔧 故障处理
常见问题
- 支付回调失败:检查nginx配置、SSL证书、防火墙
- 签名错误:验证支付密钥配置
- 金额不一致:检查金额单位和优惠计算
- 重复支付:添加防重机制和状态检查
应急处理
# 查看支付日志
tail -f runtime/log/payment.log
# 禁用问题支付方式
php think pay:disable weixin
# 启用备用支付
php think pay:enable alipay
文档版本: v2.0
更新日期: 2024-01-17
适用版本: CRMEB 5.6.4+
💡 提示:支付功能涉及资金安全,请严格遵循安全规范,定期进行安全审计。
支付开发流程文档
🎯 支付功能概述
支付场景
- 商品购买支付:普通商品订单支付
- 服务购买支付:虚拟服务、会员购买
- 充值支付:余额充值、积分充值
- 保证金支付:商户保证金、服务保证金
- 退款处理:订单退款、冲正处理
支持的支付方式
const PAY_TYPE_WECHAT = 'wechat'; // 微信支付
const PAY_TYPE_ALIPAY = 'alipay'; // 支付宝
const PAY_TYPE_BALANCE = 'balance'; // 余额支付
const PAY_TYPE_INTEGRAL = 'integral'; // 积分支付
const PAY_TYPE_UNION = 'union'; // 云闪付
const PAY_TYPE_BANK = 'bank'; // 银行卡支付
🏗️ 支付系统架构
支付模块架构
┌─────────────────────────────────────────────────────┐
│ 支付控制器 (Controller) │
│ - 支付入口处理 │
│ - 参数验证 │
│ - 结果返回 │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 支付服务层 (PaymentService) │
│ - 支付逻辑处理 │
│ - 支付方式路由 │
│ - 支付状态管理 │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 支付渠道适配层 (PaymentAdapter) │
│ - 微信支付适配器 (WechatPayment) │
│ - 支付宝适配器 (AlipayPayment) │
│ - 余额支付适配器 (BalancePayment) │
│ - 积分支付适配器 (IntegralPayment) │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ 第三方支付SDK │
│ - 微信支付官方SDK │
│ - 支付宝官方SDK │
│ - 银行支付接口 │
└─────────────────────────────────────────────────────┘
数据库设计
-- 支付记录表
CREATE TABLE `store_pay` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` varchar(32) NOT NULL COMMENT '订单号',
`out_trade_no` varchar(32) NOT NULL COMMENT '支付流水号',
`pay_type` varchar(20) NOT NULL COMMENT '支付方式',
`pay_price` decimal(10,2) NOT NULL COMMENT '支付金额',
`trade_no` varchar(64) DEFAULT NULL COMMENT '第三方支付流水号',
`pay_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '支付状态',
`pay_time` int(11) DEFAULT NULL COMMENT '支付时间',
`create_time` int(11) NOT NULL COMMENT '创建时间',
`update_time` int(11) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_out_trade_no` (`out_trade_no`),
KEY `idx_order_id` (`order_id`),
KEY `idx_pay_status` (`pay_status`)
) ENGINE=InnoDB COMMENT='支付记录表';
-- 退款记录表
CREATE TABLE `store_refund` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` varchar(32) NOT NULL COMMENT '订单号',
`refund_no` varchar(32) NOT NULL COMMENT '退款流水号',
`refund_amount` decimal(10,2) NOT NULL COMMENT '退款金额',
`refund_reason` varchar(255) DEFAULT NULL COMMENT '退款原因',
`refund_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '退款状态',
`refund_time` int(11) DEFAULT NULL COMMENT '退款时间',
`create_time` int(11) NOT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_refund_no` (`refund_no`),
KEY `idx_order_id` (`order_id`)
) ENGINE=InnoDB COMMENT='退款记录表';
🔧 开发流程
1. 需求分析与设计
1. 确定支付场景和需求
2. 选择支持的支付方式
3. 设计支付流程和状态流转
4. 确定退款政策和规则
5. 设计对账和清算流程
2. 环境准备
# 安装支付SDK依赖
composer require overtrue/wechat
composer require alipay-sdk/php-all
# 配置支付参数
cp .env.example .env
# 配置微信支付参数
WECHAT_APPID=your_appid
WECHAT_MCHID=your_mchid
WECHAT_KEY=your_key
WECHAT_APPSECRET=your_appsecret
# 配置支付宝参数
ALIPAY_APPID=your_appid
ALIPAY_PRIVATE_KEY=your_private_key
ALIPAY_PUBLIC_KEY=your_public_key
3. 支付控制器开发
<?php
namespace app\api\controller\v1;
use app\services\PaymentService;
use app\validate\PaymentValidate;
class PaymentController
{
/**
* 发起支付
* @route('api/v1/payment/create')
*/
public function createPayment()
{
// 参数验证
$params = $this->request->post();
validate(PaymentValidate::class)->scene('create')->check($params);
// 调用支付服务
$paymentService = app()->make(PaymentService::class);
$result = $paymentService->createPayment($params);
return $this->success($result);
}
/**
* 支付回调处理
* @route('api/v1/payment/notify/:type')
*/
public function paymentNotify($type)
{
try {
$paymentService = app()->make(PaymentService::class);
$result = $paymentService->handleNotify($type, $this->request->post());
// 返回第三方支付要求的成功响应
return response($result['response']);
} catch (\Exception $e) {
Log::error('支付回调处理失败: ' . $e->getMessage());
return response('FAIL');
}
}
}
4. 支付服务层开发
<?php
namespace app\services;
use app\exception\PaymentException;
use app\services\payment\WechatPayment;
use app\services\payment\AlipayPayment;
use app\services\payment\BalancePayment;
class PaymentService extends BaseService
{
/**
* 创建支付
*/
public function createPayment(array $params): array
{
// 验证订单状态
$orderInfo = $this->validateOrder($params['order_id']);
// 选择支付方式
$paymentAdapter = $this->getPaymentAdapter($params['pay_type']);
// 创建支付记录
$payData = $this->createPayRecord($orderInfo, $params);
// 调用支付适配器
return $paymentAdapter->createPayment($payData);
}
/**
* 获取支付适配器
*/
protected function getPaymentAdapter(string $payType): PaymentInterface
{
switch ($payType) {
case 'wechat':
return app()->make(WechatPayment::class);
case 'alipay':
return app()->make(AlipayPayment::class);
case 'balance':
return app()->make(BalancePayment::class);
default:
throw new PaymentException('不支持的支付方式', 5001);
}
}
/**
* 处理支付回调
*/
public function handleNotify(string $payType, array $notifyData): array
{
$paymentAdapter = $this->getPaymentAdapter($payType);
$verifyResult = $paymentAdapter->verifyNotify($notifyData);
if (!$verifyResult['success']) {
throw new PaymentException('回调验证失败', 5002);
}
// 更新支付状态
$this->updatePaymentStatus($verifyResult['out_trade_no'], $verifyResult);
return ['response' => 'SUCCESS'];
}
}
5. 支付适配器开发(以微信支付为例)
<?php
namespace app\services\payment;
use EasyWeChat\Factory;
use app\exception\PaymentException;
class WechatPayment implements PaymentInterface
{
protected $app;
public function __construct()
{
$config = [
'app_id' => env('wechat.app_id'),
'mch_id' => env('wechat.mch_id'),
'key' => env('wechat.key'),
'cert_path' => env('wechat.cert_path'),
'key_path' => env('wechat.key_path'),
'notify_url' => env('wechat.notify_url'),
];
$this->app = Factory::payment($config);
}
/**
* 创建支付
*/
public function createPayment(array $payData): array
{
try {
$result = $this->app->order->unify([
'body' => $payData['body'],
'out_trade_no' => $payData['out_trade_no'],
'total_fee' => $payData['total_fee'],
'trade_type' => 'JSAPI',
'openid' => $payData['openid'],
]);
if ($result['return_code'] === 'SUCCESS' && $result['result_code'] === 'SUCCESS') {
return [
'pay_params' => $this->app->jssdk->bridgeConfig($result['prepay_id']),
'pay_type' => 'wechat'
];
} else {
throw new PaymentException($result['return_msg'] ?? '微信支付创建失败', 5003);
}
} catch (\Exception $e) {
throw new PaymentException('微信支付异常: ' . $e->getMessage(), 5004);
}
}
/**
* 验证回调
*/
public function verifyNotify(array $notifyData): array
{
try {
$message = $this->app->handlePaidNotify(function($message, $fail) {
// 验证支付状态
if ($message['return_code'] !== 'SUCCESS') {
return $fail('通信失败,请稍后再通知我');
}
if ($message['result_code'] !== 'SUCCESS') {
return $fail('支付失败,请稍后再通知我');
}
return [
'out_trade_no' => $message['out_trade_no'],
'trade_no' => $message['transaction_id'],
'pay_amount' => $message['total_fee'] / 100,
'pay_time' => strtotime($message['time_end']),
'success' => true
];
});
return $message;
} catch (\Exception $e) {
throw new PaymentException('回调验证异常: ' . $e->getMessage(), 5005);
}
}
}
6. 支付接口定义
<?php
namespace app\services\payment;
interface PaymentInterface
{
/**
* 创建支付
*/
public function createPayment(array $payData): array;
/**
* 处理支付回调
*/
public function verifyNotify(array $notifyData): array;
/**
* 查询支付状态
*/
public function queryPayment(string $outTradeNo): array;
/**
* 申请退款
*/
public function refund(array $refundData): array;
}
🧪 测试流程
1. 单元测试
<?php
namespace tests\services;
use app\services\PaymentService;
use app\services\payment\WechatPayment;
use think\testing\TestCase;
class PaymentServiceTest extends TestCase
{
public function testCreatePayment()
{
// 模拟支付参数
$params = [
'order_id' => 'TEST202401170001',
'pay_type' => 'wechat',
'pay_amount' => 100.00
];
// 创建支付服务实例
$paymentService = new PaymentService();
// 测试支付创建
$result = $paymentService->createPayment($params);
$this->assertArrayHasKey('pay_params', $result);
$this->assertEquals('wechat', $result['pay_type']);
}
public function testPaymentNotify()
{
// 模拟微信支付回调数据
$notifyData = [
'return_code' => 'SUCCESS',
'result_code' => 'SUCCESS',
'out_trade_no' => 'TEST202401170001',
'transaction_id' => '420000202401170001',
'total_fee' => '10000',
'time_end' => '20240117153000'
];
$paymentService = new PaymentService();
$result = $paymentService->handleNotify('wechat', $notifyData);
$this->assertEquals('SUCCESS', $result['response']);
}
}
2. 集成测试
# 运行支付相关测试
php think test tests/services/PaymentServiceTest
php think test tests/services/payment/WechatPaymentTest
php think test tests/services/payment/AlipayPaymentTest
# 生成测试覆盖率报告
php think test --coverage-html coverage/payment
3. 沙箱环境测试
// 配置沙箱环境
'wechat' => [
'app_id' => '沙箱appid',
'mch_id' => '沙箱商户号',
'key' => '沙箱key',
'sandbox' => true, // 开启沙箱模式
]
// 支付宝沙箱配置
'alipay' => [
'app_id' => '沙箱appid',
'gateway_url' => 'https://openapi.alipaydev.com/gateway.do',
'sign_type' => 'RSA2',
'sandbox' => true,
]
🚀 部署上线
1. 生产环境配置
# 设置生产环境配置
cp .env.production .env
# 配置生产环境支付参数
WECHAT_APPID=生产环境appid
WECHAT_MCHID=生产环境商户号
WECHAT_KEY=生产环境key
WECHAT_CERT_PATH=/path/to/cert/apiclient_cert.pem
WECHAT_KEY_PATH=/path/to/cert/apiclient_key.pem
ALIPAY_APPID=生产环境appid
ALIPAY_PRIVATE_KEY=生产环境私钥
ALIPAY_PUBLIC_KEY=生产环境公钥
2. SSL证书配置
# Nginx SSL配置
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /path/to/ssl/cert.pem;
ssl_certificate_key /path/to/ssl/key.pem;
# 支付回调接口
location /api/v1/payment/notify/ {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
3. 监控告警配置
# 支付监控指标
payment:
success_rate:
type: gauge
help: 支付成功率
labels: [pay_type]
response_time:
type: histogram
help: 支付响应时间分布
labels: [pay_type]
error_count:
type: counter
help: 支付错误次数
labels: [pay_type, error_code]
📊 运维监控
1. 日志监控
// 支付关键日志记录
Log::info('支付创建', [
'order_id' => $orderId,
'pay_type' => $payType,
'amount' => $amount,
'user_id' => $userId
]);
Log::error('支付失败', [
'order_id' => $orderId,
'error_code' => $errorCode,
'error_msg' => $errorMsg,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)
]);
2. 性能监控
# 监控支付接口性能
# 平均响应时间 < 200ms
# 95%响应时间 < 500ms
# 错误率 < 0.1%
# 使用Prometheus监控
payment_api_duration_seconds_bucket{pay_type="wechat",le="0.1"} 12345
payment_api_duration_seconds_bucket{pay_type="wechat",le="0.5"} 23456
3. 对账处理
/**
* 每日对账任务
*/
public function dailyReconciliation()
{
$yesterday = strtotime('yesterday');
$today = strtotime('today');
// 查询本地支付记录
$localRecords = $this->payDao->getRecordsByTime($yesterday, $today);
// 查询第三方支付记录
foreach (['wechat', 'alipay'] as $payType) {
$adapter = $this->getPaymentAdapter($payType);
$thirdPartyRecords = $adapter->queryBill($yesterday, $today);
// 对账处理
$result = $this->reconcile($localRecords, $thirdPartyRecords);
// 记录对账结果
$this->saveReconciliationResult($result);
}
}
🔧 故障处理
常见问题处理
1. **支付回调失败**
- 检查网络连通性
- 验证证书有效性
- 检查回调地址配置
2. **支付签名错误**
- 检查密钥配置
- 验证签名算法
- 检查参数编码
3. **支付金额不符**
- 检查金额单位(分/元)
- 验证金额计算逻辑
- 检查优惠券抵扣
4. **重复支付**
- 检查支付状态验证
- 添加防重机制
- 人工审核处理
应急处理流程
# 1. 暂停支付功能
php think payment:disable wechat
# 2. 查看支付日志
tail -f runtime/log/payment.log
# 3. 回滚有问题的版本
git revert <commit-hash>
# 4. 启用备用支付通道
php think payment:enable alipay
文档版本: v1.0
最后更新: 2024-01-17
维护人员: 支付开发团队
💡 提示: 支付功能涉及资金安全,请严格遵循安全规范和审计要求。
评论({{cateWiki.comment_num}})
最新
最早
{{cateWiki.page_view_num}}人看过该文档
评论(0)
最新
最早
402人看过
登录/注册
即可发表评论
{{item.user ? item.user.nickname : ''}}
(自评)
{{item.content}}
搜索结果
为您找到{{wikiCount}}条结果
{{item.page_view_num}}
{{item.like ? item.like.like_num : 0}}
{{item.comment ? item.comment.comment_num : 0}}
位置:
{{path.name}}
{{(i+1) == item.catalogue.path_data.length ? '':'/'}}
