#调用统一支付接口
有什么优势,开发者再也不用去关注支付宝或者微信等三方支付的任何逻辑,只需要调用钱包模块暴露出来的通用支付接口就可以完成一切支付。
以官方模块为例,官方的商城模块、VIP模块、应用市场模块都是调用的钱包的统一支付接口。
接口地址:U('Wallet/Index/pay')
##模块提交订单
有支付需求的模块将用户的订单信息保存到数据库,比如商城模块将订单号为test_123的订单信息保存到ly_shop_order表里。
##模块调用支付接口
以session方式设置支付信息和配置
有种调用接口的方式:
### 第一代
out_trade_no: 订单号
title:订单标题
money:订单需要支付的金额
callback:当前模块的一个控制器地址
allow_redbag:允许红包参与支付
allow_coupon:允许折扣券参与支付
### 第二代(钱包模块必须大于1.6.0版本)
out_trade_no: 订单号
title:订单标题
money:订单需要支付的金额
callback:
> 支持两种回调
action:模块/控制器:方法
model:模块/模型:方法
allow_third:是否允许直接调用第三方支付
allow_money:是否允许余额支付,设为false表示直接采用参访支付
return_url:支付完成后钱包模块跳转回去的地址
allow_redbag:允许红包参与支付
allow_coupon:允许折扣券参与支付
##钱包模块提交账单
根据支付配置生成支付页面
用户选择支付方式,提交支付信息
钱包模块内部支付
### 第一代方式或者第二代方式余额足够本次支付
钱包处理完成后直接通过指定的callback地址或者方法处理模块订单的回调事情。
### 第二代方式
如果是需第三方支付的第二代方式,计算账单,并写入数据库。跳转到钱包模块openPay方法准备调用第三方支付。
根据数据库账单信息,生成第三方支付地址,并转到第三方支付页面,支付完成后第三方服务器会异步通知钱包模块处理订单。用户在第三方服务器支付完成后根据传递给第三方服务器的地址跳转到return_url,回调处理会在notify方法中得到异步处理。
## 第一代调用实例
```php
// +----------------------------------------------------------------------
namespace Vip\Controller;
use Home\Controller\HomeController;
/**
* 订单控制器
* @author jry <598821125@qq.com>
*/
class OrderController extends HomeController
{
/**
* 初始化方法
* @author jry <598821125@qq.com>
*/
protected function _initialize()
{
parent::_initialize();
$this->is_login();
}
/**
* 开通会员
* @author jry <598821125@qq.com>
*/
public function index()
{
if (request()->isPost()) {
$data['out_trade_no'] = \lyf\Str::createOutTradeNo(); // 随机生成一个订单号,你可以定义自己的规则
$data['total_price'] = 88.88;
$order_object = D('Vip/Order');
$add_data = $order_object->create($data);
if ($add_data) {
$result = $order_object->add($add_data);
if ($result) {
$pay_data['out_trade_no'] = $add_data['out_trade_no'];
$pay_data['title'] = '开通VIP';
$pay_data['money'] = $add_data['total_price'];
$pay_data['callback'] = U('Vip/Order/callback', array('out_trade_no' => $pay_data['out_trade_no']), true, true);
$pay_data['allow_redbag'] = true;
$pay_data['allow_coupon'] = true;
session('pay_data_' . $pay_data['out_trade_no'], $pay_data);
// 注意了,这里就是跳转到钱包模块统一支付接口
redirect(U('Wallet/Index/pay', array('out_trade_no' => $pay_data['out_trade_no']), true, true));
} else {
$this->error('订单错误' . $order_object->getError());
}
} else {
$this->error('订单错误' . $order_object->getError());
}
} else {
$this->assign('meta_title', "开通会员");
$this->display();
}
}
/**
* 开通会员回调接口
* @author jry <598821125@qq.com>
*/
public function callback($out_trade_no)
{
$pay_data = session('pay_data_' . $out_trade_no);
if (($pay_data['pay_verify'] === true) && ($pay_data['is_callback'] !== true)) {
if (!$pay_data['out_trade_no']) {
$this->error('参数错误');
} else {
$order_object = D('Vip/Order');
$order_info = $order_object->where(array('out_trade_no' => $pay_data['out_trade_no']))->find();
if (($order_info['total_price'] !== $pay_data['money']) || ($order_info['out_trade_no'] !== $pay_data['out_trade_no'])) {
$this->error('订单异常');
} else {
$result = $order_object->where(array('id' => $order_info['id']))->setField('is_pay', 1);
if ($result) {
// 这里是开通会员处理逻辑
// 这里是开通会员处理逻辑
// 这里是开通会员处理逻辑
session('pay_data_' . $out_trade_no . '.is_callback', true);
$this->success('支付成功', U('index'));
} else {
$order_object->where(array('id' => $order_info['id']))->setField('status', 0);
$this->error('订单异常');
}
}
}
} else {
$this->error('支付失败');
}
}
}
```
## 第二代调用实例
```php
where($map)->find();
if (!$order_info) {
$this->error('订单无效');
}
if ($order_info['is_pay']) {
$this->success('订单已支付');
}
//清除支付session
session('pay_data_' . $out_trade_no, null);
$order_object = D('Order');
$map['out_trade_no'] = $out_trade_no;
$order_info = $order_object->where($map)->find();
if (empty($order_info) || $order_info['is_pay']) {
$this->error('订单已支付或订单无效');
}
$pay_data['out_trade_no'] = $order_info['out_trade_no'];
$pay_data['title'] = '在线订单-首饰金额';
$pay_data['money'] = $order_info['price'] + 20;
$pay_data['callback'] = 'action:Shop/Order:callback';//action:模块/控制器:方法,或者//model:模块/模型:方法
// 这是钱包模块支付网关完成支付后跳转到指定的网址
$pay_data['return_url'] = U('Order/paySuccess', array('out_trade_no' => $order_info['out_trade_no']), true, true);
$pay_data['allow_redbag'] = true;
$pay_data['allow_coupon'] = true;
$pay_data['allow_third'] = true;
$pay_data['allow_money'] = true;
session('pay_data_' . $pay_data['out_trade_no'], $pay_data);
redirect(U('Wallet/Index/pay', array('out_trade_no' => $pay_data['out_trade_no']), true, true)); // 余额支付接口
}
//完成以上步骤之后,页面跳转到支付页面/wallet/index/pay,用户最终确认订单信息,同时需要用户在前端操作来完成支付。前端代码示例如下:
<form class="col-xs-12 form-horizontal form-pay" action="{:U('Wallet/Index/dopay')}" method="POST" role="form">
<legend>订单信息</legend>
<div class="form-group">
<label class="col-xs-3">订单标题:</label>
<p class="col-xs-9 text-primary">{$pay_data.title}</p>
</div>
<div class="form-group">
<label class="col-xs-3">应付金额</label>
<p class="col-xs-9 text-primary original-money">{$pay_data.money}</p>
</div>
<?php if($redbag_list): ?>
<div class="form-group">
<label class="col-xs-3">使用红包</label>
<p class="col-xs-9">
<select name="redbag_id" class="form-control lyui-select col-sm-4">
<option value="" data-price="0">选择可用红包</option>
<volist name="redbag_list" id="rl">
<option value="{$rl.id}" data-price="{$rl.money}">{$rl.money}元红包-满{$rl.limit}可用-{$rl.title}</option>
</volist>
</select>
</p>
</div>
<?php endif; ?>
<?php if($coupon_list): ?>
<div class="form-group">
<label class="col-xs-3">使用折扣券</label>
<p class="col-xs-9">
<select name="coupon_id" class="form-control lyui-select col-sm-4">
<option value="" data-price="0">选择可用折扣券</option>
<volist name="coupon_list" id="cl">
<option value="{$cl.id}" data-price="{$cl.coupon}">{$cl.coupon}折扣券-满{$cl.limit}可用-{$cl.title}</option>
</volist>
</select>
</p>
</div>
<?php endif; ?>
<div class="form-group">
<label class="col-xs-3">实际需付</label>
<p class="col-xs-9 text-danger">¥ <span class="actual-money">{$pay_data.money}</span></p>
</div>
<div class="form-group">
<label class="col-xs-3">钱包余额</label>
<p class="col-xs-9" id="user-money">
<span>¥ {$user_info.money|default='0.00'}</span>
<a class="m-l" target="blank" href="{:U('Wallet/Recharge/index', '', true, true)}">余额充值</a>
</p>
</div>
<?php if($pay_data['allow_money']): ?>
<div class="form-group">
<label class="col-xs-3">余额支付</label>
<div class="col-xs-9 checkbox checkbox-slider--b-flat checkbox-slider-md">
<label style="position: relative;">
<input id="allow_money_toggle" type="checkbox" checked="checked">
<span>使用余额支付</span>
<input id="allow_money" type="hidden" name="allow_money" value="1">
</label>
</div>
</div>
<?php endif; ?>
<?php if($pay_data['allow_third']): ?>
<div class="form-group" id="allow_pay_type">
<label class="col-xs-3">支付方式</label>
<p class="col-xs-9 text-primary">
<volist name="allow_pay_type" id="pt">
<label class="radio" for="pay_type_{$pt.type}">
<input type="radio" id="pay_type_{$pt.type}" class="radio" name="pay_type"
value="{$pt.type}" <if condition="$i eq 1">checked="checked"</if>>
<img src="{$pt.logo}" style="height: 30px;">
</label>
</volist>
</p>
</div>
<?php endif; ?>
<div class="form-group">
<div class="col-xs-12 col-sm-4 col-sm-offset-8">
<a class="btn btn-warning" data-toggle="modal" href='#modal-pay'>立即支付</a>
</div>
<div class="modal fade" id="modal-pay">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">确认支付</h4>
</div>
<div class="modal-body row">
<div class=" col-xs-12">
<input type="password" class="form-control input-lg" name="password" placeholder="请输入用户密码">
</div>
</div>
<div class="modal-footer">
<input type="hidden" class="form-control" name="out_trade_no" value="{$pay_data.out_trade_no}">
<button type="submit" class="btn btn-block btn-lg btn-success" id="pay_submit" target-form="form-pay">确认支付</button>
</div>
</div>
</div>
</div>
</div>
</form>
//以上的表单将支付信息提交到wallet/index/dopay最终执行支付,该方法较为完善,后期开发中一般不需要过多改动。
//支付成功之后钱包模块会调用callback字段中的方法(支持类型为action和model)
//此处只允许读取钱包模块数据,禁止修改账单的任何数据
//订单表必须支持事务 此处无需开启事务,所有回调事务均在Wallet/pay页面或notify页面
public function callback($out_trade_no = null) {
if (!$out_trade_no) {
$this->error = '订单号必须';
return false;
}
//获取订单数据
$order_object = D('Shop/Order');
$order_info = $order_object->where(array('out_trade_no' => $out_trade_no))->find();
//数据校对
if (!$order_info) {
$this->error = '订单不存在';
return false;
}
//判断订单是否已回调,此处已is_pay为标记
if ($order_info['is_pay']) {
return true;
}
//执行回调,并将is_pay设为1, 作为上一步骤的回调成功标记
$data = array();
$data['is_pay'] = 1;
$data['pay_time'] = time();
$data['pay_money'] = $pay_data['money'] + $pay_data['third_money'];
$result = $order_object->where(array('id' => $order_info['id']))->setField($data);
if (false === $result) {
$this->error = $order_object->getError();
return false;
}
return true;
}
?>
```
- 简介
- 环境要求
- 安装系统
- 目录结构
- 常见问题
- 基础知识
- 编辑器
- 前端规范
- 前端框架文档
- Builder教程
- Builder的来历
- ListBuilder使用
- setMetaTitle
- addTopButton
- setSearch
- addSearchItem
- setTabNav
- addTableColumn
- setTableDataList
- setTableDataListKey
- setTableDataPage
- addRightButton
- alterTableData
- setExtraHtml
- setTemplate
- FormBuilder使用
- setMetaTitle
- setTabNav
- setExtraItems
- setPostUrl
- addFormItem
- setFormData
- setExtraHtml
- setAjaxSubmit
- setTemplate
- 扩展FormBuilder
- 模块开发
- 创建模块
- 描述文件
- 模型( M )
- 模版( V )
- 控制器( C )
- API接口
- 核心模块
- 文件上传
- 微信小程序模块
- 注册登陆接口
- 钱包模块
- 统一支付
- Cms模块
- 幻灯片接口
- 文档列表接口
- 文档详情接口
- 发表评论接口
- 评论列表接口
- 收藏的文档接口
- 收藏接口
- 分类列表接口
- IM模块
- 发送消息接口
- 最近聊天列表接口
- 查询新消息接口
- 插件相关
- 短信插件
- 支付插件
- 支付宝支付
- 微信支付
- 站群模块
- 模板开发
- 准备工作
- 目录结构
- 数据调用
- 专题
- 插件开发
- 图片显示
- 获取用户信息
- 判断用户登陆
- 表单提交AjaX
- 文件上传
- 2.0兼容写法
- 模板标签
- 核心模块
- Cms模块
- 栏目分类调用
- Cordova
- 配置跨域支持
- 本地开发调试教程
- 打包成apk和ipa
- 自定义APP信息
- 常见问题
- 申请Apple开发者账户
- 多主题开发
- 新建主题
- 目录结构
- 模板变量
- 定制安装部署