325 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						||
 | 
						||
namespace app\api\controller\school;
 | 
						||
 | 
						||
use addons\epay\library\Service;
 | 
						||
use addons\third\model\Third;
 | 
						||
use app\common\model\school\classes\order\Order as OrderModel;
 | 
						||
use Exception;
 | 
						||
 | 
						||
use think\Log;
 | 
						||
 | 
						||
/**
 | 
						||
 * 课程支付接口
 | 
						||
 */
 | 
						||
class Pay extends Base
 | 
						||
{
 | 
						||
 | 
						||
    protected $noNeedLogin = '*';
 | 
						||
    protected $noNeedRight = '*';
 | 
						||
    protected $model = null;
 | 
						||
 | 
						||
    /**
 | 
						||
     * 初始化操作
 | 
						||
     * @access protected
 | 
						||
     */
 | 
						||
    protected function _initialize()
 | 
						||
    {
 | 
						||
 | 
						||
        $this->model = new OrderModel;
 | 
						||
        parent::_initialize();
 | 
						||
 | 
						||
        //判断登录用户是否是员工
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * @ApiTitle( 课程第三方支付)
 | 
						||
     * @ApiSummary(课程第三方支付(微信等支付))
 | 
						||
     * @ApiRoute(/api/school/pay/payment)
 | 
						||
     * @ApiMethod(POST)
 | 
						||
     * @ApiParams(name = "order_no", type = "string",required=true,description = "订单id或订单号")
 | 
						||
     * @ApiParams(name = "type", type = "string",required=true,description = "服务商:alipay=支付宝,wechat=微信")
 | 
						||
     * @ApiParams(name = "platform", type = "string",required=true,description = "平台:web=PC网页支付,wap=H5手机网页支付,app=APP支付,scan=扫码支付,mp=微信公众号支付,miniapp=微信小程序支付")
 | 
						||
     * @ApiParams(name = "openid", type = "string",required=false,description = "用户openid(非必填)")
 | 
						||
     * @ApiReturn({
 | 
						||
     *
 | 
						||
     *})
 | 
						||
     */
 | 
						||
    public function payment()
 | 
						||
    {
 | 
						||
        $this->setUrlLock();
 | 
						||
 | 
						||
        $order_no = $this->request->post('order_no/s');
 | 
						||
        $type = $this->request->post('type/s');
 | 
						||
        $method = $this->request->post('platform/s');
 | 
						||
        $openid = $this->request->post('openid/s', "");
 | 
						||
        $platform = $method;
 | 
						||
        try {
 | 
						||
            //订单支付前校验
 | 
						||
            $this->model->checkPay($order_no,$type);
 | 
						||
            $order = OrderModel::where('order_no', $order_no)->find();
 | 
						||
            $amount = $order["totalprice"];
 | 
						||
        } catch (\Exception $e) {
 | 
						||
            $this->error($e->getMessage());
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        if (!$amount || $amount < 0) {
 | 
						||
            $this->error("支付金额必须大于0");
 | 
						||
        }
 | 
						||
 | 
						||
        if (!$type || !in_array($type, ['alipay', 'wechat'])) {
 | 
						||
            $this->error("支付类型不能为空");
 | 
						||
        }
 | 
						||
 | 
						||
        if (in_array($method, ['miniapp', 'mp']) && !$openid) {
 | 
						||
 | 
						||
            // 微信公众号,小程序支付,必须有 openid
 | 
						||
                    if (isset($openid) && $openid) {
 | 
						||
                        // 如果传的有 openid
 | 
						||
                    } else {
 | 
						||
                        // 没有 openid 默认拿下单人的 openid
 | 
						||
                        $oauth = Third::where([
 | 
						||
                            'user_id' => $order->user_id,
 | 
						||
                            'platform' => $type,
 | 
						||
                            'apptype' => $platform
 | 
						||
                        ])->find();
 | 
						||
 | 
						||
                        $openid = $oauth ? $oauth->openid : '';
 | 
						||
                    }
 | 
						||
 | 
						||
                    if (!$openid) {
 | 
						||
                        // 缺少 openid
 | 
						||
                        $this->error("授权过期,请您重新授权登录");
 | 
						||
                    }
 | 
						||
        }
 | 
						||
 | 
						||
        //订单号
 | 
						||
        $out_trade_no = $order_no;
 | 
						||
 | 
						||
        //订单标题
 | 
						||
        $title = '课程订单['.$out_trade_no."]支付";
 | 
						||
 | 
						||
        //回调链接
 | 
						||
        $notifyurl = $this->request->root(true) . '/api/school/pay/notifyx/paytype/' . $type. '/platform/' . $method;
 | 
						||
        $returnurl = $this->request->root(true) . '/api/school/pay/returnx/paytype/' . $type . '/out_trade_no/' . $out_trade_no;
 | 
						||
 | 
						||
        $response = Service::submitOrder($amount, $out_trade_no, $type, $title, $notifyurl, $returnurl, $method, $openid);
 | 
						||
 | 
						||
        $this->success('查询成功', ["paydata"=>$response]);
 | 
						||
 | 
						||
//        return $response;
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * @ApiTitle( 第三方支付支付成功回调)
 | 
						||
     * @ApiSummary(第三方支付成功回调)
 | 
						||
     * @ApiRoute(/api/school/pay/notifyx)
 | 
						||
     * @ApiMethod(GET)
 | 
						||
     * @ApiReturn({
 | 
						||
     *
 | 
						||
     *})
 | 
						||
     */
 | 
						||
    public function notifyx()
 | 
						||
    {
 | 
						||
        $paytype = $this->request->param('paytype');
 | 
						||
        $platform = $this->request->param('platform');
 | 
						||
        $pay = Service::checkNotify($paytype);
 | 
						||
        if (!$pay) {
 | 
						||
            return json(['code' => 'FAIL', 'message' => '失败'], 500, ['Content-Type' => 'application/json']);
 | 
						||
        }
 | 
						||
        $payment = $paytype;
 | 
						||
        // 获取回调数据,V3和V2的回调接收不同
 | 
						||
        $data = Service::isVersionV3() ? $pay->callback() : $pay->verify();
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        Log::write('notifyx-result:'. json_encode($data));
 | 
						||
 | 
						||
        $out_trade_no = $data['out_trade_no'];
 | 
						||
        $out_refund_no = $data['out_biz_no'] ?? '';
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        // 判断是否是支付宝退款(支付宝退款成功会通知该接口)
 | 
						||
        if ($paytype == 'alipay'    // 支付宝支付
 | 
						||
            && $data['notify_type'] == 'trade_status_sync'      // 同步交易状态
 | 
						||
            && $data['trade_status'] == 'TRADE_CLOSED'          // 交易关闭
 | 
						||
            && $out_refund_no                                   // 退款单号
 | 
						||
        ) {
 | 
						||
            // 退款回调
 | 
						||
 | 
						||
//            $this->refundFinish($out_trade_no, $out_refund_no,$platform);
 | 
						||
 | 
						||
            return $pay->success()->send();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        // 判断支付宝微信是否是支付成功状态,如果不是,直接返回响应
 | 
						||
        if ($payment == 'alipay' && $data['trade_status'] != 'TRADE_SUCCESS') {
 | 
						||
            // 不是交易成功的通知,直接返回成功
 | 
						||
            return $pay->success()->send();
 | 
						||
        }
 | 
						||
        if ($payment == 'wechat' && ($data['result_code'] != 'SUCCESS' || $data['return_code'] != 'SUCCESS')) {
 | 
						||
            // 微信交易未成功,返回 false,让微信再次通知
 | 
						||
            return false;
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        try {
 | 
						||
            //微信支付V3返回和V2不同
 | 
						||
            if (Service::isVersionV3() && $paytype === 'wechat') {
 | 
						||
                $data = $data['resource']['ciphertext'];
 | 
						||
                $data['total_fee'] = $data['amount']['total'];
 | 
						||
            }
 | 
						||
 | 
						||
            \think\Log::record($data);
 | 
						||
 | 
						||
            $payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
 | 
						||
            $out_trade_no = $data['out_trade_no'];
 | 
						||
 | 
						||
            \think\Log::record("回调成功,订单号:{$out_trade_no},金额:{$payamount}");
 | 
						||
 | 
						||
            //你可以在此编写订单逻辑
 | 
						||
 | 
						||
            // 支付成功流程
 | 
						||
            //获取支付金额、订单号
 | 
						||
            $pay_fee = $payment == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
 | 
						||
 | 
						||
            //你可以在此编写订单逻辑
 | 
						||
            $order = OrderModel::getNopayOrder($out_trade_no);
 | 
						||
 | 
						||
            if (!$order || $order["status"] != '0') {
 | 
						||
                // 订单不存在,或者订单已支付
 | 
						||
                return $pay->success()->send();
 | 
						||
            }
 | 
						||
            $notify = [
 | 
						||
                'order_no' => $data['out_trade_no'],
 | 
						||
                'transaction_id' => $payment == 'alipay' ? $data['trade_no'] : $data['transaction_id'],
 | 
						||
                'notify_time' => date('Y-m-d H:i:s', strtotime($data['time_end'])),
 | 
						||
                'buyer_email' => $payment == 'alipay' ? $data['buyer_logon_id'] : $data['openid'],
 | 
						||
                'payment_json' => json_encode($data->all()),
 | 
						||
                'pay_fee' => $pay_fee,
 | 
						||
                'pay_type' => $payment,              // 支付方式
 | 
						||
                'platform' => $platform,
 | 
						||
            ];
 | 
						||
 | 
						||
            $this->model->paySuccess($order['order_no'],$notify,$pay_fee,true,true);
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        } catch (Exception $e) {
 | 
						||
            \think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error");
 | 
						||
        }
 | 
						||
 | 
						||
        //下面这句必须要执行,且在此之前不能有任何输出
 | 
						||
        if (Service::isVersionV3()) {
 | 
						||
            return $pay->success()->getBody()->getContents();
 | 
						||
        } else {
 | 
						||
            return $pay->success()->send();
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 支付返回,网页支付版本(小程序忽略)
 | 
						||
     */
 | 
						||
    public function returnx()
 | 
						||
    {
 | 
						||
        $paytype = $this->request->param('paytype');
 | 
						||
        $out_trade_no = $this->request->param('out_trade_no');
 | 
						||
        $pay = Service::checkReturn($paytype);
 | 
						||
        if (!$pay) {
 | 
						||
            $this->error('签名错误', '');
 | 
						||
        }
 | 
						||
 | 
						||
        //你可以在这里定义你的提示信息,但切记不可在此编写逻辑
 | 
						||
        $this->success("请返回网站查看支付结果", addon_url("epay/index/index"));
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
     public function notifyRefund($callback)
 | 
						||
    {
 | 
						||
        $pay = $this->getPay();
 | 
						||
 | 
						||
        try {
 | 
						||
            $data = $pay->verify(null, true); // 是的,验签就这么简单!
 | 
						||
 | 
						||
            $result = $callback($data, $pay);
 | 
						||
 | 
						||
            // Log::debug('Wechat notify', $data->all());
 | 
						||
        } catch (\Exception $e) {
 | 
						||
            // $e->getMessage();
 | 
						||
        }
 | 
						||
 | 
						||
        return $result;
 | 
						||
   }
 | 
						||
 | 
						||
 | 
						||
        /**
 | 
						||
     * 退款成功回调
 | 
						||
     */
 | 
						||
    public function notifyr()
 | 
						||
    {
 | 
						||
        Log::write('notifyreturn-comein:');
 | 
						||
 | 
						||
        $payment = $this->request->param('payment');
 | 
						||
        $platform = $this->request->param('platform');
 | 
						||
 | 
						||
            $config = Service::getConfig('wechat');
 | 
						||
 | 
						||
            $notify_url = request()->domain() . '/api/school/pay/notifyr/payment/' . $payment . '/platform/' . $platform;
 | 
						||
 | 
						||
            $config['notify_url'] = $notify_url;
 | 
						||
            $pay = \Yansongda\Pay\Pay::wechat($config);
 | 
						||
 | 
						||
        try {
 | 
						||
            $data = $pay->verify(null, true); // 是的,验签就这么简单!
 | 
						||
 | 
						||
           Log::write('notifyr-result:' . json_encode($data));
 | 
						||
 | 
						||
           $out_refund_no = $data['out_refund_no'];
 | 
						||
           $out_trade_no = $data['out_trade_no'];
 | 
						||
 | 
						||
                // 退款
 | 
						||
           $this->refundFinish($out_trade_no, $out_refund_no,$platform);
 | 
						||
 | 
						||
 | 
						||
           return $pay->success()->send();
 | 
						||
            // Log::debug('Wechat notify', $data->all());
 | 
						||
        } catch (\Exception $e) {
 | 
						||
            Log::write('notifyreturn-error:' . $e->getMessage());
 | 
						||
        }
 | 
						||
        return $pay->success()->send();
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
      private function refundFinish($out_trade_no, $out_refund_no,$platform) {
 | 
						||
 | 
						||
//        $order = Order::where('order_sn', $out_trade_no)->find();
 | 
						||
//        $refundLog = \app\admin\model\shopro\order\RefundLog::where('refund_sn', $out_refund_no)->find();
 | 
						||
//
 | 
						||
//        if (!$order || !$refundLog || $refundLog->status != 0) {
 | 
						||
//            // 订单不存在,或者订单已退款
 | 
						||
//            return true;
 | 
						||
//        }
 | 
						||
//
 | 
						||
//        $item = \app\admin\model\shopro\order\OrderItem::where('id', $refundLog->order_item_id)->find();
 | 
						||
//
 | 
						||
//        Db::transaction(function () use ($order, $item, $refundLog) {
 | 
						||
//            \app\admin\model\shopro\order\Order::refundFinish($order, $item, $refundLog);
 | 
						||
//        });
 | 
						||
        \app\common\model\school\classes\order\ServiceOrder::refundSuccess($out_refund_no,true);
 | 
						||
        return true;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
} |