DiverseYouthNightSchool/application/common/model/school/classes/hourorder/Order.php

1322 lines
47 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\hourorder;
use app\admin\model\Admin;
use app\admin\model\school\classes\Blacklist;
use app\common\model\school\classes\ClassesLib;
use app\common\model\school\classes\ClassesSpec;
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 app\common\model\BaseModel;
class Order extends BaseModel
{
use SoftDelete;
// 表名
protected $name = 'school_classes_hour_order';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = 'deletetime';
// 追加属性
protected $append = [
'start_time_text',
'end_time_text',
'status_text',
'reservation_time_text',
'finish_time_text',
'cancel_time_text'
];
protected $order_user_id;
public function getStatusList()
{
return ['-3' => __('Status -3'),'-1' => __('Status -1'), '0' => __('Status 0'), '3' => __('Status 3')];
}
public function getStartTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['start_time']) ? $data['start_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getEndTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['end_time']) ? $data['end_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $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 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['finish_time']) ? $data['finish_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getCancelTimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['cancel_time']) ? $data['cancel_time'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
protected function setStartTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
protected function setEndTimeAttr($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 setCancelTimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
public function classesorder()
{
return $this->belongsTo('app\common\model\school\classes\order\Order', 'classes_order_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function spec()
{
return $this->belongsTo('app\common\model\school\classes\ClassesSpec', 'classes_lib_spec_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function user()
{
return $this->belongsTo('app\common\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function detail()
{
return $this->belongsTo('app\common\model\school\classes\order\OrderDetail', 'classes_order_detail_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
public function lib()
{
return $this->belongsTo(ClassesLib::class, 'classes_lib_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
/**得到基础条件
* @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, ['createtime','start_time','status','classes_lib_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['keywords'])&&$whereData['keywords']) $model = $model->where("{$alisa}order_no|{$alisa}id", '=', $whereData['keywords']);
if (isset($whereData['createtime'])&&$whereData['createtime']){
$model = $model->time(["createtime",$whereData['createtime']]);
}
if (isset($whereData['start_time'])&&$whereData['start_time']){
$model = $model->time(["start_time",$whereData['start_time']]);
}
if (isset($whereData['user_id']) && $whereData['user_id']) $model = $model->where("{$alisa}user_id", '=', $whereData['user_id']);
if (isset($whereData['classes_lib_ids']) && $whereData['classes_lib_ids']) $model = $model->where("{$alisa}classes_lib_id", 'in', $whereData['classes_lib_ids']);
if (isset($whereData['classes_lib_id']) && $whereData['classes_lib_id']) $model = $model->where("{$alisa}classes_lib_id", 'in', $whereData['classes_lib_id']);
return $model;
}
/**展示订单信息
* @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,$classes_lib_id = [],$classes_lib_ids = []){
$model = self::where('order_no|id',$order_no);
if($classes_lib_id)$model = $model->where("classes_lib_id","in",$classes_lib_id);
if($classes_lib_ids)$model = $model->where("classes_lib_id","in",$classes_lib_ids);
$data = $model->find();
if(!$data) return $data;
//加载订单详情
$data->detail->teacher;
//订单用户
$data->user->visible(['id','nickname','mobile','avatar','realname']);
//订单机构
$data->classesorder;
// //得到二维码
// $data->code_url = Common::getQrcode([
// 'text' => $data['code'],
// 'size' => 200,
// ]);
// $data->one_code_url = Common::getBarcode([
// 'text' => $data['code'],
// 'size' => 200,
// ]);
return $data;
}
public static function allList($user_id,$page, $limit,$keywords,$status,$classes_order_id=0,$classes_lib_id = [],$start_time = null,$createtime = null){
$with_field = [
'user'=>['nickname','mobile','avatar','realname'],
'base'=>['*'],
'classesorder'=>['*'],
'detail'=>['*'],
];
$CANCEL = '-3';
$NOAUDIT = '-1';
$HAVE = '0';
$FINISH = '3';
$alisa = (new self)->getWithAlisaName();
$sort = "field({$alisa}.status,'{$NOAUDIT}','{$HAVE}','{$FINISH}','{$CANCEL}') asc,{$alisa}.id desc";
$serch_where = ['status'=>$status,'user_id'=>$user_id,'keywords'=>$keywords,'classes_order_id'=>$classes_order_id,'classes_lib_id'=>$classes_lib_id,"start_time"=>$start_time,"createtime"=>$createtime];
// if($type)$serch_where['type'] = $type;
return (new self)->getBaseList($serch_where, $page, $limit,$sort,$with_field);
}
public static function baseCount($where = []){
$CANCEL = '-3';
$NOAUDIT = '-1';
$HAVE = '0';
$FINISH = '3';
$cancel_number = self::getBaseWhere(array_merge(['status'=>$CANCEL],$where))->count();
$noaudit_number = self::getBaseWhere(array_merge(['status'=>$NOAUDIT],$where))->count();
$have_number = self::getBaseWhere(array_merge(['status'=>$HAVE],$where))->count();
$finish_number = self::getBaseWhere(array_merge(['status'=>$FINISH],$where))->count();
return compact('cancel_number','noaudit_number','have_number','finish_number');
}
/**订单数量统计
* @param int $user_id
* @return array
*/
public static function orderCount($user_id = 0,$classes_order_id=0,$classes_lib_id=[]){
return self::baseCount(['user_id'=>$user_id,'classes_order_id'=>$classes_order_id,"classes_lib_id"=>$classes_lib_id]);
}
public static function workList($page, $limit,$keywords,$status,$classes_order_id=0,$user_id=0,$classes_lib_id = [],$classes_lib_ids = [],$start_time = null,$createtime = null){
$with_field = [
'user'=>['nickname','mobile','avatar','realname'],
'base'=>['*'],
'classesorder'=>['*'],
'detail'=>['*'],
];
$CANCEL = '-3';
$NOAUDIT = '-1';
$HAVE = '0';
$FINISH = '3';
$alisa = (new self)->getWithAlisaName();
$sort = "field({$alisa}.status,'{$NOAUDIT}','{$HAVE}','{$FINISH}','{$CANCEL}') asc,{$alisa}.id desc";
$serch_where = ['status'=>$status,'user_id'=>$user_id,'keywords'=>$keywords,'classes_order_id'=>$classes_order_id,"classes_lib_id"=>$classes_lib_id,"classes_lib_ids"=>$classes_lib_ids,"start_time"=>$start_time,"createtime"=>$createtime];
// 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_lib_id = [],$classes_lib_ids = [],$classes_order_id=0){
return self::baseCount(['classes_lib_id'=>$classes_lib_id,'classes_order_id'=>$classes_order_id,"classes_lib_ids"=>$classes_lib_ids]);
}
/**
* 设置订单缓存
* @param $uid
* @param $data
* @return bool
*/
public static function setOrderCache($uid, $data)
{
//缓存名 = uid + order_no
$cacheNmae = 'classes_hourorder_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_hourorder_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_hourorder_cache' . $uid . $order_no;
// 缓存在3600秒之后过期
return Cache::rm($cacheNmae);
}
/** 订单确认(订单计算)
* @param $user_id 下单用户
* @param $order_no 订单号(缓存标识)
* @param $classes_order_id 課程订单id
* @param $classes_lib_spec_id 課程课时规格id
* @param $param 額外参数(扩展用)
* @param bool $is_compute 是否重新计算订单
* @return array
*/
public function confirm($user_id, $classes_order_id,$order_no,$classes_lib_spec_id=0,$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_order_id,$order_no,$classes_lib_spec_id, $param);
//订单支付信息
$price_info = $this->getCost($user_id,$classes_order_id,$classes_lib_spec_id,$param);
//生成订单号
if (!$order_no) $order_no = get_order_sn();
//生成缓存
$data = compact('user_id', 'classes_order_id','param', 'order_no', 'price_info','classes_lib_spec_id');
self::setOrderCache($user_id, $data);
}
\think\Hook::listen('classeshour_order_create_before', $data);
//下单数据展示
return $this->showInfo($order_no, $price_info);
}
/**订单校验
* @param $user_id 用户id
* @param $classes_order_id 课程订单id
* @param $order_no 订单号
* @param $param 表单扩展参数
* @return bool
*/
public function orderVaild($user_id,$classes_order_id,$order_no,$classes_lib_spec_id, $param,$check=false){
if(!$user_id||!$classes_order_id)throw new \Exception("缺少必要参数");
//代下单检测是否有代下单权限
if(isset($param["help_user_id"]) && $param["help_user_id"]){
if(!isset($param["help_type"]) || !$param["help_type"])throw new \Exception("请选择代下单类型!");
//课程是否存在并上架
$classesOrder = \app\common\model\school\classes\order\Order::where("id",$classes_order_id)->find();
if(!$classesOrder)throw new \Exception("订单不存在!");
//代下单时将下单人修正成课程下单人,不影响后续判断
$user_id = $classesOrder["user_id"];
//用户操作权限检测
self::checkOptionAuth($classes_order_id,$param["help_user_id"],$param["help_type"]);
}
//默认校验订单是否已创建
if($check){
//判断订单是否已创建
$order_info = self::where(['order_no'=>$order_no])->find();
if($order_info) throw new \Exception("订单已生成,如需重新下单请退出页面重新进入!");
if(!$classes_lib_spec_id)throw new \Exception("请选择您要预约的课时信息!");
}
//校验订单参数
//更新最近次数后进行验证
\app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($classes_order_id);
//课程是否存在并上架
$classesOrder = \app\common\model\school\classes\order\Order::where("id",$classes_order_id)
->where("user_id",$user_id)
->find();
if(!$classesOrder){
throw new \Exception("课程不存在!");
}
$detail = $classesOrder->detail;
if(!$detail)throw new \Exception("课程不存在!");
//是否还有次数
if($detail['sub_num']<=0) throw new \Exception("该课程已无剩余课时!");
//不是可用状态
if($classesOrder['status']!="3") throw new \Exception("该课程单当前状态不可操作!");
//售后中
if($classesOrder['server_status']=="3") throw new \Exception("该课程单正在售后中,请勿操作!");
//判断课时信息
if($classes_lib_spec_id){
self::checkLibSpec($user_id,$detail["classes_lib_id"],$classes_lib_spec_id,true);
}
// $classes_lib_info = ClassesLib::where('id',$classesOrder["classes_lib_id"])->find();
// if(!$classes_lib_info || $classes_lib_info['status']!='1') throw new \Exception("该课程不存在或已下架!");
//用户存不存在
$user_info = User::where('id',$user_id)->find();
if(!$user_info) throw new \Exception("用户不存在!");
return true;
}
//计算订单所需返回数据接口
public static function getCost($user_id,$classes_order_id,$classes_lib_spec_id,$param=[],$other_params=[],$check = false){
if(isset($param["help_user_id"]) && $param["help_user_id"]){
//课程是否存在并上架
$classesOrder = \app\common\model\school\classes\order\Order::where("id",$classes_order_id)->find();
if(!$classesOrder)throw new \Exception("订单不存在!");
//代下单时将下单人修正成课程下单人,不影响后续判断
$user_id = $classesOrder["user_id"];
}
//校验订单参数
//课程是否存在并上架
$classesOrder = \app\common\model\school\classes\order\Order::where("id",$classes_order_id)
->where("user_id",$user_id)
->find();
$detail = $classesOrder->detail;
$classes_lib_info = $detail;
$classes_lib_spec_info = null;
//判断课时信息
if($classes_lib_spec_id){
$classes_lib_spec_info = ClassesSpec::where('id',$classes_lib_spec_id)
->where('classes_lib_id',$detail["classes_lib_id"])
->find();
if($classes_lib_spec_info){
$classes_lib_spec_info = $classes_lib_spec_info->toArray();
}
}
//用户
$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"],
];
//组装订单下单数据
$order_data = [];
$order_data["user_id"] = $user_id;
$order_data["classes_order_id"] = $classes_order_id;
$order_data["classes_lib_spec_id"] = $classes_lib_spec_id;
$order_data["classes_order_detail_id"] = $detail["id"];
$order_data["classes_lib_id"] = $detail["classes_lib_id"];
$order_data["manystore_id"] = $detail["manystore_id"];
$order_data["shop_id"] = $detail["shop_id"];
$order_data["status"] = '-1';
$order_data["verification_user_id"] = 0;
$order_data["reservation_time"] = time();
$order_data["type"] = $param["type"] ?? '1';
$order_data["help_user_id"] = $param["help_user_id"] ?? 0;
$order_data["help_type"] = $param["help_type"] ?? null;
$order_data["reason"] = '';
$order_data["auth_status"] = '0';
return compact('order_data','classes_lib_info','user_data','classes_lib_spec_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订单执行创建
$order = $this->createOrder($user_id,$orderInfo['classes_order_id'],$orderInfo['classes_lib_spec_id'],$order_no,$orderInfo['param'],$remark);
//5删除缓存
self::deleteOrderCache($user_id, $order_no);
// var_dump($order["type"]);
//代下单直接执行审核成功的预约中状态
if($order["type"] == '2'){
//兼容代下单逻辑,修正下单人信息
// $user_id =$order['user_id'];
// var_dump($order["status"]);
//do something...
if(config("site.admin_approved_swtich"))$this->examine($order_no,1,"",0,false,$order["help_type"],$order["help_user_id"],false);
}
if ($trans) {
self::commitTrans();
}
} catch (\Exception $e) {
if ($trans) {
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return self::showInfo($order_no);
}
/**得到可核销的订单
* @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 getNoVerificationOrder($order_no){
$order = self::where('order_no|id',$order_no)->where("status","in",['0'])->find();
if(!$order)throw new \Exception("待核销订单不存在");
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 getHaveUpdateOrder($order_no){
$order = self::where('order_no|id',$order_no)->where("status","in",['0','-1'])->find();
if(!$order)throw new \Exception("可更新课时订单不存在");
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 getHaveCancelOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id',$order_no)->where("status","in",['0','-1'])->find();
if(!$order)throw new \Exception("只有待审核和已预约的订单可以取消!");
return $order;
}
//生成或更新课时
public static function buildLibSpec($order,$classes_lib_spec){
if(is_string($order)||is_numeric($order))$order = self::getHaveUpdateOrder($order);
if(is_string($classes_lib_spec)||is_numeric($classes_lib_spec))$classes_lib_spec = ClassesSpec::where('id',$classes_lib_spec)->where('classes_lib_id',$order["classes_lib_id"])->find();
if(!$classes_lib_spec)throw new \Exception("课时信息不正确!");
$classes_lib_spec_data = $classes_lib_spec->toArray();
$classes_lib_spec_data['classes_lib_spec_id'] = $classes_lib_spec_data['id'];
unset($classes_lib_spec_data['id']);
unset($classes_lib_spec_data['status']);
unset($classes_lib_spec_data['createtime']);
unset($classes_lib_spec_data['updatetime']);
unset($classes_lib_spec_data['deletetime']);
$order_detail_data = $order->toArray();
$order_detail_data = array_merge($order_detail_data,$classes_lib_spec_data);
$order->allowField(true)->save($order_detail_data);
return $order;
}
public function createOrder($user_id,$classes_order_id,$classes_lib_spec_id,$order_no,$param,$remark='',$other_params=[]){
$this->orderVaild($user_id,$classes_order_id, $order_no, $classes_lib_spec_id, $param,true);
//订单支付信息
$order_info = self::getCost($user_id,$classes_order_id,$classes_lib_spec_id,$param,$other_params,true);
//组装订单数据
$order_data = $order_info['order_data'];
$order_data["order_no"] = $order_no;
//兼容代下单逻辑,修正下单人信息
$user_id =$order_data['user_id'];
//课时数据
$classes_lib_spec_info = $order_info['classes_lib_spec_info'];
$res1 = self::create($order_data);
if (!$res1) throw new \Exception('创建订单失败');
//课时规格更新
$order = self::buildLibSpec($res1,$classes_lib_spec_id);
//扣减课程数
\app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($classes_order_id);
//记录订单日志
if($order["type"] == "1"){
OrderLog::log($order['id'],"课时预约下单成功,等待机构老师审核",'user',$user_id);
}else{
OrderLog::log($order['id'],"课时预约机构老师代下单成功",'user',$order["help_user_id"]);
}
//7事件
$data = ['order' => $res1];
\think\Hook::listen('classeshour_order_create_after', $data);
return $res1;
}
/**更新订单取消状态
* @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->cancel_time = 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['classes_order_id'],$user_id ?: $oper_id,$oper_type);
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新订单取消状态
$order = Order::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('classeshour_order_cancel_after', $data);
//执行课时数更新
\app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res;
}
/** 课时信息选择合法检测
* @param $user_id 下单用户
* @param $classes_lib_id 课程id
* @param $classes_lib_spec_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_lib_id,$classes_lib_spec_id,$add=false,$order=null){
if(!$classes_lib_spec_id || !$classes_lib_id)throw new \Exception("缺少必要信息!");
$classes_lib_spec_info = ClassesSpec::where('id',$classes_lib_spec_id)
->where('classes_lib_id',$classes_lib_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_lib_spec_id',$classes_lib_spec_id)
->where('status','in',['-1',"0"])
->where('user_id',$user_id)
->find();
if($order_info) throw new \Exception("该课时已预约,请勿重复预约!");
//新增或更换课时时判断
//是否达成限制人数
//允许人数为0说明不限制
if($classes_lib_spec_info['limit_num'] > 0){
//得到当前课时已参与人数
$sign_num = self::where("classes_lib_spec_id",$classes_lib_spec_id)->where("status","in",["-1","0"])->count();
if($add){
//订单新增课时
//判断是否达到限制人数
if($sign_num >= $classes_lib_spec_info['limit_num']){
throw new \Exception("该课时已满,请选择其他课时!");
}
}else{
//订单更换课时
//判断是否达到限制人数
if($sign_num >= $classes_lib_spec_info['limit_num']){
throw new \Exception("该课时已满,请选择其他课时!");
}
}
}
//判断是否是免费课
$lib = $classes_lib_spec_info->lib;
if(!$lib){
throw new \Exception("该课时课程信息缺失!");
}
if($lib["price"] == 0){
//免费课开始和结束时间有交叠无法下预约
if(!config("site.free_time_overlap_check")){
//如果是免费课
//判断时间是否有交叠
$start_time = $classes_lib_spec_info['start_time'];
$end_time = $classes_lib_spec_info['end_time'];
$as = (new self)->getWithAlisaName();
//判断时间是否有交叠(只查所有的免费的预约记录)
$order_info = self::with("detail")->where("detail.price",0)
->where("{$as}.status","in",["-1","0"])
->where(function ($query) use ($as,$start_time,$end_time) {
//兩個時間區間重合 存在任意交集 都不行
$query->where("{$as}.start_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("{$as}.end_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("{$as}.start_time <= {$start_time} AND {$as}.end_time >= {$end_time}");
$query->whereOr("{$as}.start_time >= {$start_time} AND {$as}.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_overlap_check")){
//判断时间是否有交叠
$start_time = $classes_lib_spec_info['start_time'];
$end_time = $classes_lib_spec_info['end_time'];
$as = (new self)->getWithAlisaName();
//判断时间是否有交叠(只查所有的免费的预约记录)
$order_info = self::with("detail")
->where("{$as}.status","in",["-1","0"])
->where(function ($query) use ($as,$start_time,$end_time) {
//兩個時間區間重合 存在任意交集 都不行
$query->where("{$as}.start_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("{$as}.end_time BETWEEN {$start_time} AND {$end_time}");
$query->whereOr("{$as}.start_time <= {$start_time} AND {$as}.end_time >= {$end_time}");
$query->whereOr("{$as}.start_time >= {$start_time} AND {$as}.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($classes_lib_spec_info["end_time"] <= time()){
throw new \Exception("该课时已过期结束,无法预约!");
}
}
//执行免费课黑名单判断
public static function checkBlackList($user_id,$check=false){
$as = (new self)->getWithAlisaName();
//黑名单配置
$black_limit = config("site.free_classes_not_verify_num");
//如果免费课程报名通过后到结束时间不去核销N次 ,则进入黑名单
$order_count = self::with("detail")->where("{$as}.status",'in',["0"])
->where("detail.feel",'1')
->where("{$as}.user_id",$user_id)
->where("{$as}.end_time" ,'<=',time())
->count();
//已达到进入黑名单条件
if($order_count >= $black_limit){
$where = [
"user_id"=>$user_id
];
$blacklist = Blacklist::where($where)->find();
if(!$blacklist){
$blacklist = new Blacklist();
}
$blacklist->save($where);
}
if($check){
//判断用户是否在黑名单中
$where = [
"user_id"=>$user_id
];
$blacklist = Blacklist::where($where)->find();
if($blacklist)throw new \Exception("您已进入黑名单,无法进行其他免费课时报名!");
}
}
/** 课时订单操作权限检测
* @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){
//课程是否存在并上架
$classesOrder = \app\common\model\school\classes\order\Order::where("id",$classes_order_id)->find();
if(!$classesOrder)throw new \Exception("订单不存在!");
switch ($oper_type) {
case 'user':
//自己或操作员
if($oper_id != $classesOrder["user_id"]){
//说明是操作员
$help_user_info = User::where('id',$oper_id)->find();
if(!$help_user_info) throw new \Exception("代下单员工不存在!");
$classes_lib_ids = (new ClassesLib)->getClassesAuthIds($oper_id);
//判断当前订单课程是否在此课程授权范围内
if(!in_array($classesOrder["classes_lib_id"],$classes_lib_ids)) throw new \Exception("该课程不在您的授权范围内,无法代操作!");
}
break;
case 'admin':
$admin_info = Admin::where('id',$oper_id)->find();
if(!$admin_info) throw new \Exception("代下单管理员不存在!");
break;
case 'shop':
$admin_info = Manystore::where('id',$oper_id)->find();
if(!$admin_info) 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 getHaveExamineOrder($order_no){
// $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
$order = self::where('order_no|id',$order_no)->where("status","in",['-1'])->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 = "0";//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_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['classes_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();
}
$res = true;
try{
//事务逻辑
//插入订单取消日志
if(!$user_id ||$order["user_id"] !=$user_id ){
$pron = "[员工操作]";
}else{
$pron = "";
}
//审核成功逻辑
if($auth_status == 1){
//更新订单状态
$order = Order::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('classeshour_order_auth_success_after', $data);
}else{
//更新订单状态
$order = Order::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('classeshour_order_auth_fail_after', $data);
//执行订单取消逻辑
$this->cancel($order_no,$user_id,$check,$oper_type,$oper_id);
}
//执行课时数更新
// $res1 = \app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
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 updateVerification($order,$oper_id = 0,$oper_type='user'){
if(is_string($order))$order = self::getHaveVerificationOrder($order);
$order->status = "3";//refund_status
$order->verification_user_id = $oper_id;
$order->verification_type = $oper_type;
$order->finish_time = 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',$order_no)->where("status","in",['-1',"0"])->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['classes_order_id'],$user_id ?: $oper_id,$oper_type);
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//事务逻辑
//更新订单状态
//如果没有审核,先审核成功再核销
if($order["status"] == '-1'){
$order = $this->examine($order_no,'1',"",$user_id,$check,$oper_type,$oper_id);
}
$order = Order::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('classeshour_order_finish_after', $data);
//执行课时数更新
\app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $res;
}
/**订单修改课时
* @param $order_no
* @param int $user_id
* @param bool $check
* @param bool $trans
* @return bool
* @throws \Exception
*/
public function updateClassesSpec($order_no,$classes_lib_spec_id,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
//得到可取消订单
$order = self::getHaveUpdateOrder($order_no);
if($check){
//用户操作权限检测
self::checkOptionAuth($order['classes_order_id'],$user_id ?: $oper_id,$oper_type);
}
//判断逻辑
if($trans){
self::beginTrans();
}
$res = true;
try{
//执行课时数更新
$res1 = \app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($classes_lib_spec_id == $order["classes_lib_spec_id"])throw new \Exception("请勿重复提交!");
self::checkLibSpec($order['user_id'],$order["classes_lib_id"],$classes_lib_spec_id,false,$res1);
//事务逻辑
//更新订单状态
//课时规格更新
$order = self::buildLibSpec($order_no,$classes_lib_spec_id);
//插入订单取消日志
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('classeshour_order_update_after', $data);
//执行课时数更新
$res1 = \app\common\model\school\classes\order\Order::statisticsAndUpdateClassesNumber($order['classes_order_id']);
if($trans){
self::commitTrans();
}
}catch (\Exception $e){
if($trans){
self::rollbackTrans();
}
throw new \Exception($e->getMessage());
}
return $order;
}
}