feat/task1-c-wallet
devil_gong 2018-09-28 14:31:41 +08:00
parent dff4e631f9
commit ae22ba2b6d
14 changed files with 460 additions and 58 deletions

View File

@ -2,6 +2,8 @@
namespace Api\Controller;
use Service\ResourcesService;
/**
* 订单支付异步通知
* @author Devil
@ -25,15 +27,18 @@ class OrderNotifyController extends CommonController
}
/**
* [PayNotify 支付异步处理]
* [Notify 支付异步处理]
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @datetime 2018-03-04T14:35:38+0800
*/
public function PayNotify()
public function Notify()
{
$data = (new \Library\Alipay())->Respond(C("alipay_key_secret"));
$payment = ResourcesService::PaymentList(['where'=>['id'=>34]]);
$ret = (new \Library\Payment\Alipay($payment[0]['config']))->Respond();
file_put_contents(ROOT_PATH.'order-pay-notify-'.rand().'.txt', json_encode($ret));
die;
if($data == 'no') exit('error');
// 开始处理支付信息

View File

@ -70,7 +70,18 @@ function DataReturn($msg = '', $code = 0, $data = '')
*/
function HomeUrl($c='Index', $a='Index', $params=[])
{
return str_replace('admin.php', 'index.php', U("Home/{$c}/{$a}", $params));
$url = U("Home/{$c}/{$a}", $params);
$location = stripos($url, '.php');
if($location !== false)
{
$before = substr($url, 0, $location+4);
$suffix = substr($before, strrpos($before, '/')+1);
if(!empty($suffix))
{
$url = str_replace($suffix, 'index.php', $url);
}
}
return $url;
}
/**

View File

@ -277,6 +277,7 @@ return array(
'common_so_tips' => '其实搜索很简单 ^_^!',
'common_go_top_text' => '回到顶部',
'common_toview_home_text' => '查看首页',
'common_go_home_text' => '回到首页',
'common_email_send_user_reg_title' => '用户注册',
'common_email_send_user_forget_title'=> '密码找回',
'common_layout_slider_more_text' => '了解更多',

View File

@ -3,6 +3,7 @@
namespace Home\Controller;
use Service\OrderService;
use Service\ResourcesService;
/**
* 订单管理
@ -30,11 +31,25 @@ class OrderController extends CommonController
}
/**
* [Index 首页]
* 订单列表
* @author Devil
* @blog http://gong.gg/
* @version 0.0.1
* @datetime 2017-02-25T15:30:36+0800
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-28
* @desc description
*/
public function Index()
{
$this->display('Index');
}
/**
* 订单支付
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-28
* @desc description
*/
public function Pay()
{
@ -49,5 +64,28 @@ class OrderController extends CommonController
$this->display('/Public/TipsError');
}
}
/**
* 支付同步返回处理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-28
* @desc description
*/
public function Respond()
{
$params = $_REQUEST;
$params['user'] = $this->user;
$ret = OrderService::Respond($params);
if($ret['code'] == 0)
{
$this->assign('msg', '支付成功');
$this->display('/Public/PaySuccess');
} else {
$this->assign('msg', $ret['msg']);
$this->display('/Public/PayError');
}
}
}
?>

View File

@ -0,0 +1,26 @@
<include file="Public/Header" />
<!-- header top nav -->
<include file="Public/HeaderTopNav" />
<!-- search -->
<include file="Public/NavSearch" />
<!-- header nav -->
<include file="Public/HeaderNav" />
<!-- goods category -->
<include file="Public/GoodsCategory" />
<!-- content -->
<div class="am-container category-list">
<notempty name="goods_category_list">
订单管理
<else />
<div class="table-no"><i class="am-icon-warning"></i> {{:L('common_not_data_tips')}}</div>
</notempty>
</div>
<!-- footer start -->
<include file="Public/Footer" />
<!-- footer end -->

View File

@ -0,0 +1,34 @@
<include file="Public/Header" />
<!-- header top nav -->
<include file="Public/HeaderTopNav" />
<!-- search -->
<include file="Public/NavSearch" />
<!-- header nav -->
<include file="Public/HeaderNav" />
<!-- goods category -->
<include file="Public/GoodsCategory" />
<!-- conntent start -->
<div class="am-g my-content">
<div class="am-u-md-6 am-u-sm-centered">
<div class="am-panel am-radius tips-error tips-pay-error">
<div class="am-panel-bd">
<i class="am-icon-times-circle am-icon-lg"></i>
<span class="msg">{{$msg}}</span>
<div class="tips-nav">
<a href="{{:__MY_URL__}}" class="am-btn am-btn-secondary am-radius">{{:L('common_go_home_text')}}</a>
<a href="{{:U('Home/Order/Index')}}" class="am-btn am-btn-primary am-radius">我的订单</a>
</div>
</div>
</div>
</div>
</div>
<!-- conntent end -->
<!-- footer start -->
<include file="Public/Footer" />
<!-- footer end -->

