|  | @@ -0,0 +1,148 @@
 | 
	
		
			
				|  |  | +<?php
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +namespace App\Libs\Pay\Merchants;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +use App\Modules\Subscribe\Services\OrderService;
 | 
	
		
			
				|  |  | +use Exception;
 | 
	
		
			
				|  |  | +use GuzzleHttp\Client;
 | 
	
		
			
				|  |  | +use Illuminate\Http\Request;
 | 
	
		
			
				|  |  | +use DB;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * 银联支付
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +class UnionPay implements PayMerchantInterface
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    private $make_order_url = 'https://qr-test2.chinaums.com/netpay-portal/webpay/pay.do';
 | 
	
		
			
				|  |  | +    private $query_order_url = 'https://qr-test2.chinaums.com/netpay-route-server/api/';
 | 
	
		
			
				|  |  | +    private $msgType = 'WXPay.jsPay';
 | 
	
		
			
				|  |  | +    private $signType = 'MD5';
 | 
	
		
			
				|  |  | +    private $mid;
 | 
	
		
			
				|  |  | +    private $tid;
 | 
	
		
			
				|  |  | +    private $instMid;
 | 
	
		
			
				|  |  | +    private $msgSrc;
 | 
	
		
			
				|  |  | +    private $msgSrcId;
 | 
	
		
			
				|  |  | +    private $key;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public function __construct(array $config)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        $this->mid = $config['mid'];
 | 
	
		
			
				|  |  | +        $this->tid = $config['tid'];
 | 
	
		
			
				|  |  | +        $this->instMid = $config['instMid'];
 | 
	
		
			
				|  |  | +        $this->msgSrc = $config['msgSrc'];
 | 
	
		
			
				|  |  | +        $this->msgSrcId = $config['msgSrcId'];
 | 
	
		
			
				|  |  | +        $this->key = $config['key'];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private function setConfig(array $config)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        $this->mid = $config['mid'];
 | 
	
		
			
				|  |  | +        $this->tid = $config['tid'];
 | 
	
		
			
				|  |  | +        $this->instMid = $config['instMid'];
 | 
	
		
			
				|  |  | +        $this->msgSrc = $config['msgSrc'];
 | 
	
		
			
				|  |  | +        $this->msgSrcId = $config['msgSrcId'];
 | 
	
		
			
				|  |  | +        $this->key = $config['key'];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public function send(array $data)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        $result = [
 | 
	
		
			
				|  |  | +            'mid' => $this->mid,
 | 
	
		
			
				|  |  | +            'tid' => $this->tid,
 | 
	
		
			
				|  |  | +            'instMid' => $this->instMid,
 | 
	
		
			
				|  |  | +            'msgSrc' => $this->msgSrc,
 | 
	
		
			
				|  |  | +            'msgSrcId' => $this->msgSrcId,
 | 
	
		
			
				|  |  | +            'msgType' => $this->msgType,
 | 
	
		
			
				|  |  | +            'signType' => $this->signType,
 | 
	
		
			
				|  |  | +            'requestTimestamp' => date('Y-m-d H:i:s'),
 | 
	
		
			
				|  |  | +            'notifyUrl' => env('UNIONPAY_NOFITY_URL'),
 | 
	
		
			
				|  |  | +            'returnUrl' => urlencode($data['pay_wait_url']),
 | 
	
		
			
				|  |  | +            'totalAmount' => $data['price'],
 | 
	
		
			
				|  |  | +            'merOrderId' => $this->msgSrcId . $data['trade_no'],
 | 
	
		
			
				|  |  | +        ];
 | 
	
		
			
				|  |  | +        $result['sign'] = $this->makeSign($result);
 | 
	
		
			
				|  |  | +        $query_params = http_build_query($result);
 | 
	
		
			
				|  |  | +        return $this->make_order_url . '?' . $query_params;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public function query($trade_no)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        $query_params = [
 | 
	
		
			
				|  |  | +            'msgType' => 'query',
 | 
	
		
			
				|  |  | +            'requestTimestamp' => date('Y-m-d H:i:s'),
 | 
	
		
			
				|  |  | +            'mid' => $this->mid,
 | 
	
		
			
				|  |  | +            'tid' => $this->tid,
 | 
	
		
			
				|  |  | +            'instMid' => $this->instMid,
 | 
	
		
			
				|  |  | +            'msgSrc' => $this->msgSrc,
 | 
	
		
			
				|  |  | +            'msgSrcId' => $this->msgSrcId,
 | 
	
		
			
				|  |  | +            'signType' => $this->signType,
 | 
	
		
			
				|  |  | +            'merOrderId' => $trade_no,
 | 
	
		
			
				|  |  | +        ];
 | 
	
		
			
				|  |  | +        $query_params['sign'] = $this->makeSign($query_params);
 | 
	
		
			
				|  |  | +        try {
 | 
	
		
			
				|  |  | +            $client = new Client(['base_uri' => $this->query_order_url, 'timeout' => 3]);
 | 
	
		
			
				|  |  | +            $result = $client->request('POST', '/mct1/payorder', ['form_params' => $query_params])->getBody()->getContents();
 | 
	
		
			
				|  |  | +            if ($result) {
 | 
	
		
			
				|  |  | +                $result = json_decode($result);
 | 
	
		
			
				|  |  | +                if ($result->errCode === 'SUCCESS' && $result->status === 'TRADE_SUCCESS') {
 | 
	
		
			
				|  |  | +                    return true;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        } catch (Exception $e) { }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public static function notify(Request $request, callable $callback)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        $data = $request->all();
 | 
	
		
			
				|  |  | +        if ($data['status'] === 'TRADE_SUCCESS') {
 | 
	
		
			
				|  |  | +            $trade_no = $data['merOrderId'];
 | 
	
		
			
				|  |  | +            if ($trade_no) {
 | 
	
		
			
				|  |  | +                $order = OrderService::getByTradeNo($trade_no);
 | 
	
		
			
				|  |  | +                $order->transaction_id = $data['targetOrderId'];
 | 
	
		
			
				|  |  | +                if ($order) {
 | 
	
		
			
				|  |  | +                    $pay_merchant = DB::table('pay_merchants')->select('appid', 'source', 'config_info')
 | 
	
		
			
				|  |  | +                        ->where('id', $order->pay_merchant_id)->where('is_enabled', 1)->first();
 | 
	
		
			
				|  |  | +                    $instance = new UnionPay(json_decode($pay_merchant->config_info, true));
 | 
	
		
			
				|  |  | +                    $sign = $instance->makeSign($data);
 | 
	
		
			
				|  |  | +                    if ($sign === $data['sign']) {
 | 
	
		
			
				|  |  | +                        if (call_user_func_array($callback, [$order])) {
 | 
	
		
			
				|  |  | +                            return 'SUCCESS';
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return 'FAILED';
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /**
 | 
	
		
			
				|  |  | +     * 生成订单号
 | 
	
		
			
				|  |  | +     */
 | 
	
		
			
				|  |  | +    public function generateTradeNo()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        return $this->msgSrcId . date("YmdHis") . substr(uniqid(), 0, 12);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private function makeSign(array $data)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        //签名步骤一:按字典序排序参数
 | 
	
		
			
				|  |  | +        ksort($data);
 | 
	
		
			
				|  |  | +        $buff = "";
 | 
	
		
			
				|  |  | +        foreach ($data as $k => $v) {
 | 
	
		
			
				|  |  | +            if ($k != "sign" && $v != "" && !is_array($v)) {
 | 
	
		
			
				|  |  | +                $buff .= $k . "=" . $v . "&";
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        $buff = trim($buff, "&");
 | 
	
		
			
				|  |  | +        //签名步骤二:在string后加入KEY
 | 
	
		
			
				|  |  | +        $string = $buff . $this->key;
 | 
	
		
			
				|  |  | +        //签名步骤三:MD5加密
 | 
	
		
			
				|  |  | +        $string = md5($string);
 | 
	
		
			
				|  |  | +        //签名步骤四:所有字符转为大写
 | 
	
		
			
				|  |  | +        $result = strtoupper($string);
 | 
	
		
			
				|  |  | +        return $result;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 |