1271 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1271 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace app\common\model\school\classes\order;
 | 
						|
 | 
						|
 | 
						|
use app\admin\model\Admin;
 | 
						|
use app\common\model\BaseModel;
 | 
						|
use app\common\model\dyqc\ManystoreShop;
 | 
						|
use app\common\model\school\classes\ClassesLib;
 | 
						|
use app\common\model\school\classes\ClassesSpec;
 | 
						|
use app\common\model\school\classes\Evaluate;
 | 
						|
use app\common\model\User;
 | 
						|
use bw\Common;
 | 
						|
use fast\Random;
 | 
						|
use think\Cache;
 | 
						|
use think\Model;
 | 
						|
use traits\model\SoftDelete;
 | 
						|
 | 
						|
class Order extends BaseModel
 | 
						|
{
 | 
						|
 | 
						|
    use SoftDelete;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    // 表名
 | 
						|
    protected $name = 'school_classes_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',
 | 
						|
        'result_status_text',
 | 
						|
        'canceltime_text',
 | 
						|
        'paytime_text',
 | 
						|
        'finishtime_text',
 | 
						|
        'refundtime_text'
 | 
						|
    ];
 | 
						|
    
 | 
						|
 | 
						|
    
 | 
						|
    public function getPayTypeList()
 | 
						|
    {
 | 
						|
        return ['yue' => __('Pay_type yue'), 'wechat' => __('Pay_type wechat')];
 | 
						|
    }
 | 
						|
 | 
						|
    public function getStatusList()
 | 
						|
    {
 | 
						|
        return ['-3' => __('Status -3'), '0' => __('Status 0'), '3' => __('Status 3'),'4' => __('Status 4'), '6' => __('Status 6'), '9' => __('Status 9')];
 | 
						|
    }
 | 
						|
 | 
						|
    public function getBeforeStatusList()
 | 
						|
    {
 | 
						|
        return ['-3' => __('Before_status -3'), '0' => __('Before_status 0'), '3' => __('Before_status 3'), '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 getResultStatusList()
 | 
						|
    {
 | 
						|
        return ['0' => __('Result_status 0'), '3' => __('Result_status 3'), '6' => __('Result_status 6')];
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    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 getResultStatusTextAttr($value, $data)
 | 
						|
    {
 | 
						|
        $value = $value ? $value : (isset($data['result_status']) ? $data['result_status'] : '');
 | 
						|
        $list = $this->getResultStatusList();
 | 
						|
        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 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;
 | 
						|
    }
 | 
						|
 | 
						|
    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 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 manystore()
 | 
						|
    {
 | 
						|
        return $this->belongsTo('app\admin\model\Manystore', 'manystore_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public function user()
 | 
						|
    {
 | 
						|
        return $this->belongsTo('app\common\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public function shop()
 | 
						|
    {
 | 
						|
        return $this->belongsTo(ManystoreShop::class, 'shop_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public function lib()
 | 
						|
    {
 | 
						|
        return $this->belongsTo(ClassesLib::class, 'classes_lib_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public function detail()
 | 
						|
    {
 | 
						|
        return $this->belongsTo(OrderDetail::class, 'classes_order_detail_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public function admin()
 | 
						|
    {
 | 
						|
        return $this->belongsTo('app\admin\model\Admin', 'admin_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    public function serviceorder()
 | 
						|
    {
 | 
						|
        return $this->belongsTo(ServiceOrder::class, 'classes_service_order_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						|
    }
 | 
						|
 | 
						|
    public function evaluate()
 | 
						|
    {
 | 
						|
        return $this->hasOne(Evaluate::class, 'classes_order_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,$classes_lib_id = []){
 | 
						|
        $model = self::where('order_no|id|pay_no|code',$order_no);
 | 
						|
        if($classes_lib_id)$model = $model->where("classes_lib_id","in",$classes_lib_id);
 | 
						|
        $data = $model->find();
 | 
						|
 | 
						|
        if(!$data)  return $data;
 | 
						|
        //加载订单详情
 | 
						|
        $data->detail->teacher;
 | 
						|
        //订单用户
 | 
						|
//        $data->user;
 | 
						|
        $data->user->visible(['id','nickname','mobile','avatar','realname']);
 | 
						|
        //订单机构
 | 
						|
        $data->shop;
 | 
						|
        //售后单信息
 | 
						|
        $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 $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订单执行创建
 | 
						|
            $order = $this->createOrder($user_id,$orderInfo['classes_lib_id'],$order_no,$orderInfo['param'],$remark);
 | 
						|
 | 
						|
 | 
						|
            //如果是免费订单,则直接调用支付完成
 | 
						|
            if ($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());
 | 
						|
        }
 | 
						|
        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();
 | 
						|
 | 
						|
 | 
						|
        if($res1["classes_lib_spec_id"]){
 | 
						|
 | 
						|
              //记录代下单人信息
 | 
						|
              $param  =  [
 | 
						|
                "classes_lib_spec_id" =>$res1["classes_lib_spec_id"],
 | 
						|
              ];
 | 
						|
 | 
						|
            //课时是否合法判断
 | 
						|
            $res = (new \app\common\model\school\classes\hourorder\Order)->confirm($res1["user_id"],$res1['id'],null, $res1["classes_lib_spec_id"],$param, true);
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        //记录订单日志
 | 
						|
        OrderLog::log($res1['id'],"课程订单创建成功,等待【学员】支付",'user',$user_id);
 | 
						|
        //7事件
 | 
						|
        $data = ['order' => $res1];
 | 
						|
        \think\Hook::listen('classes_order_create_after', $data);
 | 
						|
 | 
						|
 | 
						|
        //更新订单数据
 | 
						|
        self::statisticsAndUpdateClassesNumber($res1);
 | 
						|
 | 
						|
 | 
						|
        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||!$classes_lib_id )throw new \Exception("缺少必要参数");
 | 
						|
 | 
						|
        //默认校验订单是否已创建
 | 
						|
        if($check){
 | 
						|
            //判断订单是否已创建
 | 
						|
            $order_info = self::where(['order_no'=>$order_no])->find();
 | 
						|
            if($order_info) throw new \Exception("订单已生成,如需重新下单请退出页面重新进入!");
 | 
						|
 | 
						|
        }
 | 
						|
        //校验订单参数
 | 
						|
        //课程是否存在并上架
 | 
						|
         $classes_lib_info = ClassesLib::where('id',$classes_lib_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("该课程已过期,是往期课程,无法购买!");
 | 
						|
               //执行免费课黑名单判断
 | 
						|
         //免费课才进行判断
 | 
						|
        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("用户不存在!");
 | 
						|
 | 
						|
 | 
						|
        $classes_lib_spec_id = $param['classes_lib_spec_id'] ?? null;
 | 
						|
          if($classes_lib_spec_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);
 | 
						|
              //只简单判断课程和课时
 | 
						|
               \app\common\model\school\classes\hourorder\Order::checkLibSpec($user_id,$classes_lib_id ,$classes_lib_spec_id,true);
 | 
						|
          }
 | 
						|
 | 
						|
        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["classes_lib_spec_id"] = $param['classes_lib_spec_id'] ?? 0;
 | 
						|
        $order_data["status"] = '0';
 | 
						|
        $order_type = "multiple";
 | 
						|
        //如果课程只存在一个规格,则订单类型为单课
 | 
						|
        $classes_spec_count = ClassesSpec::where('classes_lib_id',$classes_lib_id)->count();
 | 
						|
        if($classes_spec_count==1){
 | 
						|
            $order_type = "single";
 | 
						|
        }
 | 
						|
        $classes_lib_spec = null;
 | 
						|
          $classes_lib_spec_id = $param['classes_lib_spec_id'] ?? null;
 | 
						|
          if($classes_lib_spec_id){
 | 
						|
              $classes_lib_spec = ClassesSpec::get($classes_lib_spec_id);
 | 
						|
          }
 | 
						|
 | 
						|
 | 
						|
        return  compact('order_data','classes_lib_info','user_data','order_type',"classes_lib_spec");
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    /**得到待支付订单
 | 
						|
     * @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;
 | 
						|
    }
 | 
						|
 | 
						|
    /**得到订单
 | 
						|
     * @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;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    /**
 | 
						|
     * 检测支付开关(待扩展)
 | 
						|
     */
 | 
						|
    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);
 | 
						|
 | 
						|
            //如果需要快捷预约
 | 
						|
            $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());
 | 
						|
        }
 | 
						|
        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);
 | 
						|
        //更新订单数据
 | 
						|
        self::statisticsAndUpdateClassesNumber($order);
 | 
						|
        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->sub_refundprice = $order->payprice; //剩余未退 = 支付金额
 | 
						|
 | 
						|
        $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,
 | 
						|
        ]))['url'];
 | 
						|
        //一维码
 | 
						|
        $order->codeoneimage = (Common::getBarcode([
 | 
						|
            'text'           => $params,
 | 
						|
            'size'           => 200,
 | 
						|
        ]))['url'];
 | 
						|
        $order->save();
 | 
						|
        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','classes_lib_id','has_evaluate']))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}pay_no|{$alisa}code", '=', $whereData['keywords']);
 | 
						|
        if (isset($whereData['time'])&&$whereData['time']){
 | 
						|
 | 
						|
            $model = $model->time($whereData['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']);
 | 
						|
 | 
						|
        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_lib_id=[],$has_evaluate=0){
 | 
						|
        $with_field = [
 | 
						|
            'user'=>['nickname','mobile','avatar','realname'],
 | 
						|
            'base'=>['*'],
 | 
						|
            'shop'=>['*'],
 | 
						|
            'detail'=>['*'],
 | 
						|
            'evaluate'=>['*'],
 | 
						|
            'serviceorder'=>['*']
 | 
						|
        ];
 | 
						|
        $CANCEL = '-3';
 | 
						|
        $NOPAY = '0';
 | 
						|
        $PAYED = '3';
 | 
						|
        $REFUND = '6';
 | 
						|
        $FINISH = '9';
 | 
						|
        $IN_SERVICE = '4';
 | 
						|
        $alisa = (new self)->getWithAlisaName();
 | 
						|
        $sort = "field({$alisa}.status,'{$NOPAY}','{$PAYED}','{$FINISH}','{$REFUND}','{$IN_SERVICE}','{$CANCEL}') asc,{$alisa}.id desc";
 | 
						|
        $serch_where = ['status'=>$status,'user_id'=>$user_id,'keywords'=>$keywords,"classes_lib_id"=>$classes_lib_id,"has_evaluate"=>$has_evaluate];
 | 
						|
//        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 = '3';
 | 
						|
        $REFUND = '6';
 | 
						|
        $FINISH = '9';
 | 
						|
        $IN_SERVICE = '4';
 | 
						|
        $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();
 | 
						|
        $retund_number =  self::getBaseWhere(array_merge(['status'=>$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','finish_number');
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    /**订单数量统计
 | 
						|
     * @param int $user_id
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public static function orderCount($user_id = 0,$classes_lib_id=[]){
 | 
						|
        return self::baseCount(['user_id'=>$user_id,"classes_lib_id"=>$classes_lib_id]);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    public static function workList($user_id,$page, $limit,$keywords,$status,$classes_lib_id=[],$classes_lib_ids=[],$has_evaluate=0){
 | 
						|
        $with_field = [
 | 
						|
            'user'=>['nickname','mobile','avatar','realname'],
 | 
						|
            'base'=>['*'],
 | 
						|
            'shop'=>['*'],
 | 
						|
            'detail'=>['*'],
 | 
						|
            'evaluate'=>['*'],
 | 
						|
            'serviceorder'=>['*']
 | 
						|
        ];
 | 
						|
        $CANCEL = '-3';
 | 
						|
        $NOPAY = '0';
 | 
						|
        $PAYED = '3';
 | 
						|
        $IN_SERVICE = '4';
 | 
						|
        $REFUND = '6';
 | 
						|
        $FINISH = '9';
 | 
						|
        $alisa = (new self)->getWithAlisaName();
 | 
						|
        $sort = "field({$alisa}.status,'{$NOPAY}','{$PAYED}','{$FINISH}','{$REFUND}','{$IN_SERVICE}','{$CANCEL}') asc,{$alisa}.id desc";
 | 
						|
        $serch_where = ['status'=>$status,'keywords'=>$keywords,"classes_lib_id"=>$classes_lib_id,"classes_lib_ids"=>$classes_lib_ids];
 | 
						|
//        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=[]){
 | 
						|
        return self::baseCount(["classes_lib_id"=>$classes_lib_id,"classes_lib_ids"=>$classes_lib_ids]);
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    //统计并更新课时数等相关统计数据
 | 
						|
    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\hourorder\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->lib;
 | 
						|
        if($lib){
 | 
						|
            $lib->sale = self::where("classes_lib_id",$lib["id"])->where("status","<>","-3")->count();
 | 
						|
 | 
						|
            //遍历课程课时规格,更新课时统计数据
 | 
						|
             $specs = $lib->specs;
 | 
						|
            if($specs){
 | 
						|
                foreach ($specs as $spec){
 | 
						|
                    //  '已核销人数',
 | 
						|
                    $spec->verification_num = \app\common\model\school\classes\hourorder\Order::where("classes_lib_spec_id",$spec["id"])->where("status","=","3")->count();
 | 
						|
                    //已报名人数
 | 
						|
                    $spec->sign_num = \app\common\model\school\classes\hourorder\Order::where("classes_lib_spec_id",$spec["id"])->where("status","in",["-1","0","3"])->count();
 | 
						|
                    $spec->save();
 | 
						|
                }
 | 
						|
 | 
						|
            }
 | 
						|
            //统计课程总报名和总核销
 | 
						|
            $lib->sign_num = \app\common\model\school\classes\hourorder\Order::where("classes_lib_id",$lib["id"])->where("status","in",["-1","0","3"])->count();
 | 
						|
            $lib->verification_num = \app\common\model\school\classes\hourorder\Order::where("classes_lib_id",$lib["id"])->where("status","=","3")->count();
 | 
						|
            $lib->save();
 | 
						|
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        //检测订单完成状态
 | 
						|
        self::statisticsAndUpdateOrderFinish($order->id);
 | 
						|
       //将课程信息和课时信息同步到所有已下单的订单信息中
 | 
						|
        ClassesLib::orderInfoSync($order["classes_lib_id"]);
 | 
						|
 | 
						|
        //如果有评价执行评价更新
 | 
						|
        return $order;
 | 
						|
    }
 | 
						|
 | 
						|
    /** 检测订单完成状态
 | 
						|
     * @param $order
 | 
						|
     * @return void
 | 
						|
     * @throws \think\Exception
 | 
						|
     * @throws \think\db\exception\DataNotFoundException
 | 
						|
     * @throws \think\db\exception\ModelNotFoundException
 | 
						|
     * @throws \think\exception\DbException
 | 
						|
     */
 | 
						|
    public static function statisticsAndUpdateOrderFinish($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\hourorder\Order::where("status","=",'3')
 | 
						|
            ->where("classes_order_id","=",$order["id"])
 | 
						|
            ->count();
 | 
						|
        //可完成的订单
 | 
						|
       if($order["status"] == '3' && (in_array($order["server_status"],['0','6'])) && !$order['finishtime']){
 | 
						|
           //判定是否达成完成条件
 | 
						|
            //条件:课程课时已全部完成
 | 
						|
           if($hourorderOrderCount >= $detail->classes_num){
 | 
						|
                 //执行订单完成的更新逻辑
 | 
						|
               self::updateFinish($order);
 | 
						|
           }
 | 
						|
       }
 | 
						|
    }
 | 
						|
 | 
						|
    /** 更新订单成已完成
 | 
						|
     * @param $order
 | 
						|
     * @return void
 | 
						|
     */
 | 
						|
    public static function updateFinish($order){
 | 
						|
        if(is_string($order)||is_numeric($order))$order = self::getOrder($order);
 | 
						|
        //更新订单
 | 
						|
        $order["status"] = '9';
 | 
						|
        $order["finishtime"] = time();
 | 
						|
 | 
						|
        $order->save();
 | 
						|
        //记录订单日志
 | 
						|
        OrderLog::log($order['id'],"课程订单,课时已全部完成",'user',$order['user_id']);
 | 
						|
        //调用支付成功事件
 | 
						|
        $data = ['order' => $order];
 | 
						|
        \think\Hook::listen('classes_order_finish_after', $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 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;
 | 
						|
        if(!$detail) throw new \Exception("订单信息缺失!");
 | 
						|
        if(!$order)throw new \Exception("只有待支付订单可取消,已支付请走售后申请,已取消请忽略!");
 | 
						|
        //非免费单进行中无法取消
 | 
						|
        if($detail["feel"] == "0" && $order['status'] != '0'){
 | 
						|
            throw new \Exception("只有待支付订单可取消,已支付请走售后申请,已取消请忽略!");
 | 
						|
        }
 | 
						|
        if($detail["feel"] == "1" &&  !in_array($order['status'],['0','3'])){
 | 
						|
            throw new \Exception("只有进行中订单可取消,已取消请忽重复取消!");
 | 
						|
        }
 | 
						|
 | 
						|
        return $order;
 | 
						|
    }
 | 
						|
 | 
						|
    /** 得到可评价订单
 | 
						|
     * @param $order_no
 | 
						|
     * @return array|bool|\PDOStatement|string|Model
 | 
						|
     * @throws \think\db\exception\DataNotFoundException
 | 
						|
     * @throws \think\db\exception\ModelNotFoundException
 | 
						|
     * @throws \think\exception\DbException
 | 
						|
     */
 | 
						|
    public static function getHaveEvaluateOrder($order_no){
 | 
						|
        $order = self::where('order_no|id|pay_no|code',$order_no)->whereExists(function ($query){
 | 
						|
            $self_order_table_name = (new \app\common\model\school\classes\hourorder\Order())->getQuery()->getTable();
 | 
						|
            $order_table_name = (new self())->getQuery()->getTable();
 | 
						|
            $query->table($self_order_table_name)->whereRaw($self_order_table_name . '.classes_order_id=' . $order_table_name . '.id')->where('status', '=', '3');
 | 
						|
        })->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 updateCancel($order){
 | 
						|
        if(is_string($order))$order = self::getHaveCancelOrder($order);
 | 
						|
        $order->status = "-3";//refund_status
 | 
						|
        $order->canceltime = time();
 | 
						|
        $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 updateEvaluate($order,$classes_evaluate_id){
 | 
						|
        if(is_string($order))$order = self::getHaveEvaluateOrder($order);
 | 
						|
        $order->classes_evaluate_id = $classes_evaluate_id;
 | 
						|
        $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){
 | 
						|
            //用户操作权限检测
 | 
						|
            \app\common\model\school\classes\hourorder\Order::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type);
 | 
						|
 | 
						|
            //进行中,用户自己无法操作取消
 | 
						|
            if($order['status'] == '3' && $user_id == $order['user_id']){
 | 
						|
                throw new \Exception("您无权操作取消!请您联系机构操作!");
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
        //判断逻辑
 | 
						|
        if($trans){
 | 
						|
            self::beginTrans();
 | 
						|
        }
 | 
						|
        $res = true;
 | 
						|
        try{
 | 
						|
            //事务逻辑
 | 
						|
             //有进行中的课时全部取消
 | 
						|
              //查询所有存在的课时单,进行批量取消
 | 
						|
            $hour_orders = \app\common\model\school\classes\hourorder\Order::where("classes_order_id",$order["id"])->
 | 
						|
             where("status","in",["-1","0"])->select();
 | 
						|
            foreach ($hour_orders as $hour_order){
 | 
						|
 | 
						|
                (new \app\common\model\school\classes\hourorder\Order)->cancel($hour_order["id"],$hour_order["user_id"],false,'admin',0);
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
 | 
						|
            //更新订单取消状态
 | 
						|
            $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('classes_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;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
}
 |