View File

@ -0,0 +1,34 @@
<include file="Public/Header" />
<!-- header top nav -->
<include file="Public/HeaderTopNav" />
<!-- search -->
<include file="Public/NavSearch" />
<!-- header nav -->
<include file="Public/HeaderNav" />
<!-- goods category -->
<include file="Public/GoodsCategory" />
<!-- conntent start -->
<div class="am-g my-content">
<div class="am-u-md-6 am-u-sm-centered">
<div class="am-panel am-radius tips-success tips-pay-success">
<div class="am-panel-bd">
<i class="am-icon-check-circle am-icon-lg"></i>
<span class="msg">{{$msg}}</span>
<div class="tips-nav">
<a href="{{:__MY_URL__}}" class="am-btn am-btn-secondary am-radius">{{:L('common_go_home_text')}}</a>
<a href="{{:HomeUrl('Order', 'Index')}}" class="am-btn am-btn-primary am-radius">我的订单</a>
</div>
</div>
</div>
</div>
</div>
<!-- conntent end -->
<!-- footer start -->
<include file="Public/Footer" />
<!-- footer end -->

View File

@ -61,16 +61,6 @@ class Alipay
'is_required' => 1,
'message' => '请填写支付宝账号',
],
[
'element' => 'input',
'type' => 'text',
'default' => '',
'name' => 'key',
'placeholder' => '交易安全校验码 key',
'title' => '交易安全校验码 key',
'is_required' => 1,
'message' => '请填写交易安全校验码 key',
],
[
'element' => 'input',
'type' => 'text',
@ -81,6 +71,16 @@ class Alipay
'is_required' => 1,
'message' => '请填写合作者身份 partner ID',
],
[
'element' => 'input',
'type' => 'text',
'default' => '',
'name' => 'key',
'placeholder' => '交易安全校验码 key',
'title' => '交易安全校验码 key',
'is_required' => 1,
'message' => '请填写交易安全校验码 key',
],
[
'element' => 'input', // 表单标签
'type' => 'text', // input类型
@ -217,7 +217,7 @@ class Alipay
'service' => 'alipay.wap.auth.authAndExecute',
'format' => 'xml',
'v' => '2.0',
'partner' => $this->config['key'],
'partner' => $this->config['partner'],
'sec_id' => 'MD5',
'req_data' => $req_data,
'request_token' => $ret['data']
@ -242,7 +242,7 @@ class Alipay
'service' => 'alipay.wap.trade.create.direct',
'format' => 'xml',
'v' => '2.0',
'partner' => $this->config['key'],
'partner' => $this->config['partner'],
'req_id' => $params['order_sn'],
'sec_id' => 'MD5',
'req_data' => $this->GetReqData($params),
@ -320,7 +320,7 @@ class Alipay
{
$parameter = array(
'service' => 'create_direct_pay_by_user',
'partner' => $this->config['key'],
'partner' => $this->config['partner'],
'_input_charset' => C('DEFAULT_CHARSET'),
'notify_url' => $params['notify_url'],
'return_url' => $params['call_back_url'],
@ -334,12 +334,12 @@ class Alipay
'payment_type' => 1,
/* 物流参数 */
'logistics_type' => 'EXPRESS',
'logistics_fee' => 0,
'logistics_payment' => 'BUYER_PAY_AFTER_RECEIVE',
// 'logistics_type' => 'EXPRESS',
// 'logistics_fee' => 0,
// 'logistics_payment' => 'BUYER_PAY_AFTER_RECEIVE',
/* 买卖双方信息 */
'seller_email' => $this->config['account']
'seller_email' => $this->config['account'],
);
$param = $this->GetParamSign($parameter);
@ -371,9 +371,9 @@ class Alipay
'urlcode' => substr($urlcode, 0, -1),
'url' => substr($url, 0, -1),
);
if(!empty($this->config['partner']))
if(!empty($this->config['key']))
{
$result['sign'] = $result['url'].$this->config['partner'];
$result['sign'] = $result['url'].$this->config['key'];
}
return $result;
}
@ -389,9 +389,48 @@ class Alipay
*/
public function Respond($params = [])
{
// 编写代码
return 'Respond success';
if(empty($this->config))
{
return DataReturn('配置有误', -1);
}
$data = empty($_POST) ? $_GET : array_merge($_GET, $_POST);
ksort($data);
$sign = '';
if(isset($data['sec_id']) && $data['sec_id'] == 'MD5')
{
$data_xml = json_decode(json_encode((array) simplexml_load_string($data['notify_data'])), true);
$data = array_merge($data, $data_xml);
$sign = 'service='.$data['service'].'&v='.$data['v'].'&sec_id='.$data['sec_id'].'&notify_data='.$data['notify_data'];
} else {
foreach($data AS $key=>$val)
{
if ($key != 'sign' && $key != 'sign_type' && $key != 'code')
{
$sign .= "$key=$val&";
}
}
$sign = substr($sign, 0, -1);
}
// 签名校验
if(!isset($data['sign']) || md5($sign.$this->config['key']) != $data['sign'])
{
return DataReturn('签名校验失败', -1);
}
// 支付状态
$status = isset($data['trade_status']) ? $data['trade_status'] : $data['result'];
switch($status)
{
case 'TRADE_SUCCESS':
case 'TRADE_FINISHED':
case 'success':
return DataReturn('支付成功', 0, $data);
break;
}
return DataReturn('处理异常错误', -100);
}
}
?>

