275 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			275 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						||
 | 
						||
 | 
						||
namespace addons\xilufitness\services\pay;
 | 
						||
 | 
						||
 | 
						||
use addons\xilufitness\services\BaseService;
 | 
						||
use addons\xilufitness\services\user\UserService;
 | 
						||
use think\Db;
 | 
						||
use think\Exception;
 | 
						||
use function EasyWeChat\Kernel\Support\get_client_ip;
 | 
						||
 | 
						||
class PayService extends BaseService
 | 
						||
{
 | 
						||
 | 
						||
    /**
 | 
						||
     * 支付网关
 | 
						||
     * @param int $order_id 订单id
 | 
						||
     * @param int $order_type 订单类型 0 充值订单 1 团课 2 私教课 3 活动
 | 
						||
     * @param int $pay_type 支付类型 0 免支付 1 会员卡支付 2 微信支付
 | 
						||
     */
 | 
						||
    public function gateWay(int $order_id, int $order_type,int $pay_type = 2){
 | 
						||
        $orderInfo = $this->getOrderInfo($order_id,$order_type);
 | 
						||
        if(empty($orderInfo)){
 | 
						||
            $this->resultError('订单不存在');
 | 
						||
        } else if($orderInfo['pay_status'] == 1){
 | 
						||
            $this->resultError('订单已支付');
 | 
						||
        } else {
 | 
						||
            $cashResult = $this->createCash($orderInfo,$order_type);
 | 
						||
            if(false !== $cashResult){
 | 
						||
                if($pay_type == 0){
 | 
						||
                    $result = $this->freePay($orderInfo);
 | 
						||
                } elseif ($pay_type == 1){
 | 
						||
                    $result = $this->getMemberCardPay($orderInfo);
 | 
						||
                } else {
 | 
						||
                    $result = $this->getWechatPay($orderInfo,$order_type);
 | 
						||
                }
 | 
						||
                return $result;
 | 
						||
            } else {
 | 
						||
                $this->resultError('支付发起失败');
 | 
						||
            }
 | 
						||
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 创建支付流水记录
 | 
						||
     * @param object $orderInfo 订单详情
 | 
						||
     * @param int $order_type 订单类型
 | 
						||
     */
 | 
						||
    private function createCash(object $orderInfo, int $order_type){
 | 
						||
        $cashModel = new \addons\xilufitness\model\CashFlow;
 | 
						||
        $cashInfo = $cashModel
 | 
						||
            ->where(['user_id' => $orderInfo->user_id, 'order_no' => $orderInfo->order_no, 'order_type' => $order_type])
 | 
						||
            ->field(['id','user_id','order_no','updatetime','createtime'])
 | 
						||
            ->find();
 | 
						||
        if(!empty($cashInfo)){
 | 
						||
            $result = $cashInfo->save(['updatetime' => time(), 'createtime' => time()]);
 | 
						||
        } else {
 | 
						||
            $result = $cashModel->save([
 | 
						||
                'brand_id' => $orderInfo->brand_id,
 | 
						||
                'user_id' => $orderInfo->user_id,
 | 
						||
                'order_type' => $order_type,
 | 
						||
                'order_no' => $orderInfo->order_no,
 | 
						||
                'pay_amount' => $orderInfo->pay_amount,
 | 
						||
                'pay_type' => $orderInfo->pay_type,
 | 
						||
            ]);
 | 
						||
        }
 | 
						||
        return $result;
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取订单详情
 | 
						||
     * @param int $order_id 订单id
 | 
						||
     * @param int $order_type 订单类型 0 充值订单 1 团课 2 私教课 3 活动
 | 
						||
     * @param string $order_no 订单号
 | 
						||
     */
 | 
						||
    public function getOrderInfo(int $order_id, int $order_type,string $order_no='') {
 | 
						||
        $orderModel = new \addons\xilufitness\model\Order;
 | 
						||
        if(!empty($this->getUserId())){
 | 
						||
            $where['user_id'] = $this->getUserId();
 | 
						||
        }
 | 
						||
        if(!empty($order_id)){
 | 
						||
            $where['id'] = $order_id;
 | 
						||
        }
 | 
						||
        if(!empty($order_no)){
 | 
						||
            $where['order_no'] = $order_no;
 | 
						||
        }
 | 
						||
        $info = $orderModel
 | 
						||
            ->where($where)
 | 
						||
            ->find();
 | 
						||
        return $info;
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取用户小程序openid
 | 
						||
     */
 | 
						||
    public function getOpenid(){
 | 
						||
        $model = new \addons\xilufitness\model\UserConnect;
 | 
						||
        $openid = $model
 | 
						||
            ->where(['brand_id' => $this->brand_id, 'account_user_id' => $this->getUserId()])
 | 
						||
            ->value('openid');
 | 
						||
        return $openid;
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 微信支付发起
 | 
						||
     * @param object $orderInfo 订单详情
 | 
						||
     * @param int $order_type 订单类型
 | 
						||
     */
 | 
						||
    public function getWechatPay(object $orderInfo,int $order_type){
 | 
						||
        try {
 | 
						||
            $test_pay_uids = array_filter(explode(',',config('site.wechar_pay_user_ids')));
 | 
						||
            $wechat = \WeChat\Pay::instance($this->data['mini_config']);
 | 
						||
            // 4. 组装参数,可以参考官方商户文档
 | 
						||
            $options = [
 | 
						||
                'body'             => $orderInfo['pay_body'] ?? '健身小程序商品支付',
 | 
						||
                'out_trade_no'     => $orderInfo['order_no'],
 | 
						||
                'total_fee'        => !empty($test_pay_uids) && in_array($orderInfo['user_id'],$test_pay_uids) ? 1 : $orderInfo['pay_amount']*100,
 | 
						||
                'openid'           => $this->getOpenid(),
 | 
						||
                'trade_type'       => 'JSAPI',
 | 
						||
                'notify_url'       => url('/addons/xilufitness/pay/notify',['order_type' => $order_type, 'brand_id' => $orderInfo['brand_id'] ?? 0],true,true),
 | 
						||
                'spbill_create_ip' => get_client_ip(),
 | 
						||
            ];
 | 
						||
            // 生成预支付码
 | 
						||
            $result = $wechat->createOrder($options);
 | 
						||
            // 创建JSAPI参数签名
 | 
						||
            $options = $wechat->createParamsForJsApi($result['prepay_id']);
 | 
						||
            return $options;
 | 
						||
        } catch (\Exception $e){
 | 
						||
            $this->resultError($e->getMessage());
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 会员卡支付
 | 
						||
     * @param object $orderInfo 订单详情
 | 
						||
     */
 | 
						||
    public function getMemberCardPay(object $orderInfo){
 | 
						||
        return $orderInfo->payAfter($orderInfo,time(),1);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 免支付
 | 
						||
     * @param object $orderInfo 订单详情
 | 
						||
     */
 | 
						||
    public function freePay(object $orderInfo){
 | 
						||
        return $orderInfo->payAfter($orderInfo,time(),0);
 | 
						||
    }
 | 
						||
    /**
 | 
						||
     * 支付异步通知
 | 
						||
     */
 | 
						||
    public function notify($order_type){
 | 
						||
        try {
 | 
						||
            $wechat = \WeChat\Pay::instance($this->data['mini_config']);
 | 
						||
            // 4. 获取通知参数
 | 
						||
            $data = $wechat->getNotify();
 | 
						||
//            Db::name('xilufitness_logs')->insertGetId(['content' => json_encode($data)]);
 | 
						||
//            $data = json_decode(Db::name('xilufitness_logs')->where(['id' => 37])->value('content'),true);
 | 
						||
            $orderInfo = $this->getOrderInfo(0,$order_type,$data['out_trade_no']);
 | 
						||
            if ($data['return_code'] === 'SUCCESS' && $data['result_code'] === 'SUCCESS') {
 | 
						||
                if(!empty($orderInfo) && $orderInfo['pay_status'] == 0){
 | 
						||
                    $orderInfo->payAfter($orderInfo,$data['transaction_id'] ?? '',$orderInfo['pay_type']);
 | 
						||
                }
 | 
						||
                // 返回接收成功的回复
 | 
						||
                ob_clean();
 | 
						||
                echo $wechat->getNotifySuccessReply();
 | 
						||
            }
 | 
						||
        } catch (\Exception $e){
 | 
						||
            echo $e->getMessage() . PHP_EOL;
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 退款申请
 | 
						||
     * @param int $order_id 订单id
 | 
						||
     * @param int $brand_id 品牌商id
 | 
						||
     * @return bool
 | 
						||
     */
 | 
						||
    public function refundOrder(int $order_id,int $brand_id = 0){
 | 
						||
        $model = new \addons\xilufitness\model\Order;
 | 
						||
        $where['id'] = $order_id;
 | 
						||
        if(!empty($this->getUserId())){
 | 
						||
            $where['user_id'] = $this->getUserId();
 | 
						||
        }
 | 
						||
        $where['brand_id'] = !empty($brand_id) ? $brand_id : $this->brand_id;
 | 
						||
        $orderInfo = $model->where($where)->find();
 | 
						||
        $cancel_able_time = $orderInfo['starttime'] - 300;
 | 
						||
        if(empty($orderInfo)){
 | 
						||
            throw new Exception('订单不存在');
 | 
						||
        } else if($cancel_able_time < time()){
 | 
						||
            throw new Exception('离开课不到5分钟,暂时不能取消');
 | 
						||
        } else if($orderInfo['pay_type'] == 0){
 | 
						||
            throw new Exception('免支付订单,暂时不能取消');
 | 
						||
        } else {
 | 
						||
            if($orderInfo['pay_type'] == 1){
 | 
						||
                //会员卡
 | 
						||
                return  $this->refundCard($orderInfo);
 | 
						||
            } elseif($orderInfo['pay_type'] == 2) {
 | 
						||
                //微信支付
 | 
						||
                return  $this->refundWechat($orderInfo);
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 会员卡原路退回
 | 
						||
     */
 | 
						||
    private function refundCard($orderInfo){
 | 
						||
        $title = $this->getRefundTitle($orderInfo);
 | 
						||
        return UserService::getInstance()->userAccountChange($title,$orderInfo->user_id,xilufitness_get_id_value($orderInfo->id),$orderInfo['pay_amount'],1,$orderInfo['order_type']);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 微信原路退回
 | 
						||
     */
 | 
						||
    private function refundWechat($orderInfo){
 | 
						||
        $wechat = \WeChat\Pay::instance($this->data['mini_config']);
 | 
						||
        $return_no = 'R'.xilufitness_build_order_no();
 | 
						||
        $test_pay_uids = array_filter(explode(',',config('site.wechar_pay_user_ids')));
 | 
						||
        // 4. 组装参数,可以参考官方商户文档
 | 
						||
        $options = [
 | 
						||
            'transaction_id' => $orderInfo['trade_no'],
 | 
						||
            'out_refund_no'  => $return_no,
 | 
						||
            'total_fee'      => !empty($test_pay_uids) && in_array($orderInfo['user_id'],$test_pay_uids) ? 1 : $orderInfo['pay_amount'] * 100,
 | 
						||
            'refund_fee'     => !empty($test_pay_uids) && in_array($orderInfo['user_id'],$test_pay_uids) ? 1 : $orderInfo['pay_amount'] * 100,
 | 
						||
        ];
 | 
						||
        $result = $wechat->createRefund($options);
 | 
						||
        if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
 | 
						||
            $orderInfo->allowField(true)->save(['re_no' => $return_no ?? '']);
 | 
						||
            return true;
 | 
						||
        } else {
 | 
						||
            throw new Exception($result['err_code_des'] ?? '微信退款申请失败');
 | 
						||
        }
 | 
						||
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取退款标题
 | 
						||
     */
 | 
						||
    private function getRefundTitle($orderInfo){
 | 
						||
        if($orderInfo['order_type'] == 1){
 | 
						||
            $title = '团课取消退款:'.$orderInfo['order_no'];
 | 
						||
        } elseif ($orderInfo['order_type'] == 2){
 | 
						||
            $title = '私教课取消退款:'.$orderInfo['order_no'];
 | 
						||
        } else {
 | 
						||
            $title = '活动取消退款:'.$orderInfo['order_no'];
 | 
						||
        }
 | 
						||
        return $title;
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 排队释放
 | 
						||
     * @param int $num 释放人数
 | 
						||
     * @param int $data_id 排课id
 | 
						||
     * @param int $course_type 课程类型 1 团课 2 私教课 3 活动
 | 
						||
     * @return bool
 | 
						||
     */
 | 
						||
    public function orderQueue(int $num = 0,int $data_id,int $course_type,int $brand_id=0){
 | 
						||
        if($num == 0) return false;
 | 
						||
        $model = new \addons\xilufitness\model\Order;
 | 
						||
        $queueList = $model
 | 
						||
            ->where(['brand_id' => $brand_id, 'data_id' => $data_id, 'order_type' => $course_type, 'order_status' => 10])
 | 
						||
            ->order("pay_time asc")
 | 
						||
            ->limit($num)
 | 
						||
            ->select();
 | 
						||
        if(empty($queueList)) return false;
 | 
						||
        foreach ($queueList as $key => $val){
 | 
						||
            $val->save(['order_status' => 1]);
 | 
						||
        }
 | 
						||
        return true;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
} |