DiverseYouthNightSchool/application/common/model/school/classes/activity/order/Order.php

1960 lines
69 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\common\model\school\classes\activity\order;
use addons\epay\library\Service;
use app\admin\model\Admin;
use app\admin\model\manystore\Shop;
use app\common\model\BaseModel;
use app\common\model\dyqc\ManystoreShop;
use app\common\model\school\classes\activity\Activity;
use app\common\model\school\classes\activity\ActivityItem;
use app\common\model\school\classes\ClassesLib;
use app\common\model\school\classes\ClassesSpec;
use app\common\model\school\classes\order\ServiceOrder;
use app\common\model\User;
use app\manystore\model\Manystore;
use bw\Common;
use fast\Random;
use think\Cache;
use think\Model;
use traits\model\SoftDelete;
use Yansongda\Pay\Pay;
class Order extends BaseModel
{
use SoftDelete;
// 表名
protected $name = 'school_classes_activity_order';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = 'deletetime';
// 追加属性
protected $append = [
'pay_type_text',
'status_text',
'before_status_text',
'server_status_text',
'canceltime_text',
'paytime_text',
'auth_time_text',
'reservation_time_text',
'finishtime_text',
'refundtime_text',
'auth_status_text'
];
public function getPayTypeList()
{
return ['yue' => __('Pay_type yue'), 'wechat' => __('Pay_type wechat')];
}
public function getStatusList()
{
return ['-3' => __('Status -3'), '0' => __('Status 0'), '2' => __('Status 2'), '3' => __('Status 3'), '4' => __('Status 4'), '5' => __('Status 5'), '6' => __('Status 6'), '9' => __('Status 9')];
}
public function getBeforeStatusList()
{
return ['-3' => __('Before_status -3'), '0' => __('Before_status 0'), '2' => __('Before_status 2'), '3' => __('Before_status 3'), '4' => __('Before_status 4'), '6' => __('Before_status 6'), '9' => __('Before_status 9')];
}
public function getServerStatusList()
{
return ['0' => __('Server_status 0'), '3' => __('Server_status 3'), '6' => __('Server_status 6')];
}
public function getAuthStatusList()
{
return ['0' => __('Auth_status 0'), '1' => __('Auth_status 1'), '2' => __('Auth_status 2')];
}
public function getPayTypeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['pay_type']) ? $data['pay_type'] : '');
$list = $this->getPayTypeList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getBeforeStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['before_status']) ? $data['before_status'] : '');
$list = $this->getBeforeStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getServerStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['server_status']) ? $data['server_status'] : '');
$list = $this->getServerStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public function getCanceltimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['canceltime']) ? $data['canceltime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getPaytimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['paytime']) ? $data['paytime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getAuthTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['auth_time']) ? $data['auth_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getReservationTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['reservation_time']) ? $data['reservation_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getFinishtimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['finishtime']) ? $data['finishtime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getRefundtimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['refundtime']) ? $data['refundtime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getAuthStatusTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['auth_status']) ? $data['auth_status'] : '');
$list = $this->getAuthStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
protected function setCanceltimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setPaytimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setAuthTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setReservationTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setFinishtimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setRefundtimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
public function getCodeimageAttr($value, $data)
{
if (!empty($value)) return cdnurl($value, true);
}
public function getCodeoneimageAttr($value, $data)
{
if (!empty($value)) return cdnurl($value, true);
}
public function user()
{
return $this->belongsTo('app\admin\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function manystore()
{
return $this->belongsTo(Manystore::class, 'manystore_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function shop()
{
return $this->belongsTo(ManystoreShop::class, 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function activity()
{
return $this->belongsTo(Activity::class, 'classes_activity_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function detail()
{
return $this->belongsTo(OrderDetail::class, 'activity_order_detail_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function orderitem()
{
return $this->belongsTo(OrderItem::class, 'activity_order_item_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
//统计并更新活动数等相关统计数据
public static function statisticsAndUpdateClassesNumber($order){
if(is_string($order)||is_numeric($order))$order = self::getOrder($order);
$detail = $order->detail;
if(!$detail)throw new \think\Exception("订单信息缺失!");
// //得到当前订单的所有未取消课时订单
// $hourorderOrderCount = \app\common\model\school\classes\activity\order\Order::where("status","<>",'-3')
// ->where("classes_order_id","=",$order["id"])
// ->count();
// //更新已用课程数和剩余课程数
// $detail->use_num = $hourorderOrderCount;
// $detail->sub_num = $detail->classes_num - $detail->use_num;
// //更新已用课程金额和剩余课程金额
//// $detail->used_price = bcmul($detail->unit_price , $detail->use_num,2);
// $detail->save();
// //得到所有售后单的已退金额
// $order->real_refundprice = ServiceOrder::where("classes_order_id" , $order["id"])->where("status","in",['7'])->where("sales_type","in",['10'])->sum("real_refundprice");
// //实际付款额 - 已退金额 = 剩余未退
// //更新剩余未退
// $order->sub_refundprice = bcsub($order->payprice,$order->real_refundprice,2);
// //更新订单应退金额
// $order->total_refundprice = bcsub($order->totalprice,$detail->used_price,2);
// $order->save();
//课程下单时已核销人数更新
$lib = $order->activity;
if($lib){
}
//将课程信息和课时信息同步到所有已下单的订单信息中
Activity::update_classes($order["classes_activity_id"]);
//如果有评价执行评价更新
return $order;
}
/**得到基础条件
* @param $status
* @param null $model
* @param string $alisa
*/
public static function getBaseWhere($whereData = [], $model = null, $alisa = '',$with = false)
{
if (!$model) {
$model = new static;
if ($alisa&&!$with) $model = $model->alias($alisa);
}
if ($alisa) $alisa = $alisa . '.';
$tableFields = (new static)->getTableFields();
foreach ($tableFields as $fields)
{
if(in_array($fields, ['status',"auth_status",'classes_activity_id']))continue;
// if (isset($whereData[$fields]) && $whereData[$fields]) $model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
if (isset($whereData[$fields]) && $whereData[$fields]){
if(is_array($whereData[$fields])){
$model = $model->where("{$alisa}{$fields}", $whereData[$fields][0], $whereData[$fields][1]);
}else{
$model = $model->where("{$alisa}{$fields}", '=', $whereData[$fields]);
}
}
}
if (isset($whereData['status'])) $model = $model->where("{$alisa}status", 'in', $whereData['status']);
if (isset($whereData['not_status'])) $model = $model->where("{$alisa}status", 'not in', $whereData['not_status']);
if (isset($whereData['auth_status']) && $whereData['auth_status']!=="") $model = $model->where("{$alisa}auth_status", 'in', $whereData['auth_status']);
if (isset($whereData['not_auth_status'])&& $whereData['not_auth_status']!=="") $model = $model->where("{$alisa}auth_status", 'not in', $whereData['not_auth_status']);
if (isset($whereData['keywords'])&&$whereData['keywords']) $model = $model->where("{$alisa}order_no|{$alisa}pay_no|{$alisa}code", '=', $whereData['keywords']);
if (isset($whereData['time'])&&$whereData['time']){
$model = $model->time(["{$alisa}createtime",$whereData['time']]);
}
if (isset($whereData['user_id']) && $whereData['user_id']) $model = $model->where("{$alisa}user_id", '=', $whereData['user_id']);
if (isset($whereData['classes_activity_ids']) && $whereData['classes_activity_ids']) $model = $model->where("{$alisa}classes_activity_id", 'in', $whereData['classes_activity_ids']);
if (isset($whereData['classes_activity_id']) && $whereData['classes_activity_id']) $model = $model->where("{$alisa}classes_activity_id", 'in', $whereData['classes_activity_id']);
// if (isset($whereData['has_evaluate'])&&$whereData['has_evaluate']){
// //1查已评价 2查未评价
// if($whereData['has_evaluate'] == 1){
// //1查已评价
// $model = $model->where("{$alisa}classes_evaluate_id", '<>', 0);
// }else{
// //2查未评价
// $model = $model->whereExists(function ($query) use ($alisa) {
// $order_table_name = (new \app\common\model\school\classes\hourorder\Order())->getQuery()->getTable();
// $query->table($order_table_name)->where($order_table_name . '.classes_order_id=' . $alisa . 'id')->where('status', '=', '3');
// })->where("{$alisa}classes_evaluate_id", '=', 0);
//
// }
// }
return $model;
}
public static function allList($user_id,$page, $limit,$keywords,$status,$classes_activity_id=[],$has_evaluate=0,$auth_status=""){
$with_field = [
'user'=>['nickname','mobile','avatar','realname'],
'base'=>['*'],
'shop'=>['name','logo','image'],
'detail'=>['*'],
'orderitem'=>['*'],
];
$CANCEL = '-3';
$NOPAY = '0';
$PAYED = '2';
$RESERV = '3';
$REFUND = '6';
$FINISH = '9';
$IN_SERVICE = '4';
$IN_REFUND = '5';
$alisa = (new self)->getWithAlisaName();
$sort = "field({$alisa}.status,'{$NOPAY}','{$PAYED}','{$RESERV}','{$FINISH}','{$REFUND}','{$IN_SERVICE}','{$CANCEL}' ,'{$IN_REFUND}') asc,{$alisa}.id desc";
$serch_where = ['status'=>$status,'user_id'=>$user_id,'keywords'=>$keywords,"classes_activity_id"=>$classes_activity_id,"has_evaluate"=>$has_evaluate,"auth_status"=>$auth_status];
// if($type)$serch_where['type'] = $type;
return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
}
public static function baseCount($where = []){
$CANCEL = '-3';
$NOPAY = '0';
$PAYED = '2';
$RESERV = '3';
$REFUND = '6';
$FINISH = '9';
$IN_SERVICE = '4';
$IN_REFUND = '5';
$cancel_number = self::getBaseWhere(array_merge(['status'=>$CANCEL],$where))->count();
$nopay_number = self::getBaseWhere(array_merge(['status'=>$NOPAY],$where))->count();
$payed_number = self::getBaseWhere(array_merge(['status'=>$PAYED],$where))->count();
$reserv_number = self::getBaseWhere(array_merge(['status'=>$RESERV],$where))->count();
$retund_number = self::getBaseWhere(array_merge(['status'=>$REFUND],$where))->count();
$in_retund_number = self::getBaseWhere(array_merge(['status'=>$IN_REFUND],$where))->count();
$finish_number = self::getBaseWhere(array_merge(['status'=>$FINISH],$where))->count();
$in_service_number = self::getBaseWhere(array_merge(['status'=>$IN_SERVICE],$where))->count();
return compact('cancel_number','nopay_number','payed_number','in_service_number','retund_number','in_retund_number','finish_number','reserv_number');
}
/**订单数量统计
* @param int $user_id
* @return array
*/
public static function orderCount($user_id = 0,$classes_activity_id=[]){
return self::baseCount(['user_id'=>$user_id,"classes_activity_id"=>$classes_activity_id]);
}
public static function workList($user_id,$page, $limit,$keywords,$status,$classes_activity_id=[],$classes_activity_ids=[],$has_evaluate=0,$auth_status=""){
if(!$classes_activity_ids) $classes_activity_ids = [-5];
$with_field = [
'user'=>['nickname','mobile','avatar','realname'],
'base'=>['*'],
'shop'=>['name','logo','image'],
'detail'=>['*'],
'orderitem'=>['*'],
];
$CANCEL = '-3';
$NOPAY = '0';
$PAYED = '2';
$RESERV = '3';
$REFUND = '6';
$FINISH = '9';
$IN_SERVICE = '4';
$IN_REFUND = '5';
$alisa = (new self)->getWithAlisaName();
$sort = "field({$alisa}.status,'{$NOPAY}','{$PAYED}','{$RESERV}','{$FINISH}','{$REFUND}','{$IN_SERVICE}','{$CANCEL}','{$IN_REFUND}') asc,{$alisa}.id desc";
$serch_where = ['status'=>$status,'keywords'=>$keywords,"classes_activity_id"=>$classes_activity_id,"classes_activity_ids"=>$classes_activity_ids,"auth_status"=>$auth_status];
// if($type)$serch_where['type'] = $type;
return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
}
/**订单数量统计
* @param int $user_id
* @return array
*/
public static function workCount($classes_activity_id=[],$classes_activity_ids=[]){
if(!$classes_activity_ids) $classes_activity_ids = [-5];
return self::baseCount(["classes_activity_id"=>$classes_activity_id,"classes_activity_ids"=>$classes_activity_ids]);
}
/**得到订单详情
* @param $order_no
*/
public static function getDetail($order_no,$classes_activity_id = []){
$model = self::where('order_no|id|pay_no|code',$order_no);
if($classes_activity_id)$model = $model->where("classes_activity_id","in",$classes_activity_id);
$data = $model->find();
if(!$data) return $data;
//加载订单详情
$data->detail;
//订单用户
// $data->user;
$data->user->visible(['id','nickname','mobile','avatar','realname']);
//订单机构
$data->shop;
//规格信息
$data->orderitem;
//售后单信息
// $data->serviceorder;
// //得到二维码
// $data->code_url = Common::getQrcode([
// 'text' => $data['code'],
// 'size' => 200,
// ]);
// $data->one_code_url = Common::getBarcode([
// 'text' => $data['code'],
// 'size' => 200,
// ]);
//评价
// $data->evaluate;
return $data;
}
/**展示订单信息
* @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
* @return array|false|\PDOStatement|string|Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function getOrder($order_no){
$order = self::where('order_no|id|pay_no|code',$order_no)->find();
if(!$order)throw new \Exception("订单不存在");
return $order;
}
/**
* 设置订单缓存
* @param $uid
* @param $data
* @return bool
*/
public static function setOrderCache($uid, $data)
{
//缓存名 = uid + order_no
$cacheNmae = 'classes_activity_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_activity_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_activity_order_cache' . $uid . $order_no;
// 缓存在3600秒之后过期
return Cache::rm($cacheNmae);
}
//计算订单所需返回数据接口
public static function getCost($user_id,$classes_activity_id,$classes_activity_item_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"],
];
//课程
$activity_info = Activity::get($classes_activity_id);
$activity_info = $activity_info->toArray();
$activity_info["classes_activity_id"] = $classes_activity_id;
$activity_info["classes_activity_order_id"] = 0;
// $activity_info['use_num'] = 0;//已使用课时
// $activity_info['sub_num'] = $activity_info['classes_num'];//剩余课时
// //单价 = 课程价格/总课时
// $activity_info["unit_price"] = bcdiv($activity_info['price'],$activity_info['classes_num'],2);
// $activity_info["used_price"] = 0;
//组装订单下单数据
$order_data = [];
$order_data["user_id"] = $user_id;
$order_data["manystore_id"] = $activity_info["manystore_id"];
$order_data["shop_id"] = $activity_info["shop_id"];
$order_data["classes_activity_id"] = $classes_activity_id;
$order_data["activity_order_detail_id"] = 0;
$order_data["classes_activity_item_id"] = $classes_activity_item_id;
$order_data["beforeprice"] = $activity_info["price"];
$order_data["totalprice"] = $activity_info["price"];
$order_data["payprice"] = 0;
$order_data["status"] = '0';
$order_type = "multiple";
//如果课程只存在一个规格,则订单类型为单课
$classes_spec_count = ActivityItem::where('classes_activity_id',$classes_activity_id)->count();
if($classes_spec_count==1){
$order_type = "single";
}
$classes_activity_item = null;
if($classes_activity_item_id){
$classes_activity_item = ActivityItem::get($classes_activity_item_id);
$order_data["beforeprice"] = $classes_activity_item["price"];
$order_data["totalprice"] = $classes_activity_item["price"];
}
return compact('order_data','activity_info','user_data','order_type',"classes_activity_item");
}
/** 订单确认(订单计算)
* @param $user_id 下单用户
* @param $order_no 订单号(缓存标识)
* @param $classes_activity_id 課程活动id
* @param $classes_activity_item_id 課程活动规格id
* @param $param 額外参数(扩展用)
* @param bool $is_compute 是否重新计算订单
* @return array
*/
public function confirm($user_id, $classes_activity_id,$classes_activity_item_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_activity_id,$classes_activity_item_id,$order_no, $param);
//订单支付信息
$price_info = $this->getCost($user_id,$classes_activity_id,$classes_activity_item_id,$param);
//生成订单号
if (!$order_no) $order_no = get_order_sn();
//生成缓存
$data = compact('user_id', 'classes_activity_id','classes_activity_item_id','param', 'order_no', 'price_info');
self::setOrderCache($user_id, $data);
}
\think\Hook::listen('classes_activity_order_create_before', $data);
//下单数据展示
return $this->showInfo($order_no, $price_info);
}
/**订单校验
* @param $user_id 用户id
* @param $classes_lib_id 课程id
* @param $order_no 订单号
* @param $param 表单扩展参数
* @return bool
*/
public function orderVaild($user_id,$classes_activity_id,$classes_activity_item_id, $order_no, $param,$check=false){
if(!$user_id||!$classes_activity_id )throw new \Exception("缺少必要参数");
//校验订单参数
//课程活动是否存在并上架
$classes_lib_info = Activity::where('id',$classes_activity_id)->find();
if(!$classes_lib_info || $classes_lib_info['status']!='1') throw new \Exception("该活动不存在或已下架!");
//往期课程活动无法下单
$now_time = time();
if($classes_lib_info['end_time'] <= $now_time) throw new \Exception("该活动已过期,是往期活动,无法购买!");
//当前时间不在改报名时间段sign_start_time 和 sign_end_time 内则无法购买
if($classes_lib_info['sign_start_time'] > $now_time || $classes_lib_info['sign_end_time'] < $now_time) throw new \Exception("不在活动报名时间范围内,无法购买!");
//默认校验订单是否已创建
if($check){
//判断订单是否已创建
$order_info = self::where(['order_no'=>$order_no])->find();
if($order_info) throw new \Exception("订单已生成,如需重新下单请退出页面重新进入!");
//下单必须传规格id
if(!$classes_activity_item_id) throw new \Exception("请选择活动规格!");
//判断数量是否超出库存
$classes_lib_info = Activity::update_classes($classes_activity_id);
$sale = Order::where("classes_activity_id",$classes_activity_id)->where("status","<>","-3")->count();
if($sale >= $classes_lib_info['stock']) throw new \Exception("该活动已满人,无法参与!");
}
//执行免费课黑名单判断
//免费课才进行判断
// if($classes_lib_info && $classes_lib_info['feel']=='1'){
// \app\common\model\school\classes\hourorder\Order::checkBlackList($user_id,true);
// }
// //免费课才进行判断(同個免費單只能买一次)
// if($classes_lib_info && $classes_lib_info['feel']=='1'){
// \app\common\model\school\classes\hourorder\Order::checkOnlyone($user_id,$classes_lib_info,true);
// }
//用户存不存在
$user_info = User::where('id',$user_id)->find();
if(!$user_info) throw new \Exception("用户不存在!");
if($classes_activity_item_id){
//没有订单id无法判断
// //记录代下单人信息
// $param = [
// "type" =>'2',
// "help_user_id" =>$user_id,
// "help_type" =>'admin',
// "classes_lib_id" =>$classes_lib_id
// ];
//
//
// //确认订单
// $res = (new \app\common\model\school\classes\hourorder\Order)->confirm($user_id,0,null, $classes_lib_spec_id,$param, true);
//只简单判断课程和课时 记得判断库存
self::checkLibSpec($user_id,$classes_activity_id ,$classes_activity_item_id,true,$order=null,$check);
}
return true;
}
/** 课时信息选择合法检测
* @param $user_id 下单用户
* @param $classes_activity_id 活动id
* @param $classes_activity_item_id 活动规格id
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function checkLibSpec($user_id,$classes_activity_id ,$classes_activity_item_id,$add=false,$order=null,$check=false){
if(!$classes_activity_id || !$classes_activity_item_id)throw new \Exception("缺少必要信息!");
$classes_lib_spec_info = ActivityItem::where('id',$classes_activity_item_id)
->where('classes_activity_id',$classes_activity_id)
->find();
if(!$classes_lib_spec_info)throw new \Exception("规格信息不正确!");
//课时已下架
if($classes_lib_spec_info['status']!='1') throw new \Exception("该规格已下架,请选择其他规格!");
//存在同规格正在进行中的课时预约
$order_info = self::where('classes_activity_item_id',$classes_activity_item_id)
->where('status',"not in",["-3","5","6"])
->where('user_id',$user_id)
->find();
if($order_info && $check) throw new \Exception("该活动规格已预约或已上过,请勿重复预约!");
//新增或更换课时时判断
//是否达成限制人数
//允许人数为0说明不限制
if($classes_lib_spec_info['limit_num'] > 0 && $check){
//得到当前课时已参与人数
$sign_num = self::where('classes_activity_item_id',$classes_activity_item_id)->where("status","not in",["-3","5","6"])->count();
if($sign_num >= $classes_lib_spec_info['limit_num']){
throw new \Exception("该活动已满,请选择其他活动!");
}
if($add){
}else{
}
}
//判断是否是免费课
$lib = $classes_lib_spec_info->activity;
if(!$lib){
throw new \Exception("该课程活动信息缺失!");
}
if($classes_lib_spec_info["feel"] == '1' && $check){
//免费课开始和结束时间有交叠无法下预约
if(!config("site.free_time_activity_check")){
//如果是免费课
//判断时间是否有交叠
$start_time = $lib['start_time'];
$end_time = $lib['end_time'];
$as = (new self)->getWithAlisaName();
//判断时间是否有交叠(只查所有的免费的预约记录)
$order_info = self::with("detail")->where("detail.price",0)
->where("{$as}.status","not in",["-3","5","6","9"])
->where(function ($query) use ($as,$start_time,$end_time) {
//兩個時間區間重合 存在任意交集 都不行
$query->where("detail.start_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("detail.end_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("detail.start_time <= {$start_time} AND detail.end_time >= {$end_time}");
$query->whereOr("detail.start_time >= {$start_time} AND detail.end_time <= {$end_time}");
})
->where("{$as}.user_id",$user_id)->find();
if($order_info) throw new \Exception("当前时间区间内,您已预约免费活动{$order_info['detail']['title']},无法再预约其他免费活动");
}
}
if(!config("site.all_time_activity_check") && $check){
//判断时间是否有交叠
$start_time = $lib['start_time'];
$end_time = $lib['end_time'];
$as = (new self)->getWithAlisaName();
//判断时间是否有交叠(只查所有的免费的预约记录)
$order_info = self::with("detail")
->where("{$as}.status","not in",["-3","5","6","9"])
->where(function ($query) use ($as,$start_time,$end_time) {
//兩個時間區間重合 存在任意交集 都不行
$query->where("detail.start_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("detail.end_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("detail.start_time <= {$start_time} AND detail.end_time >= {$end_time}");
$query->whereOr("detail.start_time >= {$start_time} AND detail.end_time <= {$end_time}");
})
->where("{$as}.user_id",$user_id)->find();
if($order_info) throw new \Exception("当前时间区间内,您已预约活动{$order_info['detail']['title']},无法再预约其他活动");
}
//执行免费课黑名单判断
// //免费课才进行判断
// if($lib && $lib['feel']=='1'){
// self::checkBlackList($user_id,true);
// }
//过期课时无法下单(结束时间小于等于当前时间)
if($lib["end_time"] <= time()){
throw new \Exception("该活动已过期结束,无法预约!");
}
}
/**
* 根据缓存创建订单
*/
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 {
//'classes_activity_id','classes_activity_item_id'
//1订单执行创建
$order = $this->createOrder($user_id,$orderInfo['classes_activity_id'],$orderInfo['classes_activity_item_id'],$order_no,$orderInfo['param'],$remark);
$orderitem = $order->orderitem;
//如果是免费订单,则直接调用支付完成
if ($orderitem['feel'] == '1' || $order['totalprice'] == 0) {
//调用订单支付成功事件
$this->paySuccess($order_no,['platform'=>"miniapp",'pay_type'=>'yue']);
}
//5删除缓存
self::deleteOrderCache($user_id, $order_no);
if ($trans) {
self::commitTrans();
}
} catch (\Exception $e) {
if ($trans) {
self::rollbackTrans();
}
throw new \Exception($e->getMessage().$e->getFile() . $e->getLine());
}
return self::showInfo($order_no);
}
public function createOrder($user_id,$classes_activity_id,$classes_activity_item_id,$order_no,$param,$remark='',$other_params=[]){
$this->orderVaild($user_id,$classes_activity_id,$classes_activity_item_id, $order_no, $param,true);
//订单支付信息
$order_info = self::getCost($user_id,$classes_activity_id,$classes_activity_item_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_activity_item = $order_info["classes_activity_item"];
if(!$classes_activity_item)throw new \Exception('订单未选规格!');
//課程详情
$activity_info = $order_info['activity_info'];
$order_detail_data = [];
$order_detail_data = array_merge($order_detail_data,$activity_info);
$order_detail_data["classes_activity_id"] = $activity_info['id'];
$order_detail_data["classes_activity_order_id"] = $res1['id'];
unset($order_detail_data['id']);
unset($order_detail_data['createtime']);
$orderDetail = (new OrderDetail());
$orderDetail->allowField(true)->save($order_detail_data);
$order_item_data = [];
$order_item_data = array_merge($order_item_data,$classes_activity_item->toArray());
$order_item_data["classes_activity_item_id"] = $classes_activity_item['id'];
$order_item_data["classes_activity_order_id"] = $res1['id'];
unset($order_item_data['id']);
unset($order_item_data['createtime']);
$orderItem = (new OrderItem());
$orderItem->allowField(true)->save($order_item_data);
//更新订单详情id
$res1->activity_order_detail_id = $orderDetail->id;
$res1->activity_order_item_id = $orderItem->id;
$res1->save();
//记录订单日志
OrderLog::log($res1['id'],"活动订单创建成功,等待【学员】支付",'user',$user_id);
//7事件
$data = ['order' => $res1];
\think\Hook::listen('classes_activity_order_create_after', $data);
//更新订单数据
self::statisticsAndUpdateClassesNumber($res1);
return $res1;
}
/**余额支付
* @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);
// //如果需要快捷预约
// $classes_lib_spec_id = $order['classes_lib_spec_id'];
// if($classes_lib_spec_id){
// //记录代下单人信息
// $param = [
// "type" =>'2',
// "help_user_id" =>$order["user_id"] ,
// "help_type" => 'admin',
// ];
//
// //确认订单
// $res = (new \app\common\model\school\classes\hourorder\Order)->confirm($order["user_id"],$order['id'],null, $classes_lib_spec_id,$param, true);
// $remark = "订单支付完成同时快捷预约一个课时";
// //创建订单
// $result = (new \app\common\model\school\classes\hourorder\Order)->cacheCreateOrder($res['order_no'], $order["user_id"],$remark);
//
// }
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
}
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_activity_order_payed_after', $data);
//更新订单数据
self::statisticsAndUpdateClassesNumber($order);
return true;
}
public static function updatePay($order,$notify=[]){
if(is_string($order)||is_numeric($order))$order = self::getNopayOrder($order);
$order->status ='2';
$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->sub_refundprice = $order->payprice; //剩余未退 = 支付金额
$order->save();
return $order;
}
/**得到待支付订单
* @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|code',$order_no)->where("status",'0')->find();
if(!$order)throw new \Exception("待支付订单不存在");
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"=>"activity_verification",
"vcode" =>$vcode,
"order_id"=>$order['id'],
];
//$params生成get参数
$params = http_build_query($params);
//生成二维码和一维码
//二维码
$order->codeimage = (Common::getQrcode([
'text' => $params,
'size' => 200,
]))['url'];
//一维码
$order->codeoneimage = (Common::getBarcode([
'text' => $params,
'size' => 200,
]))['url'];
$order->save();
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通用判
$this->orderVaild($order['user_id'],$order['classes_activity_id'],$order['classes_activity_item_id'],$order['order_no'], []);
//...
$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;
}
/** 课时订单操作权限检测
* @param $order 订单
* @param $oper_id 操作人id
* @param $oper_type 操作人类型user-用户或员工admin-管理员
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function checkOptionAuth($classes_order_id,$oper_id,$oper_type,$only_user=false,$only_shop=false,$only_admin=false){
//课程是否存在并上架
$classesOrder = Order::where("id",$classes_order_id)->find();
if(!$classesOrder)throw new \Exception("订单不存在!");
switch ($oper_type) {
case 'user':
if($only_admin)throw new \Exception("您无权操作该订单!");
//自己或操作员
if($oper_id != $classesOrder["user_id"]){
if($only_user) throw new \Exception("您无权操作该订单!");
$Shop = \app\common\model\manystore\Shop::where("user_id",$oper_id)->find();
if($Shop){
if($Shop["id"] == $classesOrder["shop_id"]){
break;
}
}
//说明是操作员
$help_user_info = User::where('id',$oper_id)->find();
if(!$help_user_info) throw new \Exception("代下单员工不存在!");
$classes_activity_ids = (new Activity())->getActivityAuthIds($oper_id);
//判断当前订单课程是否在此课程授权范围内
if(!in_array($classesOrder["classes_activity_id"],$classes_activity_ids)) throw new \Exception("该活动不在您的授权范围内,无法代操作!");
}else{
$classes_activity_ids = (new Activity())->getActivityAuthIds($oper_id);
//不是员工并且想操作只有机构能操作的单
if(!in_array($classesOrder["classes_activity_id"],$classes_activity_ids) && $only_shop)throw new \Exception("您无权操作该订单!");
}
break;
case 'admin':
$admin_info = Admin::where('id',$oper_id)->find();
if(!$admin_info) throw new \Exception("代下单管理员不存在!");
break;
case 'shop':
if($only_admin)throw new \Exception("您无权操作该订单!");
if($only_user) throw new \Exception("您无权操作该订单!");
$admin_info = Manystore::where('id',$oper_id)->find();
if(!$admin_info) throw new \Exception("代下单管理员不存在!");
$classes_activity_ids = Activity::where("manystore_id",$oper_id)->column("id");
//判断当前订单课程是否在此课程授权范围内
if(!in_array($classesOrder["classes_activity_id"],$classes_activity_ids)) throw new \Exception("该活动不在您的授权范围内,无法代操作!");
break;
default:
throw new \Exception("请选择正确的代下单类型!");
}
}
/**得到可取消订单
* @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 getHaveCancelOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id|pay_no|code',$order_no)->find();
$detail = $order->detail;
$orderitem = $order->orderitem;
if(!$detail) throw new \Exception("订单信息缺失!");
if(!$orderitem) throw new \Exception("订单信息缺失!");
if(!$order)throw new \Exception("只有待支付订单可取消,已支付请走售后申请,已取消请忽略!");
//非免费单进行中无法取消
if($orderitem["feel"] == "0" && $order['status'] != '0'){
throw new \Exception("只有待支付订单可取消,已支付请走售后申请,已取消请忽略!");
}
if(($orderitem["feel"] == "1" || $order['totalprice'] == 0)&& !in_array($order['status'],['0','2','3'])){
throw new \Exception("只有进行中订单可取消,已取消请忽重复取消!");
}
return $order;
}
/**更新订单取消状态
* @param $order
* @return array|false|\PDOStatement|string|Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function updateCancel($order){
if(is_string($order))$order = self::getHaveCancelOrder($order);
$order->status = "-3";//refund_status
$order->canceltime = time();
$order->save();
return $order;
}
/**订单取消
* @param $order_no
* @param int $user_id
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function cancel($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到可取消订单
$order = self::getHaveCancelOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type);
//进行中,用户自己无法操作取消
if(($order['status'] == '2' || $order['status'] == '3' )&& $user_id == $order['user_id']){
throw new \Exception("您无权操作取消!请您联系机构操作!");
}
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新订单取消状态
$order = self::updateCancel($order);
//插入订单取消日志
if(!$user_id ||$order["user_id"] !=$user_id ){
OrderLog::log($order['id'],"[系统操作]课程活动订单取消成功",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
OrderLog::log($order['id'],"课程活动订单取消成功",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['order' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_activity_order_cancel_after', $data);
//执行课时数更新
$res1 = self::statisticsAndUpdateClassesNumber($order['id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
}
return $res1;
}
/**得到可审核订单
* @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 getHaveExamineOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id|pay_no|code',$order_no)->where("status","in",['2'])->find();
if(!$order)throw new \Exception("不是待审核的订单!");
return $order;
}
/**更新订单取消状态
* @param $order
* @return array|false|\PDOStatement|string|Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function updateExamineSuccess($order,$oper_id = 0,$oper_type='user'){
if(is_string($order))$order = self::getHaveExamineOrder($order);
$order->status = "3";//refund_status
$order->auth_status = "1";//refund_status
$order->auth_time = time();
$order->auth_user_id = $oper_id;
$order->auth_type = $oper_type;
$order->save();
return $order;
}
/**更新订单取消状态
* @param $order
* @return array|false|\PDOStatement|string|Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function updateExamineFail($order,$reason,$oper_id = 0,$oper_type='user'){
if(is_string($order))$order = self::getHaveExamineOrder($order);
$order->auth_status = "2";
$order->auth_time = time();
$order->reason = $reason;
$order->auth_user_id = $oper_id;
$order->auth_type = $oper_type;
$order->save();
return $order;
}
/**更新订单结算中状态
* @param $order
* @return array|false|\PDOStatement|string|Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function updateExamineFailSettlement($order,$reason,$oper_id = 0,$oper_type='user'){
if(is_string($order))$order = self::getHaveExamineOrder($order);
$order->status = "5";
$order->auth_status = "2";
$order->auth_time = time();
$order->refundsendtime = time();
$order->reason = $reason;
$order->auth_user_id = $oper_id;
$order->auth_type = $oper_type;
$order->save();
return $order;
}
/**活动订单审核
* @param $order_no
* @param int $user_id
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function examine($order_no,$auth_status,$reason="",$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到可取消订单
$order = self::getHaveExamineOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type);
}
//审核状态字段检测
$auth_status_arr = [1,2];//0=待审核,1=审核通过,2=审核失败
if( !in_array($auth_status,$auth_status_arr)) throw new \Exception("审核状态不正确!");
//审核失败需要传理由
if($auth_status==2 && empty($reason)) throw new \Exception("审核失败需要填写理由!");
//判断逻辑
if($trans){
self::beginTrans();
}
$return = false;
$res = true;
try{
//事务逻辑
//插入订单取消日志
if(!$user_id ||$order["user_id"] !=$user_id ){
$pron = "[员工操作]";
}else{
$pron = "";
}
//审核成功逻辑
if($auth_status == 1){
//更新订单状态
$order = self::updateExamineSuccess($order,$user_id ?: $oper_id,$oper_type);
OrderLog::log($order['id'],$pron."课程活动单审核成功,预约成功等待核销!",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
//调用订单事件
$data = ['order' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_activity_order_auth_success_after', $data);
}else{
$detail = $order->detail;
$orderitem = $order->orderitem;
//如果是免费的订单,直接取消订单
if($orderitem['feel'] == '1' || $order['payprice'] <= 0){
//更新订单状态
$order = self::updateExamineFail($order,$reason,$user_id ?: $oper_id,$oper_type);
//审核失败逻辑
OrderLog::log($order['id'],$pron."课程活动单审核不通过,原因;{$reason},该活动单将取消",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
//调用订单事件
$data = ['order' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_activity_order_auth_fail_after', $data);
//执行订单取消逻辑
$this->cancel($order_no,$user_id,false,$oper_type,$oper_id);
}else{
//调用退款发起
//更新订单状态
$order = self::updateExamineFailSettlement($order['order_no'],$reason,$user_id ?: $oper_id,$oper_type);
//审核失败逻辑
OrderLog::log($order['id'],$pron."课程活动单审核不通过,原因;{$reason},该活动单将自动退款以便重新下单",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
//调用订单事件
$data = ['order' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_activity_order_auth_fail_after', $data);
$return = true;
// throw new \Exception("测试错误!".$order["status"]);
// self::orderRefund($order['order_no'],$order['sub_refundprice'],$oper_type,$oper_id,$trans=false,$admin=false);
}
}
//执行课时数更新
// $res1 = \app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Throwable $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
}
if($return)self::orderRefund($order['order_no'],$order['sub_refundprice'],$oper_type,$oper_id,$trans=false,$admin=false);
return $order;
}
/**预约订单退款(退全款)
* @param $order
* @param $refund_money
* @param $trans
*/
public static function orderRefund($order,$refund_money,$oper_type='user',$oper_id=0,$trans=false,$admin=false){
if(is_numeric($order))$order = self::getHaveRefundOrder($order);
if(!$order)throw new \Exception("找不到订单");
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//生成退款单号
if(!$order['refund_no']){
$order['refund_no'] = get_order_sn();
$order->save();
}
if(!$refund_money)$refund_money = $order['sub_refundprice'];
if($refund_money<=0)$refund_money = 0;
if(!$refund_money)throw new \Exception("退款金额异常!");
//事务逻辑
switch ($order['pay_type']) {
case "wechat": //微信退款
self::wechatRefund($order,$refund_money,$oper_type,$oper_id);
break;
// case "alipay": //支付宝退款
// self::alipayRefund($order,$refund_money,$oper_type,$oper_id);
// break;
// case "wallet": //钱包支付退款
// self::walletRefund($order,$refund_money,$oper_type,$oper_id);
// break;
// case "offline": //线下支付退款
//
// break;
default:
throw new \Exception("订单币种异常!");
}
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res;
}
/**微信退款
* @param $order
* @param $refund_money
*/
public static function wechatRefund($order,$refund_money,$refund_desc="",$oper_type='user',$oper_id=0,$trans=false){
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//创建订单退款订单
$classesorder = $order;
$detail = $order->detail;
//执行微信退款sdk
$order_data = [
'out_trade_no' => $classesorder->order_no
];
$total_fee = $classesorder->payprice * 100;
$refund_fee = $refund_money * 100;
$order_data = array_merge($order_data, [
'out_refund_no' => $order->refund_no,
'total_fee' => $total_fee,
'refund_fee' => $refund_fee,
'refund_desc' => $refund_desc ?: "活动[{$detail["title"]}]订单[ID:{$classesorder['id']}]退款{$refund_money}已到账户",
]);
$config = Service::getConfig('wechat',[],$classesorder->platform);
$notify_url = request()->domain() . '/api/school.activity.pay/notifyr/payment/' . $classesorder->pay_type . '/platform/' . $classesorder->platform;
$config['notify_url'] = $notify_url;
$pay = Pay::wechat($config);
// throw new \Exception($trans."111测试错误".$order["status"]);
$result = $pay->refund($order_data);
\think\Log::write('refund-result' . json_encode($result));
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
$res = true;
} else {
throw new \Exception($result['return_msg']);
}
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
}
return $res;
}
/**得到可直接退款订单(正常取消退全款非售后)
* @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 getHaveRefundOrder($refund_sn){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('refund_no|order_no|id',$refund_sn)->where('status','5')->where("sub_refundprice",">",0)->find();
if(!$order)throw new \Exception("不是可直接退款的订单!");
return $order;
}
/**同意并发放退款金额
* @param $order 退款单号
* @return array|false|\PDOStatement|string|Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function updateRefundOrder($order,$pay_json=[]){
if(is_string($order))$order = self::getHaveRefundOrder($order);
$order->before_status = $order->status;//refund_status
$order->status = "6";
$order->server_status = "6";
$order->real_refundprice = bcadd($order->real_refundprice ?:'0',$order->sub_refundprice ,2);
$order->sub_refundprice = 0;
$order->refundtime = time();
$order->refund_json = json_encode($pay_json);
$order->save();
return $order;
}
/**退款成功处理逻辑(需修改)
* @param $refund_sn
* @param bool $trans
* @return bool
* @throws \Exception
*/
public static function refundSuccess($refund_sn,$refund_json=[],$trans=false){
//得到机构售后提交确认订单
$order = self::getHaveRefundOrder($refund_sn);
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新订单状态为同意
$order = self::updateRefundOrder($refund_sn,$refund_json);
//插入订单日志
OrderLog::log($order['id'],"活动订单退全款已原路退回", 'admin', 0);
//执行课时数更新
$res1 = self::statisticsAndUpdateClassesNumber($order['id']);
//调用订单取消事件
$data = ['order' => $order,"user_id"=>$order['user_id'],"oper_type"=>'admin',"oper_id"=>0];
\think\Hook::listen('classes_activity_order_refund_success_after', $data);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res;
}
/**订单退款失败记录
* @param $order
* @param $refund_money
* @param $trans
*/
public static function orderRefundFail($order,$msg,$oper_type='user',$oper_id=0,$trans=false,$admin=false){
if(is_numeric($order))$order = self::getOrder($order);
if(!$order)throw new \Exception("找不到订单");
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
$order->refund_error = $msg;
$order->save();
//插入订单日志
OrderLog::log($order['id'],"活动订单退款失败:".$msg, $oper_type, $oper_id);
//调用订单取消事件
$data = ['order' => $order,"user_id"=>$order['user_id'],"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_activity_order_refund_fail_after', $data);
if($trans){
self::commitTrans();
}
}catch (\Throwable $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res;
}
/**更新订单核销状态
* @param $order
* @return array|false|\PDOStatement|string|Model
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function updateVerification($order,$oper_id = 0,$oper_type='user'){
if(is_string($order))$order = self::getHaveVerificationOrder($order);
$order->status = "9";//refund_status
$order->verification_user_id = $oper_id;
$order->verification_type = $oper_type;
$order->finishtime = time();
$order->save();
return $order;
}
/**得到可核销订单
* @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 getHaveVerificationOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id|code',$order_no)->where("status","in",["3"])->find();
if(!$order)throw new \Exception("不是待核销的订单!");
return $order;
}
/**订单核销
* @param $order_no
* @param int $user_id
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function verification($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到可取消订单
$order = self::getHaveVerificationOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type);
// self::serverCheck($order['classes_order_id']);
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新订单状态
//如果没有审核,先审核成功再核销
// if($order["status"] == '2'){
// $order = $this->examine($order_no,'1',"",$user_id,$check,$oper_type,$oper_id);
// }
$order = self::updateVerification($order,$user_id ?: $oper_id,$oper_type);
//插入订单取消日志
if(!$user_id ||$order["user_id"] !=$user_id ){
OrderLog::log($order['id'],"[员工操作]活动单核销成功,当前活动已完成",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}else{
OrderLog::log($order['id'],"活动单核销成功,当前活动已完成",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
}
//调用订单取消事件
$data = ['order' => $order,"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
\think\Hook::listen('classes_activity_order_finish_after', $data);
//执行课时数更新
self::statisticsAndUpdateClassesNumber($order['id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res;
}
}