View File

@ -25,14 +25,28 @@ class OrderService
*/
public static function Pay($params = [])
{
if(empty($params['id']))
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'id',
'error_msg' => '订单id有误',
],
[
'checked_type' => 'empty',
'key_name' => 'user',
'error_msg' => '用户信息有误',
],
];
$ret = params_checked($params, $p);
if($ret !== true)
{
return DataReturn('订单id有误', -1);
return DataReturn($ret, -1);
}
$m = M('Order');
// 获取订单信息
$where = ['id'=>intval($params['id']), 'user_id' => $params['user']['id']];
$data = $m->where($where)->field('id,status,total_price,payment_id')->find();
$data = M('Order')->where($where)->field('id,status,total_price,payment_id')->find();
if(empty($data))
{
return DataReturn(L('common_data_no_exist_error'), -1);
@ -60,16 +74,191 @@ class OrderService
'order_sn' => date('YmdHis').$data['id'],
'name' => '订单支付',
'total_price' => $data['total_price'],
'notify_url' => __MY_URL__.'Notify/order.php',
'call_back_url' => __MY_URL__.'Respond/order.php',
'notify_url' => __MY_URL__.'notify_order.php',
'call_back_url' => __MY_URL__.'respond_order.php',
);
$pay_name = '\Library\Payment\\'.$payment[0]['payment'];
$ret = (new $pay_name($payment[0]['config']))->Pay($pay_data);
if(empty($ret))
if(isset($ret['code']) && $ret['code'] == 0)
{
return DataReturn('支付接口异常', -1);
// 存储session订单id
$_SESSION['payment_order_id'] = $data['id'];
return $ret;
}
return $ret;
return DataReturn('支付接口异常', -1);
}
/**
* 支付同步处理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-28
* @desc description
* @param [array] $params [输入参数]
*/
public static function Respond($params = [])
{
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'user',
'error_msg' => '用户信息有误',
],
[
'checked_type' => 'empty',
'key_name' => 'out_trade_no',
'error_msg' => '支付回调参数缺失[out_trade_no]',
],
];
$ret = params_checked($params, $p);
if($ret !== true)
{
return DataReturn($ret, -1);
}
// 获取订单信息
$where = ['id'=>self::OutTradeNoParsing($params['out_trade_no']), 'user_id' => $params['user']['id']];
$data = M('Order')->where($where)->field('id,status,payment_id')->find();
if(empty($data))
{
return DataReturn(L('common_data_no_exist_error'), -1);
}
if($data['status'] > 1)
{
$status_text = L('common_order_user_status')[$data['status']]['name'];
return DataReturn('状态不可操作['.$status_text.']', -1);
}
// 支付方式
$payment = ResourcesService::PaymentList(['where'=>['id'=>$data['payment_id']]]);
if(empty($payment[0]))
{
return DataReturn('支付方式有误', -1);
}
// 支付数据校验
$pay_name = '\Library\Payment\\'.$payment[0]['payment'];
return (new $pay_name($payment[0]['config']))->Respond();
}
/**
* 支付异步处理
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-28
* @desc description
* @param [array] $params [输入参数]
*/
public static function Notify($params = [])
{
// 请求参数
$p = [
[
'checked_type' => 'empty',
'key_name' => 'out_trade_no',
'error_msg' => '支付回调参数缺失[out_trade_no]',
],
];
$ret = params_checked($params, $p);
if($ret !== true)
{
return $ret;
}
// 获取订单信息
$m = M('Order');
$where = ['id'=>self::OutTradeNoParsing($params['out_trade_no'])];
$data = $m->where($where)->field('id,status,total_price,payment_id,user_id,shop_id')->find();
if(empty($data))
{
return DataReturn(L('common_data_no_exist_error'), -1);
}
if($data['status'] > 1)
{
$status_text = L('common_order_user_status')[$data['status']]['name'];
return DataReturn('状态不可操作['.$status_text.']', -1);
}
// 支付方式
$payment = ResourcesService::PaymentList(['where'=>['id'=>$data['payment_id']]]);
if(empty($payment[0]))
{
return DataReturn('支付方式有误', -1);
}
// 支付数据校验
$pay_name = '\Library\Payment\\'.$payment[0]['payment'];
$ret = (new $pay_name($payment[0]['config']))->Respond();
if(!isset($ret['code']) || $ret['code'] != 0)
{
return $ret;
}
// 兼容web版本支付参数
$buyer_email = isset($ret['data']['buyer_logon_id']) ? $ret['data']['buyer_logon_id'] : (isset($ret['data']['buyer_email']) ? $ret['data']['buyer_email'] : '');
$total_amount = isset($ret['data']['total_amount']) ? $ret['data']['total_amount'] : (isset($ret['data']['total_fee']) ? $ret['data']['total_fee'] : '');
// 写入支付日志
$pay_log_data = [
'user_id' => $pay_order['user_id'],
'order_id' => $out_trade_no,
'trade_no' => $ret['data']['trade_no'],
'user' => $buyer_email,
'total_fee' => $total_amount,
'amount' => $pay_order['total_price'],
'subject' => $ret['data']['subject'],
'pay_type' => 0,
'business_type' => 0,
'add_time' => time(),
];
M('PayLog')->add($pay_log_data);
// 消息通知
$detail = '订单支付成功,金额'.PriceBeautify($pay_order['total_price']).'元';
CommonMessageAdd('订单支付', $detail, $pay_order['user_id']);
// 开启事务
$m->startTrans();
// 更新支付状态
$where = array('id' => $out_trade_no);
$upd_data = array(
'status' => 2,
'pay_status'=> 1,
'pay_price' => $total_amount,
'pay_time' => time(),
'upd_time' => time(),
);
if($m->where($where)->save($upd_data))
{
// 提交事务
$m->commit();
// 成功
return DataReturn('处理成功', 0);
}
// 事务回滚
$m->rollback();
// 处理失败
return DataReturn('处理失败', -100);
}
/**
* 订单号解析
* @author Devil
* @blog http://gong.gg/
* @version 1.0.0
* @date 2018-09-28
* @desc description
* @param [string] $out_trade_no [支付回传订单号]
*/
public static function OutTradeNoParsing($out_trade_no)
{
return substr($out_trade_no, 14);
}
}
?>

