售后单超时自动挂起 售后同意结算单收益释放(余留未退金额情况下 后台帮商户售后功能 后台帮用户取消和申请售后功能 后台用户维度查看提现,结算,订单记录 结算单,活动单,活动,提现记录增加 万以上数据导出excel
		
			
				
	
	
		
			2438 lines
		
	
	
		
			83 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			2438 lines
		
	
	
		
			83 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						||
 | 
						||
namespace app\common\model\school\activity\order;
 | 
						||
 | 
						||
use addons\epay\library\Service;
 | 
						||
use app\admin\model\Admin;
 | 
						||
use app\admin\model\Manystore;
 | 
						||
use app\common\model\BaseModel;
 | 
						||
use app\common\model\school\activity\Activity;
 | 
						||
use app\common\model\school\activity\Refund;
 | 
						||
use app\common\model\User;
 | 
						||
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_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',
 | 
						||
        'suspend_status_text',
 | 
						||
        'canceltime_text',
 | 
						||
        'paytime_text',
 | 
						||
        'auth_time_text',
 | 
						||
        'reservation_time_text',
 | 
						||
        'finishtime_text',
 | 
						||
        'refundtime_text',
 | 
						||
        'auth_status_text',
 | 
						||
        'refundsendtime_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'),'7' => __('Status 7'), '9' => __('Status 9')];
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public function getSuspendStatusList()
 | 
						||
    {
 | 
						||
        return ['0' => __('未挂起'), '1' => __('售后拒绝'), '2' => __('售后超时')];
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function getSuspendStatusTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['suspend_status']) ? $data['suspend_status'] : '');
 | 
						||
        $list = $this->getSuspendStatusList();
 | 
						||
        return isset($list[$value]) ? $list[$value] : '';
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    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] : '';
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function getRefundsendtimeTextAttr($value, $data)
 | 
						||
    {
 | 
						||
        $value = $value ? $value : (isset($data['refundsendtime']) ? $data['refundsendtime'] : '');
 | 
						||
        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 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);
 | 
						||
    }
 | 
						||
 | 
						||
    protected function setRefundsendtimeAttr($value)
 | 
						||
    {
 | 
						||
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function user()
 | 
						||
    {
 | 
						||
        return $this->belongsTo('app\common\model\User', 'user_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function activity()
 | 
						||
    {
 | 
						||
        return $this->belongsTo(Activity::class, 'activity_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function detail()
 | 
						||
    {
 | 
						||
        return $this->belongsTo(OrderDetail::class, 'activity_order_detail_id', 'id', [], 'LEFT')->setEagerlyType(0);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function ordercode()
 | 
						||
    {
 | 
						||
        return $this->hasMany(OrderCode::class,'activity_order_id');
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**得到基础条件
 | 
						||
     * @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","server_status",'activity_id','user_id','activity_order_detail_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['server_status']) && $whereData['server_status']!=="") $model = $model->where("{$alisa}server_status", 'in', $whereData['server_status']);
 | 
						||
        if (isset($whereData['not_server_status'])&&  $whereData['not_server_status']!=="") $model = $model->where("{$alisa}server_status", 'not in', $whereData['not_server_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|user.nickname|user.realname|user.mobile|detail.title|detail.address|detail.address_detail", 'LIKE', "%{$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['activity_ids']) && $whereData['activity_ids']) $model = $model->where("{$alisa}activity_id", 'in', $whereData['activity_ids']);
 | 
						||
        if (isset($whereData['activity_id']) && $whereData['activity_id']) $model = $model->where("{$alisa}activity_id", 'in', $whereData['activity_id']);
 | 
						||
 | 
						||
 | 
						||
        if (isset($whereData['activity_order_detail_id']) && $whereData['activity_order_detail_id']) $model = $model->where("{$alisa}activity_order_detail_id", 'in', $whereData['activity_order_detail_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,$activity_id=[],$has_evaluate=0,$server_status="",$params=[]){
 | 
						||
        $with_field = [
 | 
						||
            'user'=>['nickname','mobile','avatar','realname'],
 | 
						||
            'base'=>['*'],
 | 
						||
            'detail'=>['*'],
 | 
						||
            'ordercode'=>['*'],
 | 
						||
        ];
 | 
						||
        $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,"activity_id"=>$activity_id,"has_evaluate"=>$has_evaluate,"server_status"=>$server_status];
 | 
						||
//        if($type)$serch_where['type'] = $type;
 | 
						||
        return (new self)->getBaseList(array_merge($serch_where,$params), $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,$activity_id=[],$params=[]){
 | 
						||
        return self::baseCount(array_merge(['user_id'=>$user_id,"activity_id"=>$activity_id],$params));
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public static function workList($user_id,$page, $limit,$keywords,$status,$activity_id=[],$activity_ids=[],$has_evaluate=0,$server_status="",$params=[]){
 | 
						||
        if(!$activity_ids) $activity_ids = [-5];
 | 
						||
 | 
						||
        $with_field = [
 | 
						||
            'user'=>['nickname','mobile','avatar','realname'],
 | 
						||
            'base'=>['*'],
 | 
						||
            'detail'=>['*'],
 | 
						||
            'ordercode'=>['*'],
 | 
						||
        ];
 | 
						||
        $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,"activity_id"=>$activity_id,"activity_ids"=>$activity_ids,"server_status"=>$server_status];
 | 
						||
//        if($type)$serch_where['type'] = $type;
 | 
						||
        return (new self)->getBaseList(array_merge($serch_where,$params), $page, $limit,$sort,$with_field);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**订单数量统计
 | 
						||
     * @param int $user_id
 | 
						||
     * @return array
 | 
						||
     */
 | 
						||
    public static function workCount($activity_id=[],$activity_ids=[],$params=[]){
 | 
						||
        if(!$activity_ids) $activity_ids = [-5];
 | 
						||
 | 
						||
        return self::baseCount(array_merge(["activity_id"=>$activity_id,"activity_ids"=>$activity_ids],$params));
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**得到订单详情
 | 
						||
     * @param $order_no
 | 
						||
     */
 | 
						||
    public static function getDetail($order_no,$activity_id = []){
 | 
						||
        $model = self::where('order_no|id|pay_no',$order_no);
 | 
						||
        if($activity_id)$model = $model->where("activity_id","in",$activity_id);
 | 
						||
        $data = $model->find();
 | 
						||
 | 
						||
        if(!$data)  return $data;
 | 
						||
        //加载订单详情
 | 
						||
        $data->detail;
 | 
						||
        //订单用户
 | 
						||
//        $data->user;
 | 
						||
        $data->user->visible(['id','nickname','mobile','avatar','realname']);
 | 
						||
 | 
						||
        //超时检测
 | 
						||
        self::timeoutCheck($data["id"]);
 | 
						||
 | 
						||
        //规格信息
 | 
						||
        $data->ordercode;
 | 
						||
 | 
						||
 | 
						||
        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',$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 = 'activity_order_cache' . $uid . $data['order_no'];
 | 
						||
        // 缓存在3600秒之后过期
 | 
						||
        return Cache::set($cacheNmae, $data, config("site.unpaid_activity_expire_time"));
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 得到订单缓存
 | 
						||
     * @param $uid
 | 
						||
     * @param $order_no
 | 
						||
     * @return mixed
 | 
						||
     */
 | 
						||
    public static function getOrderCache($uid, $order_no)
 | 
						||
    {
 | 
						||
        //缓存名 = uid + order_no
 | 
						||
        $cacheNmae = '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 = 'activity_order_cache' . $uid . $order_no;
 | 
						||
        // 缓存在3600秒之后过期
 | 
						||
        return Cache::rm($cacheNmae);
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**订单校验
 | 
						||
     * @param $user_id  用户id
 | 
						||
     * @param $classes_lib_id 课程id
 | 
						||
     * @param $order_no 订单号
 | 
						||
     * @param $param    表单扩展参数
 | 
						||
     * @return bool
 | 
						||
     */
 | 
						||
    public  function orderVaild($user_id,$activity_id,$num, $order_no, $param,$check=false){
 | 
						||
        if(!$user_id||!$activity_id )throw new \Exception("缺少必要参数");
 | 
						||
 | 
						||
        //更新活动状态
 | 
						||
        (new Activity)->updateStatus($activity_id);
 | 
						||
        //校验订单参数
 | 
						||
        //课程活动是否存在并上架
 | 
						||
        $activity = Activity::where('id',$activity_id)->find();
 | 
						||
        if(!$activity ) throw new \Exception("该活动不存在!");
 | 
						||
 | 
						||
 | 
						||
        //默认校验订单是否已创建
 | 
						||
        if($check){
 | 
						||
            if($activity['status']!='2' || $activity['auth_status']!='1') throw new \Exception("该活动不在可报名时间段!");
 | 
						||
 | 
						||
            //此为创建订单时判断
 | 
						||
            //判断订单是否已创建
 | 
						||
            $order_info = self::where(['order_no'=>$order_no])->find();
 | 
						||
            if($order_info) throw new \Exception("订单已生成,如需重新下单请退出页面重新进入!");
 | 
						||
            //下单必须传规格id
 | 
						||
            $num = (int)$num;
 | 
						||
            if(!$num) throw new \Exception("请选择报名人数!");
 | 
						||
            $activity_max_people = config("site.activity_max_people");
 | 
						||
            if($activity_max_people){
 | 
						||
                if($num > $activity_max_people || $num < 1) throw new \Exception("单次报名人数不能超过{$activity_max_people}人!");
 | 
						||
            }
 | 
						||
            //判断数量是否超出库存
 | 
						||
            $sale = Activity::activitySale($activity_id,$num);//活动销量
 | 
						||
            if($sale > $activity['stock']){
 | 
						||
                //判断超了几人
 | 
						||
               $sub =  $sale - $activity['stock'];
 | 
						||
 | 
						||
                throw new \Exception("活动人数已超{$sub}人!无法下单!");
 | 
						||
            }
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
        //用户存不存在
 | 
						||
        $user_info = User::where('id',$user_id)->find();
 | 
						||
        if(!$user_info) throw new \Exception("用户不存在!");
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        return true;
 | 
						||
    }
 | 
						||
 | 
						||
    public static function getCost($user_id,$activity_id,$num=1,$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($activity_id);
 | 
						||
        $activity_info = $activity_info->toArray();
 | 
						||
        $activity_info["activity_id"] = $activity_id;
 | 
						||
        $activity_info["activity_order_id"] = 0;
 | 
						||
        $activity_info["refund_scale_json"] = "";
 | 
						||
        $activity_info["refund_status"]= "1";
 | 
						||
        $refund = Refund::get($activity_info["refund_id"]);
 | 
						||
        if($refund){
 | 
						||
            $activity_info["refund_scale_json"]= $refund["refund_scale_json"];
 | 
						||
            $activity_info["refund_status"]= $refund["status"];
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
//        $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;
 | 
						||
 | 
						||
        $totalprice = bcmul($num,$activity_info["price"],2);
 | 
						||
 | 
						||
 | 
						||
        //组装订单下单数据
 | 
						||
        $order_data = [];
 | 
						||
        $order_data["user_id"] = $user_id;
 | 
						||
        $order_data["activity_id"] = $activity_id;
 | 
						||
        $order_data["activity_order_detail_id"] = 0;
 | 
						||
        $order_data["num"] = $num;
 | 
						||
        $order_data["fee_scale"] = $activity_info["fee_scale"];
 | 
						||
        $order_data["beforeprice"] =  $totalprice;
 | 
						||
        $order_data["totalprice"] = $totalprice;
 | 
						||
        $order_data["payprice"] = 0;
 | 
						||
        $order_data["status"] = '0';
 | 
						||
        $order_data["settle_log_time"] = $activity_info["settlement_time"];
 | 
						||
        $order_data["last_time"] = $activity_info["end_time"] + config("site.activity_end_sales");
 | 
						||
      //根据手续费比例$activity_info["fee_scale"] 计算手续费
 | 
						||
        $order_data["fee_price"] = bcmul($order_data["totalprice"],$order_data["fee_scale"],2);
 | 
						||
        //手续费保底不能低于site.activity_settle_min_fee
 | 
						||
        $min_fee = config("site.activity_settle_min_fee");
 | 
						||
        $order_data["fee_price"] = $order_data["fee_price"] < $min_fee ? $min_fee : $order_data["fee_price"];
 | 
						||
 | 
						||
        return  compact('order_data','activity_info','user_data',"num");
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /** 订单确认(订单计算)
 | 
						||
     * @param $user_id 下单用户
 | 
						||
     * @param $order_no 订单号(缓存标识)
 | 
						||
     * @param $activity_id 課程活动id
 | 
						||
     * @param $num 人数
 | 
						||
     * @param $param 額外参数(扩展用)
 | 
						||
     * @param bool $is_compute 是否重新计算订单
 | 
						||
     * @return array
 | 
						||
     */
 | 
						||
    public function confirm($user_id, $activity_id,$num,$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,$activity_id,$num,$order_no, $param);
 | 
						||
            //订单支付信息
 | 
						||
            $price_info = $this->getCost($user_id,$activity_id,$num,$param);
 | 
						||
            //生成订单号
 | 
						||
            if (!$order_no) $order_no = get_order_sn();
 | 
						||
            //生成缓存
 | 
						||
            $data = compact('user_id', 'activity_id','num','param', 'order_no', 'price_info');
 | 
						||
            self::setOrderCache($user_id, $data);
 | 
						||
        }
 | 
						||
 | 
						||
        \think\Hook::listen('activity_order_create_before', $data);
 | 
						||
 | 
						||
        //下单数据展示
 | 
						||
        return $this->showInfo($order_no, $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 getNopayOrder($order_no){
 | 
						||
        $order = self::where('order_no|id|pay_no',$order_no)->where("status","in",['0',"-3"])->find();
 | 
						||
        if(!$order)throw new \Exception("待支付订单不存在");
 | 
						||
        return $order;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**调用订单支付成功事件
 | 
						||
     * @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);
 | 
						||
 | 
						||
            //释放结算订单
 | 
						||
          (new SettleLog)->timeoutSettleActivityCheck($order["activity_id"]);
 | 
						||
 | 
						||
//            //如果需要快捷预约
 | 
						||
//            $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 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;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    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' => self::where("id",$order['id'])->find()];
 | 
						||
        \think\Hook::listen('activity_order_payed_after', $data);
 | 
						||
        //更新订单数据
 | 
						||
        self::statisticsAndUpdateClassesNumber($order);
 | 
						||
        return true;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public static function buildCode($order){
 | 
						||
        if(is_string($order)||is_numeric($order))$order = self::getNopayOrder($order);
 | 
						||
 | 
						||
        $num = $order['num'];
 | 
						||
        for ($i=0;$i<$num;$i++){
 | 
						||
            $params = [
 | 
						||
                "activity_order_id"=>$order["id"],
 | 
						||
                "status" =>'3',
 | 
						||
                "activity_id"=>$order['activity_id'],
 | 
						||
            ];
 | 
						||
            $orderCode = OrderCode::create($params);
 | 
						||
            $orderCode["code"] = en_code($orderCode["id"]);
 | 
						||
            $orderCode["miniurl"] = self::getMiniQrcodeLink(["order_id"=>$order['id'],"code"=>$orderCode["code"]]);
 | 
						||
 | 
						||
 | 
						||
            //生成核销二维码和一维码
 | 
						||
//            //生成二维码和一维码
 | 
						||
//        //二维码
 | 
						||
//        $orderCode->codeimage = (Common::getQrcode([
 | 
						||
//            'text'           => $orderCode["miniurl"],
 | 
						||
//            'size'           => 200,
 | 
						||
//        ]))['url'];
 | 
						||
//        //一维码
 | 
						||
//        $orderCode->codeoneimage = (Common::getBarcode([
 | 
						||
//            'text'           => $orderCode["miniurl"],
 | 
						||
//            'size'           => 200,
 | 
						||
//        ]))['url'];
 | 
						||
 | 
						||
 | 
						||
            $orderCode->save();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        return $order;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    public static function getPath($params=[],$expression = '{{KEYWORD}}'){
 | 
						||
        $path = config("site.activity_verification_url");
 | 
						||
        if(!$path) throw new \Exception("请先配置小程序路径");
 | 
						||
        // 参数替换
 | 
						||
        $template = Common::parsePrintTemplateString($path,$params,$expression);
 | 
						||
        return $template;
 | 
						||
    }
 | 
						||
 | 
						||
    public static function getMiniQrcodeLink($params=[],$expression = '{{KEYWORD}}',$qrcode=false){
 | 
						||
        $path = self::getPath($params,$expression);
 | 
						||
        //如果路径开头有斜杠则去除
 | 
						||
        if(substr($path,0,1) == "/"){
 | 
						||
            $path = substr($path,1);
 | 
						||
        }
 | 
						||
        //解析该路径,获取url参数和除去参数的url
 | 
						||
        $url_params = [];
 | 
						||
        $url = "";
 | 
						||
        if(strpos($path,"?") !== false){
 | 
						||
            $url_params = explode("?",$path);
 | 
						||
            $url = $url_params[0];
 | 
						||
            $url_params = $url_params[1];
 | 
						||
        }else{
 | 
						||
            $url = $path;
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        $q_params = [];
 | 
						||
        //生成小程序二维码
 | 
						||
        $query = $url_params;
 | 
						||
        $q_params["path"] = $url;
 | 
						||
        if($query)$q_params["query"] = $query;
 | 
						||
 | 
						||
        // 实例对应的接口对象
 | 
						||
        $scheme = new \WeMini\Scheme(Service::wechatConfig());
 | 
						||
        $res=  $scheme->urlLink($q_params);
 | 
						||
        if(!isset($res["url_link"]))throw new \Exception("生成小程序二维码失败");
 | 
						||
        $url_link = $res["url_link"];
 | 
						||
        if(!$qrcode)return $url_link;
 | 
						||
 | 
						||
        //链接生成二维码
 | 
						||
        //二维码
 | 
						||
        $response = Common::getQrcode([
 | 
						||
            'text'           => $url_link,
 | 
						||
            'size'           => 200,
 | 
						||
        ],false,false,true);
 | 
						||
        //全返回
 | 
						||
        return compact("url_link","response");
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * 根据缓存创建订单
 | 
						||
     */
 | 
						||
    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['activity_id'],$orderInfo['num'],$order_no,$orderInfo['param'],$remark);
 | 
						||
 | 
						||
            $orderitem = $order->detail;
 | 
						||
            //如果是免费订单,则直接调用支付完成
 | 
						||
            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,$activity_id,$num,$order_no,$param,$remark='',$other_params=[]){
 | 
						||
 | 
						||
        $this->orderVaild($user_id,$activity_id,$num, $order_no,  $param,true);
 | 
						||
        //订单支付信息
 | 
						||
        $order_info = self::getCost($user_id,$activity_id,$num,$param,$other_params,true);
 | 
						||
 | 
						||
        //组装订单数据 compact('order_data','activity_info','user_data',"activity_info");
 | 
						||
        $order_data = $order_info['order_data'];
 | 
						||
        $order_data["order_no"] = $order_no;
 | 
						||
 | 
						||
        $res1 = self::create($order_data);
 | 
						||
        if (!$res1) throw new \Exception('创建订单失败');
 | 
						||
        $activity_info = $order_info["activity_info"];
 | 
						||
        if(!$activity_info)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["activity_id"] = $activity_info['id'];
 | 
						||
        $order_detail_data["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->save();
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        //记录订单日志
 | 
						||
        OrderLog::log($res1['id'],"活动订单创建成功,等待下一步操作(如果付费需去支付)",'user',$user_id);
 | 
						||
        //7事件
 | 
						||
        $data = ['order' => self::where("id",$res1['id'])->find()];
 | 
						||
        \think\Hook::listen('activity_order_create_after', $data);
 | 
						||
 | 
						||
 | 
						||
        //更新订单数据
 | 
						||
        self::statisticsAndUpdateClassesNumber($res1);
 | 
						||
 | 
						||
 | 
						||
        return $res1;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    //统计并更新活动数等相关统计数据
 | 
						||
    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("订单信息缺失!");
 | 
						||
//
 | 
						||
//        //课程下单时已核销人数更新
 | 
						||
//        $lib = $order->activity;
 | 
						||
//        if($lib){
 | 
						||
//
 | 
						||
//        }
 | 
						||
 | 
						||
 | 
						||
        //将课程信息和课时信息同步到所有已下单的订单信息中
 | 
						||
        (new Activity)->update_classes($order["activity_id"]);
 | 
						||
 | 
						||
        //如果有评价执行评价更新
 | 
						||
        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['activity_id'],$order['num'],$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,$only_shop_user=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("您无权操作该订单!");
 | 
						||
 | 
						||
 | 
						||
                    //说明是操作员
 | 
						||
                    $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["activity_id"],$classes_activity_ids)) throw new \Exception("该活动不在您的授权范围内,无法代操作!");
 | 
						||
                }else{
 | 
						||
                    if($only_shop_user) throw new \Exception("您无权操作该订单!");
 | 
						||
 | 
						||
                    $classes_activity_ids = (new Activity())->getActivityAuthIds($oper_id);
 | 
						||
                    //不是员工并且想操作只有机构能操作的单
 | 
						||
                    if(!in_array($classesOrder["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 = (new Activity())->getActivityAuthIds($admin_info["user_id"]);
 | 
						||
                //判断当前订单课程是否在此课程授权范围内
 | 
						||
                if(!in_array($classesOrder["activity_id"],$classes_activity_ids)) throw new \Exception("该活动不在您的授权范围内,无法代操作!");
 | 
						||
 | 
						||
                break;
 | 
						||
            default:
 | 
						||
                throw new \Exception("请选择正确的代下单类型!");
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /** 检测订单完成状态
 | 
						||
     * @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 = OrderCode::where("status","=",'6')
 | 
						||
            ->where("activity_order_id","=",$order["id"])
 | 
						||
            ->count();
 | 
						||
        //可完成的订单
 | 
						||
        if(in_array($order["status"],["2",'3']) && (in_array($order["server_status"],['0'])) && !$order['finishtime']){
 | 
						||
            //判定是否达成完成条件
 | 
						||
            //条件:课程课时已全部完成
 | 
						||
            if($hourorderOrderCount >= $order->num){
 | 
						||
                //执行订单完成的更新逻辑
 | 
						||
                self::updateFinish($order);
 | 
						||
            }elseif($order["status"] == "2"){
 | 
						||
                //更新订单状态成核销中
 | 
						||
                $order["status"] = '3';
 | 
						||
                $order["reservation_time"] = time();
 | 
						||
                $order->save();
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /** 更新订单成已完成
 | 
						||
     * @param $order
 | 
						||
     * @return void
 | 
						||
     */
 | 
						||
    public static function updateFinish($order){
 | 
						||
        if(is_string($order)||is_numeric($order))$order = self::getOrder($order);
 | 
						||
 | 
						||
        //检测未核销订单,强制核销
 | 
						||
        $orderCodes = OrderCode::where("status","=",'3')
 | 
						||
            ->where("activity_order_id","=",$order["id"])
 | 
						||
            ->select();
 | 
						||
        foreach ($orderCodes as $k=>$orderCode){
 | 
						||
            //强制核销
 | 
						||
            (new OrderCode)->forceVerification($orderCode["code"],"admin",0,false);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        //更新订单
 | 
						||
        $order["status"] = '9';
 | 
						||
 | 
						||
 | 
						||
        $order["finishtime"] = time();
 | 
						||
 | 
						||
        $order->save();
 | 
						||
        //记录订单日志
 | 
						||
        OrderLog::log($order['id'],"活动订单完成,人数已全部核销",'user',$order['user_id']);
 | 
						||
 | 
						||
 | 
						||
        //释放结算订单
 | 
						||
        (new SettleLog)->timeoutSettleActivityCheck($order["activity_id"]);
 | 
						||
 | 
						||
        //调用支付成功事件
 | 
						||
        $data = ['order' => $order];
 | 
						||
        \think\Hook::listen('activity_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 getHaveCancelFreeOrder($order_no,$check=false){
 | 
						||
//        $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
 | 
						||
        $order = self::where('order_no|id|pay_no',$order_no)->find();
 | 
						||
        $detail = $order->detail;
 | 
						||
        if(!$detail) throw new \Exception("订单信息缺失!");
 | 
						||
        if(!$order)throw new \Exception("订单信息缺失!");
 | 
						||
        //非免费单进行中无法取消
 | 
						||
        if($order['totalprice'] != 0){
 | 
						||
            //非免费单只有未支付的单才可以取消
 | 
						||
            if($order['status'] != '0'){
 | 
						||
                throw new \Exception("只有未支付的单才可以取消!");
 | 
						||
            }
 | 
						||
        }else{
 | 
						||
 | 
						||
            if($check && !in_array($order['status'],['0','2'])){
 | 
						||
                throw new \Exception("免费单只有进行中订单可取消,已取消请忽重复取消!");
 | 
						||
            }
 | 
						||
        }
 | 
						||
        if(!$check) return $order;
 | 
						||
        //活动开始后不可取消
 | 
						||
        $time = time();
 | 
						||
        if ($detail['start_time'] < $time) 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 updateFreeCancel($order,$check=false){
 | 
						||
        if(is_string($order))$order = self::getHaveCancelFreeOrder($order,$check);
 | 
						||
        $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 freeCancel($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
 | 
						||
        //得到可取消订单
 | 
						||
        $order = self::getHaveCancelFreeOrder($order_no,$check);
 | 
						||
        if($check){
 | 
						||
            //用户操作权限检测
 | 
						||
            self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type);
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        //判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
            //事务逻辑
 | 
						||
 | 
						||
            //更新订单取消状态
 | 
						||
            $order = self::updateFreeCancel($order,$check);
 | 
						||
            //插入订单取消日志
 | 
						||
            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' => self::where("id",$order['id'])->find(),"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
            \think\Hook::listen('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;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * 超时取消检测(未支付取消)
 | 
						||
     */
 | 
						||
    public static function timeoutCheck($order_id=0,$trans = false){
 | 
						||
        $count = 0;
 | 
						||
        $unpaid_order_expire_time = config("site.unpaid_activity_cancel_time");
 | 
						||
        if(!$unpaid_order_expire_time|| $unpaid_order_expire_time < 0)return $count;
 | 
						||
        $unpaid_order_expire_time = time() - $unpaid_order_expire_time;
 | 
						||
        //得到所有过期的队列
 | 
						||
        $model = self::where("status",'in',['0'])->where("createtime","<=",$unpaid_order_expire_time);
 | 
						||
        if($order_id)$model = $model->where("id",$order_id);
 | 
						||
        $list = $model->select();
 | 
						||
 | 
						||
        if ($trans) {
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        try {
 | 
						||
 | 
						||
 | 
						||
            foreach ($list as $order)
 | 
						||
            {
 | 
						||
                //取消订单
 | 
						||
                (new self)->freeCancel($order['id'],0,false,'admin',0);
 | 
						||
                $count++;
 | 
						||
            }
 | 
						||
            if ($trans) {
 | 
						||
                self::commitTrans();
 | 
						||
            }
 | 
						||
        } catch (\Exception $e) {
 | 
						||
            if ($trans) {
 | 
						||
                self::rollbackTrans();
 | 
						||
            }
 | 
						||
            throw new \Exception($e->getMessage());
 | 
						||
        }
 | 
						||
        return $count;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**得到可取消的付费订单
 | 
						||
     * @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 getHaveCancelPaidOrder($order_no,$check=true){
 | 
						||
//        $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
 | 
						||
        $order = self::where('order_no|id|pay_no',$order_no)->find();
 | 
						||
        $detail = $order->detail;
 | 
						||
        if(!$detail) throw new \Exception("订单信息缺失!");
 | 
						||
        if(!$order)throw new \Exception("订单信息缺失!");
 | 
						||
        //非免费单进行中无法取消
 | 
						||
        if($order['totalprice'] != 0){
 | 
						||
            //非免费单只有未退款可退
 | 
						||
            if(!in_array($order['status'],["2","3","9"])){
 | 
						||
                throw new \Exception("只有已报名和核销中的单才可以取消!");
 | 
						||
            }
 | 
						||
        }else{
 | 
						||
                throw new \Exception("免费单请走免费订单取消接口!");
 | 
						||
        }
 | 
						||
 | 
						||
        if($check){
 | 
						||
        //根据不同退款策略判断当前时间点是否可取消并退款
 | 
						||
        $refund_status = $detail["refund_status"];
 | 
						||
         //活动开始后不可取消,只能走售后
 | 
						||
        $time = time();
 | 
						||
        switch ($refund_status){
 | 
						||
                case "1": //不退款
 | 
						||
 | 
						||
                    throw new \Exception("当前活动不支持取消退款,请走售后流程!");
 | 
						||
                    break;
 | 
						||
                case "3":  //开始前退
 | 
						||
                case "5":  //随时退
 | 
						||
                    if ($detail['start_time'] < $time) throw new \Exception("活动开始后不可取消,请走售后流程!");
 | 
						||
                    break;
 | 
						||
               default:
 | 
						||
                   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 updatePaidCancel($order,$check=true){
 | 
						||
        if(is_string($order))$order = self::getHaveCancelPaidOrder($order,$check);
 | 
						||
        $order->status = "-3";//refund_status
 | 
						||
        $order->canceltime = time();
 | 
						||
        $order->save();
 | 
						||
 | 
						||
        //将所有资金结算记录作废
 | 
						||
        $data = [
 | 
						||
            "status" =>"-1",
 | 
						||
            "canceltime" => time(),
 | 
						||
        ];
 | 
						||
        SettleLog::where("activity_order_id",$order["id"])->where("status","in",['1','2'])->update($data);
 | 
						||
 | 
						||
        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 getHaveExamineOrder($order_no){
 | 
						||
//        $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
 | 
						||
        $order = self::where('order_no|id|pay_no',$order_no)->where("status","in",["-3",'4'])->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 updateExamineFailSettlement($order,$reason="",$oper_id = 0,$oper_type='user'){
 | 
						||
        if(is_string($order))$order = self::getHaveExamineOrder($order);
 | 
						||
        $order->before_status = $order->status;
 | 
						||
        $order->status = "5";
 | 
						||
        $order->auth_status = "1";
 | 
						||
        $order->server_status = "6";
 | 
						||
        $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 paidCancel($order_no,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$activity_cancel=false,$trans=false){
 | 
						||
        //得到可取消订单
 | 
						||
        $order = self::getHaveCancelPaidOrder($order_no,$check);
 | 
						||
        if($check){
 | 
						||
            //用户操作权限检测
 | 
						||
            self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type);
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        //判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
            //事务逻辑
 | 
						||
 | 
						||
            //更新订单取消状态
 | 
						||
            $order = self::updatePaidCancel($order,$check);
 | 
						||
            //插入订单取消日志
 | 
						||
            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' => self::where("id",$order['id'])->find(),"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
            \think\Hook::listen('activity_order_cancel_after', $data);
 | 
						||
            //执行课时数更新
 | 
						||
            $res1 = self::statisticsAndUpdateClassesNumber($order['id']);
 | 
						||
 | 
						||
            //执行退款
 | 
						||
            //调用退款发起
 | 
						||
            //更新订单状态
 | 
						||
            $reason = "活动取消自动退款";
 | 
						||
            $order = self::updateExamineFailSettlement($order['order_no'],"",$user_id ?: $oper_id,$oper_type);
 | 
						||
 | 
						||
            //审核失败逻辑
 | 
						||
            OrderLog::log($order['id'],"活动取消退款,原因;{$reason},如有退款额度,该活动单将自动退款以便重新下单(没有请忽略)",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
 | 
						||
            //调用订单事件
 | 
						||
            $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
            \think\Hook::listen('activity_order_auth_fail_after', $data);
 | 
						||
            //计算自动退款额度
 | 
						||
            $refundprice = $this->countRefundAmount($order["id"],$activity_cancel);
 | 
						||
            if($refundprice>0){
 | 
						||
                //执行退款
 | 
						||
                self::orderRefund($order['order_no'],$refundprice,$oper_type,$oper_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_id
 | 
						||
     * @param $trans
 | 
						||
     * @return true
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function countRefundAmount($order_id,$activity_cancel=false,$trans=false){
 | 
						||
        $price = 0;
 | 
						||
        $order = self::where('id',$order_id)->find();
 | 
						||
        if(!$order) return $price;
 | 
						||
        $detail = $order->detail;
 | 
						||
        if(!$detail) return $price;
 | 
						||
        //
 | 
						||
//判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
 | 
						||
 | 
						||
            //根据不同退款策略判断当前时间点是否可取消并退款
 | 
						||
            $refund_status = $detail["refund_status"];
 | 
						||
            //活动开始后不可取消,只能走售后
 | 
						||
            $time = time();
 | 
						||
 | 
						||
            if($activity_cancel){
 | 
						||
                //活动取消退全款
 | 
						||
                $price = $order["sub_refundprice"];
 | 
						||
 | 
						||
            }else{
 | 
						||
 | 
						||
                switch ($refund_status){
 | 
						||
                    case "1": //不退款
 | 
						||
 | 
						||
                        throw new \Exception("当前活动不支持取消退款,请走售后流程!");
 | 
						||
                        break;
 | 
						||
                    case "3":  //开始前退
 | 
						||
                    case "5":  //随时退 退全款
 | 
						||
                        $price = $order["sub_refundprice"];
 | 
						||
                        break;
 | 
						||
                    default:
 | 
						||
                        throw new \Exception("不支持的退款策略,请走售后流程!");
 | 
						||
 | 
						||
                }
 | 
						||
 | 
						||
            }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
            if($trans){
 | 
						||
                self::commitTrans();
 | 
						||
            }
 | 
						||
        }catch (\Exception $e){
 | 
						||
            if($trans){
 | 
						||
                self::rollbackTrans();
 | 
						||
            }
 | 
						||
            throw new \Exception($e->getMessage().$e->getFile().$e->getLine());
 | 
						||
        }
 | 
						||
        return $price;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**得到可直接退款订单(正常取消退全款非售后)
 | 
						||
     * @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
 | 
						||
     * @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["total_refundprice"] ?: $order['sub_refundprice'];
 | 
						||
            if($refund_money<=0)$refund_money = 0;
 | 
						||
            if(!$refund_money)throw new \Exception("退款金额异常!");
 | 
						||
 | 
						||
            //保存应退款额
 | 
						||
            $order->total_refundprice = $refund_money;
 | 
						||
            $order->save();
 | 
						||
 | 
						||
 | 
						||
            //事务逻辑
 | 
						||
            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.newactivity.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 退款单号
 | 
						||
     * @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,$price=0,$pay_json=[]){
 | 
						||
        if(is_string($order))$order = self::getHaveRefundOrder($order);
 | 
						||
//        //如果$price为0,尝试从$pay_json退款回调中获取退款金额
 | 
						||
//        if(!$price && $pay_json){
 | 
						||
//            if(isset($pay_json['refund_fee']))$price = bcdiv($pay_json['refund_fee'],100,2);
 | 
						||
//        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
//        $order->before_status  = $order->status;//refund_status
 | 
						||
        $order->status = "6";
 | 
						||
        $order->server_status = "6";
 | 
						||
        $order->real_refundprice = bcadd($order->real_refundprice ?:'0', $price?:$order->total_refundprice  ,2);
 | 
						||
        $order->sub_refundprice =  bcsub($order->sub_refundprice ?:'0', $price?:$order->total_refundprice  ,2);
 | 
						||
        $order->refundtime = time();
 | 
						||
        $order->refund_json = json_encode($pay_json);
 | 
						||
        $order->save();
 | 
						||
        //报废旧的结算单
 | 
						||
            SettleLog::where("activity_order_id",$order['id'])
 | 
						||
            ->where("status" ,"in",["1","2"])
 | 
						||
            ->update([
 | 
						||
                "status"=>"-1",
 | 
						||
                "canceltime" => time()
 | 
						||
            ]);
 | 
						||
 | 
						||
        //若存在剩余金额,结算给发布者
 | 
						||
        if($order->sub_refundprice > $order->fee_scale){
 | 
						||
 | 
						||
            //插入新结算单
 | 
						||
//            (new SettleLog)->generatorLog($order['id']);
 | 
						||
            //对活动订单进行结算记录插入
 | 
						||
            (new SettleLog)->timeoutSettleActivityCheck($order["activity_id"]);
 | 
						||
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        return $order;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**退款成功处理逻辑(需修改)
 | 
						||
     * @param $refund_sn
 | 
						||
     * @param bool $trans
 | 
						||
     * @return bool
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public static function refundSuccess($refund_sn,$refund_json=[],$price=0,$trans=false){
 | 
						||
        //得到机构售后提交确认订单
 | 
						||
        $order = self::getHaveRefundOrder($refund_sn);
 | 
						||
 | 
						||
        //判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
            //事务逻辑
 | 
						||
 | 
						||
            //更新订单状态为同意
 | 
						||
            $order = self::updateRefundOrder($refund_sn,$price,$refund_json);
 | 
						||
 | 
						||
            //插入订单日志
 | 
						||
            OrderLog::log($order['id'],"活动订单退款已原路退回", 'admin', 0);
 | 
						||
 | 
						||
            //执行课时数更新
 | 
						||
            $res1 = self::statisticsAndUpdateClassesNumber($order['id']);
 | 
						||
 | 
						||
            //调用订单取消事件
 | 
						||
            $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$order['user_id'],"oper_type"=>'admin',"oper_id"=>0];
 | 
						||
            \think\Hook::listen('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' => self::where("id",$order['id'])->find(),"user_id"=>$order['user_id'],"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
            \think\Hook::listen('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_no
 | 
						||
     * @return array|false|\PDOStatement|string|Model
 | 
						||
     * @throws \think\db\exception\DataNotFoundException
 | 
						||
     * @throws \think\db\exception\ModelNotFoundException
 | 
						||
     * @throws \think\exception\DbException
 | 
						||
     */
 | 
						||
    public static function getHaveAfterSalesOrder($refund_sn,$check=true){
 | 
						||
//        $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
 | 
						||
        $order = self::where('refund_no|order_no|id',$refund_sn)->where('status',"in",["2","3","9"])->where("sub_refundprice",">",0)->find();
 | 
						||
        if(!$order)throw new \Exception("不是可直接退款的订单!");
 | 
						||
        $detail = $order->detail;
 | 
						||
        if(!$detail)throw new \Exception("找不到订单详情!");
 | 
						||
        if($check){
 | 
						||
          if(!in_array($order['status'],["2","3","9"])) throw new \Exception("不是可申请售后的订单!");
 | 
						||
          //申请售后必须是活动结束后n秒内
 | 
						||
            $last_time = $detail['end_time'] + config('site.activity_end_sales');
 | 
						||
            if(time() > $last_time) throw new \Exception("已超过发起售后的最后期限!");
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
        return $order;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public function updateAfterSales($order,$total_refundprice,$auth_reason,$check=true){
 | 
						||
        if(is_numeric($order))$order = self::getHaveAfterSalesOrder($order,$check);
 | 
						||
        $order["before_status"] = $order["status"];
 | 
						||
        $order["status"] = "4";
 | 
						||
        $order["server_status"] = "3";
 | 
						||
        $order["auth_time"] = time();
 | 
						||
        $order["auth_status"] = 0;
 | 
						||
        $order["auth_reason"] = $auth_reason;
 | 
						||
        $order["total_refundprice"] = $total_refundprice;
 | 
						||
        $order["first_refundprice"] = $total_refundprice;
 | 
						||
        $order->save();
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /** 发起售后
 | 
						||
     * @param $order_no
 | 
						||
     * @param $user_id
 | 
						||
     * @param $trans
 | 
						||
     * @return true
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function afterSales($order,$num,$auth_reason,$user_id ,$check=true,$oper_type='user',$oper_id=0,$trans=false){
 | 
						||
        if(is_numeric($order))$order = self::getHaveAfterSalesOrder($order,$check);
 | 
						||
        if(!$order)throw new \Exception("找不到订单");
 | 
						||
        if($check){
 | 
						||
            //用户操作权限检测
 | 
						||
            self::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type);
 | 
						||
 | 
						||
        }
 | 
						||
        $detail = $order->detail;
 | 
						||
        if(!$detail)throw new \Exception("找不到订单详情!");
 | 
						||
        if(!$auth_reason) throw new \Exception("请填写申请原因");
 | 
						||
 | 
						||
 | 
						||
        //$num至少要1,至多要订单数量
 | 
						||
        if($num < 1 || $num > $order['num']) throw new \Exception("数量错误");
 | 
						||
        $total_refundprice = bcmul($detail['price'],$num,2);
 | 
						||
 | 
						||
        if($total_refundprice < 0.01 || $total_refundprice > $order['sub_refundprice']) throw new \Exception("退款金额错误");
 | 
						||
 | 
						||
//判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
            //设置订单申请状态
 | 
						||
            $this->updateAfterSales($order,$total_refundprice,$auth_reason,$check);
 | 
						||
 | 
						||
            //订单日志
 | 
						||
            OrderLog::log($order['id'],"活动订单申请售后:".$auth_reason,  $oper_type, $oper_id);
 | 
						||
 | 
						||
            //调用订单取消事件
 | 
						||
            $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$order['user_id'],"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
            \think\Hook::listen('activity_order_after_sales_after', $data);
 | 
						||
 | 
						||
 | 
						||
 | 
						||
            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 getHaveShopConfirmationOrder($refund_sn,$check=true){
 | 
						||
//        $where = [self::STATUS_NOPAY,self::STATUS_PAYED];
 | 
						||
        $order = self::where('refund_no|order_no|id',$refund_sn)->where('status',"in",["4","7"])->where("sub_refundprice",">",0)->find();
 | 
						||
        if(!$order)throw new \Exception("不是可直接退款的订单!");
 | 
						||
        $detail = $order->detail;
 | 
						||
        if(!$detail)throw new \Exception("找不到订单详情!");
 | 
						||
        if($check){
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
        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 updateShopConfirmationOrder($order,$price){
 | 
						||
        if(is_string($order))$order = self::getHaveShopConfirmationOrder($order);
 | 
						||
        $order->status = "5";//refund_status
 | 
						||
        $order->server_status = "6";
 | 
						||
        $order->auth_status = 1;
 | 
						||
        $order['suspend_status'] = '1';
 | 
						||
        $order->total_refundprice = $price;
 | 
						||
        $order->refundtime = 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 updateShopConfirmationFailOrder($order,$reason){
 | 
						||
        if(is_string($order))$order = self::getHaveShopConfirmationOrder($order);
 | 
						||
        $order["status"] = "7";//refund_status
 | 
						||
        $order["server_status"] = "6";
 | 
						||
        $order["auth_status"] = 2;
 | 
						||
        $order["reason"] = $reason;
 | 
						||
        $order['suspend_status'] = '1';
 | 
						||
        $order->save();
 | 
						||
        return $order;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
    /**发布者售后提交确认信息
 | 
						||
     * @param $order_no
 | 
						||
     * @param int $user_id
 | 
						||
     * @param string $status yes同意  no拒绝
 | 
						||
     *@param string $price 商定价格
 | 
						||
     *@param string $reject_reason 拒绝原因
 | 
						||
     * @param bool $check
 | 
						||
     * @param bool $trans
 | 
						||
     * @return bool
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function shopConfirmation($order_no,$status,$price,$reject_reason,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
 | 
						||
 | 
						||
 | 
						||
        //得到机构售后提交确认订单
 | 
						||
        $order = self::getHaveShopConfirmationOrder($order_no);
 | 
						||
        $this->timeoutSuspension($order['id'],$trans);
 | 
						||
        //得到机构售后提交确认订单
 | 
						||
        $order = self::getHaveShopConfirmationOrder($order_no);
 | 
						||
        if($check){
 | 
						||
            //用户操作权限检测
 | 
						||
            Order::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type,false,true);
 | 
						||
        }
 | 
						||
        $classesorder = $order;
 | 
						||
        if(!$classesorder)throw new \Exception("订单不存在!");
 | 
						||
 | 
						||
        switch ($status){
 | 
						||
            case 'yes':
 | 
						||
                //同意
 | 
						||
                //验证价格正确性
 | 
						||
                //金额必须小于等于剩余未退全额
 | 
						||
                $price = floatval($price);
 | 
						||
                if($price > $classesorder['sub_refundprice']){
 | 
						||
                    throw new \Exception("价格必须小于等于剩余应退全额!");
 | 
						||
                }
 | 
						||
                //数据修正大于剩余未退全额 则等于剩余未退
 | 
						||
                $price = $price > $classesorder['sub_refundprice'] ? $classesorder['sub_refundprice'] : $price;
 | 
						||
                if($price<=0)throw new \Exception("同意退款必须大于0!");
 | 
						||
 | 
						||
                //如果非全额退款,剩余金额必须大于订单支付时的手续费
 | 
						||
                if($price < $classesorder['sub_refundprice']){
 | 
						||
                  $sub_price = bcsub($classesorder['sub_refundprice'] , $price,2);
 | 
						||
                  if($sub_price <= $classesorder['fee_price']){
 | 
						||
                      throw new \Exception("如果未退全款,剩余未退金额必须大于订单支付时的手续费{$classesorder['fee_price']}!");
 | 
						||
                  }
 | 
						||
                }
 | 
						||
 | 
						||
                break;
 | 
						||
            case 'no':
 | 
						||
                //拒绝
 | 
						||
                //拒绝原因必填
 | 
						||
                if(!$reject_reason)throw new \Exception("拒绝原因必填!");
 | 
						||
 | 
						||
 | 
						||
 | 
						||
                break;
 | 
						||
            default:
 | 
						||
                throw new \Exception("参数错误!");
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        //判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
 | 
						||
 | 
						||
            //事务逻辑
 | 
						||
            //更新售后为取消状态
 | 
						||
            switch ($status){
 | 
						||
                case 'yes':
 | 
						||
                    //同意
 | 
						||
 | 
						||
                    //更新订单状态为同意
 | 
						||
                    $order = self::updateShopConfirmationOrder($order,$price);
 | 
						||
 | 
						||
                    //插入订单日志
 | 
						||
                    if(!$user_id ||$order["user_id"] !=$user_id ){
 | 
						||
                        OrderLog::log($order['id'],"[系统操作]活动订单售后已处理,用户发起金额为{$order['first_refundprice']},确认退款金额为{$price}元,等待退款到账",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
 | 
						||
                    }else{
 | 
						||
                        OrderLog::log($order['id'],"活动订单售后已处理,用户发起金额为{$order['first_refundprice']},确认退款金额为{$price}元,等待退款到账",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
 | 
						||
                    }
 | 
						||
 | 
						||
                    //调用订单事件
 | 
						||
                    $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
                    \think\Hook::listen('activity_order_shop_confirm_after', $data);
 | 
						||
 | 
						||
 | 
						||
                    //执行退款
 | 
						||
                    //执行退款
 | 
						||
                    self::orderRefund($order['order_no'],$price,$oper_type,$oper_id);
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
                    break;
 | 
						||
                case 'no':
 | 
						||
                    //拒绝
 | 
						||
 | 
						||
                    //更新
 | 
						||
                    //更新售后为机构驳回结单状态
 | 
						||
                    $order = self::updateShopConfirmationFailOrder($order,$reject_reason);
 | 
						||
 | 
						||
                    //插入订单日志
 | 
						||
                    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' => self::where("id",$order['id'])->find(),"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
                    \think\Hook::listen('activity_order_shop_reject_after', $data);
 | 
						||
 | 
						||
 | 
						||
                    break;
 | 
						||
                default:
 | 
						||
                    throw new \Exception("参数错误!");
 | 
						||
            }
 | 
						||
            //执行课时数更新
 | 
						||
            $res1 = order::statisticsAndUpdateClassesNumber($order);
 | 
						||
 | 
						||
 | 
						||
            if($trans){
 | 
						||
                self::commitTrans();
 | 
						||
            }
 | 
						||
        }catch (\Exception $e){
 | 
						||
            if($trans){
 | 
						||
                self::rollbackTrans();
 | 
						||
            }
 | 
						||
            throw new \Exception($e->getMessage());
 | 
						||
        }
 | 
						||
        return $res1;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /** 检测售后订单超时未处理自动挂起定时任务
 | 
						||
     * @param $id 售后订单id非必填,不填则检测所有超时未处理的
 | 
						||
     * @param $trans
 | 
						||
     * @return true
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function timeoutSuspension($id=0,$trans=false){
 | 
						||
        //去超时时间戳配置
 | 
						||
        $timeout = config('site.activity_end_sales');
 | 
						||
        //当前时间
 | 
						||
        $time = time();
 | 
						||
        //延期时间过了当前时间的时间点(用时间戳相减特性)
 | 
						||
        $delay_time = $time - $timeout;
 | 
						||
        //初始查询model
 | 
						||
        $as = $this->getWithAlisaName();
 | 
						||
        $model = self::with(["detail"])
 | 
						||
            ->where("{$as}.server_status",'3')
 | 
						||
            ->where("{$as}.suspend_status",'0')
 | 
						||
            ->where("{$as}.status",'4');
 | 
						||
        if($id){
 | 
						||
            $model = $model->where("{$as}.id",$id);
 | 
						||
        }
 | 
						||
        //查询条件2:过了活动结束时间加延期时间的订单
 | 
						||
        $model = $model->where("detail.end_time","<",$delay_time);
 | 
						||
        $list = $model->select();
 | 
						||
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
            //遍历订单,执行挂起操作
 | 
						||
            foreach ($list as $row){
 | 
						||
                //执行挂起操作
 | 
						||
                $row["status"] = "7";
 | 
						||
                $row["server_status"] = "6";
 | 
						||
                $row["suspend_status"] = "2";
 | 
						||
                $row["auth_status"] = 2;
 | 
						||
                $row["auth_time"] = time();
 | 
						||
                $row->save();
 | 
						||
 | 
						||
                //写订单日志
 | 
						||
                OrderLog::log($row['id'],"活动订单售后超时自动驳回,订单挂起,等待官方处理",'admin', 0);
 | 
						||
                //调用挂起事件
 | 
						||
                $data = ['order' => self::where("id",$row['id'])->find(),"user_id"=>0,"oper_type"=>"admin","oper_id"=>0];
 | 
						||
                \think\Hook::listen('activity_order_timeout_reject_after', $data);
 | 
						||
 | 
						||
 | 
						||
 | 
						||
            }
 | 
						||
            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
 | 
						||
     * @param int $user_id
 | 
						||
     * @param string $status yes同意  no拒绝(即订单按完成算)
 | 
						||
     * @param string $price 商定价格
 | 
						||
     * @param bool $check
 | 
						||
     * @param bool $trans
 | 
						||
     * @return bool
 | 
						||
     * @throws \Exception
 | 
						||
     */
 | 
						||
    public function adminConfirmation($order_no,$status,$price,$user_id=0,$check=false,$oper_type='user',$oper_id=0,$trans=false){
 | 
						||
        //得到机构售后提交确认订单
 | 
						||
        $order = self::getHaveShopConfirmationOrder($order_no);
 | 
						||
 | 
						||
        if($check){
 | 
						||
            //用户操作权限检测
 | 
						||
            Order::checkOptionAuth($order['id'],$user_id ?: $oper_id,$oper_type,false,false,true);
 | 
						||
        }
 | 
						||
        $classesorder = $order;
 | 
						||
        if(!$classesorder)throw new \Exception("订单不存在!");
 | 
						||
 | 
						||
        switch ($status){
 | 
						||
            case 'yes':
 | 
						||
                //同意
 | 
						||
                //验证价格正确性
 | 
						||
                //金额必须小于等于剩余未退全额
 | 
						||
                $price = floatval($price);
 | 
						||
                if($price > $classesorder['sub_refundprice']){
 | 
						||
                    throw new \Exception("价格必须小于等于剩余应退全额!");
 | 
						||
                }
 | 
						||
                //数据修正大于剩余未退全额 则等于剩余未退
 | 
						||
                $price = $price > $classesorder['sub_refundprice'] ? $classesorder['sub_refundprice'] : $price;
 | 
						||
                if($price<=0)throw new \Exception("同意退款必须大于0!");
 | 
						||
 | 
						||
                //如果非全额退款,剩余金额必须大于订单支付时的手续费
 | 
						||
                if($price < $classesorder['sub_refundprice']){
 | 
						||
                    $sub_price = bcsub($classesorder['sub_refundprice'] , $price,2);
 | 
						||
                    if($sub_price <= $classesorder['fee_price']){
 | 
						||
                        throw new \Exception("如果未退全款,剩余未退金额必须大于订单支付时的手续费{$classesorder['fee_price']}!");
 | 
						||
                    }
 | 
						||
                }
 | 
						||
 | 
						||
                break;
 | 
						||
            case 'no':
 | 
						||
                //拒绝
 | 
						||
 | 
						||
                break;
 | 
						||
            default:
 | 
						||
                throw new \Exception("参数错误!");
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        //判断逻辑
 | 
						||
        if($trans){
 | 
						||
            self::beginTrans();
 | 
						||
        }
 | 
						||
        $res = true;
 | 
						||
        try{
 | 
						||
 | 
						||
 | 
						||
            //事务逻辑
 | 
						||
            //更新售后为取消状态
 | 
						||
            switch ($status){
 | 
						||
                case 'yes':
 | 
						||
                    //同意
 | 
						||
 | 
						||
                    //更新订单状态为同意
 | 
						||
                    $order = self::updateShopConfirmationOrder($order,$price);
 | 
						||
 | 
						||
                    //插入订单日志
 | 
						||
                    if(!$user_id ||$order["user_id"] !=$user_id ){
 | 
						||
                        OrderLog::log($order['id'],"[系统操作]活动订单售后最终处理结果:用户发起金额为{$order['first_refundprice']},确认退款金额为{$price}元,等待退款到账",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
 | 
						||
                    }else{
 | 
						||
                        OrderLog::log($order['id'],"活动订单售后最终处理结果:用户发起金额为{$order['first_refundprice']},确认退款金额为{$price}元,等待退款到账",$oper_type ?: 'user', $oper_id ?: $order['user_id']);
 | 
						||
                    }
 | 
						||
 | 
						||
                    //调用订单事件
 | 
						||
                    $data = ['order' => self::where("id",$order['id'])->find(),"user_id"=>$user_id,"oper_type"=>$oper_type,"oper_id"=>$oper_id];
 | 
						||
                    \think\Hook::listen('activity_order_shop_confirm_after', $data);
 | 
						||
 | 
						||
 | 
						||
                    //执行退款
 | 
						||
                    //执行退款
 | 
						||
                    self::orderRefund($order['order_no'],$price,$oper_type,$oper_id);
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
                    break;
 | 
						||
                case 'no':
 | 
						||
                    //拒绝
 | 
						||
 | 
						||
                    //插入订单日志
 | 
						||
                    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']);
 | 
						||
                    }
 | 
						||
 | 
						||
                    //调用订单完成
 | 
						||
                    //执行订单完成的更新逻辑
 | 
						||
                    self::updateFinish($order);
 | 
						||
 | 
						||
 | 
						||
                    break;
 | 
						||
                default:
 | 
						||
                    throw new \Exception("参数错误!");
 | 
						||
            }
 | 
						||
            //执行课时数更新
 | 
						||
            $res1 = order::statisticsAndUpdateClassesNumber($order);
 | 
						||
 | 
						||
 | 
						||
            if($trans){
 | 
						||
                self::commitTrans();
 | 
						||
            }
 | 
						||
        }catch (\Exception $e){
 | 
						||
            if($trans){
 | 
						||
                self::rollbackTrans();
 | 
						||
            }
 | 
						||
            throw new \Exception($e->getMessage());
 | 
						||
        }
 | 
						||
        return $res1;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
}
 |