Completed
Pull Request — master (#617)
by mingyoung
05:10
created

Payment::configForAppPayment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 10
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 15
rs 9.4285
ccs 10
cts 10
cp 1
crap 1
1
<?php
2
3
/*
4
 * This file is part of the overtrue/wechat.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
/**
13
 * Payment.php.
14
 *
15
 * @author    overtrue <[email protected]>
16
 * @copyright 2015 overtrue <[email protected]>
17
 *
18
 * @see      https://github.com/overtrue
19
 * @see      http://overtrue.me
20
 */
21
22
namespace EasyWeChat\Payment;
23
24
use EasyWeChat\Core\Exceptions\FaultException;
25
use EasyWeChat\Support\Url as UrlHelper;
26
use EasyWeChat\Support\XML;
27
use Overtrue\Socialite\AccessTokenInterface;
28
use Symfony\Component\HttpFoundation\Response;
29
30
/**
31
 * Class Payment.
32
 *
33
 * @mixin API
34
 */
35
class Payment
36
{
37
    /**
38
     * Scheme base path.
39
     */
40
    const SCHEME_PATH = 'weixin://wxpay/bizpayurl';
41
42
    /**
43
     * @var API
44
     */
45
    protected $api;
46
47
    /**
48
     * Merchant instance.
49
     *
50
     * @var \EasyWeChat\Payment\Merchant
51
     */
52
    protected $merchant;
53
54
    /**
55
     * Constructor.
56
     *
57
     * @param Merchant $merchant
58
     */
59 10
    public function __construct(Merchant $merchant)
60
    {
61 10
        $this->merchant = $merchant;
62 10
    }
63
64
    /**
65
     * Build payment scheme for product.
66
     *
67
     * @param string $productId
68
     *
69
     * @return string
70
     */
71 1
    public function scheme($productId)
72
    {
73
        $params = [
74 1
            'appid' => $this->merchant->app_id,
75 1
            'mch_id' => $this->merchant->merchant_id,
76 1
            'time_stamp' => time(),
77 1
            'nonce_str' => uniqid(),
78 1
            'product_id' => $productId,
79 1
        ];
80
81 1
        $params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
82
83 1
        return self::SCHEME_PATH.'?'.http_build_query($params);
84
    }
85
86
    /**
87
     * Handle payment notify.
88
     *
89
     * @param callable $callback
90
     *
91
     * @return Response
92
     */
93 2
    public function handleNotify(callable $callback)
94
    {
95 2
        $notify = $this->getNotify();
96
97 2
        if (!$notify->isValid()) {
98 1
            throw new FaultException('Invalid request payloads.', 400);
99
        }
100
101 1
        $notify = $notify->getNotify();
102 1
        $successful = $notify->get('result_code') === 'SUCCESS';
103
104 1
        $handleResult = call_user_func_array($callback, [$notify, $successful]);
105
106 1
        if (is_bool($handleResult) && $handleResult) {
107
            $response = [
108 1
                'return_code' => 'SUCCESS',
109 1
                'return_msg' => 'OK',
110 1
            ];
111 1
        } else {
112
            $response = [
113 1
                'return_code' => 'FAIL',
114 1
                'return_msg' => $handleResult,
115 1
            ];
116
        }
117
118 1
        return new Response(XML::build($response));
119
    }
120
121
    /**
122
     * Handle native scan notify.
123
     * https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
124
     * The callback shall return string of prepay_id or throw an exception.
125
     *
126
     * @param callable $callback
127
     *
128
     * @return Response
129
     */
130 1
    public function handleScanNotify(callable $callback)
131
    {
132 1
        $notify = $this->getNotify();
133
134 1
        if (!$notify->isValid()) {
135
            throw new FaultException('Invalid request payloads.', 400);
136
        }
137
138 1
        $notify = $notify->getNotify();
139
140
        try {
141 1
            $prepayId = call_user_func_array($callback, [$notify->get('product_id'), $notify->get('openid'), $notify]);
142
            $response = [
143 1
                'return_code' => 'SUCCESS',
144 1
                'appid' => $this->merchant->app_id,
145 1
                'mch_id' => $this->merchant->merchant_id,
146 1
                'nonce_str' => uniqid(),
147 1
                'prepay_id' => strval($prepayId),
148 1
                'result_code' => 'SUCCESS',
149 1
            ];
150 1
            $response['sign'] = generate_sign($response, $this->merchant->key);
151 1
        } catch (\Exception $e) {
152
            $response = [
153 1
                'return_code' => 'SUCCESS',
154 1
                'return_msg' => $e->getCode(),
155 1
                'result_code' => 'FAIL',
156 1
                'err_code_des' => $e->getMessage(),
157 1
            ];
158
        }
159
160 1
        return new Response(XML::build($response));
161
    }
162
163
    /**
164
     * [WeixinJSBridge] Generate js config for payment.
165
     *
166
     * <pre>
167
     * WeixinJSBridge.invoke(
168
     *  'getBrandWCPayRequest',
169
     *  ...
170
     * );
171
     * </pre>
172
     *
173
     * @param string $prepayId
174
     * @param bool   $json
175
     *
176
     * @return string|array
177
     */
178 2
    public function configForPayment($prepayId, $json = true)
179
    {
180
        $params = [
181 2
            'appId' => $this->merchant->app_id,
182 2
            'timeStamp' => strval(time()),
183 2
            'nonceStr' => uniqid(),
184 2
            'package' => "prepay_id=$prepayId",
185 2
            'signType' => 'MD5',
186 2
        ];
187
188 2
        $params['paySign'] = generate_sign($params, $this->merchant->key, 'md5');
189
190 2
        return $json ? json_encode($params) : $params;
191
    }
192
193
    /**
194
     * [JSSDK] Generate js config for payment.
195
     *
196
     * <pre>
197
     * wx.chooseWXPay({...});
198
     * </pre>
199
     *
200
     * @param string $prepayId
201
     *
202
     * @return array|string
203
     */
204 1
    public function configForJSSDKPayment($prepayId)
205
    {
206 1
        $config = $this->configForPayment($prepayId, false);
207
208 1
        $config['timestamp'] = $config['timeStamp'];
209 1
        unset($config['timeStamp']);
210
211 1
        return $config;
212
    }
213
214
    /**
215
     * Generate app payment parameters.
216
     *
217
     * @param string $prepayId
218
     *
219
     * @return array
220
     */
221 2
    public function configForAppPayment($prepayId)
222
    {
223
        $params = [
224 2
            'appid' => $this->merchant->app_id,
225 1
            'partnerid' => $this->merchant->merchant_id,
226 1
            'prepayid' => $prepayId,
227 1
            'noncestr' => uniqid(),
228 1
            'timestamp' => time(),
229 1
            'package' => 'Sign=WXPay',
230 1
        ];
231
232 1
        $params['sign'] = generate_sign($params, $this->merchant->key);
233
234 1
        return $params;
235
    }
236
237
    /**
238
     * Generate js config for share user address.
239
     *
240
     * @param string|\Overtrue\Socialite\AccessTokenInterface $accessToken
241
     * @param bool                                            $json
242
     *
243
     * @return string|array
244
     */
245 1
    public function configForShareAddress($accessToken, $json = true)
246
    {
247 1
        if ($accessToken instanceof AccessTokenInterface) {
248 1
            $accessToken = $accessToken->getToken();
249 1
        }
250
251
        $params = [
252 1
            'appId' => $this->merchant->app_id,
253 1
            'scope' => 'jsapi_address',
254 1
            'timeStamp' => strval(time()),
255 1
            'nonceStr' => uniqid(),
256 1
            'signType' => 'SHA1',
257 1
        ];
258
259
        $signParams = [
260 1
            'appid' => $params['appId'],
261 1
            'url' => UrlHelper::current(),
262 1
            'timestamp' => $params['timeStamp'],
263 1
            'noncestr' => $params['nonceStr'],
264 1
            'accesstoken' => strval($accessToken),
265 1
        ];
266
267 1
        ksort($signParams);
268
269 1
        $params['addrSign'] = sha1(urldecode(http_build_query($signParams)));
270
271 1
        return $json ? json_encode($params) : $params;
272
    }
273
274
    /**
275
     * Merchant setter.
276
     *
277
     * @param Merchant $merchant
278
     */
279 1
    public function setMerchant(Merchant $merchant)
280
    {
281 1
        $this->merchant = $merchant;
282 1
    }
283
284
    /**
285
     * Merchant getter.
286
     *
287
     * @return Merchant
288
     */
289 1
    public function getMerchant()
290
    {
291 1
        return $this->merchant;
292
    }
293
294
    /**
295
     * Return Notify instance.
296
     *
297
     * @return \EasyWeChat\Payment\Notify
298
     */
299 1
    public function getNotify()
300
    {
301 1
        return new Notify($this->merchant);
302
    }
303
304
    /**
305
     * API setter.
306
     *
307
     * @param API $api
308
     */
309 1
    public function setAPI(API $api)
310
    {
311 1
        $this->api = $api;
312 1
    }
313
314
    /**
315
     * Return API instance.
316
     *
317
     * @return API
318
     */
319 1
    public function getAPI()
320
    {
321 1
        return $this->api ?: $this->api = new API($this->getMerchant());
322
    }
323
324
    /**
325
     * Magic call.
326
     *
327
     * @param string $method
328
     * @param array  $args
329
     *
330
     * @return mixed
331
     *
332
     * @codeCoverageIgnore
333
     */
334
    public function __call($method, $args)
335
    {
336
        if (is_callable([$this->getAPI(), $method])) {
337
            return call_user_func_array([$this->api, $method], $args);
338
        }
339
    }
340
}
341