View File

@ -1,18 +0,0 @@
<?php
/**
* 订单支付异步入口
*/
// 默认绑定模块
define('BIND_MODULE', 'Api');
define('BIND_CONTROLLER', 'OrderNotify');
define('BIND_ACTION', 'PayNotify');
// 引入公共入口文件
require '../core.php';
// 引入ThinkPHP入口文件
require '../ThinkPHP/ThinkPHP.php';
?>

View File

@ -414,7 +414,14 @@ background:url(../Images/ibar_sprites.png) no-repeat;background-position:0px -23
.price strong {color: #E4393C; font-weight: 600; }
/* 公共错误提示页面 */
.tips-error { margin: 10% 0; }
.tips-error, .tips-success { margin: 10% 0; }
.tips-pay-success, .tips-pay-error { box-shadow: none; text-align: center; }
.tips-error i.am-icon-times-circle, .tips-success i.am-icon-check-circle { font-size: 32px; }
.tips-error i.am-icon-times-circle { color: #F44336; }
.tips-success i.am-icon-check-circle { color: #4CAF50; }
.tips-error span.msg, .tips-success span.msg { font-size: 22px; margin-left: 10px; }
.tips-error .tips-nav, .tips-success .tips-nav { margin-top: 20px; }
.tips-error .tips-nav .am-btn:not(:last-child), .tips-success .tips-nav .am-btn:not(:last-child) { margin-right: 20px; }
/* 页面加载数据 */
.loding-view { text-align: center; color: #888; padding: 10px 0; }

18
service/notify_order.php Normal file
View File

@ -0,0 +1,18 @@
<?php
/**
* 订单支付异步入口
*/
// 默认绑定模块
$_GET['m'] = 'Api';
$_GET['c'] = 'OrderNotify';
$_GET['a'] = 'Notify';
// 引入公共入口文件
require './core.php';
// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';
?>

18
service/respond_order.php Normal file
View File

@ -0,0 +1,18 @@
<?php
/**
* 订单支付同步入口
*/
// 默认绑定模块
$_GET['m'] = 'Home';
$_GET['c'] = 'Order';
$_GET['a'] = 'Respond';
// 引入公共入口文件
require './core.php';
// 引入ThinkPHP入口文件
require './ThinkPHP/ThinkPHP.php';
?>