课程订单正向流程接口
This commit is contained in:
parent
b0bb197771
commit
8c91a1e794
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\api\controller\school;
|
||||||
|
|
||||||
|
use app\common\model\school\classes\order\Order as OrderModel;
|
||||||
|
use app\common\model\school\classes\Teacher as Teachermodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课时订单接口
|
||||||
|
*/
|
||||||
|
class HourOrder extends Base
|
||||||
|
{
|
||||||
|
protected $noNeedLogin = [];
|
||||||
|
protected $noNeedRight = '*';
|
||||||
|
|
||||||
|
protected $model = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化操作
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function _initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->model = new OrderModel;
|
||||||
|
parent::_initialize();
|
||||||
|
|
||||||
|
//判断登录用户是否是员工
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiTitle( 订单详情)
|
||||||
|
* @ApiSummary(订单详情)
|
||||||
|
* @ApiRoute(/api/school/order/detail)
|
||||||
|
* @ApiMethod(GET)
|
||||||
|
* @ApiParams(name = "id", type = "int",required=true,description = "订单id或订单号")
|
||||||
|
* @ApiReturn({
|
||||||
|
*
|
||||||
|
*})
|
||||||
|
*/
|
||||||
|
public function detail(){
|
||||||
|
$id = $this->request->get('id/d','');
|
||||||
|
|
||||||
|
if(empty($id)){
|
||||||
|
$this->error(__('缺少必要参数'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$res = OrderModel::getDetail($id);
|
||||||
|
} catch (\Exception $e){
|
||||||
|
// Log::log($e->getMessage());
|
||||||
|
$this->error($e->getMessage(),['errcode'=>$e->getCode()]);
|
||||||
|
}
|
||||||
|
$this->success('获取成功', ['detail' => $res]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiTitle( 订单确认/订单计算接口)
|
||||||
|
* @ApiSummary(订单确认/订单计算接口【有过期时间】)
|
||||||
|
* @ApiRoute(/api/school/order/confirm)
|
||||||
|
* @ApiMethod(POST)
|
||||||
|
* @ApiParams(name = "classes_lib_id", type = "int",required=true,description = "订单id或订单号")
|
||||||
|
* @ApiParams(name = "order_no", type = "string",required=false,description = "缓存key")
|
||||||
|
* @ApiParams(name = "is_compute", type = "int",required=false,description = "是否重新计算并更新缓存 默认传1")
|
||||||
|
* @ApiReturn({
|
||||||
|
*
|
||||||
|
*})
|
||||||
|
*/
|
||||||
|
public function confirm(){
|
||||||
|
$user_id = 0;
|
||||||
|
$user = $this->auth->getUser();//登录用户
|
||||||
|
if($user)$user_id = $user['id'];
|
||||||
|
$classes_lib_id = $this->request->post('classes_lib_id/d', 0); //课程id
|
||||||
|
// $param = urldecode($this->request->post('param/s', "{}")); //参数
|
||||||
|
$param = []; //参数
|
||||||
|
$order_no = $this->request->post('order_no/s', ''); //订单号
|
||||||
|
$is_compute = $this->request->post('is_compute/d', 1); //是否重新计算并更新缓存
|
||||||
|
try{
|
||||||
|
//当前申请状态
|
||||||
|
$res = $this->model->confirm($user_id, $classes_lib_id,$order_no,$param, $is_compute);
|
||||||
|
}catch (\Exception $e){
|
||||||
|
// Log::log($e->getMessage());
|
||||||
|
$this->error($e->getMessage(),['errcode'=>$e->getCode()]);
|
||||||
|
}
|
||||||
|
$this->success('执行成功,可用缓存key下单', $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiTitle( 订单下单接口)
|
||||||
|
* @ApiSummary(订单下单接口)
|
||||||
|
* @ApiRoute(/api/school/order/create)
|
||||||
|
* @ApiMethod(POST)
|
||||||
|
* @ApiParams(name = "order_no", type = "string",required=true,description = "缓存key")
|
||||||
|
* @ApiReturn({
|
||||||
|
*
|
||||||
|
*})
|
||||||
|
*/
|
||||||
|
public function create(){
|
||||||
|
$user_id = 0;
|
||||||
|
$user = $this->auth->getUser();//登录用户
|
||||||
|
if($user)$user_id = $user['id'];
|
||||||
|
$order_no = $this->request->post('order_no/s', ''); //订单号
|
||||||
|
$remark = $this->request->post('remark/s', ''); //下单备注
|
||||||
|
// repeat_filter("appointment\order\create".$user_id, 2);
|
||||||
|
try{
|
||||||
|
//当前申请状态
|
||||||
|
$res = $this->model->cacheCreateOrder($order_no,$user_id,$remark,true);
|
||||||
|
}catch (\Throwable $e){
|
||||||
|
// file_put_contents("test.txt",$e->getMessage().$e->getFile().$e->getLine());//写入文件,一般做正式环境测试
|
||||||
|
// Log::log($e->getMessage());
|
||||||
|
$this->error($e->getMessage(),['errcode'=>$e->getCode()]);;
|
||||||
|
}
|
||||||
|
$this->success('订单创建成功,缓存key被消耗', $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace app\api\controller\school;
|
namespace app\api\controller\school;
|
||||||
|
|
||||||
|
use app\common\model\school\classes\order\Order as OrderModel;
|
||||||
use app\common\model\school\classes\Teacher as Teachermodel;
|
use app\common\model\school\classes\Teacher as Teachermodel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +10,7 @@ use app\common\model\school\classes\Teacher as Teachermodel;
|
||||||
*/
|
*/
|
||||||
class Order extends Base
|
class Order extends Base
|
||||||
{
|
{
|
||||||
protected $noNeedLogin = ["detail",'people','spec'];
|
protected $noNeedLogin = [];
|
||||||
protected $noNeedRight = '*';
|
protected $noNeedRight = '*';
|
||||||
|
|
||||||
protected $model = null;
|
protected $model = null;
|
||||||
|
@ -21,7 +22,7 @@ class Order extends Base
|
||||||
protected function _initialize()
|
protected function _initialize()
|
||||||
{
|
{
|
||||||
|
|
||||||
$this->model = new Teachermodel;
|
$this->model = new OrderModel;
|
||||||
parent::_initialize();
|
parent::_initialize();
|
||||||
|
|
||||||
//判断登录用户是否是员工
|
//判断登录用户是否是员工
|
||||||
|
@ -29,11 +30,11 @@ class Order extends Base
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ApiTitle( x详情)
|
* @ApiTitle( 订单详情)
|
||||||
* @ApiSummary(xx详情)
|
* @ApiSummary(订单详情)
|
||||||
* @ApiRoute(/api/school/teacher/detail)
|
* @ApiRoute(/api/school/order/detail)
|
||||||
* @ApiMethod(GET)
|
* @ApiMethod(GET)
|
||||||
* @ApiParams(name = "id", type = "int",required=true,description = "老师id")
|
* @ApiParams(name = "id", type = "int",required=true,description = "订单id或订单号")
|
||||||
* @ApiReturn({
|
* @ApiReturn({
|
||||||
*
|
*
|
||||||
*})
|
*})
|
||||||
|
@ -46,12 +47,77 @@ class Order extends Base
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$res = $this->model->detail($id);
|
$res = OrderModel::getDetail($id);
|
||||||
} catch (\Exception $e){
|
} catch (\Exception $e){
|
||||||
// Log::log($e->getMessage());
|
// Log::log($e->getMessage());
|
||||||
$this->error($e->getMessage(),['errcode'=>$e->getCode()]);
|
$this->error($e->getMessage(),['errcode'=>$e->getCode()]);
|
||||||
}
|
}
|
||||||
$this->success('获取成功', ['detail' => $res]);
|
$this->success('获取成功', ['detail' => $res]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiTitle( 订单确认/订单计算接口)
|
||||||
|
* @ApiSummary(订单确认/订单计算接口【有过期时间】)
|
||||||
|
* @ApiRoute(/api/school/order/confirm)
|
||||||
|
* @ApiMethod(POST)
|
||||||
|
* @ApiParams(name = "classes_lib_id", type = "int",required=true,description = "订单id或订单号")
|
||||||
|
* @ApiParams(name = "order_no", type = "string",required=false,description = "缓存key")
|
||||||
|
* @ApiParams(name = "is_compute", type = "int",required=false,description = "是否重新计算并更新缓存 默认传1")
|
||||||
|
* @ApiReturn({
|
||||||
|
*
|
||||||
|
*})
|
||||||
|
*/
|
||||||
|
public function confirm(){
|
||||||
|
$user_id = 0;
|
||||||
|
$user = $this->auth->getUser();//登录用户
|
||||||
|
if($user)$user_id = $user['id'];
|
||||||
|
$classes_lib_id = $this->request->post('classes_lib_id/d', 0); //课程id
|
||||||
|
// $param = urldecode($this->request->post('param/s', "{}")); //参数
|
||||||
|
$param = []; //参数
|
||||||
|
$order_no = $this->request->post('order_no/s', ''); //订单号
|
||||||
|
$is_compute = $this->request->post('is_compute/d', 1); //是否重新计算并更新缓存
|
||||||
|
try{
|
||||||
|
//当前申请状态
|
||||||
|
$res = $this->model->confirm($user_id, $classes_lib_id,$order_no,$param, $is_compute);
|
||||||
|
}catch (\Exception $e){
|
||||||
|
// Log::log($e->getMessage());
|
||||||
|
$this->error($e->getMessage(),['errcode'=>$e->getCode()]);
|
||||||
|
}
|
||||||
|
$this->success('执行成功,可用缓存key下单', $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiTitle( 订单下单接口)
|
||||||
|
* @ApiSummary(订单下单接口)
|
||||||
|
* @ApiRoute(/api/school/order/create)
|
||||||
|
* @ApiMethod(POST)
|
||||||
|
* @ApiParams(name = "order_no", type = "string",required=true,description = "缓存key")
|
||||||
|
* @ApiReturn({
|
||||||
|
*
|
||||||
|
*})
|
||||||
|
*/
|
||||||
|
public function create(){
|
||||||
|
$user_id = 0;
|
||||||
|
$user = $this->auth->getUser();//登录用户
|
||||||
|
if($user)$user_id = $user['id'];
|
||||||
|
$order_no = $this->request->post('order_no/s', ''); //订单号
|
||||||
|
$remark = $this->request->post('remark/s', ''); //下单备注
|
||||||
|
// repeat_filter("appointment\order\create".$user_id, 2);
|
||||||
|
try{
|
||||||
|
//当前申请状态
|
||||||
|
$res = $this->model->cacheCreateOrder($order_no,$user_id,$remark,true);
|
||||||
|
}catch (\Throwable $e){
|
||||||
|
// file_put_contents("test.txt",$e->getMessage().$e->getFile().$e->getLine());//写入文件,一般做正式环境测试
|
||||||
|
// Log::log($e->getMessage());
|
||||||
|
$this->error($e->getMessage(),['errcode'=>$e->getCode()]);;
|
||||||
|
}
|
||||||
|
$this->success('订单创建成功,缓存key被消耗', $res);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,245 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\api\controller\school;
|
||||||
|
|
||||||
|
use addons\epay\library\Service;
|
||||||
|
use addons\third\model\Third;
|
||||||
|
use app\common\model\school\classes\order\Order as OrderModel;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
use think\Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程支付接口
|
||||||
|
*/
|
||||||
|
class Pay extends Base
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $noNeedLogin = '*';
|
||||||
|
protected $noNeedRight = '*';
|
||||||
|
protected $model = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化操作
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected function _initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->model = new OrderModel;
|
||||||
|
parent::_initialize();
|
||||||
|
|
||||||
|
//判断登录用户是否是员工
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiTitle( 课程第三方支付)
|
||||||
|
* @ApiSummary(课程第三方支付(微信等支付))
|
||||||
|
* @ApiRoute(/api/school/pay/payment)
|
||||||
|
* @ApiMethod(POST)
|
||||||
|
* @ApiParams(name = "order_no", type = "string",required=true,description = "订单id或订单号")
|
||||||
|
* @ApiParams(name = "type", type = "string",required=true,description = "服务商:alipay=支付宝,wechat=微信")
|
||||||
|
* @ApiParams(name = "platform", type = "string",required=true,description = "平台:web=PC网页支付,wap=H5手机网页支付,app=APP支付,scan=扫码支付,mp=微信公众号支付,miniapp=微信小程序支付")
|
||||||
|
* @ApiParams(name = "openid", type = "string",required=false,description = "用户openid(非必填)")
|
||||||
|
* @ApiReturn({
|
||||||
|
*
|
||||||
|
*})
|
||||||
|
*/
|
||||||
|
public function payment()
|
||||||
|
{
|
||||||
|
$order_no = $this->request->post('order_no/s');
|
||||||
|
$type = $this->request->post('type/s');
|
||||||
|
$method = $this->request->post('platform/s');
|
||||||
|
$openid = $this->request->post('openid/s', "");
|
||||||
|
$platform = $method;
|
||||||
|
try {
|
||||||
|
//订单支付前校验
|
||||||
|
$this->model->checkPay($order_no,$type);
|
||||||
|
$order = OrderModel::where('order_no', $order_no)->find();
|
||||||
|
$amount = $order["totalprice"];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!$amount || $amount < 0) {
|
||||||
|
$this->error("支付金额必须大于0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$type || !in_array($type, ['alipay', 'wechat'])) {
|
||||||
|
$this->error("支付类型不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($method, ['miniapp', 'mp']) && !$openid) {
|
||||||
|
|
||||||
|
// 微信公众号,小程序支付,必须有 openid
|
||||||
|
if (isset($openid) && $openid) {
|
||||||
|
// 如果传的有 openid
|
||||||
|
} else {
|
||||||
|
// 没有 openid 默认拿下单人的 openid
|
||||||
|
$oauth = Third::where([
|
||||||
|
'user_id' => $order->user_id,
|
||||||
|
'platform' => $type,
|
||||||
|
'apptype' => $platform
|
||||||
|
])->find();
|
||||||
|
|
||||||
|
$openid = $oauth ? $oauth->openid : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$openid) {
|
||||||
|
// 缺少 openid
|
||||||
|
$this->error("授权过期,请您重新授权登录");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//订单号
|
||||||
|
$out_trade_no = $order_no;
|
||||||
|
|
||||||
|
//订单标题
|
||||||
|
$title = '课程订单['.$out_trade_no."]支付";
|
||||||
|
|
||||||
|
//回调链接
|
||||||
|
$notifyurl = $this->request->root(true) . '/api/school/pay/notifyx/paytype/' . $type. '/platform/' . $method;
|
||||||
|
$returnurl = $this->request->root(true) . '/api/school/pay/returnx/paytype/' . $type . '/out_trade_no/' . $out_trade_no;
|
||||||
|
|
||||||
|
$response = Service::submitOrder($amount, $out_trade_no, $type, $title, $notifyurl, $returnurl, $method, $openid);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ApiTitle( 第三方支付支付成功回调)
|
||||||
|
* @ApiSummary(第三方支付成功回调)
|
||||||
|
* @ApiRoute(/api/school/pay/notifyx)
|
||||||
|
* @ApiMethod(GET)
|
||||||
|
* @ApiReturn({
|
||||||
|
*
|
||||||
|
*})
|
||||||
|
*/
|
||||||
|
public function notifyx()
|
||||||
|
{
|
||||||
|
$paytype = $this->request->param('paytype');
|
||||||
|
$platform = $this->request->param('platform');
|
||||||
|
$pay = Service::checkNotify($paytype);
|
||||||
|
if (!$pay) {
|
||||||
|
return json(['code' => 'FAIL', 'message' => '失败'], 500, ['Content-Type' => 'application/json']);
|
||||||
|
}
|
||||||
|
$payment = $paytype;
|
||||||
|
// 获取回调数据,V3和V2的回调接收不同
|
||||||
|
$data = Service::isVersionV3() ? $pay->callback() : $pay->verify();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Log::write('notifyx-result:'. json_encode($data));
|
||||||
|
|
||||||
|
$out_trade_no = $data['out_trade_no'];
|
||||||
|
$out_refund_no = $data['out_biz_no'] ?? '';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 判断是否是支付宝退款(支付宝退款成功会通知该接口)
|
||||||
|
if ($paytype == 'alipay' // 支付宝支付
|
||||||
|
&& $data['notify_type'] == 'trade_status_sync' // 同步交易状态
|
||||||
|
&& $data['trade_status'] == 'TRADE_CLOSED' // 交易关闭
|
||||||
|
&& $out_refund_no // 退款单号
|
||||||
|
) {
|
||||||
|
// 退款回调
|
||||||
|
|
||||||
|
// $this->refundFinish($out_trade_no, $out_refund_no,$platform);
|
||||||
|
|
||||||
|
return $pay->success()->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 判断支付宝微信是否是支付成功状态,如果不是,直接返回响应
|
||||||
|
if ($payment == 'alipay' && $data['trade_status'] != 'TRADE_SUCCESS') {
|
||||||
|
// 不是交易成功的通知,直接返回成功
|
||||||
|
return $pay->success()->send();
|
||||||
|
}
|
||||||
|
if ($payment == 'wechat' && ($data['result_code'] != 'SUCCESS' || $data['return_code'] != 'SUCCESS')) {
|
||||||
|
// 微信交易未成功,返回 false,让微信再次通知
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
//微信支付V3返回和V2不同
|
||||||
|
if (Service::isVersionV3() && $paytype === 'wechat') {
|
||||||
|
$data = $data['resource']['ciphertext'];
|
||||||
|
$data['total_fee'] = $data['amount']['total'];
|
||||||
|
}
|
||||||
|
|
||||||
|
\think\Log::record($data);
|
||||||
|
|
||||||
|
$payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
|
||||||
|
$out_trade_no = $data['out_trade_no'];
|
||||||
|
|
||||||
|
\think\Log::record("回调成功,订单号:{$out_trade_no},金额:{$payamount}");
|
||||||
|
|
||||||
|
//你可以在此编写订单逻辑
|
||||||
|
|
||||||
|
// 支付成功流程
|
||||||
|
//获取支付金额、订单号
|
||||||
|
$pay_fee = $payment == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
|
||||||
|
|
||||||
|
//你可以在此编写订单逻辑
|
||||||
|
$order = OrderModel::getNopayOrder($out_trade_no);
|
||||||
|
|
||||||
|
if (!$order || $order["status"] != '0') {
|
||||||
|
// 订单不存在,或者订单已支付
|
||||||
|
return $pay->success()->send();
|
||||||
|
}
|
||||||
|
$notify = [
|
||||||
|
'order_no' => $data['out_trade_no'],
|
||||||
|
'transaction_id' => $payment == 'alipay' ? $data['trade_no'] : $data['transaction_id'],
|
||||||
|
'notify_time' => date('Y-m-d H:i:s', strtotime($data['time_end'])),
|
||||||
|
'buyer_email' => $payment == 'alipay' ? $data['buyer_logon_id'] : $data['openid'],
|
||||||
|
'payment_json' => json_encode($data->all()),
|
||||||
|
'pay_fee' => $pay_fee,
|
||||||
|
'pay_type' => $payment, // 支付方式
|
||||||
|
'platform' => $platform,
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->model->paySuccess($order['order_sn'],$notify,$pay_fee,true,true);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
\think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error");
|
||||||
|
}
|
||||||
|
|
||||||
|
//下面这句必须要执行,且在此之前不能有任何输出
|
||||||
|
if (Service::isVersionV3()) {
|
||||||
|
return $pay->success()->getBody()->getContents();
|
||||||
|
} else {
|
||||||
|
return $pay->success()->send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付返回,网页支付版本(小程序忽略)
|
||||||
|
*/
|
||||||
|
public function returnx()
|
||||||
|
{
|
||||||
|
$paytype = $this->request->param('paytype');
|
||||||
|
$out_trade_no = $this->request->param('out_trade_no');
|
||||||
|
$pay = Service::checkReturn($paytype);
|
||||||
|
if (!$pay) {
|
||||||
|
$this->error('签名错误', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
//你可以在这里定义你的提示信息,但切记不可在此编写逻辑
|
||||||
|
$this->success("请返回网站查看支付结果", addon_url("epay/index/index"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -507,3 +507,66 @@ EOT;
|
||||||
return $icon;
|
return $icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
获取订单号
|
||||||
|
*/
|
||||||
|
if (!function_exists('get_order_sn')) {
|
||||||
|
function get_order_sn()
|
||||||
|
{
|
||||||
|
$time = explode(' ', microtime());
|
||||||
|
$time = $time[1] . $time[0] * 1000;
|
||||||
|
$time = explode('.', $time);
|
||||||
|
$time = isset($time[1]) ? $time[1] : 0;
|
||||||
|
$time = date('YmdHis') + $time;
|
||||||
|
mt_srand((double) microtime() * 1000000);
|
||||||
|
return $time . str_pad(mt_rand(1, 99999), 5, '0', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (!function_exists('en_code')) {
|
||||||
|
/**
|
||||||
|
* 针对于ID的可逆加密函数,也可以用作于邀请码之类
|
||||||
|
* @param int $code
|
||||||
|
*/
|
||||||
|
function en_code($code)
|
||||||
|
{
|
||||||
|
static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
|
||||||
|
$num = $code;
|
||||||
|
$code = '';
|
||||||
|
while ($num > 0) {
|
||||||
|
$mod = $num % 35;
|
||||||
|
$num = ($num - $mod) / 35;
|
||||||
|
$code = $source_string[$mod] . $code;
|
||||||
|
}
|
||||||
|
if (empty($code[3])) {
|
||||||
|
$code = str_pad($code, 4, '0', STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!function_exists('de_code')) {
|
||||||
|
/**
|
||||||
|
* 针对于ID的可逆加密函数,也可以用作于邀请码之类
|
||||||
|
* @param string $code
|
||||||
|
*/
|
||||||
|
function de_code($code)
|
||||||
|
{
|
||||||
|
static $source_string = 'E5FCDG3HQA4B1NOPIJ2RSTUV67MWX89KLYZ';
|
||||||
|
if (strrpos($code, '0') !== false) {
|
||||||
|
$code = substr($code, strrpos($code, '0') + 1);
|
||||||
|
}
|
||||||
|
$len = strlen($code);
|
||||||
|
$code = strrev($code);
|
||||||
|
$num = 0;
|
||||||
|
for ($i = 0; $i < $len; $i++) {
|
||||||
|
$num += strpos($source_string, $code[$i]) * pow(35, $i);
|
||||||
|
}
|
||||||
|
return $num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
namespace app\common\listener\classesorder;
|
||||||
|
class OrderHook
|
||||||
|
{
|
||||||
|
// 订单创建成功前(订单计算)
|
||||||
|
|
||||||
|
public function classesOrderCreateBefore(&$params)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 订单创建成功后
|
||||||
|
public function classesOrderCreateAfter(&$params)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 订单支付成功后
|
||||||
|
public function classesOrderPayedAfter(&$params)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单取消成功后
|
||||||
|
public function classesOrderCancelAfter(&$params)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -11,6 +11,9 @@ class BaseModel extends Model
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
use \traits\ModelTrait;
|
||||||
|
// use \traits\ErrorTrait;
|
||||||
|
|
||||||
public $timeKey = 'createtime';
|
public $timeKey = 'createtime';
|
||||||
public static $staticTimeKey = 'createtime';
|
public static $staticTimeKey = 'createtime';
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
|
|
||||||
namespace app\common\model;
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use app\common\library\Auth;
|
||||||
|
use app\common\library\Sms;
|
||||||
use app\common\model\school\classes\Teacher;
|
use app\common\model\school\classes\Teacher;
|
||||||
use app\common\model\school\classes\Verification;
|
use app\common\model\school\classes\Verification;
|
||||||
|
use fast\Random;
|
||||||
use think\Db;
|
use think\Db;
|
||||||
use think\Model;
|
use think\Model;
|
||||||
|
|
||||||
|
@ -88,7 +91,7 @@ class User extends Model
|
||||||
* @param int $user_id 会员ID
|
* @param int $user_id 会员ID
|
||||||
* @param string $memo 备注
|
* @param string $memo 备注
|
||||||
*/
|
*/
|
||||||
public static function money($money, $user_id, $memo)
|
public static function money($money, $user_id, $memo,$type='',$ext = [])
|
||||||
{
|
{
|
||||||
Db::startTrans();
|
Db::startTrans();
|
||||||
try {
|
try {
|
||||||
|
@ -100,7 +103,7 @@ class User extends Model
|
||||||
//更新会员信息
|
//更新会员信息
|
||||||
$user->save(['money' => $after]);
|
$user->save(['money' => $after]);
|
||||||
//写入日志
|
//写入日志
|
||||||
MoneyLog::create(['user_id' => $user_id, 'money' => $money, 'before' => $before, 'after' => $after, 'memo' => $memo]);
|
MoneyLog::create(['user_id' => $user_id, 'money' => $money, 'before' => $before, 'after' => $after, 'memo' => $memo, 'ext' => $ext?:"","type" =>$type]);
|
||||||
}
|
}
|
||||||
Db::commit();
|
Db::commit();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
@ -114,7 +117,7 @@ class User extends Model
|
||||||
* @param int $user_id 会员ID
|
* @param int $user_id 会员ID
|
||||||
* @param string $memo 备注
|
* @param string $memo 备注
|
||||||
*/
|
*/
|
||||||
public static function score($score, $user_id, $memo)
|
public static function score($score, $user_id, $memo,$type='',$ext = [])
|
||||||
{
|
{
|
||||||
Db::startTrans();
|
Db::startTrans();
|
||||||
try {
|
try {
|
||||||
|
@ -126,7 +129,7 @@ class User extends Model
|
||||||
//更新会员信息
|
//更新会员信息
|
||||||
$user->save(['score' => $after, 'level' => $level]);
|
$user->save(['score' => $after, 'level' => $level]);
|
||||||
//写入日志
|
//写入日志
|
||||||
ScoreLog::create(['user_id' => $user_id, 'score' => $score, 'before' => $before, 'after' => $after, 'memo' => $memo]);
|
ScoreLog::create(['user_id' => $user_id, 'score' => $score, 'before' => $before, 'after' => $after, 'memo' => $memo, 'ext' => $ext?:"","type" =>$type]);
|
||||||
}
|
}
|
||||||
Db::commit();
|
Db::commit();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
|
@ -179,4 +182,75 @@ class User extends Model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**检测用户设置密码情况
|
||||||
|
* @param $user_id
|
||||||
|
* @param $password
|
||||||
|
* @param bool $check
|
||||||
|
*/
|
||||||
|
public static function checkPayPassword($user_id,$password=null,$check=true){
|
||||||
|
$user = self::where('id',$user_id)->find();
|
||||||
|
if(!$user) throw new \Exception("用户不存在!");
|
||||||
|
// if(!$user["mobile"]) throw new \Exception("您未绑定手机号,请您先去绑定手机号!");
|
||||||
|
$mobile = $user["mobile"];
|
||||||
|
$auth = Auth::instance();
|
||||||
|
//是否设置支付密码
|
||||||
|
$is_setting = false;
|
||||||
|
//密码是否正确
|
||||||
|
$is_right = false;
|
||||||
|
//检测是否设置支付密码
|
||||||
|
if($user['pay_password'])$is_setting = true;
|
||||||
|
if($check){
|
||||||
|
//校验密码是否正确
|
||||||
|
$pay_password = $auth->getEncryptPassword($password, $user['pay_salt']);
|
||||||
|
if($user['pay_password']==$pay_password)$is_right = true;
|
||||||
|
}
|
||||||
|
return compact('is_setting','is_right','mobile');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** 设置用户支付密码
|
||||||
|
* @param $user_id
|
||||||
|
* @param $code
|
||||||
|
* @param $password
|
||||||
|
* @param bool $trans
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function setPayPassword($user_id, $code,$password,$trans=false,$check_sms=true){
|
||||||
|
$user = self::where('id',$user_id)->find();
|
||||||
|
if(!$user) throw new \Exception("用户不存在!");
|
||||||
|
if($check_sms){
|
||||||
|
$ret = Sms::check($user['mobile'], $code, 'pay_password');
|
||||||
|
if (!$ret)throw new \Exception("验证码错误");
|
||||||
|
}
|
||||||
|
if(!is_numeric($password) || strlen($password)!=6)throw new \Exception("支付密碼只能設置六位數字!");
|
||||||
|
//判断逻辑
|
||||||
|
if($trans){
|
||||||
|
self::beginTrans();
|
||||||
|
}
|
||||||
|
$res = true;
|
||||||
|
try{
|
||||||
|
$auth = Auth::instance();
|
||||||
|
//事务逻辑
|
||||||
|
$user['pay_salt'] = Random::alnum();
|
||||||
|
$user['pay_password'] = $auth->getEncryptPassword($password, $user['pay_salt']);
|
||||||
|
$user->save();
|
||||||
|
//清除验证码
|
||||||
|
if($check_sms)Sms::flush($user['mobile'], 'pay_password');
|
||||||
|
if($trans){
|
||||||
|
self::commitTrans();
|
||||||
|
}
|
||||||
|
}catch (\Exception $e){
|
||||||
|
if($trans){
|
||||||
|
self::rollbackTrans();
|
||||||
|
}
|
||||||
|
throw new \Exception($e->getMessage());
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,9 +243,9 @@ class ClassesLib extends Model
|
||||||
public function detail($id){
|
public function detail($id){
|
||||||
$self = $this->get($id,['shop','teacher']);
|
$self = $this->get($id,['shop','teacher']);
|
||||||
//下架判断
|
//下架判断
|
||||||
if($self['status'] != '1'){
|
// if($self['status'] != '1'){
|
||||||
$this->error("该课程已下架");
|
// $this->error("该课程已下架");
|
||||||
}
|
// }
|
||||||
|
|
||||||
//参与人数 = 虚拟人数 + 平台人数
|
//参与人数 = 虚拟人数 + 平台人数
|
||||||
return $self;
|
return $self;
|
||||||
|
|
|
@ -2,15 +2,23 @@
|
||||||
|
|
||||||
namespace app\common\model\school\classes\order;
|
namespace app\common\model\school\classes\order;
|
||||||
|
|
||||||
|
|
||||||
|
use app\common\model\BaseModel;
|
||||||
|
use app\common\model\dyqc\ManystoreShop;
|
||||||
|
use app\common\model\school\classes\ClassesLib;
|
||||||
|
use app\common\model\User;
|
||||||
|
use bw\Common;
|
||||||
|
use fast\Random;
|
||||||
|
use think\Cache;
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use traits\model\SoftDelete;
|
use traits\model\SoftDelete;
|
||||||
|
|
||||||
class Order extends Model
|
class Order extends BaseModel
|
||||||
{
|
{
|
||||||
|
|
||||||
use SoftDelete;
|
use SoftDelete;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 表名
|
// 表名
|
||||||
protected $name = 'school_classes_order';
|
protected $name = 'school_classes_order';
|
||||||
|
@ -160,25 +168,25 @@ class Order extends Model
|
||||||
|
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo('app\common\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function shop()
|
public function shop()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\manystore\Shop', 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo(ManystoreShop::class, 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function lib()
|
public function lib()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\school\classes\Lib', 'classes_lib_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo(ClassesLib::class, 'classes_lib_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function detail()
|
public function detail()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('Detail', 'classes_order_detail_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo(OrderDetail::class, 'classes_order_detail_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,4 +194,519 @@ class Order extends Model
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\Admin', 'admin_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo('app\admin\model\Admin', 'admin_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCodeimageAttr($value, $data)
|
||||||
|
{
|
||||||
|
if (!empty($value)) return cdnurl($value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCodeoneimageAttr($value, $data)
|
||||||
|
{
|
||||||
|
if (!empty($value)) return cdnurl($value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置订单缓存
|
||||||
|
* @param $uid
|
||||||
|
* @param $data
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function setOrderCache($uid, $data)
|
||||||
|
{
|
||||||
|
//缓存名 = uid + order_no
|
||||||
|
$cacheNmae = 'classes_order_cache' . $uid . $data['order_no'];
|
||||||
|
// 缓存在3600秒之后过期
|
||||||
|
return Cache::set($cacheNmae, $data, config("site.unpaid_order_expire_time"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到订单缓存
|
||||||
|
* @param $uid
|
||||||
|
* @param $order_no
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function getOrderCache($uid, $order_no)
|
||||||
|
{
|
||||||
|
//缓存名 = uid + order_no
|
||||||
|
$cacheNmae = 'classes_order_cache' . $uid . $order_no;
|
||||||
|
// 缓存在3600秒之后过期
|
||||||
|
return Cache::get($cacheNmae);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除订单缓存
|
||||||
|
* @param $uid
|
||||||
|
* @param $order_no
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function deleteOrderCache($uid, $order_no)
|
||||||
|
{
|
||||||
|
//缓存名 = uid + order_no
|
||||||
|
$cacheNmae = 'classes_order_cache' . $uid . $order_no;
|
||||||
|
// 缓存在3600秒之后过期
|
||||||
|
return Cache::rm($cacheNmae);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**展示订单信息
|
||||||
|
* @param $order_no
|
||||||
|
* @param $price_info
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function showInfo($order_no, $price_info = []){
|
||||||
|
$data = [];
|
||||||
|
$data['order_no'] =$order_no;
|
||||||
|
$data['order_info'] = self::getDetail($order_no);
|
||||||
|
return array_merge($data,$price_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**得到订单详情
|
||||||
|
* @param $order_no
|
||||||
|
*/
|
||||||
|
public static function getDetail($order_no){
|
||||||
|
$data = self::where('order_no|id|pay_no',$order_no)->find();
|
||||||
|
if(!$data) return $data;
|
||||||
|
//加载订单详情
|
||||||
|
$data->detail->teacher;
|
||||||
|
//订单用户
|
||||||
|
$data->user;
|
||||||
|
//订单机构
|
||||||
|
$data->shop;
|
||||||
|
// //得到二维码
|
||||||
|
// $data->code_url = Common::getQrcode([
|
||||||
|
// 'text' => $data['code'],
|
||||||
|
// 'size' => 200,
|
||||||
|
// ]);
|
||||||
|
// $data->one_code_url = Common::getBarcode([
|
||||||
|
// 'text' => $data['code'],
|
||||||
|
// 'size' => 200,
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** 订单确认(订单计算)
|
||||||
|
* @param $user_id 下单用户
|
||||||
|
* @param $order_no 订单号(缓存标识)
|
||||||
|
* @param $classes_lib_id 課程id
|
||||||
|
* @param $param 額外参数(扩展用)
|
||||||
|
* @param bool $is_compute 是否重新计算订单
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function confirm($user_id, $classes_lib_id,$order_no,$param=[], $is_compute = false)
|
||||||
|
{
|
||||||
|
if ($order_no && !$is_compute) {
|
||||||
|
//得到缓存
|
||||||
|
$data = self::getOrderCache($user_id, $order_no);
|
||||||
|
if (!$data) throw new \Exception('請您完善預約信息!');
|
||||||
|
$price_info = $data['price_info'];
|
||||||
|
} else {
|
||||||
|
//订单信息计算
|
||||||
|
if(!$param) throw new \Exception('缺少必要信息');
|
||||||
|
$this->orderVaild($user_id,$classes_lib_id,$order_no, $param);
|
||||||
|
//订单支付信息
|
||||||
|
$price_info = $this->getCost($user_id,$classes_lib_id,$param);
|
||||||
|
//生成订单号
|
||||||
|
if (!$order_no) $order_no = get_order_sn();
|
||||||
|
//生成缓存
|
||||||
|
$data = compact('user_id', 'classes_lib_id','param', 'order_no', 'price_info');
|
||||||
|
self::setOrderCache($user_id, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
\think\Hook::listen('classes_order_create_before', $data);
|
||||||
|
|
||||||
|
//下单数据展示
|
||||||
|
return $this->showInfo($order_no, $price_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据缓存创建订单
|
||||||
|
*/
|
||||||
|
public function cacheCreateOrder($order_no, $user_id,$remark="", $trans = false)
|
||||||
|
{
|
||||||
|
//得到缓存
|
||||||
|
$orderInfo = self::getOrderCache($user_id, $order_no); //得到下单信息
|
||||||
|
if (!$orderInfo) throw new \Exception('請您完善預約信息!');
|
||||||
|
|
||||||
|
if ($trans) {
|
||||||
|
self::beginTrans();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
//1订单执行创建
|
||||||
|
$this->createOrder($user_id,$orderInfo['classes_lib_id'],$order_no,$orderInfo['param'],$remark);
|
||||||
|
//5删除缓存
|
||||||
|
self::deleteOrderCache($user_id, $order_no);
|
||||||
|
if ($trans) {
|
||||||
|
self::commitTrans();
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
if ($trans) {
|
||||||
|
self::rollbackTrans();
|
||||||
|
}
|
||||||
|
throw new \Exception($e->getMessage());
|
||||||
|
}
|
||||||
|
return self::showInfo($order_no);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function createOrder($user_id,$classes_lib_id,$order_no,$param,$remark='',$other_params=[]){
|
||||||
|
|
||||||
|
$this->orderVaild($user_id,$classes_lib_id, $order_no, $param,true);
|
||||||
|
//订单支付信息
|
||||||
|
$order_info = self::getCost($user_id,$classes_lib_id,$param,$other_params,true);
|
||||||
|
|
||||||
|
//组装订单数据
|
||||||
|
$order_data = $order_info['order_data'];
|
||||||
|
$order_data["order_no"] = $order_no;
|
||||||
|
|
||||||
|
$res1 = self::create($order_data);
|
||||||
|
if (!$res1) throw new \Exception('创建订单失败');
|
||||||
|
|
||||||
|
//課程详情
|
||||||
|
$classes_lib_info = $order_info['classes_lib_info'];
|
||||||
|
|
||||||
|
$order_detail_data = [];
|
||||||
|
$order_detail_data = array_merge($order_detail_data,$classes_lib_info);
|
||||||
|
$order_detail_data["classes_lib_id"] = $classes_lib_info['id'];
|
||||||
|
$order_detail_data["classes_order_id"] = $res1['id'];
|
||||||
|
|
||||||
|
unset($order_detail_data['id']);
|
||||||
|
unset($order_detail_data['createtime']);;
|
||||||
|
|
||||||
|
$orderDetail = (new OrderDetail());
|
||||||
|
$orderDetail->allowField(true)->save($order_detail_data);
|
||||||
|
//更新订单详情id
|
||||||
|
$res1->classes_order_detail_id = $orderDetail->id;
|
||||||
|
$res1->save();
|
||||||
|
|
||||||
|
//记录订单日志
|
||||||
|
OrderLog::log($res1['id'],"课程订单创建成功,等待【学员】支付",'user',$user_id);
|
||||||
|
//7事件
|
||||||
|
$data = ['order' => $res1];
|
||||||
|
\think\Hook::listen('classes_order_create_after', $data);
|
||||||
|
return $res1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**订单校验
|
||||||
|
* @param $user_id 用户id
|
||||||
|
* @param $classes_lib_id 课程id
|
||||||
|
* @param $order_no 订单号
|
||||||
|
* @param $param 表单扩展参数
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function orderVaild($user_id,$classes_lib_id, $order_no, $param,$check=false){
|
||||||
|
if(!$user_id ||!$param )throw new \Exception("缺少必要参数");
|
||||||
|
|
||||||
|
//默认校验订单是否已创建
|
||||||
|
if($check){
|
||||||
|
//判断订单是否已创建
|
||||||
|
$order_info = self::where(['order_no'=>$order_no]);
|
||||||
|
if($order_info) throw new \Exception("订单已生成,如需重新下单请退出页面重新进入!");
|
||||||
|
}
|
||||||
|
//校验订单参数
|
||||||
|
//课程是否存在并上架
|
||||||
|
$classes_lib_info = ClassesLib::where('classes_lib_id',$classes_lib_id);
|
||||||
|
if(!$classes_lib_info || $classes_lib_info['status']!='1') throw new \Exception("该课程不存在或已下架!");
|
||||||
|
|
||||||
|
//用户存不存在
|
||||||
|
$user_info = User::where('user_id',$user_id)->find();
|
||||||
|
if(!$user_info) throw new \Exception("用户不存在!");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//计算订单所需返回数据接口
|
||||||
|
public static function getCost($user_id,$classes_lib_id,$param=[],$other_params=[],$check = false){
|
||||||
|
//用户
|
||||||
|
$user_info = User::get($user_id);
|
||||||
|
$user_data = [
|
||||||
|
"nickname"=>$user_info["nickname"],
|
||||||
|
"realname"=>$user_info["realname"],
|
||||||
|
"avatar"=>$user_info["avatar"],
|
||||||
|
"mobile"=>$user_info["mobile"],
|
||||||
|
"money" =>$user_info["money"],
|
||||||
|
"score" =>$user_info["score"],
|
||||||
|
];
|
||||||
|
//课程
|
||||||
|
$classes_lib_info = ClassesLib::get($classes_lib_id);
|
||||||
|
$classes_lib_info = $classes_lib_info->toArray();
|
||||||
|
|
||||||
|
$classes_lib_info['use_num'] = 0;//已使用课时
|
||||||
|
$classes_lib_info['sub_num'] = $classes_lib_info['classes_num'];//剩余课时
|
||||||
|
//单价 = 课程价格/总课时
|
||||||
|
$classes_lib_info["unit_price"] = bcdiv($classes_lib_info['price'],$classes_lib_info['classes_num'],2);
|
||||||
|
$classes_lib_info["used_price"] = 0;
|
||||||
|
|
||||||
|
|
||||||
|
//组装订单下单数据
|
||||||
|
$order_data = [];
|
||||||
|
$order_data["user_id"] = $user_id;
|
||||||
|
$order_data["manystore_id"] = $classes_lib_info["manystore_id"];
|
||||||
|
$order_data["shop_id"] = $classes_lib_info["shop_id"];
|
||||||
|
$order_data["classes_lib_id"] = $classes_lib_id;
|
||||||
|
$order_data["beforeprice"] = $classes_lib_info["price"];
|
||||||
|
$order_data["totalprice"] = $classes_lib_info["price"];
|
||||||
|
$order_data["payprice"] = $classes_lib_info["price"];
|
||||||
|
$order_data["status"] = '0';
|
||||||
|
|
||||||
|
|
||||||
|
return compact('order_data','classes_lib_info','user_data');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**得到待支付订单
|
||||||
|
* @param $order_no
|
||||||
|
* @return array|false|\PDOStatement|string|Model
|
||||||
|
* @throws \think\db\exception\DataNotFoundException
|
||||||
|
* @throws \think\db\exception\ModelNotFoundException
|
||||||
|
* @throws \think\exception\DbException
|
||||||
|
*/
|
||||||
|
public static function getNopayOrder($order_no){
|
||||||
|
$order = self::where('order_no|id|pay_no',$order_no)->where("status",'0')->find();
|
||||||
|
if(!$order)throw new \Exception("待支付订单不存在");
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检测支付开关(待扩展)
|
||||||
|
*/
|
||||||
|
public static function checkPaySwitch($pay_type,$user_id){
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**订单支付前判断
|
||||||
|
* @param $order_no
|
||||||
|
* @param $pay_type
|
||||||
|
* @return array|false|\PDOStatement|string|Model
|
||||||
|
*/
|
||||||
|
public function checkPay($order_no,$pay_type,$password = null){
|
||||||
|
$order = self::getNopayOrder($order_no);
|
||||||
|
|
||||||
|
//支付前判断
|
||||||
|
//TODO通用判
|
||||||
|
//...
|
||||||
|
$user = User::where('id',$order['user_id'])->find();
|
||||||
|
if(!$user)throw new \Exception("支付用户异常");
|
||||||
|
|
||||||
|
//是否开通此支付方式
|
||||||
|
self::checkPaySwitch($pay_type,$order['user_id']);
|
||||||
|
|
||||||
|
//各自币种判断
|
||||||
|
switch ($pay_type) {
|
||||||
|
case "wechat": //微信支付
|
||||||
|
//..
|
||||||
|
break;
|
||||||
|
case "alipay": //支付宝支付
|
||||||
|
//...
|
||||||
|
break;
|
||||||
|
case "offline": //线下支付
|
||||||
|
//..
|
||||||
|
break;
|
||||||
|
case "yue": //余额支付
|
||||||
|
//支付密码判断
|
||||||
|
// $res = User::checkPayPassword($order['user_id'],$password,true);
|
||||||
|
// if(!$res['is_setting'])throw new \Exception("您还未设置支付密码,请您先去设置支付密码");
|
||||||
|
// if(!$res['is_right'])throw new \Exception("支付密码错误");
|
||||||
|
//判断余额是否充足
|
||||||
|
//得到支付余额
|
||||||
|
$total_amount = $order['totalprice'] ?:0;
|
||||||
|
//得到用户余额
|
||||||
|
$money = $user['money'];
|
||||||
|
if(bccomp($money,$total_amount)==-1)throw new \Exception("当前余额不足以完成本次支付!");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new \Exception("不支持的支付类型验证");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**余额支付
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function moneyPay($order_no,$method,$trans=false){
|
||||||
|
$order = self::getNopayOrder($order_no);
|
||||||
|
//支付前判断
|
||||||
|
// self::checkPay($order_no,'wallet');
|
||||||
|
//判断逻辑
|
||||||
|
if($trans){
|
||||||
|
self::beginTrans();
|
||||||
|
}
|
||||||
|
$res = true;
|
||||||
|
try{
|
||||||
|
//事务逻辑
|
||||||
|
if($order['totalprice']){
|
||||||
|
$memo = "课时订单[ID:{$order['id']}]下单,支付余额{$order['totalprice']}";
|
||||||
|
try{
|
||||||
|
//扣除用户余额
|
||||||
|
User::money(-$order['totalprice'], $order['user_id'], $memo,'class_order_pay' ,[
|
||||||
|
'order_id' => $order->id,
|
||||||
|
'order_sn' => $order->order_sn,
|
||||||
|
]);
|
||||||
|
}catch (\Exception $e){
|
||||||
|
throw new \Exception("余额不足!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//调用订单支付成功事件
|
||||||
|
$this->paySuccess($order_no,['platform'=>$method,'pay_type'=>'yue']);
|
||||||
|
if($trans){
|
||||||
|
self::commitTrans();
|
||||||
|
}
|
||||||
|
}catch (\Exception $e){
|
||||||
|
if($trans){
|
||||||
|
self::rollbackTrans();
|
||||||
|
}
|
||||||
|
throw new \Exception($e->getMessage());
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**调用订单支付成功事件
|
||||||
|
* @param $order_no
|
||||||
|
* @param $pay_type
|
||||||
|
* @param $price
|
||||||
|
* @param $price_check
|
||||||
|
* @param bool $trans
|
||||||
|
* @return bool
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function paySuccess($order_no,$notify=[],$price=0,$price_check=false,$trans=false){
|
||||||
|
$order = self::getNopayOrder($order_no);
|
||||||
|
//金额校验 :第三方支付时回调入口判断
|
||||||
|
if($price_check){
|
||||||
|
if(bccomp($price,$order['totalprice'])==-1)throw new \Exception("支付金额与订单需要支付金额对应不上,回调失败!");
|
||||||
|
}
|
||||||
|
//判断逻辑
|
||||||
|
if($trans){
|
||||||
|
self::beginTrans();
|
||||||
|
}
|
||||||
|
$res = true;
|
||||||
|
try{
|
||||||
|
//事务逻辑
|
||||||
|
//不拆分订单,直接执行
|
||||||
|
self::paySetData($order,$notify);
|
||||||
|
if($trans){
|
||||||
|
self::commitTrans();
|
||||||
|
}
|
||||||
|
}catch (\Exception $e){
|
||||||
|
if($trans){
|
||||||
|
self::rollbackTrans();
|
||||||
|
}
|
||||||
|
throw new \Exception($e->getMessage());
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function paySetData($order,$notify=[]){
|
||||||
|
//订单支付更新
|
||||||
|
$order = self::updatePay($order,$notify);
|
||||||
|
//生成订单一维码和二维码
|
||||||
|
$order = self::buildCode($order);
|
||||||
|
//记录订单日志
|
||||||
|
OrderLog::log($order['id'],"课程订单支付成功,核销码生成,可以正常约课",'user',$order['user_id']);
|
||||||
|
//调用支付成功事件
|
||||||
|
$data = ['order' => $order];
|
||||||
|
\think\Hook::listen('classes_order_payed_after', $data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function updatePay($order,$notify=[]){
|
||||||
|
if(is_string($order)||is_numeric($order))$order = self::getNopayOrder($order);
|
||||||
|
$order->status ='3';
|
||||||
|
$order->paytime = time();
|
||||||
|
$order->pay_no = $notify['transaction_id'] ?? null;
|
||||||
|
$order->pay_json = $notify['payment_json'] ?? '{}';
|
||||||
|
$order->pay_type = $notify['pay_type'] ?? 'yue';
|
||||||
|
//如果订单创建时间大于预约时间,则等于预约时间
|
||||||
|
if($order['createtime']>$order['starttime'])$order['createtime'] = $order['starttime'];
|
||||||
|
switch ($order->pay_type) {
|
||||||
|
case "offline": //线下付款,线上不需要支付
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$order->payprice = $notify['pay_fee'] ?? $order->totalprice;
|
||||||
|
}
|
||||||
|
$order->platform = $notify['platform'] ?? 'miniapp';
|
||||||
|
$order->save();
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function buildCode($order){
|
||||||
|
if(is_string($order)||is_numeric($order))$order = self::getNopayOrder($order);
|
||||||
|
//生成核销二维码和一维码
|
||||||
|
//生成code
|
||||||
|
$vcode = en_code($order['id']). Random::alnum();
|
||||||
|
$order['code'] = $vcode;
|
||||||
|
$params = [
|
||||||
|
"type"=>"classes_verification",
|
||||||
|
"vcode" =>$vcode,
|
||||||
|
"id"=>$order['classes_lib_id'],
|
||||||
|
];
|
||||||
|
//$params生成get参数
|
||||||
|
$params = http_build_query($params);
|
||||||
|
//生成二维码和一维码
|
||||||
|
//二维码
|
||||||
|
$order->codeimage = Common::getQrcode([
|
||||||
|
'text' => $params,
|
||||||
|
'size' => 200,
|
||||||
|
]);
|
||||||
|
//一维码
|
||||||
|
$order->codeoneimage = Common::getBarcode([
|
||||||
|
'text' => $params,
|
||||||
|
'size' => 200,
|
||||||
|
]);
|
||||||
|
$order->save();
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace app\common\model\school\classes\order;
|
namespace app\common\model\school\classes\order;
|
||||||
|
|
||||||
|
use app\common\model\dyqc\ManystoreShop;
|
||||||
use think\Model;
|
use think\Model;
|
||||||
use traits\model\SoftDelete;
|
use traits\model\SoftDelete;
|
||||||
|
|
||||||
|
@ -74,9 +75,9 @@ class OrderDetail extends Model
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function order()
|
public function classorder()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\school\classes\Order', 'classes_order_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo(Order::class, 'classes_order_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ class OrderDetail extends Model
|
||||||
|
|
||||||
public function shop()
|
public function shop()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\manystore\Shop', 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo(ManystoreShop::class, 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,4 +97,9 @@ class OrderDetail extends Model
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function teacher()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('app\common\model\school\classes\Teacher', 'teacher_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,4 +92,49 @@ class OrderLog extends Model
|
||||||
{
|
{
|
||||||
return $this->belongsTo('app\admin\model\school\classes\Order', 'classes_order_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
return $this->belongsTo('app\admin\model\school\classes\Order', 'classes_order_id', 'id', [], 'LEFT')->setEagerlyType(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**记录订单日志
|
||||||
|
* @param $params
|
||||||
|
* @param bool $trans
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public static function log($order,$mark='更新订单状态',$oper_type='user',$oper_id = 0,$trans=false){
|
||||||
|
if(is_numeric($order))$order = Order::where('order_no|id|pay_no',$order)->find();
|
||||||
|
if(!$order)throw new \Exception("找不到订单");
|
||||||
|
//操作人信息(可扩展)
|
||||||
|
$data = [
|
||||||
|
'oper_type'=>$oper_type ?: 'user',
|
||||||
|
'oper_id'=>$oper_id ?: $order['user_id'],
|
||||||
|
'remark'=>$mark,
|
||||||
|
];
|
||||||
|
//判断逻辑
|
||||||
|
if($trans){
|
||||||
|
self::beginTrans();
|
||||||
|
}
|
||||||
|
$res = true;
|
||||||
|
try{
|
||||||
|
//事务逻辑
|
||||||
|
$log_data = $order->toArray();
|
||||||
|
$log_data["classes_order_id"] = $order['id'];
|
||||||
|
unset($log_data['id']);
|
||||||
|
unset($log_data['createtime']);
|
||||||
|
if($mark)$log_data['log_text'] = $mark;
|
||||||
|
$log = (new self);
|
||||||
|
$log->allowField(true)->save($log_data);
|
||||||
|
if($trans){
|
||||||
|
self::commitTrans();
|
||||||
|
}
|
||||||
|
}catch (\Exception $e){
|
||||||
|
if($trans){
|
||||||
|
self::rollbackTrans();
|
||||||
|
}
|
||||||
|
throw new \Exception($e->getMessage());
|
||||||
|
}
|
||||||
|
return $log;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue