|
@@ -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;
|
|
|
+ }
|
|
|
+}
|